w6c+wwstage: emit global str/slice len via .len field load (#231)

len(str-or-slice-global) was wrong in both stages, differently. cstage's
len() arm did a BP-relative slot load; localfind returns 0 for a global,
so it emitted `MOVQ 8(BP),AX` — a bogus stack slot. wwstage's arm only
handled locals; a global fell through to cgexpr, which loads the whole
header and leaves AX=.ptr, not .len.

Both stages now emit the global .len load — LEAQ name(SB),CX; MOVQ
8(CX),AX (.len field; header is ptr@0/len@8/cap@16). The LEAQ symbol
routes through the post-#1 value mangle (cstage mahint c->cur_mod,
wwstage emitsymnamehint c.curmod), not a raw name, so a private
same-module same-leaf str global can't re-open the #1 collision.

The local-str case is unchanged (control). Slice-global rows wait on
#233 (cstage rejects `let g: []u8 = [...]` init); the str global proves
the path. Byte-id-blind, so a committed runtime + cs==ww test (797) is
the net.
This commit is contained in:
2026-06-01 09:59:32 +09:00
parent 80e7ab7cf3
commit fb62aa38f1
6 changed files with 253 additions and 1 deletions

View File

@@ -5216,7 +5216,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (u && (u->kind == TY_SLICE || u->kind == TY_STR)
&& a->kind == N_IDENT) {
int off = localfind(locals, a->str);
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
if (off == 0 && let_islet(a->str)) {
/* #231: str/slice GLOBAL — the .len word
* lives at the global's address+8, not a
* BP-relative slot (off==0 → MOVQ 8(BP)
* read a bogus stack slot). Route through
* the post-#1 value mangle so a private
* same-module same-leaf global isn't
* mis-resolved. */
ins2(c, A_LEAQ,
mahint(c, a->str, c->cur_mod),
areg(D_CX));
ins2(c, A_MOVQ, amem(D_CX, 8),
areg(D_AX));
} else {
ins2(c, A_MOVQ, amem(D_BP, off + 8),
areg(D_AX));
}
} else if (u && u->kind == TY_ARRAY) {
ins2(c, A_MOVQ, aimm((long long)u->alen), areg(D_AX));
} else {