wcc/ww: per-unit prefix on _S_ strlit labels (#49)

Strlit labels were emitted as `_S_<n>` from a global counter with no
per-unit prefix (cgen.c intern_strlit + wwstage internstrlit twin).
Under separate compilation two str-bearing packages both emit `_S_0`..
-> w6l link collision.

Prefix the label with the owning package PATH (`<module>._S_<n>`,
matching mklabel's spelling). The prefix is c->cur_mod, set per-fn by
cgfn and now per-decl by let_pre_intern (save/restore so the later
emit passes, which read cur_mod for fn-ptr relocs, are unaffected).
Pure function of the module path — NOT a build-nonce — so the
self-host fixed-point holds across ww2/ww3/ww4. Both stages, symmetric.

Transparent rename on the live combined path: the label is interned
once and shared by every reference, so ref and def move in lockstep.
cs==ww byte-id holds; the w6c/wwdump combined.ww embed wcc/cgen.ww and
are regenerated.

746_strdef_inline: the strdef-inline sentinel pinned the bare
`LEAQ\t_S_` shape; update to the module-prefixed form (alpha._S_ for
the in-module def, beta._S_ for the use-site-interned cross-module
inline).

989_m3sep_run: add the #49 LINK leg. The str sub-fixture (sleaf+smid)
was keystone-only — never linked — precisely because the global
counter made both emit `_S_0`. With the prefix, compile both `-c`
separately, link (w6l) + run (sroot reads a distinguishing byte through
each string's .ptr, so a collided label would corrupt the exit), both
stages + cs==ww final exe.
This commit is contained in:
2026-06-16 01:36:14 +09:00
parent f69ef9b9da
commit f77739b1de
6 changed files with 241 additions and 37 deletions

View File

@@ -34,11 +34,11 @@
* Pin: 2 rows. Row 1 (bare ident, single module) sentinel-flips the
* cgenexpr.ww:555 deflookup-strlit-inline branch on wwstage — revert
* the branch and row 1 fails (`MOVQ\talpha.MSG(SB)` appears instead
* of `LEAQ\t_S_`). Row 2 (mod-qualified, two modules) sentinel-flips
* the cgenexpr.ww:1730 cgdot deflookup-strlit-inline branch — revert
* and row 2 fails the same way (`MOVQ\talpha.MSG(SB)` appears in
* of `LEAQ\t<mod>._S_`). Row 2 (mod-qualified, two modules) sentinel-
* flips the cgenexpr.ww:1730 cgdot deflookup-strlit-inline branch —
* revert and row 2 fails the same way (`MOVQ\talpha.MSG(SB)` appears in
* beta.b). Asserts the strlit-inline pair lands inside the right
* TEXT sym (LEAQ\t_S_ + MOVQ\t$<strlit_len>,) with the bad_movq
* TEXT sym (LEAQ\t<mod>._S_ + MOVQ\t$<strlit_len>,) with the bad_movq
* anti-check on each stage plus cs-vs-ws byte-id per row.
*/
#include <stdio.h>
@@ -77,7 +77,9 @@ static const struct row rows[] = {
"def MSG: str = \"strdef_inline_pin_aaaaaaaaaaaaaaa_43chr\";\n"
"export fn afn() str = { return MSG; };\n"
"export fn main() i32 = { return 0; };\n",
"TEXT alpha.afn", "LEAQ\t_S_", "MOVQ\t$39,", "alpha.MSG(SB)" },
/* #49: strlit labels carry the interning module's path prefix
* (here alpha — MSG's def interns in alpha's compile). */
"TEXT alpha.afn", "LEAQ\talpha._S_", "MOVQ\t$39,", "alpha.MSG(SB)" },
{ "mod_qualified_strdef",
"package alpha;\n"
"def MSG: str = \"strdef_inline_pin_aaaaaaaaaaaaaaa_43chr\";\n"
@@ -85,7 +87,9 @@ static const struct row rows[] = {
"import alpha;\n"
"export fn bfn() str = { return alpha.MSG; };\n"
"export fn main() i32 = { return 0; };\n",
"TEXT beta.bfn", "LEAQ\t_S_", "MOVQ\t$39,", "alpha.MSG(SB)" },
/* #49: the inlined sdef interns at the USE site (beta.bfn), so the
* strlit label carries beta's path prefix, not alpha's. */
"TEXT beta.bfn", "LEAQ\tbeta._S_", "MOVQ\t$39,", "alpha.MSG(SB)" },
};
static int