summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/injectdestructors.nim31
-rw-r--r--tests/destructor/tgcdestructors.nim11
-rw-r--r--tests/destructor/tnewruntime_strutils.nim3
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 =