Files
ww/test/lang/arr_struct_subtail_frame_test.ww
Hojun-Cho 83f5956df2 test: banner purge + WHY-only comment sweep (rule 8)
Every section banner dies (103 -> 0) across test/lang, the observer
suites, the C carriers, and the five comment-heavy corpus fixtures;
banner provenance (#N cites, carrier numbers, repair-cluster labels)
folded into headers or adjacent WHY comments. Narration deleted; row
provenance, ref cites, divergence pins, and layout contracts kept
(fwd-ref decl-order guards and bootstrap-gate corpus rationale
restored where the sweep over-cut). Comment-only proven: all 3742
wwbuild workdir .s byte-identical before/after; test-commit and
test-byteid (161 lang + 1399 data, 0 pinned-divergent) green.
2026-08-08 21:40:23 +09:00

66 lines
3.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// #9: a local `[N]S` where S is a struct with
// a sub-8-tail field over-sized its stack FRAME (cs≠ww, gate-visible). The
// wwstage cgen frame reader (slotsize, cgenutil.ww TY_ARRAY arm) summed the
// element's slot-PADDED width (outer.slotsize 24) × N instead of the array's
// NATURAL size (outer.size 16) × N rounded to 8 — so `[2]outer` reserved $48
// where cstage reserves natural $32, and every later local stacked at a shifted
// BP offset. ROOT was the SAME dual-SSoT slotsize leak #75 fixed for the
// TY_STRUCT arm, never carried to its TY_ARRAY sibling; #9 applies the identical
// round8(ti.size) transform. ti.size == ti.slotsize for every array of prims /
// arrays / 8-multiple tagged elements, so the fix MOVES only this nested-sub-8-
// struct case (#48 [N]Alias and 1D/2D prim arrays are unchanged).
//
// The LOAD-BEARING tooth is the test-lang-byteid .s comparison: reverting the
// cgenutil.ww slotsize arm reddens this file (ww frame $48 vs cstage $32). The
// value asserts are a SECONDARY net — standalone ww is internally consistent at
// the inflated stride (it reserves AND addresses at the same over-sized frame),
// so a pure value run can pass while broken; they guard a future stride/offset
// regression, not the frame size. element_layout pins the natural per-element
// stride (16) and field offsets (a@0, p.x@1, p.y@2, z@8); cross_element pins
// that element 0 and element 1 don't alias after the fix shrinks the frame.
//
// Inline @test fns, not a row-table: the cases vary in the WRITE/READ place
// shape over a fixed struct layout, not in data over one operation, so a
// row-array `[](in,exp){}` can't express them (and that form is blocked by cgen
// #111). Mirrors dotbase_arr_test's #135 pins.
package arr_struct_subtail_frame_test;
type inner = struct { x: u8, y: u8 }; // natural 2, align 1
type outer = struct { a: u8, p: inner, z: i64 }; // natural 16, align 8 (sub-8 tail at p)
@test fn element_layout() void = {
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
assert(arr[0].a: i32 == 1);
assert(arr[0].p.x: i32 == 2);
assert(arr[0].p.y: i32 == 3);
assert(arr[0].z == 100i64);
assert(arr[1].a: i32 == 4);
assert(arr[1].p.x: i32 == 5);
assert(arr[1].p.y: i32 == 6);
assert(arr[1].z == 200i64);
};
@test fn write_tail() void = {
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
arr[1].z = 999i64;
arr[0].a = 7u8;
assert(arr[1].z == 999i64);
assert(arr[0].a: i32 == 7);
assert(arr[0].z == 100i64); // neighbour untouched
};
@test fn cross_element() void = { // element 0 and 1 are 16 apart, no alias
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
arr[0].p.y = 77u8;
assert(arr[0].p.y: i32 == 77);
assert(arr[1].p.x: i32 == 5); // not clobbered by the elem-0 write
assert(arr[1].p.y: i32 == 6);
};