* Fix #16437

* Fix

* Small cleanup
This commit is contained in:
Clyybber 2021-03-06 22:35:02 +01:00 • committed by GitHub
commit 38d82795da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 36 deletions

View file

@ -222,14 +222,14 @@ proc initialized(code: ControlFlowGraph; pc: int,
inc pc inc pc
return pc return pc
proc isCursor(n: PNode; c: Con): bool = proc isCursor(n: PNode): bool =
case n.kind case n.kind
of nkSym: of nkSym:
sfCursor in n.sym.flags sfCursor in n.sym.flags
of nkDotExpr: of nkDotExpr:
isCursor(n[1], c) isCursor(n[1])
of nkCheckedFieldExpr: of nkCheckedFieldExpr:
isCursor(n[0], c) isCursor(n[0])
else: else:
false false
@ -528,23 +528,19 @@ 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 pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; res: PNode) =
# move the variable declaration to the top of the frame: # move the variable declaration to the top of the frame:
s.vars.add v.sym s.vars.add v.sym
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
res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info)) res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info))
elif sfThread notin v.sym.flags: elif sfThread notin v.sym.flags and sfCursor notin v.sym.flags:
# do not destroy thread vars for now at all for consistency. # do not destroy thread vars for now at all for consistency.
if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2) if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2)
c.graph.globalDestructors.add c.genDestroy(v) c.graph.globalDestructors.add c.genDestroy(v)
else: else:
s.final.add c.genDestroy(v) s.final.add c.genDestroy(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:
res.add moveOrCopy(v, ri, c, s, isDecl = true)
proc processScope(c: var Con; s: var Scope; ret: PNode): PNode = proc processScope(c: var Con; s: var Scope; ret: PNode): PNode =
result = newNodeI(nkStmtList, ret.info) result = newNodeI(nkStmtList, ret.info)
@ -744,7 +740,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
nkCallKinds + nkLiterals: nkCallKinds + nkLiterals:
result = p(n, c, s, consumed) result = p(n, c, s, consumed)
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
isLastRead(n, c) and not (n.kind == nkSym and isCursor(n, c)): isLastRead(n, c) and not (n.kind == nkSym and isCursor(n)):
# Sinked params can be consumed only once. We need to reset the memory # Sinked params can be consumed only once. We need to reset the memory
# to disable the destructor which we have not elided # to disable the destructor which we have not elided
result = destructiveMoveVar(n, c, s) result = destructiveMoveVar(n, c, s)
@ -850,17 +846,16 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
if it.kind == nkVarTuple and hasDestructor(c, ri.typ): if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner) let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner)
result.add p(x, c, s, consumed) result.add p(x, c, s, consumed)
elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c): elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ):
for j in 0..<it.len-2: for j in 0..<it.len-2:
let v = it[j] let v = it[j]
if v.kind == nkSym: if v.kind == nkSym:
if sfCompileTime in v.sym.flags: continue if sfCompileTime in v.sym.flags: continue
pVarTopLevel(v, c, s, ri, result) pVarTopLevel(v, c, s, result)
else: if ri.kind != nkEmpty:
if ri.kind == nkEmpty and c.inLoop > 0: result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym)
ri = genDefaultCall(v.typ, c, v.info) elif ri.kind == nkEmpty and c.inLoop > 0:
if ri.kind != nkEmpty: result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym)
result.add moveOrCopy(v, ri, c, s, isDecl = false)
else: # keep the var but transform 'ri': else: # keep the var but transform 'ri':
var v = copyNode(n) var v = copyNode(n)
var itCopy = copyNode(it) var itCopy = copyNode(it)
@ -870,8 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
v.add itCopy v.add itCopy
result.add v result.add v
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}:
not isCursor(n[0], c):
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c) cycleCheck(n, c)
assert n[1].kind notin {nkAsgn, nkFastAsgn} assert n[1].kind notin {nkAsgn, nkFastAsgn}
@ -1003,6 +997,14 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
if sameLocation(dest, ri): if sameLocation(dest, ri):
# rule (self-assignment-removal): # rule (self-assignment-removal):
result = newNodeI(nkEmpty, dest.info) result = newNodeI(nkEmpty, dest.info)
elif isCursor(dest):
case ri.kind:
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl)
# We know the result will be a stmt so we use that fact to optimize
handleNestedTempl(ri, process, willProduceStmt = true)
else:
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
else: else:
case ri.kind case ri.kind
of nkCallKinds: of nkCallKinds:
@ -1038,7 +1040,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
let snk = c.genSink(dest, ri, isDecl) let snk = c.genSink(dest, ri, isDecl)
result = newTree(nkStmtList, snk, c.genWasMoved(ri)) result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri):
# Rule 3: `=sink`(x, z); wasMoved(z) # Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(dest, ri, isDecl) let snk = c.genSink(dest, ri, isDecl)
result = newTree(nkStmtList, snk, c.genWasMoved(ri)) result = newTree(nkStmtList, snk, c.genWasMoved(ri))

View file

@ -4,7 +4,10 @@ discard """
Section: local Section: local
Param: Str Param: Str
Param: Bool Param: Bool
Param: Floats2''' Param: Floats2
destroy Foo
destroy Foo
'''
cmd: '''nim c --gc:arc $file''' cmd: '''nim c --gc:arc $file'''
""" """
@ -123,4 +126,36 @@ when isMainModule:
for p in cfg.params(s): for p in cfg.params(s):
echo " Param: " & p echo " Param: " & p
# bug #16437
type
Foo = object
FooRef = ref Foo
Bar = ref object
f: FooRef
proc `=destroy`(o: var Foo) =
echo "destroy Foo"
proc testMe(x: Bar) =
var c = (if x != nil: x.f else: nil)
assert c != nil
proc main =
var b = Bar(f: FooRef())
testMe(b)
main()
proc testMe2(x: Bar) =
var c: FooRef
c = (if x != nil: x.f else: nil)
assert c != nil
proc main2 =
var b = Bar(f: FooRef())
testMe2(b)
main2()

View file

@ -4,21 +4,18 @@ discard """
nimout: '''--expandArc: main nimout: '''--expandArc: main
var var
x_cursor
:tmpD :tmpD
:tmpD_1
:tmpD_2
try: try:
var x_cursor = ("hi", 5) x_cursor = ("hi", 5)
x_cursor = if cond: if cond:
:tmpD = ("different", 54) x_cursor = ("different", 54) else:
:tmpD else: x_cursor = ("string here", 80)
:tmpD_1 = ("string here", 80)
:tmpD_1
echo [ echo [
:tmpD_2 = `$`(x_cursor) :tmpD = `$`(x_cursor)
:tmpD_2] :tmpD]
finally: finally:
`=destroy`(:tmpD_2) `=destroy`(:tmpD)
-- end of expandArc ------------------------ -- end of expandArc ------------------------
--expandArc: sio --expandArc: sio

View file

@ -63,12 +63,13 @@ result.value = move lvalue
--expandArc: tt --expandArc: tt
var var
it_cursor
a a
:tmpD :tmpD
:tmpD_1 :tmpD_1
:tmpD_2 :tmpD_2
try: try:
var it_cursor = x it_cursor = x
a = ( a = (
wasMoved(:tmpD) wasMoved(:tmpD)
`=copy`(:tmpD, it_cursor.key) `=copy`(:tmpD, it_cursor.key)

View file

@ -3,17 +3,21 @@ discard """
cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
nimout: '''--expandArc: traverse nimout: '''--expandArc: traverse
var it_cursor = root var
it_cursor
jt_cursor
it_cursor = root
block :tmp: block :tmp:
while ( while (
not (it_cursor == nil)): not (it_cursor == nil)):
echo [it_cursor.s] echo [it_cursor.s]
it_cursor = it_cursor.ri it_cursor = it_cursor.ri
var jt_cursor = root jt_cursor = root
block :tmp_1: block :tmp_1:
while ( while (
not (jt_cursor == nil)): not (jt_cursor == nil)):
let ri_1_cursor = jt_cursor.ri var ri_1_cursor
ri_1_cursor = jt_cursor.ri
echo [jt_cursor.s] echo [jt_cursor.s]
jt_cursor = ri_1_cursor jt_cursor = ri_1_cursor
-- end of expandArc ------------------------''' -- end of expandArc ------------------------'''