summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/sempass2.nim37
-rw-r--r--tests/arc/torcmisc.nim32
2 files changed, 57 insertions, 12 deletions
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index e66c9596a..e124baf26 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -77,6 +77,7 @@ type
     config: ConfigRef
     graph: ModuleGraph
     c: PContext
+    escapingParams: IntSet
   PEffects = var TEffects
 
 proc `<`(a, b: TLockLevel): bool {.borrow.}
@@ -900,6 +901,25 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
     localError(tracked.config, pragma.info,
         "invalid pragma block: " & $pragma)
 
+proc trackInnerProc(tracked: PEffects, n: PNode) =
+  case n.kind
+  of nkSym:
+    let s = n.sym
+    if s.kind == skParam and s.owner == tracked.owner:
+      tracked.escapingParams.incl s.id
+  of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
+    discard
+  of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo:
+    if n[0].kind == nkSym and n[0].sym.ast != nil:
+      trackInnerProc(tracked, getBody(tracked.graph, n[0].sym))
+  of nkTypeSection, nkMacroDef, nkTemplateDef, nkError,
+     nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
+     nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
+     nkTypeOfExpr, nkMixinStmt, nkBindStmt:
+    discard
+  else:
+    for ch in n: trackInnerProc(tracked, ch)
+
 proc track(tracked: PEffects, n: PNode) =
   case n.kind
   of nkSym:
@@ -1095,8 +1115,10 @@ proc track(tracked: PEffects, n: PNode) =
     track(tracked, n.lastSon)
     unapplyBlockContext(tracked, bc)
 
-  of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
-      nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
+  of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo:
+    if n[0].kind == nkSym and n[0].sym.ast != nil:
+      trackInnerProc(tracked, getBody(tracked.graph, n[0].sym))
+  of nkTypeSection, nkMacroDef, nkTemplateDef:
     discard
   of nkCast:
     if n.len == 2:
@@ -1259,15 +1281,6 @@ proc hasRealBody(s: PSym): bool =
   ## which is not a real implementation, refs #14314
   result = {sfForward, sfImportc} * s.flags == {}
 
-proc maybeWrappedInClosure(tracked: PEffects; t: PType): bool {.inline.} =
-  ## The spec does say when to produce destructors. However, the spec
-  ## was written in mind with the idea that "lambda lifting" already
-  ## happened. Not true in our implementation, so we need to workaround
-  ## here:
-  result = tracked.isInnerProc and
-    sfSystemModule notin tracked.c.module.flags and
-    tfCheckedForDestructor notin t.flags and containsGarbageCollectedRef(t)
-
 proc trackProc*(c: PContext; s: PSym, body: PNode) =
   let g = c.graph
   var effects = s.typ.n[0]
@@ -1287,7 +1300,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
       let typ = param.typ
       if isSinkTypeForParam(typ) or
           (t.config.selectedGC in {gcArc, gcOrc} and
-            (isClosure(typ.skipTypes(abstractInst)) or maybeWrappedInClosure(t, typ))):
+            (isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
         createTypeBoundOps(t, typ, param.info)
       when false:
         if typ.kind == tyOut and param.id notin t.init:
diff --git a/tests/arc/torcmisc.nim b/tests/arc/torcmisc.nim
index 20dd18fb3..e41ad7c77 100644
--- a/tests/arc/torcmisc.nim
+++ b/tests/arc/torcmisc.nim
@@ -32,3 +32,35 @@ when true:
   waitFor hello(Flags())
   echo "success"
 
+# bug #18240
+import tables
+
+type
+  TopicHandler* = proc(topic: string,
+                       data: seq[byte]): Future[void] {.gcsafe, raises: [Defect].}
+
+  PeerID* = object
+    data*: seq[byte]
+
+  PeerInfo* = ref object of RootObj
+    peerId*: PeerID
+
+  Connection* = ref object of RootObj
+    peerInfo*: PeerInfo
+
+  PubSubPeer* = ref object of RootObj
+    codec*: string
+
+  PubSub* = ref object of RootObj
+    topics*: Table[string, seq[TopicHandler]]
+    peers*: Table[PeerID, PubSubPeer]
+
+proc getOrCreatePeer*(myParam: PubSub, peerId: PeerID, protos: seq[string]): PubSubPeer =
+  myParam.peers.withValue(peerId, peer):
+    return peer[]
+
+method handleConn*(myParam: PubSub,
+                  conn: Connection,
+                  proto: string) {.base, async.} =
+  myParam.peers.withValue(conn.peerInfo.peerId, peer):
+    let peerB = peer[]