selfhost+test: graduate structlookup same-module-first (#4b)

Class A silent miscompile, latent until two modules export the same
struct leaf name. Wwstage's structlookup (selfhost/cmd/wcc/cgenutil.ww)
walked c.structs head-first by sname, returning the FIRST match.
cgdot's *struct field-load branch handed it inner.str (the bare
leaf from a parsed N_TPTR whose inner is N_TNAME) and the head-pick
silently emitted the wrong-module field offset — a displacement
against BX that loaded whatever the colliding-module struct happened
to align there. Cstage carries no sister bug: resolve_typename
(cmd/wcc/check.c:65) already routes bare-leaf TY_STRUCT names
through scope_lookup_prefer per c->cur_mod, and cgen.c reads
fi.foff off the typed Sym — cs vs ws asm diverged on every bare-
leaf collision but no in-tree corpus declares two same-leaf
structs, so 995_self_rebuild stayed green (same surfacing pattern
as #4a enumlookup post-strings).

Fifth leaf of the trio leaf-name lookup graduation (after #27
aliaslookup, #28/#31 fnparams/fnretlookupmod, #4a enumlookup):
structlookup grows a same-module-first walk before the head-walk
fallback, mirroring aliaslookup's two-pass shape. No structlookupmod
variant — pkg.S collapses at parse time (lib/ww/parse/parse.ww
joindotted) into a single N_TNAME str routed through the existing
embedded-dot smod==pkg branch, so there's no cgdot-style N_DOT
consumer surface to add a *mod variant for (deferred per rob until
one surfaces). No cstage symmetric fix needed for the same reason
the bug doesn't surface there.

734_struct_modshadow pins the fix with 2 rows: row 1 bare-leaf in
module M must fold against M's own S even with another module's
same-leaf S at the head of c.structs (asserts the matching field-
load disp inside the right TEXT sym + bad disp NOT-presence anti-
check + byte-id between stages); row 2 pkg-qualified alpha.S
from inside alpha is defensive coverage of the pre-existing
embedded-dot smod==pkg branch — same path pre/post-fix (no
sentinel-flip on this commit), pinned here so a future regression
to the embedded-dot lookup is caught.
This commit is contained in:
2026-05-18 14:04:26 +09:00
parent 45339d2f5b
commit f8d2f92316
5 changed files with 300 additions and 21 deletions

View File

@@ -263,6 +263,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_match_4arm_cross_module \
$(BIN)/test_match_4arm_cross_module_run \
$(BIN)/test_enum_modshadow \
$(BIN)/test_struct_modshadow \
$(BIN)/test_param_shadow_mod \
$(BIN)/test_localoff_scope \
$(BIN)/test_cast_enum_movl \
@@ -613,6 +614,10 @@ $(BIN)/test_enum_modshadow: test/wcc/733_enum_modshadow.c \
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_struct_modshadow: test/wcc/734_struct_modshadow.c \
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_match_4arm_cross_module_run: test/wcc/929_match_4arm_cross_module_run.c \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \