Skip to content

Commit

Permalink
fix compiler crash with .global initializers (#1472)
Browse files Browse the repository at this point in the history
## Summary

Fix the compiler crashing for initializers of `.global` variables where
the expression contains locals or temporaries requiring destruction.

Fixes #1470.

## Details

MIR generation for `.global` init fragments is done via
`mirgen.generateAssignment`, which didn't push a scope prior to
translation. This caused any call to `mirgen_blocks.register` to crash
the compiler, as the scope/block list was empty.

A scope is now pushed prior to translating the expression, fixing the
crash. In addition to fixing the crash, this slightly changes
behaviour: unscoped temporaries/locals created as part of a `.global`
initializer are now destroyed immediately after the initialization,
instead of at the end of the module's pre-init procedure. Destruction
order w.r.t. `.global` initializers is unspecified, so this change
shouldn't be a problem.
  • Loading branch information
zerbina authored Dec 10, 2024
1 parent b626472 commit c189449
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 4 deletions.
10 changes: 6 additions & 4 deletions compiler/mir/mirgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2388,16 +2388,18 @@ proc generateAssignment*(graph: ModuleGraph, env: var MirEnv,
## `builder`'s currently selected buffer.
assert n.kind == nkIdentDefs and n.len == 3
var c = initCtx(graph, config, nil, move env)
# treat the code as top-level code so that no 'def' is generated for
# assignments to globals
c.scopeDepth = 1

template swapState() =
swap(c.sp.map, source)
swap(c.builder, builder)

swapState()
genLocInit(c, n[0], n[2])
# treat the code as top-level code so that no 'def' is generated for
# assignments to globals
c.scope(true):
# a scope is required, otherwise locals/temporaries cannot be registered
# for destruction
genLocInit(c, n[0], n[2])
swapState()
env = move c.env # move back

Expand Down
20 changes: 20 additions & 0 deletions tests/global/twith_local_requiring_destruction.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
discard """
description: '''
Ensure that not explicitly scoped locals/temporaries in `.global`
intializer expressions are destroyed.
'''
targets: c js vm
output: "destroy: 1"
"""

type Object = object
val: int

proc `=destroy`(x: var Object) =
echo "destroy: ", x.val

proc test() =
# the local (`x`) has no explicit scope
var g {.global.} = (var x = Object(val: 1); x.val)

test()

0 comments on commit c189449

Please sign in to comment.