mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-11 22:08:54 +00:00
* 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:
@@ -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
|
||||
@@ -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)
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user