The arr[i].f=src legacy assign block enumerated scalar field-type arms then fell to a 1-word scalar default, so a non-call aggregate source (ident/dot/index) cgexpr'd only its first word into AX and stored one eightbyte — silent on BOTH stages (byte-id blind). The non-indexed bases (local/deref/chained/global) reach the general assign resolver's canonical aggargsrcaddr+aggcopy; the indexed arm short-circuited before it. Route the indexed base through the block's own proven &arr[i] spine into the same aggargsrcaddr+aggcopy emitters (DRY — no third copy), dual-site symmetric. Unlike #11's in-cap arm, the source is a memory address so aggcopy is a pure memcpy: float bits and the sub-8 tail transport verbatim, no loud-stop needed. Did not fall through to the general resolver because its cgplaceaddr N_INDEX arm rejects a *[N]S (TY_PTR) base (latent resolver gap, filed separately). Contained to the indexed base + non-call aggregate-field rhs; value-asserting pins redden under each stage's independent revert.
44 lines
1.9 KiB
Plaintext
44 lines
1.9 KiB
Plaintext
// idx_dot_src_aggregate_runonly_test — #11b sub-8-tail anti-clobber through a
|
|
// LOCAL [N]<struct-with-sub-8-tail-field> array. The fix's MOVL (not MOVQ) tail
|
|
// is VALUE-verified here: the dropped tail would read the poison 9, and a tail
|
|
// WIDENED to MOVQ would write bytes 8..15 and smash the adjacent g at +12 — both
|
|
// caught by asserting f.c AND g. Exit-correct under BOTH stages.
|
|
//
|
|
// _runonly (excluded from the test-lang-byteid T2 gate) because a local
|
|
// [N]<sub-8-tail-struct> trips a SEPARATE PRE-EXISTING let-array slotsize cs!=ww
|
|
// FRAME divergence — ww sizes the array element by slotsize (s12 slot-padded),
|
|
// cstage by natural size — that PREDATES and is INDEPENDENT of #11b: empirically
|
|
// the #11b receive INSTRUCTIONS are byte-identical (both stages emit `MOVQ
|
|
// (SI),AX` then the `MOVL 8(SI),AX` tail); only the container's frame SIZE and
|
|
// the BP-relative offsets shift ($48 vs $64). The byte-id twin
|
|
// (idx_dot_src_aggregate_test) covers the same sub-8-tail shape via global-
|
|
// backed bases, where the slotsize bug does not bite (task #9).
|
|
|
|
package idx_dot_src_aggregate_runonly_test;
|
|
|
|
type t12 = struct { a: i32, b: i32, c: i32 };
|
|
type s12 = struct { f: t12, g: i32 };
|
|
|
|
fn one() i64 = { return 1i64; };
|
|
|
|
@test fn subtail_local_ident_const() void = {
|
|
let a: [2]s12 = [s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}, s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}];
|
|
let src: t12 = t12{a=10i32, b=20i32, c=30i32};
|
|
a[1].f = src;
|
|
assert(a[1].f.a == 10i32);
|
|
assert(a[1].f.b == 20i32);
|
|
assert(a[1].f.c == 30i32);
|
|
assert(a[1].g == 9i32);
|
|
assert(a[0].f.a == 9i32);
|
|
};
|
|
|
|
@test fn subtail_local_ident_runtime() void = {
|
|
let a: [2]s12 = [s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}, s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}];
|
|
let src: t12 = t12{a=10i32, b=20i32, c=30i32};
|
|
a[one()].f = src;
|
|
assert(a[1].f.a == 10i32);
|
|
assert(a[1].f.b == 20i32);
|
|
assert(a[1].f.c == 30i32);
|
|
assert(a[1].g == 9i32);
|
|
};
|