diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 095803e271..2fc37f6562 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -108,7 +108,14 @@ proc fillBackendName(m: BModule; s: PSym) = var result: Rope if s.kind in routineKinds and {optCDebug, optItaniumMangle} * m.g.config.globalOptions == {optCDebug, optItaniumMangle} and m.g.config.symbolFiles == disabledSf: - result = mangleProc(m, s, false).rope + # Under the per-module IC backend the bare-name uniqueness probe + # (`m.g.mangledPrcs`) only sees the routines of the CURRENT module, so the + # clean-vs-`makeUnique` decision is made independently per process: a + # method base mangles clean at its owner but loses the in-module race to + # its same-signature dispatcher elsewhere (clean `speak` defined twice -> + # "multiple definition"; demanders call `speak_u` that nobody defines). + # Force the stable, disamb-based unique name so every process agrees. + result = mangleProc(m, s, makeUnique = m.config.cmd == cmdNifC).rope else: let shared = sharedInstanceCName(m, s) if shared.len > 0: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 5d16881604..9960ea807b 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -114,8 +114,19 @@ proc makeUnique(m: BModule; s: PSym, name: string = ""): string = result = if name == "": s.name.s else: name # keep backend-minted ids out of the `_u` namespace; their item counter # restarts at 0 and would collide with loaded symbols' ids - result.add(if s.itemId.isBackendMinted: "_c" else: "_u") - result.add $s.itemId.item + if s.itemId.isBackendMinted: + result.add "_c" + result.add $s.itemId.item + else: + result.add "_u" + # Mirror `mangleProcNameExt`: use the per-(module,name) `disamb`, NOT + # `itemId.item`. Under the per-module IC backend the same symbol is loaded + # from a NIF in many processes and `itemId.item` is a fresh, load-order + # dependent counter — so a method base would mangle to `_u1` in one module, + # `_u3` in another and clean at its owner, none of which link. `disamb` is + # assigned deterministically per (module, name) and is serialized, so every + # process that touches the symbol derives the identical C name. + result.add $s.disamb # module suffix LAST (a strippable trailing token; see `mangleProcNameExt`) result.add "__" result.add m.g.graph.ifaces[s.itemId.module].uniqueName diff --git a/compiler/deps.nim b/compiler/deps.nim index 4ab7617d0f..fb77792c3d 100644 --- a/compiler/deps.nim +++ b/compiler/deps.nim @@ -701,6 +701,14 @@ proc computeForwardedArgs(c: DepContext): seq[string] = # buckets (and rejects calls as ambiguous that multi-dispatch accepts) if optMultiMethods in c.config.globalOptions: result.add "--multimethods:on" + # Forward the debug-info switch: the cg children — not the driver — fill the + # backend C names, and `--debugger:native` selects the Itanium mangling + # scheme (ccgtypes.fillBackendName). A child without it would name routines + # with the plain `_u` scheme while a sibling that read the project's + # config.nims (`--debugger:native`) used Itanium, so the same symbol's + # definition and cross-module references would disagree at link. + if optCDebug in c.config.globalOptions: + result.add "--debugger:native" # the children compile each MODULE as their own project file, which makes # that module's package the "main package" and unfilters foreign-package # diagnostics — a vendored package's hintAsError/warningAsError promotions diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e1b37b21c6..f72548cf72 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1126,7 +1126,15 @@ proc trackCall(tracked: PEffects; n: PNode) = # otherwise feed the magic to codegen. Mirrors the `tfTriggersCompileTime -> # sfCompileTime` path in `semProcAux`. if a.kind == nkSym and a.sym.magic in {mNLen..mNError, mSlurp..mQuoteAst} and - tracked.owner != nil and tracked.owner.kind in routineKinds: + tracked.owner != nil and tracked.owner.kind in routineKinds and + tracked.config.cmd != cmdNimscript: + # ...but NOT under `nim e`: nimscript has no codegen backend to protect, and + # marking a routine `sfCompileTime` makes `semExpr` eagerly fold calls to it + # at sem time (emConst), where module-level globals it reads have no VM slot + # yet — distros' `detectOsWithAllCmd` reaches `gorge` and reads the plain + # global `unameRes` → "cannot evaluate at compile time: unameRes". In the + # normal nimscript run (emRepl) the module's var section runs first and the + # slot exists, so the marking is both unnecessary and harmful here. incl(tracked.owner, sfCompileTime) if n.typ != nil: if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: