From cdce245a235f3a8c255d0f782bc088546343b6ed Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Jul 2020 23:59:13 +0200 Subject: fixes #14899 --- compiler/injectdestructors.nim | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'compiler') diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index e57898ae8..291cd36aa 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -37,6 +37,9 @@ type final: seq[PNode] # finally section needsTry: bool parent: ptr Scope + escapingSyms: IntSet # a construct like (block: let x = f(); x) + # means that 'x' escapes. We then destroy it + # in the parent's scope (and also allocate it there). proc nestedScope(parent: var Scope): Scope = Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) @@ -400,8 +403,11 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode = checkForErrorPragma(c, t, ri, "=") result = genCopyNoCheck(c, dest, ri) -proc addTopVar(c: var Con; s: var Scope; v: PNode) = - s.vars.add v.sym +proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope = + result = addr(s) + while v.sym.id in result.escapingSyms and result.parent != nil: + result = result.parent + result[].vars.add v.sym proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) @@ -584,9 +590,31 @@ proc cycleCheck(n: PNode; c: var Con) = message(c.graph.config, n.info, warnCycleCreated, msg) break +proc markEscapingVars(n: PNode; s: var Scope) = + case n.kind + of nkSym: + s.escapingSyms.incl n.sym.id + of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref, + nkAddr, nkHiddenAddr, nkStringToCString, nkCStringToString, nkObjDownConv, + nkObjUpConv: + markEscapingVars(n[0], s) + of nkCast, nkHiddenSubConv, nkHiddenStdConv, nkConv: + markEscapingVars(n[1], s) + of nkTupleConstr, nkBracket, nkPar, nkClosure: + for i in 0 ..< n.len: + markEscapingVars(n[i], s) + of nkObjConstr: + for i in 1 ..< n.len: + markEscapingVars(n[i], s) + of nkStmtList, nkStmtListExpr: + if n.len > 0: + markEscapingVars(n[^1], s) + else: + discard "no arbitrary tree traversal here" + proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = # move the variable declaration to the top of the frame: - c.addTopVar s, v + let owningScope = c.addTopVar(s, v) if isUnpackedTuple(v): if c.inLoop > 0: # unpacked tuple needs reset at every loop iteration @@ -596,7 +624,7 @@ proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = if sfGlobal in v.sym.flags and s.parent == nil: c.graph.globalDestructors.add genDestroy(c, v) else: - s.final.add genDestroy(c, v) + owningScope[].final.add genDestroy(c, v) if ri.kind == nkEmpty and c.inLoop > 0: res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) elif ri.kind != nkEmpty: @@ -617,6 +645,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) = for i in 0..