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

@@ -3792,6 +3792,22 @@ fn cgcall(c: *cgen, n: *node) void = {
emitline("(BP), AX\n");
return;
};
// #231: str/slice GLOBAL — the
// local-only path above lacked it,
// so cgexpr fell through and left
// AX=.ptr (not .len). The .len word
// lives at the global's address+8;
// route the LEAQ through the post-#1
// value mangle (c.curmod) so a
// private same-leaf global isn't
// mis-resolved.
if (isletvar(c, a.str)) {
emitline("\tLEAQ\t");
emitsymnamehint(c, a.str, c.curmod);
emitline("(SB), CX\n");
emitline("\tMOVQ\t8(CX), AX\n");
return;
};
};
if (u.kind == tykind.TY_ARRAY) {
emitline("\tMOVQ\t$");