Continue fold-2: migrate the pointer-deref / narrow-load / pointer-array-stride family from bespoke build+run C twins to test/lang @test, retiring each twin in the same commit. Runtime coverage MOVES from $(TESTS) to test-lang (T1 runs + asserts via `ww test`) + test-lang-byteid (T2 keeps cs==ww .s byte-id); the $(TESTS) headline drops 5. Every assert is a primitive int/bool comparison with a width-preserving (`==`) sink so a stale high half or wrong stride FAILS; the narrow-signed rows route through an `: i32` cast against a 64B-widened literal to force sign-extension onto the load. Each .c row maps to one inline @test fn (50 cases total, strict superset of the C rows): 947_deref_narrow_run.c -> deref_narrow_test.ww (#116, 10 rows: *p reads pointee width not 8B MOVQ; i32/u32/u8/i8/i16/u16 + !i32-alias + enum-i8 + bool/i64 controls) 949_ptrarr_index_run.c -> ptrarr_index_test.ww (#61, 23 rows: p[i]/(&p[i])/(*p)[i] stride by size(T); {1,2,4,8}B, const+var idx, param/local/cast bases, neighbor guards, nested *[2][3], *[3]str header, siphash round()) 949_dotbase_arr_run.c -> dotbase_arr_test.ww (#135, 3 rows: (*struct).arrayfield[i] read/write/compound addresses the field) 944_def_amp_idx_run.c -> def_amp_idx_test.ww (#94, 6 rows: &D[i] over a def-array; +plain/read/2D controls) 944_alias_amp_idx_run.c -> alias_amp_idx_test.ww (#5, 8 rows: &a[i] over an alias-typed base classifies off the chased type; local/global, narrow, fwd-ref, plain+str controls) The two sibling .c (949_dotbase_addr_slice_run, 944_alias_def_addr_run) stay in $(TESTS): the first is run-only byteid=0 (#254 cs!=ww rows), the second carries a LOUD rule-7 reject row — both routed to fold-3 (task #7). Bump LANGBYTEID_EXPECTED_MIN 38->43.
99 lines
3.0 KiB
Plaintext
99 lines
3.0 KiB
Plaintext
// alias_amp_idx_test — `&a[i]` over an ALIAS-typed array base must classify
|
|
// arrayness off the CHASED type, not the syntactic tnode, migrated from
|
|
// test/wcc/944_alias_amp_idx_run.c (#5 alias arc). cgun's TK_AMP N_INDEX
|
|
// classify keyed arrayness off the syntactic tnode (N_TNAME), so `&a[i]` over an
|
|
// alias-typed base missed the N_TARRAY gate and materialized the base as MOVQ
|
|
// (element-0 VALUE) instead of LEAQ (storage address) → wild pointer, ww SEGV
|
|
// 139 on the deref (esz was already alias-correct, ONLY the base classify moved).
|
|
// cstage classifies off the chased type and is the runtime-correct reference;
|
|
// the fix re-keys both legs off tichase(base.type_) gated on TY_NAMED, so
|
|
// non-alias rows are byte-id-neutral by construction. The .s is byte-identical
|
|
// cs==ww, so these behavioral @tests are the net.
|
|
//
|
|
// All reads/writes go THROUGH THE TAKEN POINTER; values exceed 255 to break
|
|
// little-endian prefix-luck and the LAST element is checked. amp_ctrl is the
|
|
// plain-local control; amp_l1/amp_l2 are 1-/2-level alias locals; amp_order is
|
|
// the forward-ref shape (the original placed `type arr` after the use — here
|
|
// module-level resolution subsumes it); amp_narrow pins that the alias BASE was
|
|
// the only wrong half (the narrow esz was already right); amp_g1/amp_g2 are
|
|
// alias-typed globals; amp_gctrl holds the plain-global + global-str #11 legs.
|
|
//
|
|
// NOT pinned here (filed, a DIFFERENT site both stages): `&D[i]` over a
|
|
// DEF-array — covered by def_amp_idx_test (#94).
|
|
|
|
package alias_amp_idx_test;
|
|
|
|
type arr = [4]int;
|
|
type arr2 = arr;
|
|
type A = [4]u32;
|
|
|
|
let g1: arr = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let g2: arr2 = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let gc: [4]int = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let gs: str = "wxyz";
|
|
|
|
@test fn amp_ctrl() void = {
|
|
let a: [4]int = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let p: *int = &a[2];
|
|
assert(*p == 3000);
|
|
*p = 7777;
|
|
assert(a[2] == 7777);
|
|
let q: *int = &a[3];
|
|
assert(*q == 4000);
|
|
};
|
|
|
|
@test fn amp_l1() void = {
|
|
let a: arr = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let p: *int = &a[3];
|
|
assert(*p == 4000);
|
|
*p = 8888;
|
|
assert(a[3] == 8888);
|
|
};
|
|
|
|
@test fn amp_l2() void = {
|
|
let a: arr2 = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let p: *int = &a[3];
|
|
assert(*p == 4000);
|
|
*p = 9999;
|
|
assert(a[3] == 9999);
|
|
};
|
|
|
|
@test fn amp_order() void = {
|
|
let a: arr = [1000: int, 2000: int, 3000: int, 4000: int];
|
|
let p: *int = &a[3];
|
|
assert(*p == 4000);
|
|
*p = 8888;
|
|
assert(a[3] == 8888);
|
|
};
|
|
|
|
@test fn amp_narrow() void = {
|
|
let a: A = [1000: u32, 2000: u32, 3000: u32, 4000: u32];
|
|
let p: *u32 = &a[3];
|
|
assert(*p == 4000);
|
|
*p = 5555;
|
|
assert(a[3] == 5555);
|
|
};
|
|
|
|
@test fn amp_g1() void = {
|
|
let p: *int = &g1[3];
|
|
assert(*p == 4000);
|
|
*p = 8888;
|
|
assert(g1[3] == 8888);
|
|
};
|
|
|
|
@test fn amp_g2() void = {
|
|
let p: *int = &g2[3];
|
|
assert(*p == 4000);
|
|
*p = 9999;
|
|
assert(g2[3] == 9999);
|
|
};
|
|
|
|
@test fn amp_gctrl() void = {
|
|
let p: *int = &gc[3];
|
|
assert(*p == 4000);
|
|
*p = 7777;
|
|
assert(gc[3] == 7777);
|
|
let q: *u8 = &gs[3];
|
|
assert(*q == 'z');
|
|
};
|