summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/core/seqs.nim27
-rw-r--r--tests/destructor/tgcdestructors.nim22
2 files changed, 40 insertions, 9 deletions
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index a79f0c2f5..5483c0ebc 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -104,6 +104,10 @@ proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
 proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
     compilerRtl, noSideEffect, raises: [].} =
   {.noSideEffect.}:
+    template `+!`(p: pointer, s: int): pointer =
+      cast[pointer](cast[int](p) +% s)
+
+    const headerSize = sizeof(int) + sizeof(Allocator)
     if addlen <= 0:
       result = p
     elif p == nil:
@@ -112,14 +116,23 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
       # Note: this means we cannot support things that have internal pointers as
       # they get reallocated here. This needs to be documented clearly.
       var p = cast[ptr PayloadBase](p)
-      let allocator = if p.allocator == nil: getLocalAllocator() else: p.allocator
       let cap = max(resize(p.cap), len+addlen)
-      var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
-        sizeof(int) + sizeof(Allocator) + elemSize * p.cap,
-        sizeof(int) + sizeof(Allocator) + elemSize * cap))
-      q.allocator = allocator
-      q.cap = cap
-      result = q
+      if p.allocator == nil:
+        let allocator = getLocalAllocator()
+        var q = cast[ptr PayloadBase](allocator.alloc(allocator,
+          headerSize + elemSize * cap))
+        copyMem(q +! headerSize, p +! headerSize, len * elemSize)
+        q.allocator = allocator
+        q.cap = cap
+        result = q
+      else:
+        let allocator = p.allocator
+        var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
+          headerSize + elemSize * p.cap,
+          headerSize + elemSize * cap))
+        q.allocator = allocator
+        q.cap = cap
+        result = q
 
 proc shrink*[T](x: var seq[T]; newLen: Natural) =
   mixin `=destroy`
diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim
index c0a88e650..bc9f57d20 100644
--- a/tests/destructor/tgcdestructors.nim
+++ b/tests/destructor/tgcdestructors.nim
@@ -5,7 +5,8 @@ ho
 ha
 @["arg", "asdfklasdfkl", "asdkfj", "dfasj", "klfjl"]
 @[1, 2, 3]
-25 25'''
+@["red", "yellow", "orange", "rtrt1", "pink"]
+30 30'''
 """
 
 import allocators
@@ -139,7 +140,7 @@ type
   Obj* = object
     f*: seq[int]
 
-method main(o: Obj) =
+method main(o: Obj) {.base.} =
   for newb in o.f:
     discard
 
@@ -151,6 +152,23 @@ proc testforNoMove =
 
 testforNoMove()
 
+# bug #11065
+type
+  Warm = seq[string]
+
+proc testWarm =
+  var w: Warm
+  w = @["red", "yellow", "orange"]
+
+  var x = "rt"
+  var y = "rt1"
+  w.add(x & y)
+
+  w.add("pink")
+  echo w
+
+testWarm()
+
 #echo s
 let (a, d) = allocCounters()
 discard cprintf("%ld %ld\n", a, d)