From 0803b532f44fc7b0039e31187af76e36828ca89d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 10 Oct 2018 21:00:45 +0200 Subject: fixes #9263 --- compiler/destroyer.nim | 142 ++++++++++++++++++++++++------------------- tests/destructor/tmatrix.nim | 117 +++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 62 deletions(-) create mode 100644 tests/destructor/tmatrix.nim diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 599d97c22..56cc02171 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -282,8 +282,6 @@ template recurse(n, dest) = proc isSinkParam(s: PSym): bool {.inline.} = result = s.kind == skParam and s.typ.kind == tySink -const constrExprs = nkCallKinds+{nkObjConstr} - proc destructiveMoveSink(n: PNode; c: var Con): PNode = # generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam) result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -299,39 +297,6 @@ proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = result.add(newSymNode(createMagic(c.graph, magicname, m))) result.add n -proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = - if ri.kind in constrExprs: - result = genSink(c, dest.typ, dest, ri) - # watch out and no not transform 'ri' twice if it's a call: - let ri2 = copyNode(ri) - recurse(ri, ri2) - result.add ri2 - elif ri.kind == nkSym and ri.sym.kind != skParam and isHarmlessVar(ri.sym, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = genSink(c, dest.typ, dest, ri) - snk.add p(ri, c) - result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) - elif ri.kind == nkSym and isSinkParam(ri.sym): - result = genSink(c, dest.typ, dest, ri) - result.add destructiveMoveSink(ri, c) - else: - result = genCopy(c, dest.typ, dest, ri) - result.add p(ri, c) - -proc passCopyToSink(n: PNode; c: var Con): PNode = - result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let tmp = getTemp(c, n.typ, n.info) - if hasDestructor(n.typ): - var m = genCopy(c, n.typ, tmp, n) - m.add p(n, c) - result.add m - message(c.graph.config, n.info, hintPerformance, - ("passing '$1' to a sink parameter introduces an implicit copy; " & - "use 'move($1)' to prevent it") % $n) - else: - result.add newTree(nkAsgn, tmp, p(n, c)) - result.add tmp - proc genWasMoved(n: PNode; c: var Con): PNode = # The mWasMoved builtin does not take the address. result = genMagicCall(n, c, "wasMoved", mWasMoved) @@ -355,6 +320,83 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = result.add genWasMoved(n, c) result.add tempAsNode +proc passCopyToSink(n: PNode; c: var Con): PNode = + result = newNodeIT(nkStmtListExpr, n.info, n.typ) + let tmp = getTemp(c, n.typ, n.info) + if hasDestructor(n.typ): + var m = genCopy(c, n.typ, tmp, n) + m.add p(n, c) + result.add m + message(c.graph.config, n.info, hintPerformance, + ("passing '$1' to a sink parameter introduces an implicit copy; " & + "use 'move($1)' to prevent it") % $n) + else: + result.add newTree(nkAsgn, tmp, p(n, c)) + result.add tmp + +proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = + if isSink: + if arg.kind in nkCallKinds: + # recurse but skip the call expression in order to prevent + # destructor injections: Rule 5.1 is different from rule 5.4! + let a = copyNode(arg) + recurse(arg, a) + result = a + elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}: + discard "object construction to sink parameter: nothing to do" + result = arg + elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isHarmlessVar(arg.sym, c): + # if x is a variable and it its last read we eliminate its + # destructor invokation, but don't. We need to reset its memory + # to disable its destructor which we have not elided: + result = destructiveMoveVar(arg, c) + elif arg.kind == nkSym and isSinkParam(arg.sym): + # mark the sink parameter as used: + result = destructiveMoveSink(arg, c) + else: + # an object that is not temporary but passed to a 'sink' parameter + # results in a copy. + result = passCopyToSink(arg, c) + else: + result = p(arg, c) + +proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = + case ri.kind + of nkCallKinds: + result = genSink(c, dest.typ, dest, ri) + # watch out and no not transform 'ri' twice if it's a call: + let ri2 = copyNode(ri) + let parameters = ri[0].typ + let L = if parameters != nil: parameters.len else: 0 + ri2.add ri[0] + for i in 1..