summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2017-12-15 11:21:49 +0100
committerAraq <rumpf_a@web.de>2017-12-15 11:21:49 +0100
commita5e4d2f7a3afdf4e068ae5e6c48392a29c0e8ced (patch)
tree432ed41b3f691259bcc5064e492f90830a66b173
parent196977f623c3e3384e943c08cb85e6e0ded31109 (diff)
downloadNim-a5e4d2f7a3afdf4e068ae5e6c48392a29c0e8ced.tar.gz
fixes #668
-rw-r--r--compiler/aliases.nim8
-rw-r--r--compiler/ccgexprs.nim22
-rw-r--r--tests/ccgbugs/tobjconstr_bad_aliasing.nim26
3 files changed, 51 insertions, 5 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
index c0371e159..cd7e7f19a 100644
--- a/compiler/aliases.nim
+++ b/compiler/aliases.nim
@@ -179,5 +179,11 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
           result = isPartOf(a[0], b)
           if result == arNo: result = arMaybe
       else: discard
+    of nkObjConstr:
+      result = arNo
+      for i in 1..<b.len:
+        let res = isPartOf(a, b[i][1])
+        if res != arNo:
+          result = res
+          if res == arYes: break
     else: discard
-
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 5f107f21f..1505052cc 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1236,18 +1236,32 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   else:
     genAssignment(p, d, tmp, {})
 
+proc lhsDoesAlias(a, b: PNode): bool =
+  for y in b:
+    if isPartOf(a, y) != arNo: return true
+
 proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
-  var arr: TLoc
-  if d.k == locNone:
+  var arr, tmp: TLoc
+  # bug #668
+  let doesAlias = lhsDoesAlias(d.lode, n)
+  let dest = if doesAlias: addr(tmp) else: addr(d)
+  if doesAlias:
+    getTemp(p, n.typ, tmp)
+  elif d.k == locNone:
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
-  genNewSeqAux(p, d, intLiteral(sonsLen(n)))
+  genNewSeqAux(p, dest[], intLiteral(sonsLen(n)))
   for i in countup(0, sonsLen(n) - 1):
     initLoc(arr, locExpr, n[i], OnHeap)
-    arr.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
+    arr.r = rfmt(nil, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
     arr.storage = OnHeap            # we know that sequences are on the heap
     expr(p, n[i], arr)
   gcUsage(n)
+  if doesAlias:
+    if d.k == locNone:
+      d = tmp
+    else:
+      genAssignment(p, d, tmp, {})
 
 proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
   var elem, a, arr: TLoc
diff --git a/tests/ccgbugs/tobjconstr_bad_aliasing.nim b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
new file mode 100644
index 000000000..ea51ecacb
--- /dev/null
+++ b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''(10, (20, ))'''
+"""
+
+import strutils, sequtils
+
+# bug #668
+
+type
+  TThing = ref object
+    data: int
+    children: seq[TThing]
+
+proc `$`(t: TThing): string =
+  result = "($1, $2)" % @[$t.data, join(map(t.children, proc(th: TThing): string = $th), ", ")]
+
+proc somethingelse(): seq[TThing] =
+  result = @[TThing(data: 20, children: @[])]
+
+proc dosomething(): seq[TThing] =
+  result = somethingelse()
+
+  result = @[TThing(data: 10, children: result)]
+
+when isMainModule:
+  echo($dosomething()[0])