// dotbase_arr_test — an N_INDEX with an N_DOT base on a `[N]T`-typed field // (`(*struct).array_field[i]`) must compute the field's ADDRESS, not load its // value, migrated from test/wcc/949_dotbase_arr_run.c (#135). Pre-#135 the // N_INDEX read + plain-assign + compound fallbacks all invoked cgexpr on the // N_DOT base, which auto-derefs and loads the field's first 8 bytes as if a // pointer → every read/write/compound through a packed array field segfaulted, // cs==ww BOTH stages broken identically (gate-blind). The fix // (cg_dotbase_addr/dotbaseaddr) detects an N_DOT base whose FIELD is TY_ARRAY, // walks to the inner ident, and emits address-of-field inline; the TY_ARRAY // gate keeps it inert on pointer/slice/str fields. The .s is byte-identical, so // these behavioral @tests are the runtime net. // // read_u8 / write_u8 / compound_u8 are the 3 fix shapes on a `*struct` base // with an [8]u8 field (the strconv decimal.ha:178 compound shape, #133+#135 // prereqs). Wider element widths and the TY_ARRAY-gate no-over-fire control are // left to the bootstrap byte-id corpus (994/995) per the C twin's note: the i32 // return ABI's MOVL-vs-MOVSXD is a pre-existing cs/ww divergence below the // helper, unrelated to #135. package dotbase_arr_test; type t = struct { digits: [8]u8, nd: size }; fn rd(d: *t) i32 = { return d.digits[3]: i32; }; fn setit(d: *t) void = { d.digits[3] = 99u8; }; fn bump(d: *t) void = { d.digits[3] += 1u8; }; @test fn read_u8() void = { let x: t; x.digits[0] = 50u8; x.digits[3] = 77u8; assert(rd(&x) == 77i32); }; @test fn write_u8() void = { let x: t; setit(&x); assert(x.digits[3]: i32 == 99i32); }; @test fn compound_u8() void = { let x: t; x.digits[3] = 10u8; bump(&x); assert(x.digits[3]: i32 == 11i32); };