// str_tuple_elem_cap_test — a tuple POSITIONAL str element read `t.N` (N_IDENT // base, TY_TUPLE) must load the full 24B {ptr,len,cap} header, not just // {ptr,len}, migrated from test/wcc/935_str_tuple_elem_cap_run.c (C4.6 S3). str // is 24B since Phase 2 (#1); pre-S3 the tuple str-element arm loaded 2 words // (ptr in AX, len in BX) and dropped cap. The miscompile was cs==ww, so the // 990-997 byte-id gates stayed GREEN while the runtime was wrong — behavioral // @test is the net. UNLIKE the field/elem arms there is no adjacent slice- // element arm to fold onto, so the 3-word triple is authored directly to the // canonical slice-header ABI (AX=ptr, BX=len, CX=cap). // // The tuple is built by a (i64, str)-returning mk() so the poisoned cap=8 rides // the 4-word return ABI into the tuple slot's +24 word (do NOT simplify to a // local tuple literal — different codegen path); `t.1` then reads it back // 3-word. spoil() interposes a CX-clobbering call between the build and the // `t.1` read so a broken 2-word read observes 44 not 8, not a stale CX. package str_tuple_elem_cap_test; fn mk() (i64, str) = { let p: str = "hi"; p.cap = 8i32; return (5i64, p); }; fn spoil() i32 = { let z: str = "zzzz"; z.cap = 44i32; let w: str = z; return w.cap: i32; }; @test fn tuple_positional_str_elem() void = { // `t.1` positional str element of a local (i64, str) tuple. Poison cap=8 // (len=2) rides mk()'s return ABI into the str element's slot. let t: (i64, str) = mk(); let junk: i32 = spoil(); let s: str = t.1; assert(s.cap: i32 == 8); assert(s.len: i32 == 2); assert(junk == 44); };