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.
57 lines
2.0 KiB
Plaintext
57 lines
2.0 KiB
Plaintext
// def_amp_idx_test — `&D[i]` over a DEF-array (indexed &-base), migrated from
|
|
// test/wcc/944_def_amp_idx_run.c (#94). BOTH stages SEGV'd at the TK_AMP
|
|
// N_INDEX N_IDENT base classify: a def-array base matched neither the local nor
|
|
// the let leg and fell to a wrong else — cstage zero-based the addend (XORQ
|
|
// BX,BX → wild ptr) while wwstage value-loaded the symbol (MOVQ name(SB) = D[0],
|
|
// not its address). DIVERGENT asm, both wild — only a RUNTIME row pins this
|
|
// class. The fix adds one def-array leg per stage mirroring the working let leg
|
|
// (cs `def_isarraydef → LEAQ name(SB),BX`; ww `defvartnode`→isglobalarr→LEAQ),
|
|
// so the existing i*esz scale + ADDQ round-trips; cs/ww now emit byte-identical
|
|
// LEAQ-SB asm. The `*p` deref is spelled `let v: T = *p;` because `*p: T` parses
|
|
// as `*(p: T)` (cast binds tighter than prefix-*), a spurious "cannot deref".
|
|
//
|
|
// amp_int/amp_u32/amp_arg are the SEGV repros (read the def-array element back
|
|
// through the taken pointer, narrow esz on amp_u32); ctrl_plain/ctrl_read/ctrl_2d
|
|
// are the controls the new leg must not perturb (plain &D, indexed read, 2D
|
|
// &M[1][1]). Distinct def symbol names per shape since they share one module.
|
|
|
|
package def_amp_idx_test;
|
|
|
|
def Dint: [3]int = [1000: int, 2000: int, 3000: int];
|
|
def Du32: [3]u32 = [1000: u32, 2000: u32, 3000: u32];
|
|
def M2: [2][2]int = [[10: int, 20: int], [30: int, 40: int]];
|
|
|
|
fn deref_int(p: *int) int = { let v: int = *p; return v; };
|
|
|
|
@test fn amp_int() void = {
|
|
let p: *int = &Dint[2];
|
|
let v: int = *p;
|
|
assert(v == 3000);
|
|
};
|
|
|
|
@test fn amp_u32() void = {
|
|
let p: *u32 = &Du32[2];
|
|
let v: u32 = *p;
|
|
assert(v == 3000u32);
|
|
};
|
|
|
|
@test fn amp_arg() void = {
|
|
// &D[2] as a func-arg (context-independent base).
|
|
assert(deref_int(&Dint[2]) == 3000);
|
|
};
|
|
|
|
@test fn ctrl_plain() void = {
|
|
let p: *[3]int = &Dint;
|
|
assert((*p)[0] == 1000);
|
|
};
|
|
|
|
@test fn ctrl_read() void = {
|
|
assert(Dint[1] == 2000);
|
|
};
|
|
|
|
@test fn ctrl_2d() void = {
|
|
let q: *int = &M2[1][1];
|
|
let v: int = *q;
|
|
assert(v == 40);
|
|
};
|