Skip to content

Commit

Permalink
Fixes #5738
Browse files Browse the repository at this point in the history
  • Loading branch information
yglukhov committed Jul 6, 2017
1 parent ee43fc8 commit fc75a8b
Show file tree
Hide file tree
Showing 3 changed files with 70 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 = cast[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()
27 changes: 27 additions & 0 deletions tests/async/tasync_gcunsafe.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
discard """
cmd: "nim c --threads:on $file"
file: "asyncmacro.nim"
errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'gcUnsafeProc'"
"""

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 anotherGCSafeAsyncProc() {.async, gcsafe.} =
# We should be able to call other gcsafe procs
await asyncExplicitlyGCSafeProc()
await asyncImplicitlyGCSafeProc()
# But we can't call gcunsafe procs
gcUnsafeProc()

0 comments on commit fc75a8b

Please sign in to comment.