summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-11-29 11:55:50 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-11-29 19:46:21 +0100
commitb688250202ea479a51cbd20003e2ea2a147a3c3d (patch)
tree2eb58c4d78f3f763c6ba5ad9e506f3d6dc5089c3
parenta114a40b57086fb317ce42590db917612853a69b (diff)
downloadNim-b688250202ea479a51cbd20003e2ea2a147a3c3d.tar.gz
fixes #12766
-rw-r--r--compiler/injectdestructors.nim20
-rw-r--r--tests/destructor/const_smart_ptr.nim77
-rw-r--r--tests/destructor/tconst_smart_ptr.nim7
3 files changed, 96 insertions, 8 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 7fc2ccd78..de723b776 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -239,7 +239,7 @@ proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
 proc genWasMoved(n: PNode; c: var Con): PNode =
   result = newNodeI(nkCall, n.info)
   result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved)))
-  result.add n #mWasMoved does not take the address
+  result.add copyTree(n) #mWasMoved does not take the address
 
 proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
   result = newNodeI(nkCall, info)
@@ -401,6 +401,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
       # different and can deal with 'const string sunk into var'.
       result = passCopyToSink(arg, c)
     elif arg.kind in nkLiterals:
+      # literals are save to share accross ASTs (for now!)
       result = arg # literal to sink parameter: nothing to do
     elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure}:
       # object construction to sink parameter: nothing to do
@@ -497,19 +498,22 @@ proc p(n: PNode; c: var Con; consumed = false): PNode =
   of nkCallKinds:
     let parameters = n[0].typ
     let L = if parameters != nil: parameters.len else: 0
+    result = shallowCopy(n)
     for i in 1..<n.len:
-      n[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
-    result = n
-    if result[0].kind == nkSym and result[0].sym.magic in {mNew, mNewFinalize}:
+      result[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
+    if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
+      result[0] = copyTree(n[0])
       if c.graph.config.selectedGC in {gcHooks, gcDestructors}:
         let destroyOld = genDestroy(c, result[1])
         result = newTree(nkStmtList, destroyOld, result)
     else:
-      result[0] = pArg(result[0], c, isSink = false)
+      result[0] = pArg(n[0], c, isSink = false)
   of nkDiscardStmt: # Small optimization
+    result = shallowCopy(n)
     if n[0].kind != nkEmpty:
-      n[0] = pArg(n[0], c, false)
-    result = n
+      result[0] = pArg(n[0], c, false)
+    else:
+      result[0] = copyNode(n[0])
   of nkBracket:
     result = copyTree(n)
     for i in 0..<n.len:
@@ -580,7 +584,7 @@ proc p(n: PNode; c: var Con; consumed = false): PNode =
         result = moveOrCopy(n[0], n[1], c)
     else:
       result = copyNode(n)
-      result.add n[0]
+      result.add copyTree(n[0])
       result.add p(n[1], c)
   of nkRaiseStmt:
     if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
diff --git a/tests/destructor/const_smart_ptr.nim b/tests/destructor/const_smart_ptr.nim
new file mode 100644
index 000000000..4d8c7c9a3
--- /dev/null
+++ b/tests/destructor/const_smart_ptr.nim
@@ -0,0 +1,77 @@
+type
+  ConstPtr*[T] = object
+    val: ptr T
+
+proc `=destroy`*[T](p: var ConstPtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newConstPtr*[T](val: sink T): ConstPtr[T] {.inline.} =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertConstPtrToObj*[T](p: ConstPtr[T]): lent T =
+  result = p.val[]
+
+
+#-------------------------------------------------------------
+
+type
+  MySeqNonCopyable* = object
+    len: int
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
+
+proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeqNonCopyable): int {.inline.} = m.len
+
+proc `[]`*(m: MySeqNonCopyable; i: int): float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeqNonCopyable; i: int, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeqNonCopyable, val: float) =
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeqNonCopyable =
+  result.len = size
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+  result.setTo(initial_value)
+
+#----------------------------------------------------------------------
+
+
+proc test*(x1: int): ConstPtr[MySeqNonCopyable] {.inline.} = # remove inline here to make it work as expected
+  if x1 == 0:
+    let x = newMySeq(1, 0.0)
+    result = newConstPtr(x)
+  else:
+    let y = newMySeq(x1, 0.0)
+    result = newConstPtr(y)
+
+discard test(10)
diff --git a/tests/destructor/tconst_smart_ptr.nim b/tests/destructor/tconst_smart_ptr.nim
new file mode 100644
index 000000000..39fe12612
--- /dev/null
+++ b/tests/destructor/tconst_smart_ptr.nim
@@ -0,0 +1,7 @@
+discard """
+  action: "compile"
+"""
+
+import const_smart_ptr
+
+discard test(0)