wwstage: nested-array outer-index esz = sub-array size (#270-2)

elemsizeofc drilled a 2D `[N][M]T` base's OUTER-index stride down to the
scalar T (the documented elemsizeof FOOTGUN: it bottoms out at the inner
prim size, 4 for [M]u32). The `direct != 8` short-circuit then returned
that scalar size, so wwstage emitted esz=$4 where cstage emits $12 (the
sub-array size, idx_eff(bt)->sub->size = sub.size*elen, type.c:121). The
runtime stayed self-consistent (write+read the same wrong stride) so it
masked until a CROSS-CELL access — a[0][j] and a[1][j] alias.

Fix: detect a nested-array element ([M]T inside [N][M]T) before the
short-circuit and return the element-array tinfo's natural .size, the
sub-array stride. wwstage-only; aligns up to cstage. w6c unchanged.

949 rows: nest2d_u32/u8/i32 (cross-cell write+readback, byte-id).
This commit is contained in:
2026-06-02 12:24:43 +09:00
parent ebbc3f98c2
commit 33bd2b1054
4 changed files with 91 additions and 0 deletions

View File

@@ -1059,6 +1059,24 @@ fn elemsizeof(t: *node) i32 = {
// whose Alias resolves to a tagged union (e.g. `[N]formattable`).
fn elemsizeofc(c: *cgen, t: *node) i32 = {
if (t == nil) { return 1; };
// #270-2: a NESTED-array element ([N][M]T) — the OUTER index stride
// is the WHOLE sub-array [M]T, not the scalar T that elemsizeof
// drills down to (the documented elemsizeof FOOTGUN). elemsizeof
// returns the inner prim size (4 for [M]u32), so the `direct != 8`
// short-circuit below would mis-emit esz=$4 where cstage emits the
// sub-array stride $12. Mirror cstage esz = idx_eff(bt)->sub->size
// (cmd/w6c/cgen.c:4923): the element-array tinfo's natural size
// (sub.size*elen, type.c:121) IS the outer stride.
let nk: nkind = t.kind;
let nest: *node = nil;
if (nk == nkind.N_TPTR) { nest = t.lhs; };
if (nk == nkind.N_TSLICE) { nest = t.lhs; };
if (nk == nkind.N_TARRAY) { nest = t.lhs; };
if (nest != nil && nest.kind == nkind.N_TARRAY) {
let eti: *tinfo = nest.type_: *tinfo;
for (eti != nil && eti.kind == tykind.TY_NAMED) { eti = eti.under; };
if (eti != nil) { return eti.size: i32; };
};
let direct: i32 = elemsizeof(t);
if (direct != 8) { return direct; };
let k: nkind = t.kind;