fixes #21171; dynamic acyclic refs need to use dyn decRef (#21184)

* fixes #21171; dyn destructors for acyclic inherited  refs

* add a test

* Update compiler/liftdestructors.nim
This commit is contained in:
ringabout
2022-12-28 23:23:37 +08:00
committed by GitHub
parent 7a74c2dc3a
commit 4b63ac4b87
3 changed files with 97 additions and 0 deletions

View File

@@ -609,6 +609,11 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
# dynamic Acyclic refs need to use dyn decRef
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, x)
@@ -632,6 +637,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
elif isInheritableAcyclicRef:
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
cond.typ = getSysType(c.g, x.info, tyBool)

View File

@@ -485,6 +485,19 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
#if cell.color == colPurple:
rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[])
proc nimDecRefIsLastDyn(p: pointer): bool {.compilerRtl, inl.} =
if p != nil:
var cell = head(p)
if (cell.rc and not rcMask) == 0:
result = true
#cprintf("[DESTROY] %p\n", p)
else:
dec cell.rc, rcIncrement
#if cell.color == colPurple:
if result:
if cell.rootIdx > 0:
unregisterCycle(cell)
proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
if p != nil:
var cell = head(p)

77
tests/arc/t21184.nim Normal file
View File

@@ -0,0 +1,77 @@
discard """
matrix: "--mm:orc"
"""
import std/[with]
type
Node* {.acyclic.} = ref object of RootObj
name: string
data: pointer
children: seq[Node]
TextNode = ref object of Node
text: string
proc fakeEcho(s: string) =
if s.len < 0:
echo s
proc newNode[T: Node](parent: Node): T =
new result
result.data = alloc0(250)
parent.children.add(result)
proc newRootNode(): Node =
new result
result.data = alloc0(250)
method printNode(node: Node) {.base.} =
fakeEcho node.name
method printNode(node: TextNode) =
procCall printNode(Node(node))
fakeEcho node.text
proc printChildren(node: Node) =
for child in node.children:
child.printNode()
printChildren(child)
proc free(node: Node) =
for child in node.children:
free(child)
dealloc(node.data)
template node(parent: Node, body: untyped): untyped =
var node = newNode[Node](parent)
with node:
body
proc textNode(parent: Node, text: string) =
var node = newNode[TextNode](parent)
node.text = text
template withRootNode(body: untyped): untyped =
var root = newRootNode()
root.name = "root"
with root:
body
root.printNode()
printChildren(root)
root.free()
proc doTest() =
withRootNode:
node:
name = "child1"
node:
name = "child2"
node:
name = "child3"
textNode "Hello, world!"
# bug #21171
if isMainModule:
for i in 0..100000:
doTest()