w6c,ww: mangle an imported package's fn main under separate compilation (M4 E3, #99)

The bare-`main` carve-out (which keeps the link entry's main unmangled)
keyed on `leaf == "main" && imported == 0`. Under the combined path a
dependency's body folds in with imported==1, so only the root's main
stayed bare. Under separate compilation each package is its own unit and
a dependency's body carries a path-mangling module-reset but imported==0
(#57) — so an imported `fn main` matched the carve-out, emitted a bare
`TEXT main`, and collided with the root entry (`w6l: duplicate symbol
main`). The combined path was unaffected, so this only surfaced under sep.

Gate the carve-out with sep_isdep = (wwiout != NULL): the producer emits a
.wwi output only for dependency units, never for the root/link-entry unit
(root stripped, #69), symmetric on both stages. Only the root unit's main
now stays bare; an imported package's main mangles on its import path
(e.g. aa.bb.main). Both stages.

Gate: test/wcc/989_depmain_sep.c (table-driven, dotted + single-component
shapes, both stages; asserts the mangled dep main + a single bare root
main + cs==ww byte-id; combined path stays neutral).
This commit is contained in:
2026-06-18 12:47:41 +09:00
parent 200f51ca94
commit 7b6f24adea
14 changed files with 399 additions and 10 deletions

View File

@@ -607,8 +607,11 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
// (undefined `main`). #84's bare-module handling is the orthogonal
// axis (a package-LESS `//ww:module-reset` fn, nmod empty), resolved
// in modlookupforfn, NOT here.
// #99: gate on sepisdep — under sep a dep unit's main is imported==0
// (path-carrying `//ww:module-reset`, #57); only the root/link-entry
// unit (wwiout==nil, #69) keeps the bare label.
emitline("TEXT ");
if (syntax.streq(fn_.str, "main") && fn_.imported == 0) {
if (syntax.streq(fn_.str, "main") && fn_.imported == 0 && c.sepisdep == 0) {
emitbytes(fn_.str.ptr, fn_.str.len: u64);
} else {
emitfnname(c, fn_.str, fn_.nmod);