Fan out the str-cap read (933-936) and store (937-939) families into in-language @test files, following the 932 str_elem_cap template. Additive: the *_run.c stay in the C corpus (they are the only wwstage-runtime net for these cs==ww byte-id-blind shapes); de-dup deferred to fold 6. Per-shape @test fns, not a data table: each fn varies the codegen shape (base reg / chain depth / tuple return-ABI / store position), so the row-array idiom (blocked by #111) would lose coverage. Read family keeps the spoil()/register-clobber + junk==44 discrimination where the .c has it; store family pre-poisons the slot via a path distinct from the store under test. Asserts are primitives only.
69 lines
2.2 KiB
Plaintext
69 lines
2.2 KiB
Plaintext
// str_field_cap_test — reading a str-typed FIELD of a struct (N_DOT value
|
|
// read) must load the full 24B {ptr,len,cap} header, not just {ptr,len},
|
|
// migrated from test/wcc/933_str_field_cap_run.c (C4.6 S1+S2 case A). str is
|
|
// 24B since Phase 2 (#1); pre-C4.6 the N_DOT str-field arms loaded 2 words and
|
|
// dropped cap. The miscompile was cs==ww, so the 990-997 byte-id gates stayed
|
|
// GREEN while the runtime was wrong — a behavioral @test is the net.
|
|
//
|
|
// The global row is load-bearing: in ww the global struct-field load is a
|
|
// separate codegen arm with no slice sibling (cstage folds local+global in one
|
|
// base_reg arm; ww splits them), so a cap-drop there would hide from the
|
|
// local-field rows — hence its own @test fn.
|
|
//
|
|
// Each shape POISONS the source str so cap != len (a `.cap =` pseudo-field
|
|
// write, no malloc / no import), then observes cap through `let s: str =
|
|
// <field>` (a 3-word copy into the slot) and `s.cap` (an N_IDENT pseudo-field
|
|
// read off the slot). spoil() interposes a CX-clobbering call between the field
|
|
// store and the read so a broken 2-word read observes spoil's leftover (44),
|
|
// not a stale poison the store coincidentally left behind. .len is the control.
|
|
|
|
package str_field_cap_test;
|
|
|
|
type rec = struct { f: str };
|
|
|
|
let g: rec;
|
|
|
|
fn spoil() i32 = {
|
|
let z: str = "zzzz";
|
|
z.cap = 44i32;
|
|
let w: str = z;
|
|
return w.cap: i32;
|
|
};
|
|
|
|
@test fn s1local_field() void = {
|
|
// `st.f` direct struct local field (base BP). Poison cap=8 (len=2).
|
|
let p: str = "hi";
|
|
p.cap = 8i32;
|
|
let st: rec;
|
|
st.f = p;
|
|
let junk: i32 = spoil();
|
|
let s: str = st.f;
|
|
assert(s.cap: i32 == 8);
|
|
assert(s.len: i32 == 2);
|
|
assert(junk == 44);
|
|
};
|
|
|
|
@test fn s1global_field() void = {
|
|
// `g.f` direct struct global field (base CX path), the no-local-sibling
|
|
// arm in ww. Poison cap=9 (len=5).
|
|
let p: str = "world";
|
|
p.cap = 9i32;
|
|
g.f = p;
|
|
let s: str = g.f;
|
|
assert(s.cap: i32 == 9);
|
|
assert(s.len: i32 == 5);
|
|
};
|
|
|
|
@test fn s2ptr_field() void = {
|
|
// `pst.f` field via a *struct local (deref, base BX). Poison cap=7
|
|
// (len=3).
|
|
let p: str = "abc";
|
|
p.cap = 7i32;
|
|
let st: rec;
|
|
st.f = p;
|
|
let pst: *rec = &st;
|
|
let s: str = pst.f;
|
|
assert(s.cap: i32 == 7);
|
|
assert(s.len: i32 == 3);
|
|
};
|