Skip to content

Commit

Permalink
Fixes #5738
Browse files Browse the repository at this point in the history
  • Loading branch information
yglukhov committed Jul 14, 2017
1 parent 8b10797 commit 8bd791e
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
10 changes: 7 additions & 3 deletions lib/pure/asyncmacro.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ template createCb(retFutureSym, iteratorNameSym,
name, futureVarCompletions: untyped) =
var nameIterVar = iteratorNameSym
#{.push stackTrace: off.}
proc cb {.closure,gcsafe.} =
proc cb {.closure.} =
try:
if not nameIterVar.finished:
var next = nameIterVar()
Expand All @@ -38,7 +38,8 @@ template createCb(retFutureSym, iteratorNameSym,
"`nil` Future?"
raise newException(AssertionError, msg % name)
else:
next.callback = cb
{.gcsafe.}:
next.callback = (proc() {.closure, gcsafe.})(cb)
except:
futureVarCompletions

Expand Down Expand Up @@ -379,7 +380,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
procBody, nnkIteratorDef)
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
closureIterator.addPragma(newIdentNode("closure"))
closureIterator.addPragma(newIdentNode("gcsafe"))

# If proc has an explicit gcsafe pragma, we add it to iterator as well.
if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == "gcsafe") != nil:
closureIterator.addPragma(newIdentNode("gcsafe"))
outerProcBody.add(closureIterator)

# -> createCb(retFuture)
Expand Down
36 changes: 36 additions & 0 deletions tests/async/tasync_gcsafe.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
discard """
cmd: "nim c --threads:on $file"
output: '''
1
2
3
'''
"""

assert compileOption("threads"), "this test will not do anything useful without --threads:on"

import asyncdispatch

var globalDummy: ref int
proc gcUnsafeProc() =
if not globalDummy.isNil:
echo globalDummy[]
echo "1"

proc gcSafeAsyncProcWithNoAnnotation() {.async.} =
echo "2"

proc gcSafeAsyncProcWithAnnotation() {.gcsafe, async.} =
echo "3"

proc gcUnsafeAsyncProc() {.async.} =
# We should be able to call gcUnsafe
gcUnsafeProc()

# We should be able to call async implicitly gcsafe
await gcSafeAsyncProcWithNoAnnotation()

# We should be able to call async explicitly gcsafe
await gcSafeAsyncProcWithAnnotation()

waitFor gcUnsafeAsyncProc()
30 changes: 30 additions & 0 deletions tests/async/tasync_gcunsafe.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
discard """
cmd: "nim c --threads:on $file"
file: "asyncmacro.nim"
errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'"
"""

assert compileOption("threads"), "this test will not do anything useful without --threads:on"

import asyncdispatch

var globalDummy: ref int
proc gcUnsafeProc() =
if not globalDummy.isNil:
echo globalDummy[]

proc asyncExplicitlyGCSafeProc() {.gcsafe, async.} =
echo "hi"

proc asyncImplicitlyGCSafeProc() {.async.} =
echo "hi"

proc asyncGCUnsafeProc() {.async.} =
gcUnsafeProc()

proc anotherGCSafeAsyncProc() {.async, gcsafe.} =
# We should be able to call other gcsafe procs
await asyncExplicitlyGCSafeProc()
await asyncImplicitlyGCSafeProc()
# But we can't call gcunsafe procs
await asyncGCUnsafeProc()

0 comments on commit 8bd791e

Please sign in to comment.