diff options
-rw-r--r-- | compiler/injectdestructors.nim | 42 | ||||
-rw-r--r-- | tests/arc/tcursor_on_localvar.nim | 37 | ||||
-rw-r--r-- | tests/arc/topt_cursor.nim | 19 | ||||
-rw-r--r-- | tests/arc/topt_no_cursor.nim | 3 | ||||
-rw-r--r-- | tests/arc/topt_refcursors.nim | 10 |
5 files changed, 75 insertions, 36 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 846dcdf5d..8cfd14cc4 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -222,14 +222,14 @@ proc initialized(code: ControlFlowGraph; pc: int, inc pc return pc -proc isCursor(n: PNode; c: Con): bool = +proc isCursor(n: PNode): bool = case n.kind of nkSym: sfCursor in n.sym.flags of nkDotExpr: - isCursor(n[1], c) + isCursor(n[1]) of nkCheckedFieldExpr: - isCursor(n[0], c) + isCursor(n[0]) else: false @@ -528,23 +528,19 @@ proc cycleCheck(n: PNode; c: var Con) = message(c.graph.config, n.info, warnCycleCreated, msg) 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: s.vars.add v.sym if isUnpackedTuple(v): if c.inLoop > 0: # unpacked tuple needs reset at every loop iteration 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. if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2) c.graph.globalDestructors.add c.genDestroy(v) else: 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 = result = newNodeI(nkStmtList, ret.info) @@ -744,7 +740,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = nkCallKinds + nkLiterals: result = p(n, c, s, consumed) 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 # to disable the destructor which we have not elided 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): let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner) 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: let v = it[j] if v.kind == nkSym: if sfCompileTime in v.sym.flags: continue - pVarTopLevel(v, c, s, ri, result) - else: - if ri.kind == nkEmpty and c.inLoop > 0: - ri = genDefaultCall(v.typ, c, v.info) - if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, s, isDecl = false) + pVarTopLevel(v, c, s, result) + if ri.kind != nkEmpty: + result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym) + elif ri.kind == nkEmpty and c.inLoop > 0: + result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) @@ -870,8 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = v.add itCopy result.add v of nkAsgn, nkFastAsgn: - if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and - not isCursor(n[0], c): + if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}: if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: cycleCheck(n, c) 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): # rule (self-assignment-removal): 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: case ri.kind 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) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) 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) let snk = c.genSink(dest, ri, isDecl) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) diff --git a/tests/arc/tcursor_on_localvar.nim b/tests/arc/tcursor_on_localvar.nim index 81b48271f..0f53c5efa 100644 --- a/tests/arc/tcursor_on_localvar.nim +++ b/tests/arc/tcursor_on_localvar.nim @@ -4,7 +4,10 @@ discard """ Section: local Param: Str Param: Bool - Param: Floats2''' + Param: Floats2 +destroy Foo +destroy Foo +''' cmd: '''nim c --gc:arc $file''' """ @@ -123,4 +126,36 @@ when isMainModule: for p in cfg.params(s): 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() diff --git a/tests/arc/topt_cursor.nim b/tests/arc/topt_cursor.nim index 300402094..5c35b454f 100644 --- a/tests/arc/topt_cursor.nim +++ b/tests/arc/topt_cursor.nim @@ -4,21 +4,18 @@ discard """ nimout: '''--expandArc: main var + x_cursor :tmpD - :tmpD_1 - :tmpD_2 try: - var x_cursor = ("hi", 5) - x_cursor = if cond: - :tmpD = ("different", 54) - :tmpD else: - :tmpD_1 = ("string here", 80) - :tmpD_1 + x_cursor = ("hi", 5) + if cond: + x_cursor = ("different", 54) else: + x_cursor = ("string here", 80) echo [ - :tmpD_2 = `$`(x_cursor) - :tmpD_2] + :tmpD = `$`(x_cursor) + :tmpD] finally: - `=destroy`(:tmpD_2) + `=destroy`(:tmpD) -- end of expandArc ------------------------ --expandArc: sio diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index dbfcff52b..f1eb8575a 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -63,12 +63,13 @@ result.value = move lvalue --expandArc: tt var + it_cursor a :tmpD :tmpD_1 :tmpD_2 try: - var it_cursor = x + it_cursor = x a = ( wasMoved(:tmpD) `=copy`(:tmpD, it_cursor.key) diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim index 372fc18bf..f097150a3 100644 --- a/tests/arc/topt_refcursors.nim +++ b/tests/arc/topt_refcursors.nim @@ -3,17 +3,21 @@ discard """ cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' nimout: '''--expandArc: traverse -var it_cursor = root +var + it_cursor + jt_cursor +it_cursor = root block :tmp: while ( not (it_cursor == nil)): echo [it_cursor.s] it_cursor = it_cursor.ri -var jt_cursor = root +jt_cursor = root block :tmp_1: while ( 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] jt_cursor = ri_1_cursor -- end of expandArc ------------------------''' |