fixes #15038 [backport:1.2]

This commit is contained in:
Andreas Rumpf
2020-07-25 22:29:45 +02:00
parent 624762cfb7
commit aae998feff
3 changed files with 29 additions and 46 deletions

View File

@@ -62,52 +62,6 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
proc nestedScope(parent: var Scope): Scope =
Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent))
proc optimize(s: var Scope) =
# optimize away simple 'wasMoved(x); destroy(x)' pairs.
#[ Unfortunately this optimization is only really safe when no exceptions
are possible, see for example:
proc main(inp: string; cond: bool) =
if cond:
try:
var s = ["hi", inp & "more"]
for i in 0..4:
use s
consume(s)
wasMoved(s)
finally:
destroy(x)
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
proc findCorrespondingDestroy(final: seq[PNode]; moved: PNode): int =
# remember that it's destroy(addr(x))
for i in 0 ..< final.len:
if final[i] != nil and exprStructuralEquivalent(final[i][1].skipAddr, moved, strictSymEquality = true):
return i
return -1
var removed = 0
for i in 0 ..< s.wasMoved.len:
let j = findCorrespondingDestroy(s.final, s.wasMoved[i][1])
if j >= 0:
s.wasMoved[i] = nil
s.final[j] = nil
inc removed
if removed > 0:
template filterNil(field) =
var m = newSeq[PNode](s.field.len - removed)
var mi = 0
for i in 0 ..< s.field.len:
if s.field[i] != nil:
m[mi] = s.field[i]
inc mi
assert mi == m.len
s.field = m
filterNil(wasMoved)
filterNil(final)
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode
@@ -411,6 +365,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
if not hasDestructor(n.typ):
assert n.kind != nkSym or not hasDestructor(n.sym.typ)
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)

View File

@@ -840,6 +840,8 @@ proc track(tracked: PEffects, n: PNode) =
useVar(tracked, n)
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if not hasDestructor(n.typ): n.typ = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym):
useVarNoInitCheck(tracked, n[0], n[0].sym)

View File

@@ -25,6 +25,7 @@ new line before - @['a']
new line after - @['a']
finalizer
aaaaa
hello
closed
destroying variable: 20
destroying variable: 10
@@ -293,3 +294,28 @@ proc mutstrings =
echo data
mutstrings()
# bug #15038
type
Machine = ref object
hello: string
var machineTypes: seq[tuple[factory: proc(): Machine]]
proc registerMachine(factory: proc(): Machine) =
var mCreator = proc(): Machine =
result = factory()
machineTypes.add((factory: mCreator))
proc facproc(): Machine =
result = Machine(hello: "hello")
registerMachine(facproc)
proc createMachine =
for machine in machineTypes:
echo machine.factory().hello
createMachine()