diff options
-rw-r--r-- | compiler/injectdestructors.nim | 31 | ||||
-rw-r--r-- | tests/destructor/tgcdestructors.nim | 11 | ||||
-rw-r--r-- | tests/destructor/tnewruntime_strutils.nim | 3 |
3 files changed, 40 insertions, 5 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b9fa1e3ae..dd71e2dfb 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -450,6 +450,25 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = result.add newTree(nkAsgn, tmp, p(n, c)) result.add tmp +proc isDangerousSeq(t: PType): bool {.inline.} = + let t = t.skipTypes(abstractInst) + result = t.kind == tySequence and tfHasOwned notin t.sons[0].flags + +proc containsConstSeq(n: PNode): bool = + if n.kind == nkBracket and n.len > 0 and n.typ != nil and isDangerousSeq(n.typ): + return true + result = false + case n.kind + of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv: + result = containsConstSeq(n[1]) + of nkObjConstr, nkClosure: + for i in 1 ..< n.len: + if containsConstSeq(n[i]): return true + of nkCurly, nkBracket, nkPar, nkTupleConstr: + for i in 0 ..< n.len: + if containsConstSeq(n[i]): return true + else: discard + proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = template pArgIfTyped(argPart: PNode): PNode = # typ is nil if we are in if/case expr branch with noreturn @@ -466,7 +485,12 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = result.add arg[0] for i in 1..<arg.len: result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i])) - elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkTripleStrLit}: + elif arg.containsConstSeq: + # const sequences are not mutable and so we need to pass a copy to the + # sink parameter (bug #11524). Note that the string implemenation is + # different and can deal with 'const string sunk into var'. + result = passCopyToSink(arg, c) + elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkCharLit..nkTripleStrLit}: discard "object construction to sink parameter: nothing to do" result = arg elif arg.kind == nkSym and isSinkParam(arg.sym): @@ -595,7 +619,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = result.add branch of nkBracket: # array constructor - result = genSink(c, dest.typ, dest, ri) + if ri.len > 0 and isDangerousSeq(ri.typ): + result = genCopy(c, dest.typ, dest, ri) + else: + result = genSink(c, dest.typ, dest, ri) let ri2 = copyTree(ri) for i in 0..<ri.len: # everything that is passed to an array constructor is consumed, diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index bc9f57d20..e0f973ecc 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -6,7 +6,8 @@ ha @["arg", "asdfklasdfkl", "asdkfj", "dfasj", "klfjl"] @[1, 2, 3] @["red", "yellow", "orange", "rtrt1", "pink"] -30 30''' +a: @[4, 2, 3] +35 35''' """ import allocators @@ -169,6 +170,14 @@ proc testWarm = testWarm() +proc mutConstSeq() = + # bug #11524 + var a = @[1,2,3] + a[0] = 4 + echo "a: ", a + +mutConstSeq() + #echo s let (a, d) = allocCounters() discard cprintf("%ld %ld\n", a, d) diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 5b8684354..c77177f58 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -1,6 +1,6 @@ discard """ cmd: '''nim c --newruntime $file''' - output: '''442 442''' + output: '''443 443''' """ import strutils, os @@ -10,7 +10,6 @@ import system / ansi_c # bug #11004 proc retTuple(): (seq[int], int) = - # XXX this doesn't allocate yet but probably it should return (@[1], 1) proc nonStaticTests = |