mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-02 01:48:00 +00:00
fixes #15038 [backport:1.2]
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user