Skip to content

Commit 4bdeddc

Browse files
ringaboutnarimiran
authored andcommitted
deprecate NewFinalize with the ref T finalizer (#24354)
pre-existing issues: ```nim block: type FooObj = object data: int Foo = ref ref FooObj proc delete(self: Foo) = echo self.data var s: Foo new(s, delete) ``` it crashed with arc/orc in 1.6.x and 2.x.x ```nim block: type Foo = ref int proc delete(self: Foo) = echo self[] var s: Foo new(s, delete) ``` The simple fix is to add a type restriction for the type `T` for arc/orc versions ```nim proc new*[T: object](a: var ref T, finalizer: proc (x: T) {.nimcall.}) ``` (cherry picked from commit 2af602a)
1 parent 9be3559 commit 4bdeddc

File tree

4 files changed

+88
-41
lines changed

4 files changed

+88
-41
lines changed

compiler/semmagic.nim

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -536,31 +536,33 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
536536
else:
537537
if fin.instantiatedFrom != nil and fin.instantiatedFrom != fin.owner: #undo move
538538
setOwner(fin, fin.instantiatedFrom)
539-
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
540-
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
541-
selfSymNode.typ() = fin.typ.firstParamType
542-
wrapperSym.flags.incl sfUsed
543-
544-
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
545-
params = nkFormalParams.newTree(c.graph.emptyNode,
546-
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
547-
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
548-
),
549-
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
550-
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
551-
552-
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
553-
setOwner(transFormedSym, fin)
554-
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
555-
let origParamType = transFormedSym.ast[bodyPos][1].typ
556-
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
557-
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
558-
selfPtr.add transFormedSym.ast[bodyPos][1]
559-
selfPtr.typ() = selfSymbolType
560-
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
561-
# TODO: suppress var destructor warnings; if newFinalizer is not
562-
# TODO: deprecated, try to implement plain T destructor
563-
bindTypeHook(c, transFormedSym, n, attachedDestructor, suppressVarDestructorWarning = true)
539+
540+
if fin.typ[1].skipTypes(abstractInst).kind != tyRef:
541+
bindTypeHook(c, fin, n, attachedDestructor)
542+
else:
543+
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
544+
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
545+
selfSymNode.typ() = fin.typ.firstParamType
546+
wrapperSym.flags.incl sfUsed
547+
548+
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
549+
params = nkFormalParams.newTree(c.graph.emptyNode,
550+
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
551+
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
552+
),
553+
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
554+
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
555+
556+
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
557+
setOwner(transFormedSym, fin)
558+
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
559+
let origParamType = transFormedSym.ast[bodyPos][1].typ
560+
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
561+
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
562+
selfPtr.add transFormedSym.ast[bodyPos][1]
563+
selfPtr.typ() = selfSymbolType
564+
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
565+
bindTypeHook(c, transFormedSym, n, attachedDestructor)
564566
result = addDefaultFieldForNew(c, n)
565567

566568
proc semPrivateAccess(c: PContext, n: PNode): PNode =

compiler/semstmts.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,7 +2092,7 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
20922092
incl(s.flags, sfUsed)
20932093
incl(s.flags, sfOverridden)
20942094

2095-
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressVarDestructorWarning = false) =
2095+
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
20962096
let t = s.typ
20972097
var noError = false
20982098
let cond = case op
@@ -2116,7 +2116,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressV
21162116
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
21172117
else: break
21182118
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
2119-
if (not suppressVarDestructorWarning) and op == attachedDestructor and t.firstParamType.kind == tyVar and
2119+
if op == attachedDestructor and t.firstParamType.kind == tyVar and
21202120
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
21212121
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
21222122
obj = canonType(c, obj)

lib/system.nim

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,38 @@ proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
125125

126126
const ThisIsSystem = true
127127

128-
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
129-
magic: "NewFinalize", noSideEffect.}
130-
## Creates a new object of type `T` and returns a safe (traced)
131-
## reference to it in `a`.
132-
##
133-
## When the garbage collector frees the object, `finalizer` is called.
134-
## The `finalizer` may not keep a reference to the
135-
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
136-
## freeing the object.
137-
##
138-
## **Note**: The `finalizer` refers to the type `T`, not to the object!
139-
## This means that for each object of type `T` the finalizer will be called!
128+
const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
129+
130+
when defined(nimAllowNonVarDestructor) and arcLikeMem:
131+
proc new*[T](a: var ref T, finalizer: proc (x: T) {.nimcall.}) {.
132+
magic: "NewFinalize", noSideEffect.}
133+
## Creates a new object of type `T` and returns a safe (traced)
134+
## reference to it in `a`.
135+
##
136+
## When the garbage collector frees the object, `finalizer` is called.
137+
## The `finalizer` may not keep a reference to the
138+
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
139+
## freeing the object.
140+
##
141+
## **Note**: The `finalizer` refers to the type `T`, not to the object!
142+
## This means that for each object of type `T` the finalizer will be called!
143+
144+
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
145+
magic: "NewFinalize", noSideEffect, deprecated: "pass a finalizer of the 'proc (x: T) {.nimcall.}' type".}
146+
147+
else:
148+
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
149+
magic: "NewFinalize", noSideEffect.}
150+
## Creates a new object of type `T` and returns a safe (traced)
151+
## reference to it in `a`.
152+
##
153+
## When the garbage collector frees the object, `finalizer` is called.
154+
## The `finalizer` may not keep a reference to the
155+
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
156+
## freeing the object.
157+
##
158+
## **Note**: The `finalizer` refers to the type `T`, not to the object!
159+
## This means that for each object of type `T` the finalizer will be called!
140160

141161
proc `=wasMoved`*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
142162
## Generic `wasMoved`:idx: implementation that can be overridden.
@@ -362,8 +382,6 @@ proc arrGet[I: Ordinal;T](a: T; i: I): T {.
362382
proc arrPut[I: Ordinal;T,S](a: T; i: I;
363383
x: S) {.noSideEffect, magic: "ArrPut".}
364384

365-
const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
366-
367385

368386
when defined(nimAllowNonVarDestructor) and arcLikeMem and defined(nimPreviewNonVarDestructor):
369387
proc `=destroy`*[T](x: T) {.inline, magic: "Destroy".} =

tests/arc/tarcmisc.nim

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,3 +834,30 @@ block: # bug #24141
834834
doAssert abc == "fbc"
835835

836836
main()
837+
838+
block:
839+
type
840+
FooObj = object
841+
data: int
842+
Foo = ref FooObj
843+
844+
845+
proc delete(self: FooObj) =
846+
discard
847+
848+
var s = Foo()
849+
new(s, delete)
850+
851+
block:
852+
type
853+
FooObj = object
854+
data: int
855+
i1, i2, i3, i4: float
856+
Foo = ref FooObj
857+
858+
859+
proc delete(self: FooObj) =
860+
discard
861+
862+
var s = Foo()
863+
new(s, delete)

0 commit comments

Comments
 (0)