* 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
This commit is contained in:
parent
3d2f0e2c7c
commit
80e739f2bf
3 changed files with 112 additions and 24 deletions
|
|
@ -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)
|
localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s)
|
||||||
result = n
|
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 =
|
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
||||||
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
||||||
c.currentScope.allowPrivateAccess.add t.sym
|
c.currentScope.allowPrivateAccess.add t.sym
|
||||||
|
|
@ -513,30 +560,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
else:
|
else:
|
||||||
result = plugin(c, n)
|
result = plugin(c, n)
|
||||||
of mNewFinalize:
|
of mNewFinalize:
|
||||||
# Make sure the finalizer procedure refers to a procedure
|
result = semNewFinalize(c, n)
|
||||||
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
|
|
||||||
of mDestroy:
|
of mDestroy:
|
||||||
result = n
|
result = n
|
||||||
let t = n[1].typ.skipTypes(abstractVar)
|
let t = n[1].typ.skipTypes(abstractVar)
|
||||||
|
|
|
||||||
32
tests/arc/t19401.nim
Normal file
32
tests/arc/t19401.nim
Normal file
|
|
@ -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
tests/arc/t19402.nim
Normal file
32
tests/arc/t19402.nim
Normal file
|
|
@ -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()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue