This commit is contained in:
Araq
2020-07-07 23:59:13 +02:00
committed by Andreas Rumpf
parent b17e1efc67
commit cdce245a23
2 changed files with 51 additions and 4 deletions

View File

@@ -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..<n.len-1:
result.add p(n[i], c, s, normal)
result.add maybeVoid(n[^1], s)
markEscapingVars(n[^1], s)
of nkCaseStmt:
result = copyNode(n)
@@ -630,6 +659,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
for j in 0 ..< it.len-1:
branch[j] = copyTree(it[j])
var ofScope = nestedScope(s)
markEscapingVars(it[^1], ofScope)
let ofResult = maybeVoid(it[^1], ofScope)
branch[^1] = toTree(ofScope, ofResult, treeFlags)
result.add branch
@@ -650,6 +680,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
if alwaysStmt: result.typ = nil
result.add n[0]
var bodyScope = nestedScope(s)
markEscapingVars(n[1], bodyScope)
let bodyResult = processCall(n[1], bodyScope)
result.add toTree(bodyScope, bodyResult, treeFlags)
rememberParent(s, bodyScope)
@@ -667,6 +698,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars})
branchScope.parent = addr(s)
markEscapingVars(it[^1], branchScope)
var branchResult = processCall(it[^1], branchScope)
branch[^1] = toTree(branchScope, branchResult, treeFlags)
result.add branch
@@ -676,6 +708,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
result = copyNode(n)
if alwaysStmt: result.typ = nil
var tryScope = nestedScope(s)
markEscapingVars(n[0], tryScope)
var tryResult = maybeVoid(n[0], tryScope)
result.add toTree(tryScope, tryResult, treeFlags)
rememberParent(s, tryScope)

View File

@@ -88,3 +88,17 @@ proc ifexpr(i, a, b: int) {.compilerproc, noinline.} =
else: "index " & $i & " not in " & $a & " .. " & $b)
ifexpr(2, 0, 1)
# bug #14899
template toSeq(): untyped =
block:
var result = @[1]
result
proc clItems(s: seq[int]) =
assert s.len == 1
proc escapeCheck =
clItems(toSeq())
escapeCheck()