summary refs log tree commit diff stats
path: root/compiler
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 /compiler
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
Diffstat (limited to 'compiler')
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/injectdestructors.nim30
-rw-r--r--compiler/modulegraphs.nim1
3 files changed, 26 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