Skip to content

Commit

Permalink
fixes #19401; fixes #19402; rework Forward declaration and finalizer …
Browse files Browse the repository at this point in the history
…for ORC (#20295)

* fixes #19401; fixes #19402; rework Forward declaration and finalizer for ORC

* add more tests

* give it a name

* make more tests

* fixes tests

* hidden addr for cpp

* move code to a function
  • Loading branch information
ringabout authored Sep 27, 2022
1 parent 3d2f0e2 commit 80e739f
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 24 deletions.
72 changes: 48 additions & 24 deletions compiler/semmagic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,53 @@ proc semOld(c: PContext; n: PNode): PNode =
localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s)
result = n

proc semNewFinalize(c: PContext; n: PNode): PNode =
# Make sure the finalizer procedure refers to a procedure
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
elif optTinyRtti in c.config.globalOptions:
let nfin = skipConvCastAndClosure(n[^1])
let fin = case nfin.kind
of nkSym: nfin.sym
of nkLambda, nkDo: nfin[namePos].sym
else:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
nil
if fin != nil:
if fin.kind notin {skProc, skFunc}:
# calling convention is checked in codegen
localError(c.config, n.info, "finalizer must be a direct reference to a proc")

# check if we converted this finalizer into a destructor already:
let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and getAttachedOp(c.graph, t, attachedDestructor) != nil and
getAttachedOp(c.graph, t, attachedDestructor).owner == fin:
discard "already turned this one into a finalizer"
else:
if sfForward in fin.flags:
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), nextSymId c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, nextSymId c.idgen))
wrapperSym.flags.incl sfUsed
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
params = nkFormalParams.newTree(c.graph.emptyNode,
newTree(nkIdentDefs, selfSymNode, fin.ast[paramsPos][1][1], c.graph.emptyNode)
),
name = newSymNode(wrapperSym), pattern = c.graph.emptyNode,
genericParams = c.graph.emptyNode, pragmas = c.graph.emptyNode, exceptions = c.graph.emptyNode), {})
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
transFormedSym.owner = fin
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
let origParamType = transFormedSym.ast[bodyPos][1].typ
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
bindTypeHook(c, transFormedSym, n, attachedDestructor)
else:
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
result = n

proc semPrivateAccess(c: PContext, n: PNode): PNode =
let t = n[1].typ[0].toObjectFromRefPtrGeneric
c.currentScope.allowPrivateAccess.add t.sym
Expand Down Expand Up @@ -513,30 +560,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
else:
result = plugin(c, n)
of mNewFinalize:
# Make sure the finalizer procedure refers to a procedure
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
elif optTinyRtti in c.config.globalOptions:
let nfin = skipConvCastAndClosure(n[^1])
let fin = case nfin.kind
of nkSym: nfin.sym
of nkLambda, nkDo: nfin[namePos].sym
else:
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
nil
if fin != nil:
if fin.kind notin {skProc, skFunc}:
# calling convention is checked in codegen
localError(c.config, n.info, "finalizer must be a direct reference to a proc")

# check if we converted this finalizer into a destructor already:
let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and getAttachedOp(c.graph, t, attachedDestructor) != nil and
getAttachedOp(c.graph, t, attachedDestructor).owner == fin:
discard "already turned this one into a finalizer"
else:
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
result = n
result = semNewFinalize(c, n)
of mDestroy:
result = n
let t = n[1].typ.skipTypes(abstractVar)
Expand Down
32 changes: 32 additions & 0 deletions tests/arc/t19401.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
discard """
output: '''
delete foo
delete foo
delete foo
'''
matrix: "--mm:arc"
"""

type Foo = ref object
data: int
proc delete(self: Foo)
proc newFoo: Foo =
let x = 12
discard x
new(result, delete)
result.data = x
proc delete(self: Foo) =
doAssert self.data == 12
echo("delete foo")

if isMainModule:
proc test() =
let x1 = newFoo()
let x2 = newFoo()
discard x1
discard x2
var x3: Foo
new(x3, delete)
x3.data = 12
discard x3
test()
32 changes: 32 additions & 0 deletions tests/arc/t19402.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
discard """
output: '''
delete foo
delete foo
delete foo
'''
matrix: "--mm:arc"
"""

type Foo = ref object of RootObj
data: int
proc delete(self: Foo)
proc newFoo: Foo =
let x = 12
discard x
new(result, delete)
result.data = x
proc delete(self: Foo) =
doAssert self.data == 12
echo("delete foo")

if isMainModule:
proc test() =
let x1 = newFoo()
let x2 = newFoo()
discard x1
discard x2
var x3: Foo
new(x3, delete)
x3.data = 12
discard x3
test()

0 comments on commit 80e739f

Please sign in to comment.