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

@@ -343,6 +343,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_xmod_ident_prefer \
$(BIN)/test_xmod_valglobal_run \
$(BIN)/test_xmod_valglobal_dot_run \
$(BIN)/test_len_strglobal_run \
$(BIN)/test_widen_pad_zero_run \
$(BIN)/test_named_ptr_alias_variant_widen \
$(BIN)/test_single_field_struct_zeroinit \
@@ -831,6 +832,14 @@ $(BIN)/test_xmod_valglobal_dot_run: test/wcc/796_xmod_valglobal_dot_run.c \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# #231: len(str/slice global) must load the .len field via the global's
# address (LEAQ name(SB),CX; MOVQ 8(CX),AX), not a bogus BP-relative slot
# (cstage) or the whole header's .ptr (wwstage) — runtime + cs==ww byte-id.
$(BIN)/test_len_strglobal_run: test/wcc/797_len_strglobal_run.c \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# #15: widening a bare *vtable into a NAMED-alias variant (`stream` =
# *vtable) of `(file | stream)` must compute the right tag, not default
# to tag 0. Both-stage byte-id + runtime, plus a degenerate-ambiguity