Skip to content

Commit

Permalink
fix(sem): crash with forward-declared =destroy hook (#1252)
Browse files Browse the repository at this point in the history
## Summary

Fix the compiler crashing when using a type with an, at that point,
forward-declared `=destroy` hook.

## Details

If the `=destroy` hook is forward-declared, its body is an `nkEmpty`
node, which caused a `FieldDefect` error in
`liftdestructors.createTypeBoundOps`, where the body AST is expected
to support `len`.

To resolve the issue, the `getBody(...).len` access is guarded by first
checking that the destroy hook is not overridden (indicated by the
`sfOverriden`  flag); only overridden hooks can be forward-declared.
This
works because `sfOverriden` implies that the attached-to type has
the `tfHasAsgn` flag already included.
  • Loading branch information
zerbina authored Mar 21, 2024
1 parent 8ca0787 commit 19b0b9f
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
4 changes: 3 additions & 1 deletion compiler/sem/liftdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,9 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
setAttachedOp(g, idgen.module, orig, k, getAttachedOp(g, canon, k))

let op = getAttachedOp(g, orig, attachedDestructor)
if op != nil and getBody(g, op).len != 0:
# if the destructor is overridden, the ``tfHasAsgn`` flag was already
# included
if op != nil and sfOverriden notin op.flags and getBody(g, op).len != 0:
#or not isTrival(orig.assignment) or
# not isTrival(orig.sink):
orig.flags.incl tfHasAsgn
Expand Down
27 changes: 27 additions & 0 deletions tests/lang_objects/destructor/tforward_declared_destructor.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
discard """
description: '''
Regression test for a forward-declared destroy hook causing a compiler
crash when hooks are requested before the forward-declaration is
completed
'''
"""

# note: the comments refer to implementation details that were present at the
# time of writing

type
Object* = object

# it's important that the destroy hook is forward-declared here
proc `=destroy`(x: var Object)

# use `Object` in a way so that no hooks are requested before `p` is
# instantiated
proc test(x: Object) =
# request hooks for the type with the still-forward-declared destroy hook,
# resulting in a compiler crash
var x = x

# finish the forward declaration
proc `=destroy`(x: var Object) =
discard

0 comments on commit 19b0b9f

Please sign in to comment.