mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-04 22:48:38 +00:00
IC: bugfix
This commit is contained in:
@@ -198,8 +198,16 @@ proc ownsRuntimeRoutine(s: PSym; modPos: int): bool =
|
||||
{sfForward, sfImportc, sfCompileTime, sfError} * s.flags == {} and
|
||||
s.typ != nil and not signatureHasMetaType(s.typ) and
|
||||
s.ast != nil and s.ast.safeLen > bodyPos and
|
||||
s.ast[genericParamsPos].kind == nkEmpty and
|
||||
s.ast[bodyPos].kind != nkEmpty
|
||||
s.ast[genericParamsPos].kind == nkEmpty
|
||||
# NOTE: an `nkEmpty` body is NOT a disqualifier. A concrete, owned, non-
|
||||
# forward/-importc/-magic routine whose body folds to nothing is still a real
|
||||
# definition the owner must emit (`void f(void){}`), exactly as whole-program
|
||||
# cgen does — else a cross-module caller links to nothing. This bites e.g.
|
||||
# Nimbus' `extras.incInternalErrors`, a plain `proc` whose sole statement is a
|
||||
# metrics-counter `.inc()` that the `metrics` library expands to a no-op when
|
||||
# the importing tool (ncli) builds with `-u:metrics`; the body is then a bare
|
||||
# `nkEmpty`, but `state_transition_epoch` still calls it. Forward declarations
|
||||
# (the other empty-body case) carry `sfForward` and are excluded above.
|
||||
|
||||
proc generateCodeForModule(g: ModuleGraph; precomp: PrecompiledModule) =
|
||||
## Generate C code for a single module.
|
||||
|
||||
9
tests/ic/memptycaller.nim
Normal file
9
tests/ic/memptycaller.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
# Calls `emptyOwned` from a DIFFERENT module than the one that owns it, so the
|
||||
# reference at link time must resolve to a definition the owning module emits.
|
||||
|
||||
import memptyowned
|
||||
|
||||
proc callEmpty*(cond: bool) =
|
||||
if cond:
|
||||
emptyOwned()
|
||||
echo "called ", cond
|
||||
12
tests/ic/memptyowned.nim
Normal file
12
tests/ic/memptyowned.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
# Helper for `temptyowned`: exports a concrete proc whose body folds to
|
||||
# nothing (an `nkEmpty` body, like Nimbus' `extras.incInternalErrors` when the
|
||||
# metrics counter's `.inc()` expands to a no-op under `-u:metrics`). The proc is
|
||||
# NOT called within its own module — only `memptycaller` references it — so the
|
||||
# per-module backend's owned-routine seeding is the ONLY thing that can emit it.
|
||||
|
||||
template maybe*(x: untyped) =
|
||||
when false:
|
||||
x
|
||||
|
||||
proc emptyOwned*() =
|
||||
maybe(echo "unreachable")
|
||||
18
tests/ic/temptyowned.nim
Normal file
18
tests/ic/temptyowned.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
output: '''called false
|
||||
done'''
|
||||
"""
|
||||
|
||||
# Regression test for the per-module IC backend dropping an owned routine whose
|
||||
# body folds to `nkEmpty`. `memptyowned.emptyOwned` is a real, concrete, owned
|
||||
# proc with an empty body; `memptycaller.callEmpty` references it across a module
|
||||
# boundary. The owning module's `ownsRuntimeRoutine` seeding used to reject any
|
||||
# routine with an `nkEmpty` body, so nobody emitted `emptyOwned` -> undefined
|
||||
# reference at link (mirrors Nimbus `ncli` linking `extras.incInternalErrors`).
|
||||
# Whole-program cgen always emits it as `void emptyOwned(void){}`; the per-module
|
||||
# backend must too.
|
||||
|
||||
import memptycaller
|
||||
|
||||
callEmpty(false)
|
||||
echo "done"
|
||||
Reference in New Issue
Block a user