// Whole-struct field-copy ragged tail (#73, #263 both // stages), migrated from test/wcc/989_structcopytail_run.c. A `x.i = o` copy of // a struct whose NATURAL size is not 8-aligned must move exactly that many bytes // via a descending-greedy 8->4->2->1 tail (MOVL/MOVW/MOVB), NOT round up to an // 8-byte MOVQ that bleeds into the field's natural-offset successor. Pre-#73 // both stages' inline tail handled only {4,1}; a natural size %8 in {2,3,5,6,7} // fell to a single MOVQ writing [0,8) and clobbering the `mark` field placed at // the inner struct's natural offset. The fix routes both stages' field copy // through the canonical greedy emitter. Each row poisons `mark` first, copies, // then reads every field back; the .c returned the 1-based index of the first // mismatch (0 = all-correct), here each field is asserted directly. T2 // (test-lang-byteid) keeps the cs==ww net the .c twin's dual-driver run gave. package structcopytail_test; type inner2 = struct { a: u8, b: u8 }; type outer2 = struct { i: inner2, mark: i32 }; type inner6 = struct { a: u16, b: u16, c: u16 }; type outer6 = struct { i: inner6, mark: u8 }; type inner7 = struct { a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8 }; type outer7 = struct { i: inner7, mark: u8 }; type inner8 = struct { a: i64 }; type outer8 = struct { i: inner8, mark: i64 }; @test fn tail2() void = { // 2-byte inner; mark (nat offset 4) must survive the MOVW tail. let o: inner2 = inner2 { a = 0x11, b = 0x22 }; let x: outer2; x.mark = 0x7f7f7f7f; x.i = o; assert(x.i.a: int == 0x11); assert(x.i.b: int == 0x22); assert(x.mark == 0x7f7f7f7f); }; @test fn tail6() void = { // 6-byte inner; mark:u8 (nat offset 6) must survive the MOVL+MOVW tail. let o: inner6 = inner6 { a = 0x1111, b = 0x2222, c = 0x3333 }; let x: outer6; x.mark = 0x5a; x.i = o; assert(x.i.a: int == 0x1111); assert(x.i.b: int == 0x2222); assert(x.i.c: int == 0x3333); assert(x.mark: int == 0x5a); }; @test fn tail7() void = { // 7-byte inner; the full MOVL+MOVW+MOVB ladder; mark:u8 at nat offset 7. let o: inner7 = inner7 { a = 0x11, b = 0x22, c = 0x33, d = 0x44, e = 0x55, f = 0x66, g = 0x77 }; let x: outer7; x.mark = 0x5a; x.i = o; assert(x.i.a: int == 0x11); assert(x.i.b: int == 0x22); assert(x.i.c: int == 0x33); assert(x.i.d: int == 0x44); assert(x.i.e: int == 0x55); assert(x.i.f: int == 0x66); assert(x.i.g: int == 0x77); assert(x.mark: int == 0x5a); }; @test fn ctl8() void = { // 8-aligned inner; the MOVQ loop alone, zero tail iterations (unchanged). let o: inner8 = inner8 { a = 0x1234567 }; let x: outer8; x.mark = 0x76543210; x.i = o; assert(x.i.a == 0x1234567); assert(x.mark == 0x76543210); };