summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/liftdestructors.nim9
-rw-r--r--tests/destructor/towned_binary_tree.nim92
2 files changed, 96 insertions, 5 deletions
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 5fbf86071..2dcaa7984 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -126,7 +126,7 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
 
 proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
   result = optNimV2 in c.graph.config.globalOptions and
-    (tfHasGCedMem in t.flags or t.isGCedMem)
+    ({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
 
 proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
                         field: var PSym): bool =
@@ -171,7 +171,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
     body.add newAsgnCall(c.graph, op, x, y)
     result = true
 
-proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool =
+proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) =
   var op = t.destructor
   if op == nil and useNoGc(c, t):
     op = produceSym(c.c, t, attachedDestructor, c.info)
@@ -182,7 +182,6 @@ proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool =
     markUsed(c.graph.config, c.info, op, c.graph.usageSym)
     onUse(c.info, op)
     body.add destructorCall(c.graph, op, x)
-    result = true
   elif useNoGc(c, t):
     internalError(c.graph.config, c.info,
       "type-bound operator could not be resolved")
@@ -365,10 +364,10 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   #var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x)
 
   if isFinal(elemType):
-    discard addDestructorCall(c, elemType, actions, genDeref(x))
+    addDestructorCall(c, elemType, actions, genDeref(x))
     actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x)
   else:
-    discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x))
+    addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x))
     actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x)
 
   case c.kind
diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim
new file mode 100644
index 000000000..372b1d3d8
--- /dev/null
+++ b/tests/destructor/towned_binary_tree.nim
@@ -0,0 +1,92 @@
+discard """
+  cmd: '''nim c --newruntime $file'''
+  output: '''331665
+allocs 0'''
+"""
+
+#  bug #11053
+
+import random
+
+type Node = ref object
+  x, y: int32
+  left, right: owned Node
+
+proc newNode(x: int32): owned Node =
+  result = Node(x: x, y: rand(high int32).int32)
+
+proc merge(lower, greater: owned Node): owned Node =
+  if lower.isNil:
+    result = greater
+  elif greater.isNil:
+    result = lower
+  elif lower.y < greater.y:
+    lower.right = merge(lower.right, greater)
+    result = lower
+  else:
+    greater.left = merge(lower, greater.left)
+    result = greater
+
+proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) =
+  if orig.isNil:
+    result = (nil, nil)
+  elif orig.x < value:
+    let splitPair = splitBinary(orig.right, value)
+    orig.right = splitPair[0]
+    result = (orig, splitPair[1])
+  else:
+    let splitPair = splitBinary(orig.left, value)
+    orig.left = splitPair[1]
+    result = (splitPair[0], orig)
+
+proc merge3(lower, equal, greater: owned Node): owned Node =
+  merge(merge(lower, equal), greater)
+
+proc split(orig: owned Node, value: int32): tuple[lower, equal, greater: owned Node] =
+  let
+    (lower, equalGreater) = splitBinary(orig, value)
+    (equal, greater) = splitBinary(equalGreater, value + 1)
+  result = (lower, equal, greater)
+
+type Tree = object
+  root: owned Node
+
+proc hasValue(self: var Tree, x: int32): bool =
+  let splited = split(move self.root, x)
+  result = not splited.equal.isNil
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc insert(self: var Tree, x: int32) =
+  var splited = split(move self.root, x)
+  if splited.equal.isNil:
+    splited.equal = newNode(x)
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc erase(self: var Tree, x: int32) =
+  let splited = split(move self.root, x)
+  self.root = merge(splited.lower, splited.greater)
+
+proc main() =
+  var
+    tree = Tree()
+    cur = 5'i32
+    res = 0
+
+  for i in 1 ..< 1000000:
+    let a = i mod 3
+    cur = (cur * 57 + 43) mod 10007
+    case a:
+    of 0:
+      tree.insert(cur)
+    of 1:
+      tree.erase(cur)
+    of 2:
+      if tree.hasValue(cur):
+        res += 1
+    else:
+      discard
+  echo res
+
+when isMainModule:
+  main()
+  echo "allocs ", allocs