diff options
author | Clyybber <darkmine956@gmail.com> | 2019-05-13 08:28:33 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-05-13 08:28:33 +0200 |
commit | 0c869eaa475caab9558aaf5b39b8e3519388f811 (patch) | |
tree | 6a1ee425e34f811c6e82cd6e48145465dad3a7d5 | |
parent | a3e27ffa2c721b2ef3b0481d7db5c45039072050 (diff) | |
download | Nim-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.nim | 3 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 30 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 1 | ||||
-rw-r--r-- | tests/destructor/objFile.nim | 8 | ||||
-rw-r--r-- | tests/destructor/texplicit_move.nim | 1 | ||||
-rw-r--r-- | tests/destructor/tglobaldestructor.nim | 9 | ||||
-rw-r--r-- | tests/destructor/topt.nim | 1 |
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 |