diff options
-rw-r--r-- | compiler/injectdestructors.nim | 21 | ||||
-rw-r--r-- | tests/destructor/tdangingref_simple.nim | 32 |
2 files changed, 50 insertions, 3 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 0ea04c638..c2d135e86 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -338,10 +338,23 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = addrExp.add(dest) result = newTree(nkCall, newSymNode(op), addrExp) +when false: + proc preventMoveRef(dest, ri: PNode): bool = + let lhs = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + var ri = ri + if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mUnown: + ri = ri[1] + let rhs = ri.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + result = lhs.kind == tyRef and rhs.kind == tyOwned + +proc canBeMoved(t: PType): bool {.inline.} = + let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) + result = t.kind != tyRef and t.attachedOps[attachedSink] != nil + proc genSink(c: Con; t: PType; dest, ri: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) let k = if t.attachedOps[attachedSink] != nil: attachedSink - else: attachedAsgn + else: attachedAsgn if t.attachedOps[k] != nil: result = genOp(c, t, k, dest, ri) else: @@ -659,7 +672,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = var snk = genSink(c, dest.typ, dest, ri) snk.add ri result = newTree(nkStmtList, snk, genWasMoved(ri, c)) - elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c): + elif ri.sym.kind != skParam and ri.sym.owner == c.owner and + isLastRead(ri, c) and canBeMoved(dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) var snk = genSink(c, dest.typ, dest, ri) snk.add ri @@ -691,7 +705,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = result = genCopy(c, dest.typ, dest, ri) result.add p(ri, c) else: - if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c): + if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and + canBeMoved(dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) var snk = genSink(c, dest.typ, dest, ri) snk.add ri diff --git a/tests/destructor/tdangingref_simple.nim b/tests/destructor/tdangingref_simple.nim new file mode 100644 index 000000000..279581b0f --- /dev/null +++ b/tests/destructor/tdangingref_simple.nim @@ -0,0 +1,32 @@ +discard """ + output: '''a +[FATAL] dangling references exist +''' + exitCode: 1 + cmd: "nim c --newruntime $file" +""" + +# bug #11350 + +type + Node = ref object + data: int + +proc use(x: Node) = discard + +proc main = + var x = Node(data: 3) # inferred to be an ``owned ref`` + var dangling = unown x + assert dangling.data == 3 + #use x + #dangling = nil + # reassignment causes the memory of what ``x`` points to to be freed: + echo "a" + x = Node(data: 4) + echo "b" + # accessing 'dangling' here is invalid as it is nil. + # at scope exit the memory of what ``x`` points to is freed + if dangling != nil: + echo dangling.data + +main() |