summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-07-27 23:27:20 +0200
committerGitHub <noreply@github.com>2020-07-27 23:27:20 +0200
commite6f0d4a5a59f8230133481d25ce1c3f6e8daf0a5 (patch)
tree4a5081869ac285012a06851fd2a74cbdd0a4b8ad /compiler
parent377f71676629d5621d052e662996d30323ea3bee (diff)
downloadNim-e6f0d4a5a59f8230133481d25ce1c3f6e8daf0a5.tar.gz
fixes #15076 (#15095)
Diffstat (limited to 'compiler')
-rw-r--r--compiler/injectdestructors.nim33
-rw-r--r--compiler/liftdestructors.nim2
-rw-r--r--compiler/sempass2.nim29
3 files changed, 36 insertions, 28 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 231ece0ce..fa960b5cf 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -48,6 +48,13 @@ type
 
 const toDebug {.strdefine.} = ""
 
+proc hasDestructor(c: Con; t: PType): bool {.inline.} =
+  result = ast.hasDestructor(t)
+  when toDebug.len > 0:
+    # for more effective debugging
+    if not result and c.graph.config.selectedGC in {gcArc, gcOrc}:
+      assert(not containsGarbageCollectedRef(t))
+
 template dbg(body) =
   when toDebug.len > 0:
     if c.owner.name.s == toDebug or toDebug == "always":
@@ -330,7 +337,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
   let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le
   let objType = leDotExpr[0].typ
 
-  if hasDestructor(objType):
+  if hasDestructor(c, objType):
     if objType.attachedOps[attachedDestructor] != nil and
         sfOverriden in objType.attachedOps[attachedDestructor].flags:
       localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor.
@@ -364,8 +371,8 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
 
 proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
   # generate: (let tmp = v; reset(v); tmp)
-  if not hasDestructor(n.typ):
-    assert n.kind != nkSym or not hasDestructor(n.sym.typ)
+  if not hasDestructor(c, n.typ):
+    assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
     result = copyTree(n)
   else:
     result = newNodeIT(nkStmtListExpr, n.info, n.typ)
@@ -393,7 +400,7 @@ proc isCapturedVar(n: PNode): bool =
 proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let tmp = c.getTemp(s, n.typ, n.info)
-  if hasDestructor(n.typ):
+  if hasDestructor(c, n.typ):
     result.add c.genWasMoved(tmp)
     var m = c.genCopy(tmp, n)
     m.add p(n, c, s, normal)
@@ -432,7 +439,7 @@ proc containsConstSeq(n: PNode): bool =
 proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
   # it can happen that we need to destroy expression contructors
   # like [], (), closures explicitly in order to not leak them.
-  if arg.typ != nil and hasDestructor(arg.typ):
+  if arg.typ != nil and hasDestructor(c, arg.typ):
     # produce temp creation for (fn, env). But we need to move 'env'?
     # This was already done in the sink parameter handling logic.
     result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
@@ -521,7 +528,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
   # tricky because you would have to intercept moveOrCopy at a certain point
   let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
   tmp.sym.flags.incl sfSingleUsedTemp
-  let cpy = if ret.typ.hasDestructor:
+  let cpy = if hasDestructor(c, ret.typ):
               moveOrCopy(tmp, ret, c, s, isDecl = true)
             else:
               newTree(nkFastAsgn, tmp, p(ret, c, s, normal))
@@ -774,10 +781,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
       result = newNodeI(nkStmtList, n.info)
       for it in n:
         var ri = it[^1]
-        if it.kind == nkVarTuple and hasDestructor(ri.typ):
+        if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
           let x = lowerTupleUnpacking(c.graph, it, c.owner)
           result.add p(x, c, s, consumed)
-        elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0], c):
+        elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c):
           for j in 0..<it.len-2:
             let v = it[j]
             if v.kind == nkSym:
@@ -797,7 +804,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
           v.add itCopy
           result.add v
     of nkAsgn, nkFastAsgn:
-      if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
+      if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
           not isCursor(n[0], c):
         # rule (self-assignment-removal):
         if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
@@ -828,7 +835,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
       result = shallowCopy(n)
       for i in 0 ..< n.len:
         result[i] = p(n[i], c, s, normal)
-      if n.typ != nil and hasDestructor(n.typ):
+      if n.typ != nil and hasDestructor(c, n.typ):
         if mode == normal:
           result = ensureDestruction(result, n, c, s)
 
@@ -858,7 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
       result[0] = p(n[0], c, s, normal)
       for i in 1 ..< n.len:
         result[i] = n[i]
-      if mode == sinkArg and hasDestructor(n.typ):
+      if mode == sinkArg and hasDestructor(c, n.typ):
         if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c):
           s.wasMoved.add c.genWasMoved(n)
         else:
@@ -868,7 +875,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
       result = shallowCopy(n)
       for i in 0 ..< n.len:
         result[i] = p(n[i], c, s, normal)
-      if mode == sinkArg and hasDestructor(n.typ):
+      if mode == sinkArg and hasDestructor(c, n.typ):
         if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c):
           # consider 'a[(g; destroy(g); 3)]', we want to say 'wasMoved(a[3])'
           # without the junk, hence 'c.genWasMoved(n)'
@@ -1004,7 +1011,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     let params = owner.typ.n
     for i in 1..<params.len:
       let t = params[i].sym.typ
-      if isSinkTypeForParam(t) and hasDestructor(t.skipTypes({tySink})):
+      if isSinkTypeForParam(t) and hasDestructor(c, t.skipTypes({tySink})):
         scope.final.add c.genDestroy(params[i])
   #if optNimV2 in c.graph.config.globalOptions:
   #  injectDefaultCalls(n, c)
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 034e62494..1e6b552e2 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -507,6 +507,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   var actions = newNodeI(nkStmtList, c.info)
   let elemType = t.lastSon
 
+  createTypeBoundOps(c.g, c.c, elemType, c.info)
+
   if isFinal(elemType):
     addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
     actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index e9dcc7d8a..ab360ab95 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -84,6 +84,19 @@ proc `<=`(a, b: TLockLevel): bool {.borrow.}
 proc `==`(a, b: TLockLevel): bool {.borrow.}
 proc max(a, b: TLockLevel): TLockLevel {.borrow.}
 
+proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
+  if typ == nil: return
+  when false:
+    let realType = typ.skipTypes(abstractInst)
+    if realType.kind == tyRef and
+        optSeqDestructors in tracked.config.globalOptions:
+      createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
+
+  createTypeBoundOps(tracked.graph, tracked.c, typ, info)
+  if (tfHasAsgn in typ.flags) or
+      optSeqDestructors in tracked.config.globalOptions:
+    tracked.owner.flags.incl sfInjectDestructors
+
 proc isLocalVar(a: PEffects, s: PSym): bool =
   # and (s.kind != skParam or s.typ.kind == tyOut)
   s.kind in {skVar, skResult} and sfGlobal notin s.flags and
@@ -400,6 +413,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
           if b[j].isInfixAs():
             assert(b[j][1].kind == nkType)
             catches(tracked, b[j][1].typ)
+            createTypeBoundOps(tracked, b[j][2].typ, b[j][2].info)
           else:
             assert(b[j].kind == nkType)
             catches(tracked, b[j].typ)
@@ -720,20 +734,6 @@ proc checkRange(c: PEffects; value: PNode; typ: PType) =
     checkLe(c, lowBound, value)
     checkLe(c, value, highBound)
 
-proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
-  if typ == nil: return
-  let realType = typ.skipTypes(abstractInst)
-  when false:
-    # XXX fix this in liftdestructors instead
-    if realType.kind == tyRef and
-        optSeqDestructors in tracked.config.globalOptions:
-      createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
-
-  createTypeBoundOps(tracked.graph, tracked.c, typ, info)
-  if (tfHasAsgn in typ.flags) or
-      optSeqDestructors in tracked.config.globalOptions:
-    tracked.owner.flags.incl sfInjectDestructors
-
 proc trackCall(tracked: PEffects; n: PNode) =
   template gcsafeAndSideeffectCheck() =
     if notGcSafe(op) and not importedFromC(a):
@@ -799,7 +799,6 @@ proc trackCall(tracked: PEffects; n: PNode) =
 
     # check required for 'nim check':
     if n[1].typ.len > 0:
-      createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
       createTypeBoundOps(tracked, n[1].typ, n.info)
       # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?