fixes #14899
This commit is contained in:
parent
b17e1efc67
commit
cdce245a23
2 changed files with 51 additions and 4 deletions
|
|
@ -37,6 +37,9 @@ type
|
||||||
final: seq[PNode] # finally section
|
final: seq[PNode] # finally section
|
||||||
needsTry: bool
|
needsTry: bool
|
||||||
parent: ptr Scope
|
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 =
|
proc nestedScope(parent: var Scope): Scope =
|
||||||
Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent))
|
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, "=")
|
checkForErrorPragma(c, t, ri, "=")
|
||||||
result = genCopyNoCheck(c, dest, ri)
|
result = genCopyNoCheck(c, dest, ri)
|
||||||
|
|
||||||
proc addTopVar(c: var Con; s: var Scope; v: PNode) =
|
proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope =
|
||||||
s.vars.add v.sym
|
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 =
|
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)
|
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)
|
message(c.graph.config, n.info, warnCycleCreated, msg)
|
||||||
break
|
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) =
|
proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) =
|
||||||
# move the variable declaration to the top of the frame:
|
# move the variable declaration to the top of the frame:
|
||||||
c.addTopVar s, v
|
let owningScope = c.addTopVar(s, v)
|
||||||
if isUnpackedTuple(v):
|
if isUnpackedTuple(v):
|
||||||
if c.inLoop > 0:
|
if c.inLoop > 0:
|
||||||
# unpacked tuple needs reset at every loop iteration
|
# 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:
|
if sfGlobal in v.sym.flags and s.parent == nil:
|
||||||
c.graph.globalDestructors.add genDestroy(c, v)
|
c.graph.globalDestructors.add genDestroy(c, v)
|
||||||
else:
|
else:
|
||||||
s.final.add genDestroy(c, v)
|
owningScope[].final.add genDestroy(c, v)
|
||||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||||
res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true)
|
res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true)
|
||||||
elif ri.kind != nkEmpty:
|
elif ri.kind != nkEmpty:
|
||||||
|
|
@ -617,6 +645,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
for i in 0..<n.len-1:
|
for i in 0..<n.len-1:
|
||||||
result.add p(n[i], c, s, normal)
|
result.add p(n[i], c, s, normal)
|
||||||
result.add maybeVoid(n[^1], s)
|
result.add maybeVoid(n[^1], s)
|
||||||
|
markEscapingVars(n[^1], s)
|
||||||
|
|
||||||
of nkCaseStmt:
|
of nkCaseStmt:
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
|
|
@ -630,6 +659,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
for j in 0 ..< it.len-1:
|
for j in 0 ..< it.len-1:
|
||||||
branch[j] = copyTree(it[j])
|
branch[j] = copyTree(it[j])
|
||||||
var ofScope = nestedScope(s)
|
var ofScope = nestedScope(s)
|
||||||
|
markEscapingVars(it[^1], ofScope)
|
||||||
let ofResult = maybeVoid(it[^1], ofScope)
|
let ofResult = maybeVoid(it[^1], ofScope)
|
||||||
branch[^1] = toTree(ofScope, ofResult, treeFlags)
|
branch[^1] = toTree(ofScope, ofResult, treeFlags)
|
||||||
result.add branch
|
result.add branch
|
||||||
|
|
@ -650,6 +680,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
if alwaysStmt: result.typ = nil
|
if alwaysStmt: result.typ = nil
|
||||||
result.add n[0]
|
result.add n[0]
|
||||||
var bodyScope = nestedScope(s)
|
var bodyScope = nestedScope(s)
|
||||||
|
markEscapingVars(n[1], bodyScope)
|
||||||
let bodyResult = processCall(n[1], bodyScope)
|
let bodyResult = processCall(n[1], bodyScope)
|
||||||
result.add toTree(bodyScope, bodyResult, treeFlags)
|
result.add toTree(bodyScope, bodyResult, treeFlags)
|
||||||
rememberParent(s, bodyScope)
|
rememberParent(s, bodyScope)
|
||||||
|
|
@ -667,6 +698,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars})
|
branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars})
|
||||||
|
|
||||||
branchScope.parent = addr(s)
|
branchScope.parent = addr(s)
|
||||||
|
markEscapingVars(it[^1], branchScope)
|
||||||
var branchResult = processCall(it[^1], branchScope)
|
var branchResult = processCall(it[^1], branchScope)
|
||||||
branch[^1] = toTree(branchScope, branchResult, treeFlags)
|
branch[^1] = toTree(branchScope, branchResult, treeFlags)
|
||||||
result.add branch
|
result.add branch
|
||||||
|
|
@ -676,6 +708,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
if alwaysStmt: result.typ = nil
|
if alwaysStmt: result.typ = nil
|
||||||
var tryScope = nestedScope(s)
|
var tryScope = nestedScope(s)
|
||||||
|
markEscapingVars(n[0], tryScope)
|
||||||
var tryResult = maybeVoid(n[0], tryScope)
|
var tryResult = maybeVoid(n[0], tryScope)
|
||||||
result.add toTree(tryScope, tryResult, treeFlags)
|
result.add toTree(tryScope, tryResult, treeFlags)
|
||||||
rememberParent(s, tryScope)
|
rememberParent(s, tryScope)
|
||||||
|
|
|
||||||
|
|
@ -88,3 +88,17 @@ proc ifexpr(i, a, b: int) {.compilerproc, noinline.} =
|
||||||
else: "index " & $i & " not in " & $a & " .. " & $b)
|
else: "index " & $i & " not in " & $a & " .. " & $b)
|
||||||
|
|
||||||
ifexpr(2, 0, 1)
|
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()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue