diff options
-rw-r--r-- | compiler/dfa.nim | 39 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 10 | ||||
-rw-r--r-- | tests/destructor/tobjfield_analysis.nim | 34 |
3 files changed, 60 insertions, 23 deletions
diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0072c9410..45e1aaffe 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -567,19 +567,36 @@ proc genReturn(c: var Con; n: PNode) = const InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp} - PathKinds* = {nkDotExpr, nkCheckedFieldExpr, + PathKinds0 = {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, - nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv} + nkObjDownConv, nkObjUpConv} + PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv} + +proc getRoot(n: PNode): PNode = + result = n + while true: + case result.kind + of PathKinds0: + result = result[0] + of PathKinds1: + result = result[1] + else: break + +proc skipConvDfa*(n: PNode): PNode = + result = n + while true: + case result.kind + of nkObjDownConv, nkObjUpConv: + result = result[0] + of PathKinds1: + result = result[1] + else: break proc genUse(c: var Con; orig: PNode) = - var n = orig - var iters = 0 - while n.kind in PathKinds: - n = n[0] - inc iters + let n = dfa.getRoot(orig) if n.kind == nkSym and n.sym.kind in InterestingSyms: - c.code.add Instr(n: orig, kind: use, sym: if iters > 0: nil else: n.sym) + c.code.add Instr(n: orig, kind: use, sym: if orig != n: nil else: n.sym) proc aliases(obj, field: PNode): bool = var n = field @@ -729,7 +746,7 @@ proc gen(c: var Con; n: PNode) = # "uses" 'i'. But we are only talking about builtin array indexing so # it doesn't matter and 'x = 34' is NOT a usage of 'x'. genDef(c, n[0]) - of PathKinds: + of PathKinds0 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}: genUse(c, n) of nkIfStmt, nkIfExpr: genIf(c, n) of nkWhenStmt: @@ -746,8 +763,8 @@ proc gen(c: var Con; n: PNode) = nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr: for x in n: gen(c, x) of nkPragmaBlock: gen(c, n.lastSon) - of nkDiscardStmt: gen(c, n.sons[0]) - of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast: + of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n.sons[0]) + of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv: gen(c, n.sons[1]) of nkStringToCString, nkCStringToString: gen(c, n.sons[0]) of nkVarSection, nkLetSection: genVarSection(c, n) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 4bcc38cb3..5958d89ae 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -195,15 +195,17 @@ proc isLastRead(n: PNode; c: var Con): bool = # first we need to search for the instruction that belongs to 'n': c.otherRead = nil var instr = -1 + let m = dfa.skipConvDfa(n) + for i in 0..<c.g.len: # This comparison is correct and MUST not be ``instrTargets``: - if c.g[i].kind == use and c.g[i].n == n: + if c.g[i].kind == use and c.g[i].n == m: if instr < 0: instr = i break dbg: - echo "starting point for ", n, " is ", instr + echo "starting point for ", n, " is ", instr, " ", n.kind if instr < 0: return false # we go through all paths beginning from 'instr+1' and need to @@ -625,7 +627,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = result = genCopy(c, dest.typ, dest, ri) result.add p(ri, c) of nkHiddenSubConv, nkHiddenStdConv: - if ri[1].kind in movableNodeKinds: + if sameType(ri.typ, ri[1].typ): + result = moveOrCopy(dest, ri[1], c) + elif ri[1].kind in movableNodeKinds: result = moveOrCopy(dest, ri[1], c) var b = newNodeIT(ri.kind, ri.info, ri.typ) b.add ri[0] # add empty node diff --git a/tests/destructor/tobjfield_analysis.nim b/tests/destructor/tobjfield_analysis.nim index 24cf02aee..83f394c3b 100644 --- a/tests/destructor/tobjfield_analysis.nim +++ b/tests/destructor/tobjfield_analysis.nim @@ -2,30 +2,46 @@ discard """ output: '''works''' """ +# bug #11095 + type - MyVal = object - f: ptr float + MyVal[T] = object + f: ptr T -proc `=destroy`(x: var MyVal) = +proc `=destroy`[T](x: var MyVal[T]) = if x.f != nil: dealloc(x.f) -proc `=sink`(x1: var MyVal, x2: Myval) = +proc `=sink`[T](x1: var MyVal[T], x2: MyVal[T]) = if x1.f != x2.f: `=destroy`(x1) x1.f = x2.f -proc `=`(x1: var MyVal, x2: Myval) {.error.} +proc `=`[T](x1: var MyVal[T], x2: MyVal[T]) {.error.} -proc newVal(x: float): MyVal = - result.f = create(float) +proc newVal[T](x: sink T): MyVal[T] = + result.f = create(T) result.f[] = x -proc sinkMe(x: sink MyVal) = +proc set[T](x: var MyVal[T], val: T) = + x.f[] = val + +proc sinkMe[T](x: sink MyVal[T]) = discard +var flag = false + proc main = - var y = (newVal(3.0), newVal(4.0)) + var y = case flag + of true: + var x1 = newVal[float](1.0) + var x2 = newVal[float](2.0) + (newVal(x1), newVal(x2)) + + of false: + var x1 = newVal[float](1.0) + var x2 = newVal[float](2.0) + (newVal(x1), newVal(x2)) sinkMe y[0] sinkMe y[1] |