test/lang: absorb retired-carrier coverage

local_zeroinit_test.ww takes the 840/944 zero-init seam (dirty-frame
prime and probe share one @test because the runtime forks per test);
alias_cgen_b6, alloc_nested_field, array_static_init, and
strarray_static gain the rows their retired wrappers held; the
remaining files re-point reject-row citations at the r788_* and
stage-matrix fixtures.
This commit is contained in:
2026-08-07 23:02:56 +09:00
parent a95a7a316b
commit 1a57de6ffe
8 changed files with 247 additions and 18 deletions

View File

@@ -169,12 +169,16 @@ type c3es_my32b = c3es_my32;
};
type c3kw_my32 = u32;
type c3kw_S = struct { arr: [3]c3kw_my32, n: int };
type c3kw_my32b = c3kw_my32;
type c3kw_S = struct { arr: [3]c3kw_my32b, tail: int };
@test fn kw1_101() void = {
let s = c3kw_S { arr = [10u32, 20u32, 30u32], n = 4 };
assert(s.arr[0] + s.arr[1] + s.arr[2] == 60u32);
assert(s.n == 4);
let s = c3kw_S { arr = [10u32, 20u32, 30u32], tail = 77 };
assert(size(c3kw_my32b) == 4);
assert(s.arr[0] == 10u32);
assert(s.arr[1] == 20u32);
assert(s.arr[2] == 30u32);
assert(s.tail == 77);
};
type c3kc_my16 = u16;

View File

@@ -7,8 +7,8 @@
// on the UNCHASED N_TARRAY tnode so an alias-typed global ARRAY got `undefined
// reference to main.g`. Both fixed by ONE tichase at the dispatch entry.
//
// This table is the PERMANENT GUARD: the global decl path is lint-invisible
// (ww side is a no-peel consumer; cs helpers spell the one chased accessor).
// This table is the PERMANENT GUARD for the global-declaration dispatch path:
// ww starts from a raw type node while cs starts from resolved type metadata.
// Values exceed 255 (no little-endian prefix-luck) and readbacks assert the
// LAST element. The C driver ran each row both stages + asserted cs==ww exit;
// here the cstage run is test-lang (T1) and byte-id is test-lang-byteid (T2).

View File

@@ -9,12 +9,11 @@
// helper in DST_PTR_SP mode (base reloaded from the pushed heap ptr at
// (SP)), which recurses to arbitrary depth.
//
// Every row reads the heap struct back via `let o: T = *p` (a whole-
// struct deref-load to a BP-rel local) so the assertions never traverse
// the chained-dot-through-heap-ptr read path (a separate pre-existing
// cs!=ww the C7c fill fix does not touch). Each row asserts the nested
// leaf VALUE (reddens when the fix is reverted: the dropped leaf reads
// 0) AND the sibling scalar leaves before/after it (no clobber).
// The nested-field rows read the heap struct back via `let o: T = *p` so
// they isolate heap filling from chained pointer traversal. The alias-head and
// exact direct control both read p.x/p.y: together they preserve the old #26
// wrapper's alias-vs-non-alias comparison. Every row asserts the affected
// values independently.
package alloc_nested_field_test;
@@ -28,6 +27,21 @@ type WithArr = struct { lead: i64, arr: [3]i64, trail: i64 };
type TwoNest = struct { head: i64, s: Inner, arr: [2]i64, tail: i64 };
type AliasPoint = struct { x: i64, y: i64 };
type AliasPt = AliasPoint;
@test fn alias_named_struct() void = {
let p: *AliasPt = alloc(AliasPt{ x = 1, y = 2 })!;
assert(p.x == 1);
assert(p.y == 2);
};
@test fn direct_named_struct_control() void = {
let p: *AliasPoint = alloc(AliasPoint{ x = 1, y = 2 })!;
assert(p.x == 1);
assert(p.y == 2);
};
@test fn depth1_nested_struct() void = {
// Inner{q=10} is the field VALUE of x; pre-fix x.q dropped to 0.
let p = alloc(Outer{ x = Inner{ q = 10 }, y = 5 })!;

View File

@@ -11,12 +11,18 @@
// array-field elements directly (D1.buf[k], D2.m[i][j]): the old #137/#150 cs≠ww
// global-struct-field-base bug is CLOSED at HEAD, so the read is now cs==ww IDENT
// — the original deferred this to byte-id only because the bug was then open.
// The under-length and `...` rows distinguish the two scalar-tail policies:
// ordinary omitted slots are zero, while an explicit repeat marker replays the
// last value. Every slot is asserted independently so neither policy can mask
// the other through a sum.
package array_static_init_test;
let A_U8: [4]u8 = [1u8, 2u8, 3u8, 4u8];
let A_U32: [4]u32 = [1u32, 2u32, 3u32, 4u32];
let A_U64: [2]u64 = [1u64, 2u64];
let A_U64_TAIL: [4]u64 = [1, 2];
let A_U64_REPEAT: [4]u64 = [7, 9...];
let A_INEG: [4]i32 = [-1, -2, -3, -4];
let A_F64: [4]f64 = [1.5, -2.5, 3.5, -4.5];
let A_F32: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32];
@@ -53,6 +59,21 @@ fn at(i: i32, j: i32) u64 = { return A2V[i][j]; };
@test fn let_u8_arr() void = { assert(A_U8[0]: i32 == 1); };
@test fn let_u32_arr() void = { assert(A_U32[0]: i32 == 1); };
@test fn let_u64_arr() void = { assert(A_U64[0]: i32 == 1); };
@test fn let_u64_zero_tail() void = {
assert(A_U64_TAIL[0] == 1u64);
assert(A_U64_TAIL[1] == 2u64);
assert(A_U64_TAIL[2] == 0u64);
assert(A_U64_TAIL[3] == 0u64);
};
@test fn let_u64_repeat_tail() void = {
assert(A_U64_REPEAT[0] == 7u64);
assert(A_U64_REPEAT[1] == 9u64);
assert(A_U64_REPEAT[2] == 9u64);
assert(A_U64_REPEAT[3] == 9u64);
};
@test fn let_i32_neg_arr() void = { assert(A_INEG[0] == -1); };
@test fn let_f64_arr() void = {

View File

@@ -1,8 +1,7 @@
// arrlit_slice_test — #25/#31: a one-step array-LITERAL initialiser for a SLICE
// local (`let xs: []T = [..]`). Migrated from test/wcc/953_arrlit_slice_run.c
// (value rows; cs==ww byte-id rides T2). Reject rows (out-of-range element +
// the three non-let-borrow contexts) stay as runww //ww:error carriers under
// test/wcc/data/.
// (value rows; cs==ww byte-id rides T2). Reject rows, including the
// stage-asymmetric assignment diagnostic, live under test/wcc/data/.
//
// #31 (silent cs!=ww): the borrow wrapped the un-addressable arrlit directly,
// so .ptr pointed at garbage (xs[1] returned 1, not 20; []u8/[]str SEGV). #25

View File

@@ -0,0 +1,182 @@
// local_zeroinit_test preserves the retired C wrappers' dirty-frame runtime
// seam. Each @test child
// dirties a callee frame and immediately calls a sibling probe whose bare local
// is its first slot. Keeping the calls in one @test matters: the native runner
// forks once per test, so separate dirty and probe tests could receive clean
// pages and mask a missing zero-fill.
package local_zeroinit_test;
type tiny3 = struct { a: u8, b: u8, c: u8 };
// Preserve the two original poison frames. Besides their distinct byte values,
// the 512-byte int frame exercises the larger array cases while the 64-byte u8
// frame is the historical sub-8 aggregate reproducer.
fn dirty_int_frame() int = {
let j: [64]int;
for (let i: int = 0; i < 64; i += 1) {
j[i] = 165;
};
return j[0];
};
fn dirty_byte_frame() void = {
let big: [64]u8;
let i: i32 = 0;
for (i < 64) {
big[i] = 222u8;
i += 1;
};
};
fn probe_int3() i32 = {
let a: [3]int;
return (a[0] + a[1] + a[2]): i32;
};
fn probe_u32x4() i32 = {
let a: [4]u32;
return (a[0] + a[1] + a[2] + a[3]): i32;
};
fn probe_u8x20_int_frame() i32 = {
let b: [20]u8;
let s: i32 = 0;
for (let i: int = 0; i < 20; i += 1) {
s += b[i]: i32;
};
return s;
};
fn probe_int2x2() i32 = {
let m: [2][2]int;
return (m[0][0] + m[0][1] + m[1][0] + m[1][1]): i32;
};
fn probe_initialized_int3() i32 = {
let c: [3]int = [7, 8, 9];
return (c[0] + c[1] + c[2]): i32;
};
@test fn array_int3_zero() void = {
dirty_int_frame();
assert(probe_int3() == 0);
};
@test fn array_u32x4_zero() void = {
dirty_int_frame();
assert(probe_u32x4() == 0);
};
@test fn array_u8x20_zero() void = {
dirty_int_frame();
assert(probe_u8x20_int_frame() == 0);
};
@test fn nested_array_int2x2_zero() void = {
dirty_int_frame();
assert(probe_int2x2() == 0);
};
@test fn initialized_array_control() void = {
dirty_int_frame();
assert(probe_initialized_int3() == 24);
};
fn probe_u8x3() i32 = {
let c: [3]u8;
return (c[0]: i32) + (c[1]: i32) + (c[2]: i32);
};
fn probe_u8x5() i32 = {
let c: [5]u8;
let acc: i32 = 0;
let j: i32 = 0;
for (j < 5) {
acc += c[j]: i32;
j += 1;
};
return acc;
};
fn probe_u8x7() i32 = {
let c: [7]u8;
let acc: i32 = 0;
let j: i32 = 0;
for (j < 7) {
acc += c[j]: i32;
j += 1;
};
return acc;
};
fn probe_tiny3() i32 = {
let s: tiny3;
return (s.a: i32) + (s.b: i32) + (s.c: i32);
};
fn probe_scalar_i32() i32 = {
let x: i32;
return x;
};
fn probe_u8x20_byte_frame() i32 = {
let c: [20]u8;
let acc: i32 = 0;
let j: i32 = 0;
for (j < 20) {
acc += c[j]: i32;
j += 1;
};
return acc;
};
fn probe_str_len() i32 = {
let empty: str;
return empty.len;
};
fn probe_slice_len() i32 = {
let xs: []i32;
return xs.len;
};
@test fn sub8_array_u8x3_zero() void = {
dirty_byte_frame();
assert(probe_u8x3() == 0);
};
@test fn sub8_array_u8x5_zero() void = {
dirty_byte_frame();
assert(probe_u8x5() == 0);
};
@test fn sub8_array_u8x7_zero() void = {
dirty_byte_frame();
assert(probe_u8x7() == 0);
};
@test fn sub8_struct_u8x3_zero() void = {
dirty_byte_frame();
assert(probe_tiny3() == 0);
};
@test fn scalar_i32_control() void = {
dirty_byte_frame();
assert(probe_scalar_i32() == 0);
};
@test fn array_u8x20_control() void = {
dirty_byte_frame();
assert(probe_u8x20_byte_frame() == 0);
};
@test fn str_header_control() void = {
dirty_byte_frame();
assert(probe_str_len() == 0);
};
@test fn slice_header_control() void = {
dirty_byte_frame();
assert(probe_slice_len() == 0);
};

View File

@@ -7,7 +7,8 @@
// .len-only check would miss a wrong/swapped element relocation. The empty-slot
// and `...` repeat-suffix rows pin that an empty element doesn't shift the
// following element's reloc and that the repeat-fill row's DATAR resolves to the
// last explicit element.
// last explicit element. The under-length row separately pins that omitted
// elements have zero-length headers rather than replaying the last string.
package strarray_static_test;
@@ -16,6 +17,7 @@ let TPTR: [3]str = ["A", "B", "C"];
let TVAR: [3]str = ["xx", "yyy", "z"];
let TEMP: [2]str = ["", "Z"];
let TREP: [3]str = ["X", "Y"...];
let TTAIL: [4]str = ["ab", "cde"];
@test fn strtab_len() void = {
assert((TLEN[0].len + TLEN[1].len + TLEN[2].len): i32 == 6);
@@ -42,3 +44,10 @@ let TREP: [3]str = ["X", "Y"...];
let p: *u8 = TREP[2].ptr;
assert((*p): i32 == 89);
};
@test fn strtab_zero_tail() void = {
assert(TTAIL[0].len == 2);
assert(TTAIL[1].len == 3);
assert(TTAIL[2].len == 0);
assert(TTAIL[3].len == 0);
};

View File

@@ -1,8 +1,8 @@
// type_value_shadow_test — #225: a value binding that shadows a same-named TYPE
// must NOT hide that type in type-annotation or cast position. ww keeps type and
// value namespaces separate. Migrated from test/wcc/788_type_value_shadow_run.c
// (value rows; cs==ww byte-id rides T2). The value-in-type-position reject row
// (no same-named type) stays as a carrier pin.
// (value rows; cs==ww byte-id rides T2). The value-in-type-position reject and
// its positive control are stage-matrix fixtures under r788_*.
//
// Pre-fix cstage resolved the type name via the kind-blind lookup, so the inner
// value shadowed the global type → "unknown type". The fix is a kind-filtered