summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorClyybber <darkmine956@gmail.com>2019-05-13 08:28:33 +0200
committerAndreas Rumpf <rumpf_a@web.de>2019-05-13 08:28:33 +0200
commit0c869eaa475caab9558aaf5b39b8e3519388f811 (patch)
tree6a1ee425e34f811c6e82cd6e48145465dad3a7d5
parenta3e27ffa2c721b2ef3b0481d7db5c45039072050 (diff)
downloadNim-0c869eaa475caab9558aaf5b39b8e3519388f811.tar.gz
Fix destructor injections for global variables (#11230)
* attach global destructors at end of mainModule
* Add testcase
* Minor cleanup
* Inject topLevelVar temporaries' destructors early
* Fix megatest
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/injectdestructors.nim30
-rw-r--r--compiler/modulegraphs.nim1
-rw-r--r--tests/destructor/objFile.nim8
-rw-r--r--tests/destructor/texplicit_move.nim1
-rw-r--r--tests/destructor/tglobaldestructor.nim9
-rw-r--r--tests/destructor/topt.nim1
7 files changed, 45 insertions, 8 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index c46c846d2..dc653a260 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1963,6 +1963,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   result = n
   if b == nil: return
   var m = BModule(b)
+  if sfMainModule in m.module.flags:
+    for destructorCall in graph.globalDestructors:
+      n.add destructorCall
   if passes.skipCodegen(m.config, n): return
   # if the module is cached, we don't regenerate the main proc
   # nor the dispatchers? But if the dispatchers changed?
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index db2d9a4f2..a02621aa3 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -316,10 +316,6 @@ proc makePtrType(c: Con, baseType: PType): PType =
   result = newType(tyPtr, c.owner)
   addSonSkipIntLit(result, baseType)
 
-proc addDestroy(c: var Con; n: PNode) =
-  # append to front:
-  c.destroys = newTree(nkStmtList, n, c.destroys)
-
 proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
   var op = t.attachedOps[kind]
 
@@ -738,7 +734,7 @@ proc p(n: PNode; c: var Con): PNode =
             c.addTopVar v
             # make sure it's destroyed at the end of the proc:
             if not isUnpackedTuple(it[0].sym):
-              c.addDestroy genDestroy(c, v.typ, v)
+              c.destroys.add genDestroy(c, v.typ, v)
           if ri.kind != nkEmpty:
             let r = moveOrCopy(v, ri, c)
             result.add r
@@ -757,7 +753,7 @@ proc p(n: PNode; c: var Con): PNode =
       sinkExpr.add n
       result.add sinkExpr
       result.add tmp
-      c.addDestroy genDestroy(c, n.typ, tmp)
+      c.destroys.add genDestroy(c, n.typ, tmp)
     else:
       result = n
   of nkAsgn, nkFastAsgn:
@@ -799,6 +795,19 @@ proc p(n: PNode; c: var Con): PNode =
     result = copyNode(n)
     recurse(n, result)
 
+proc extractDestroysForTemporaries(c: Con, destroys: PNode): PNode =
+  result = newNodeI(nkStmtList, destroys.info)
+  for i in 0 ..< destroys.len:
+    if destroys[i][1][0].sym.kind == skTemp:
+      result.add destroys[i]
+      destroys[i] = c.emptyNode
+
+proc reverseDestroys(destroys: PNode) =
+  var reversed: seq[PNode]
+  for i in countdown(destroys.len - 1, 0):
+    reversed.add(destroys[i])
+  destroys.sons = reversed
+
 proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
   if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n
   var c: Con
@@ -821,7 +830,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     for i in 1 ..< params.len:
       let param = params[i].sym
       if isSinkTypeForParam(param.typ) and hasDestructor(param.typ.skipTypes({tySink})):
-        c.addDestroy genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
+        c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
 
   #if optNimV2 in c.graph.config.globalOptions:
   #  injectDefaultCalls(n, c)
@@ -830,7 +839,12 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
   if c.topLevelVars.len > 0:
     result.add c.topLevelVars
   if c.destroys.len > 0:
-    result.add newTryFinally(body, c.destroys)
+    reverseDestroys(c.destroys)
+    if owner.kind == skModule:
+      result.add newTryFinally(body, extractDestroysForTemporaries(c, c.destroys))
+      g.globalDestructors.add c.destroys
+    else:
+      result.add newTryFinally(body, c.destroys)
   else:
     result.add body
 
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 1ed939e7b..16fd70d18 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -71,6 +71,7 @@ type
     onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
     onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
     onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    globalDestructors*: seq[PNode]
 
   TPassContext* = object of RootObj # the pass's context
   PPassContext* = ref TPassContext
diff --git a/tests/destructor/objFile.nim b/tests/destructor/objFile.nim
new file mode 100644
index 000000000..436c090d1
--- /dev/null
+++ b/tests/destructor/objFile.nim
@@ -0,0 +1,8 @@
+type Obj* = object
+  v*: int
+
+proc `=destroy`(this: var Obj) =
+  echo "igotdestroyed"
+  this.v = -1
+
+var test* = Obj(v: 42)
diff --git a/tests/destructor/texplicit_move.nim b/tests/destructor/texplicit_move.nim
index 230f0b133..93795af42 100644
--- a/tests/destructor/texplicit_move.nim
+++ b/tests/destructor/texplicit_move.nim
@@ -6,6 +6,7 @@ discard """
 10
 destroyed!
 '''
+joinable: false
 """
 
 type
diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim
new file mode 100644
index 000000000..403f670a0
--- /dev/null
+++ b/tests/destructor/tglobaldestructor.nim
@@ -0,0 +1,9 @@
+discard """
+  cmd: '''nim c --newruntime $file'''
+  output: '''(v: 42)
+igotdestroyed'''
+"""
+
+import objFile
+
+echo test
diff --git a/tests/destructor/topt.nim b/tests/destructor/topt.nim
index 829500f8a..3851a4283 100644
--- a/tests/destructor/topt.nim
+++ b/tests/destructor/topt.nim
@@ -3,6 +3,7 @@ discard """
   output: '''5
 vseq destroy
 '''
+joinable: false
 """
 type
   opt*[T] = object