test: migrate Fam4 static-init/DATA-emit value tests to @test (#30)

Continues the test-arch tower past Fam8-13. 11 module-level static-init
/ DATA-emit value drivers move from test/wcc/*_run.c into @test row-
tables under test/lang/; every classification empirically re-probed at
HEAD (refuting two stale worklist tags).

- value rows -> test/lang/*_test.ww (11 files)
- reject rows -> runww //ww:error carriers (3, dual-stage non-vacuous;
  947 const-divzero confirmed a both-stage compile-reject, not run-exit)
- 840_zeroinit, 944_array_zeroinit, 989_arrlit_tail_zero kept as byte-id
  .c pins (zero-over-dirtied-frame / DATAW-length is byte-id-blind to a
  runtime @test; #263), mutation-gated
- repoint two stale comment refs to deleted test names (719,
  989_structlocal_frame)

Migrated static-init @test ride the cs==ww T2 byte-id gate, preserving
DATA-emit byte-id. 2D global-struct array-field read (#137/#150)
confirmed cs==ww + correct at HEAD. Coverage parity verified row-by-row;
two-round reviewed. Floor ratchet follows.
This commit is contained in:
2026-06-25 01:32:32 +09:00
parent 4cb697af87
commit 74cc35d488
28 changed files with 647 additions and 2790 deletions

View File

@@ -0,0 +1,41 @@
// arr_u16_store_test — [N]u16/[N]i16 array-literal init stores MOVW per slot.
// Migrated from test/wcc/914_arr_u16_store_run.c. Pre-fix a [4]u16 init emitted
// overlapping MOVQ stores (accident-corrected for some values); the fix dispatches
// a proper MOVW per 2-byte slot (op chosen by esz, not signedness). cstage
// build+run was T1; cs==ww .s byte-id rides T2 (test-lang-byteid). The full_init
// row asserts each element to catch any value drift; the [4]u8 control pins the
// MOVB path is unchanged; i16_signed pins the dispatch is not signedness-gated.
package arr_u16_store_test;
@test fn u16_full_init() void = {
let a: [4]u16 = [0xABCDu16, 0xBEEFu16, 0xC0DEu16, 0xDEADu16];
assert(a[0] == 0xABCDu16);
assert(a[1] == 0xBEEFu16);
assert(a[2] == 0xC0DEu16);
assert(a[3] == 0xDEADu16);
};
@test fn u16_small_values() void = {
let a: [4]u16 = [10u16, 20u16, 30u16, 40u16];
let s: i32 = 0;
s += a[0]: i32; s += a[1]: i32;
s += a[2]: i32; s += a[3]: i32;
assert(s == 100);
};
@test fn u8_control() void = {
let a: [4]u8 = [10u8, 20u8, 30u8, 40u8];
let s: i32 = 0;
s += a[0]: i32; s += a[1]: i32;
s += a[2]: i32; s += a[3]: i32;
assert(s == 100);
};
@test fn i16_signed() void = {
let a: [4]i16 = [10i16, 20i16, 30i16, -5i16];
let s: i32 = 0;
s += a[0]: i32; s += a[1]: i32;
s += a[2]: i32; s += a[3]: i32;
assert(s == 55);
};

View File

@@ -0,0 +1,99 @@
// array_static_init_test — module-level 1D/2D/3D array static-init, element
// read. Migrated from test/wcc/919_array_static_init_run.c (#129 Phase A.3,
// #156). emit_array_lit_bytes recurses on a TY_ARRAY element (esz=etype->size,
// rule 13); cgindex leaves the sub-array ADDRESS for an array element so the
// outer index dereferences the right cell (#135 sister). cstage build+run was
// T1; cs==ww .s byte-id rides T2 (test-lang-byteid). The nested-array `...`
// repeat reject is the runww carrier test/wcc/data/arr_nested_ellipsis_reject.
//
// Float-element rows assert bit-exact incl negative elements (drew: exercise the
// sign-XOR byte-loop per element). The struct-with-array-field rows read the
// 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.
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_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];
def DA_U32: [4]u32 = [11u32, 22u32, 33u32, 44u32];
def DA_F64: [4]f64 = [1.5, 2.5, 3.5, 4.5];
let A_UZ: [4]u8 = [0u8, 0u8, 0u8, 0u8];
let A_U1: [1]u8 = [7u8];
let A2D: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];
def DA2D: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];
let A2V: [3][2]u64 = [[10u64,11u64],[20u64,21u64],[30u64,31u64]];
let A28: [2][1]u32 = [[7u32],[9u32]];
let A2W: [2][2]u64 = [[1u64,2u64],[3u64,4u64]];
let A3D: [2][2][2]u8 = [[[1u8,2u8],[3u8,4u8]],[[5u8,6u8],[7u8,8u8]]];
type dt1 = struct { tag: i32, buf: [4]u8 };
let D1: dt1 = dt1{tag=42, buf=[1u8, 2u8, 3u8, 4u8]};
type dt2 = struct { tag: i32, m: [2][2]u64 };
let D2: dt2 = dt2{tag=42, m=[[1u64,2u64],[3u64,4u64]]};
fn bits64(v: f64) u64 = {
let x: f64 = v;
let p: *u64 = (&x): *u64;
return *p;
};
fn bits32(v: f32) u32 = {
let x: f32 = v;
let p: *u32 = (&x): *u32;
return *p;
};
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_i32_neg_arr() void = { assert(A_INEG[0] == -1); };
@test fn let_f64_arr() void = {
assert(bits64(A_F64[0]) == 0x3FF8000000000000u64);
assert(bits64(A_F64[1]) == 0xC004000000000000u64);
assert(bits64(A_F64[3]) == 0xC012000000000000u64);
};
@test fn let_f32_arr() void = {
assert(bits32(A_F32[0]) == 0x3FC00000u32);
assert(bits32(A_F32[1]) == 0xC0200000u32);
assert(bits32(A_F32[3]) == 0xC0900000u32);
};
@test fn def_u32_arr() void = { assert(DA_U32[0]: i32 == 11); };
@test fn def_f64_arr() void = {
assert(bits64(DA_F64[0]) == 0x3FF8000000000000u64);
assert(bits64(DA_F64[3]) == 0x4012000000000000u64);
};
@test fn let_struct_with_arr_field() void = {
assert(D1.tag == 42);
assert(D1.buf[0]: i32 == 1);
assert(D1.buf[3]: i32 == 4);
};
@test fn let_u8_zero_arr() void = { assert(A_UZ[0]: i32 == 0); };
@test fn let_u8_single() void = { assert(A_U1[0]: i32 == 7); };
@test fn let_2d_u64() void = { assert(A2D[1][0]: i32 == 3); };
@test fn def_2d_u64() void = { assert(DA2D[2][1]: i32 == 6); };
@test fn let_2d_varidx() void = { assert((at(1, 1) + at(2, 0)): i32 == 51); };
@test fn let_2d_u32_8byte() void = { assert(A28[1][0]: i32 == 9); };
@test fn let_2d_write() void = {
A2W[1][0] = 99u64;
assert((A2W[0][0] + A2W[0][1] + A2W[1][0] + A2W[1][1]): i32 == 106);
};
@test fn let_struct_2d_field() void = {
assert(D2.tag == 42);
assert(D2.m[1][0]: i32 == 3);
assert(D2.m[1][1]: i32 == 4);
};
@test fn let_3d_u8() void = { assert(A3D[1][1][0]: i32 == 7); };

View File

@@ -0,0 +1,62 @@
// const_slice_aggregate_test — module-level const slice of (str,*fn) tuple rows
// + scalar &fn globals, DATA emit with element relocations. Migrated from
// test/wcc/946_const_slice_aggregate_run.c (#117/#119). cstage build+run was T1;
// cs==ww .s byte-id rides T2 (test-lang-byteid). The loud non-tuple-aggregate
// reject is the runww carrier test/wcc/data/slice_of_str_reject.
//
// drew: CALL THROUGH the *fn reloc — a scalar-only / len-only assert is
// reloc-blind. Each row calls each distinct fn back so a wrong/swapped reloc is
// caught; the str-element relocs + per-row backing stride ride the T2 byte-id.
// Whole-element word0 is the only correctly-loaded backing word (#121 read
// constraint), so the fn-first / scalar-first orderings put the read target at
// word0.
package const_slice_aggregate_test;
fn fa(c: rune) bool = { return c == 'a'; };
fn fz(c: rune) bool = { return c == 'z'; };
const TBL_FN: [](*fn(c: rune) bool, str) = [(&fa, "aa"), (&fz, "zzz")];
const TBL_SF: [](str, *fn(c: rune) bool) = [("aa", &fa), ("zzz", &fz)];
const TBL_3: [](str, *fn(c: rune) bool) =
[("a", &fa), ("bb", &fa), ("ccc", &fa)];
const TSCAL: [](i64, str) = [(10i64, "a"), (20i64, "bb")];
let PF: *fn(c: rune) bool = &fa;
let PG: *fn(c: rune) bool = &fz;
@test fn fnfirst_reloc() void = {
let e0 = TBL_FN[0];
let e1 = TBL_FN[1];
let f0 = e0.0;
let f1 = e1.0;
assert((*f0)('a'));
assert(!(*f0)('z'));
assert((*f1)('z'));
assert(!(*f1)('a'));
assert(len(TBL_FN) == 2);
};
@test fn consumer_str_fn() void = {
assert(len(TBL_SF) == 2);
};
@test fn consumer_3row() void = {
assert(len(TBL_3) == 3);
};
@test fn scalar_tuple_slice() void = {
let e0 = TSCAL[0];
let e1 = TSCAL[1];
let v0 = e0.0;
let v1 = e1.0;
assert(v0 == 10);
assert(v1 == 20);
assert(len(TSCAL) == 2);
};
@test fn scalar_fnptr() void = {
assert((*PF)('a'));
assert(!(*PF)('z'));
assert((*PG)('z'));
assert(!(*PG)('a'));
};

View File

@@ -0,0 +1,62 @@
// def_float_lit_test — module-level `def`/`let` f64/f32 literal (incl negation)
// emits DATA, read back from a fn. Migrated from test/wcc/917_def_float_lit_run.c
// (#129 Phase A.1). Pre-fix `def K: f64 = lit;` fell through emit_defs's int-only
// fold gate so no DATAW landed (link: `undefined reference to main.K`); emit_lets's
// float arm never peeled N_UN(MINUS/PLUS, N_FLOATLIT) so `let g: f64 = -1.5;`
// silently zero-emitted. Fix = shared emit_floatlit_data helper (negation via
// IEEE-754 sign-bit XOR). cstage build+run was T1; cs==ww .s byte-id rides T2
// (test-lang-byteid).
//
// drew: assert BIT-EXACT incl sign — the bits()-reinterpret reads the full IEEE
// pattern, so a sign-bit or mantissa drift fails (a truncating `: i32` read would
// alias 1.5 and 1.9). The negative rows pin the sign-XOR byte path.
package def_float_lit_test;
def KDPOS: f64 = 1.5;
def KDNEG: f64 = -1.5;
def KFPOS: f32 = 1.5f32;
def KFNEG: f32 = -1.5f32;
let GDNEG: f64 = -1.5;
let GDPOS: f64 = 1.5;
let GFPOS: f32 = 1.5f32;
fn bits64(v: f64) u64 = {
let x: f64 = v;
let p: *u64 = (&x): *u64;
return *p;
};
fn bits32(v: f32) u32 = {
let x: f32 = v;
let p: *u32 = (&x): *u32;
return *p;
};
@test fn def_f64_pos() void = {
assert(bits64(KDPOS) == 0x3FF8000000000000u64);
};
@test fn def_f64_neg() void = {
assert(bits64(KDNEG) == 0xBFF8000000000000u64);
};
@test fn def_f32_pos() void = {
assert(bits32(KFPOS) == 0x3FC00000u32);
};
@test fn def_f32_neg() void = {
assert(bits32(KFNEG) == 0xBFC00000u32);
};
@test fn let_f64_neg() void = {
assert(bits64(GDNEG) == 0xBFF8000000000000u64);
};
@test fn let_f64_pos() void = {
assert(bits64(GDPOS) == 0x3FF8000000000000u64);
};
@test fn let_f32_pos() void = {
assert(bits32(GFPOS) == 0x3FC00000u32);
};

View File

@@ -0,0 +1,33 @@
// inferred_scalar_global_test — module-level inferred/const-expr scalar global
// emit + read. Migrated from test/wcc/947_inferred_scalar_global_run.c
// (#66 b-i, #134 neg, #133 const-expr). An inferred / unary / const-expr int
// global once emitted no DATAW on wwstage (MOVSXD on stale AX) and link-failed
// on cstage; the let pass-2 arm now const-folds the rhs and stamps an N_INTLIT
// so cgen's literal DATA emitter fires in BOTH stages. cstage build+run was T1;
// cs==ww .s byte-id rides T2 (test-lang-byteid). The div-by-zero const-expr
// reject is the runww carrier test/wcc/data/const_divzero_reject.
//
// The typed controls (typed_ctrl/neg_typed_ctrl/const_typed) lock the
// construction proof: the inferred decl's emitted .s equals the typed decl's
// after defaulting.
package inferred_scalar_global_test;
let SI = 42;
let STC: i64 = 42;
let SNI = -42;
let SNT: int = -42;
let SCI = 7 * 6;
let SCT: i64 = 7 * 6;
def KD: int = 6;
let SDR = KD * 7;
let SUB = -(2 * 3);
@test fn inferred() void = { assert(SI: i64 == 42); };
@test fn typed_ctrl() void = { assert(STC == 42); };
@test fn neg_inferred() void = { assert(SNI: i64 == -42); };
@test fn neg_typed_ctrl() void = { assert(SNT == -42); };
@test fn const_inferred() void = { assert(SCI: i64 == 42); };
@test fn const_typed() void = { assert(SCT == 42); };
@test fn const_defref() void = { assert(SDR: i64 == 42); };
@test fn const_unary_binop() void = { assert(SUB: i64 == -6); };

View File

@@ -0,0 +1,38 @@
// nestfield_test — nested sub-8 composite struct field at natural offsets.
// Migrated from test/wcc/989_nestfield_run.c (#44/#55). For outer{a:u8, p:inner}
// the natural offset of p is 1, but a pre-fix slot-padded layout put it at 8, so
// construction (write) and field-access (read) disagreed and o.p.x / o.p.y read
// wrong. cstage build+run was T1; the original cat-A invariant (cs==ww exit)
// now rides the stronger T2 .s byte-id (test-lang-byteid).
//
// nested3's z proves post-composite accumulation stays natural (z follows the
// 1-byte-padded inner, not the 8-byte-padded one). flat_ctl is the no-sub-8-field
// control where natural and slot-padded layouts coincide.
package nestfield_test;
type inr = struct { x: u8, y: u8 };
type ot2 = struct { a: u8, p: inr };
type ot3 = struct { a: u8, p: inr, z: i64 };
type flt = struct { a: u8, b: i64 };
@test fn nested2() void = {
let o: ot2 = ot2 { a = 5, p = inr { x = 6, y = 7 } };
assert(o.a: int == 5);
assert(o.p.x: int == 6);
assert(o.p.y: int == 7);
};
@test fn nested3() void = {
let o: ot3 = ot3 { a = 1, p = inr { x = 2, y = 3 }, z = 0x44444444i64 };
assert(o.a: int == 1);
assert(o.p.x: int == 2);
assert(o.p.y: int == 3);
assert(o.z == 0x44444444i64);
};
@test fn flat_ctl() void = {
let o: flt = flt { a = 9, b = 0x33333333i64 };
assert(o.a: int == 9);
assert(o.b == 0x33333333i64);
};

View File

@@ -0,0 +1,66 @@
// signed_data_emit_test — module-level signed i8..i64 scalar + 1D-array DATA
// emit, self-asserting the sign survives exactly. Migrated from
// test/wcc/923_signed_data_emit_run.c. Pre-fix wwstage silently zeroed negative
// array entries; cstage emitted nothing (link failed). cstage build+run was T1;
// cs==ww .s byte-id rides T2 (test-lang-byteid).
//
// drew: assert SIGN survives exactly — every row compares against the signed
// typed literal, so a sign-extension or zero-fill drift fails. i64_tilde pins
// the N_UN(TK_TILDE) fold (~0u64 == -1i64). The arrays mirror the utf8 DFA shape.
package signed_data_emit_test;
let X_I8N: i8 = -1i8;
let X_I8P: i8 = 42i8;
let X_I16N: i16 = -2i16;
let X_I16P: i16 = 1000i16;
let X_I32N: i32 = -100i32;
let X_I32P: i32 = 100000i32;
let X_I64N: i64 = -1000i64;
let X_I64P: i64 = 1000000i64;
let X_TILDE: i64 = (~0u64): i64;
let DFA: [8]i8 = [0i8, -1i8, 1i8, 2i8, 0i8, 0i8, -1i8, -1i8];
let A16: [4]i16 = [1i16, -2i16, 3i16, -4i16];
let A32: [4]i32 = [10i32, -20i32, 30i32, -40i32];
let A64: [4]i64 = [100i64, -200i64, 300i64, -400i64];
@test fn i8_neg_scalar() void = { assert(X_I8N == -1i8); };
@test fn i8_pos_scalar() void = { assert(X_I8P == 42i8); };
@test fn i16_neg_scalar() void = { assert(X_I16N == -2i16); };
@test fn i16_pos_scalar() void = { assert(X_I16P == 1000i16); };
@test fn i32_neg_scalar() void = { assert(X_I32N == -100i32); };
@test fn i32_pos_scalar() void = { assert(X_I32P == 100000i32); };
@test fn i64_neg_scalar() void = { assert(X_I64N == -1000i64); };
@test fn i64_pos_scalar() void = { assert(X_I64P == 1000000i64); };
@test fn i64_tilde_scalar() void = { assert(X_TILDE == -1i64); };
@test fn i8_arr_dfa() void = {
assert(DFA[0] == 0i8);
assert(DFA[1] == -1i8);
assert(DFA[2] == 1i8);
assert(DFA[3] == 2i8);
assert(DFA[6] == -1i8);
assert(DFA[7] == -1i8);
};
@test fn i16_arr_mixed() void = {
assert(A16[0] == 1i16);
assert(A16[1] == -2i16);
assert(A16[2] == 3i16);
assert(A16[3] == -4i16);
};
@test fn i32_arr_mixed() void = {
assert(A32[0] == 10i32);
assert(A32[1] == -20i32);
assert(A32[2] == 30i32);
assert(A32[3] == -40i32);
};
@test fn i64_arr_mixed() void = {
assert(A64[0] == 100i64);
assert(A64[1] == -200i64);
assert(A64[2] == 300i64);
assert(A64[3] == -400i64);
};

View File

@@ -0,0 +1,44 @@
// strarray_static_test — module-level [N]str static-init: per-element .len
// header sums + per-element .ptr RELOC dereferenced to chars. Migrated from
// test/wcc/919_strarray_static_run.c. cstage build+run was T1; cs==ww .s byte-id
// rides T2 (test-lang-byteid).
//
// drew: assert THROUGH the per-element .ptr deref (not just .len) — a reloc-blind
// .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.
package strarray_static_test;
let TLEN: [3]str = ["ab", "cde", "f"];
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"...];
@test fn strtab_len() void = {
assert((TLEN[0].len + TLEN[1].len + TLEN[2].len): i32 == 6);
};
@test fn strtab_ptr_elem2() void = {
let p: *u8 = TPTR[2].ptr;
assert((*p): i32 == 67);
};
@test fn strtab_ptr_varindex() void = {
let i: i32 = 1;
let p: *u8 = TVAR[i].ptr;
assert((*p): i32 == 121);
};
@test fn strtab_empty_then_ptr() void = {
assert(TEMP[0].len == 0);
let p: *u8 = TEMP[1].ptr;
assert((*p): i32 == 90);
};
@test fn strtab_repeat_suffix() void = {
let p: *u8 = TREP[2].ptr;
assert((*p): i32 == 89);
};

View File

@@ -0,0 +1,66 @@
// struct_composite_init_test — module-level `let`/`def` composite-struct
// static-init, field read. Migrated from test/wcc/918_struct_composite_init_run.c
// (#129 Phase A.2). Pre-fix emit_lets/emit_defs skipped struct-typed decls
// (link: `undefined reference to main.NAME`) and a struct def read MOVSXD'd
// stack byte 0. Fix = emit_struct_data/emit_struct_lit_bytes walking the field
// list with per-field-offset zero-fill (rule 13). cstage build+run was T1;
// cs==ww .s byte-id rides T2 (test-lang-byteid).
//
// The float-field rows assert bit-exact (drew) via bits64. let_empty/norhs read
// 0 from the statically zero-filled DATA (a global, not a dirtied stack — no
// benign-zero trap; an under-emit would shorten the symbol, not pad zero). The
// 8B-struct row pins the !is_struct gate over the sz==8 scalar short-circuit.
package struct_composite_init_test;
type cfg_t = struct { a: i32, b: u64 };
type ft = struct { a: f64, b: u32 };
type s8 = struct { a: i32, b: i32 };
let CFG_L: cfg_t = cfg_t{a=1, b=2u64};
def CFG_D: cfg_t = cfg_t{a=1, b=2u64};
let F_L: ft = ft{a=1.5, b=99u32};
def F_D: ft = ft{a=1.5, b=99u32};
let Z: cfg_t = cfg_t{};
let X8: s8 = s8{a=7, b=42};
let CFG_NR: cfg_t;
fn bits64(v: f64) u64 = {
let x: f64 = v;
let p: *u64 = (&x): *u64;
return *p;
};
@test fn let_int_struct() void = {
assert(CFG_L.a == 1);
assert(CFG_L.b == 2u64);
};
@test fn def_int_struct() void = {
assert(CFG_D.a == 1);
assert(CFG_D.b == 2u64);
};
@test fn let_float_field() void = {
assert(bits64(F_L.a) == 0x3FF8000000000000u64);
assert(F_L.b == 99u32);
};
@test fn def_float_field() void = {
assert(bits64(F_D.a) == 0x3FF8000000000000u64);
assert(F_D.b == 99u32);
};
@test fn let_empty_struct() void = {
assert(Z.a == 0);
assert(Z.b == 0u64);
};
@test fn let_int_struct_8b() void = {
assert(X8.a == 7);
assert(X8.b == 42);
};
@test fn let_norhs_struct() void = {
assert(CFG_NR.a == 0);
};

View File

@@ -0,0 +1,34 @@
// structlit_arrfield_test — struct array-field init + read (global let/def and
// local lit). Migrated from test/wcc/949_structlit_arrfield_run.c (#249). BUG B:
// reading a [4]u8 field of a module-global struct SEGFAULTed on wwstage; BUG A:
// a local struct-lit array field fell to the scalar tail and dropped every
// element but the first. Fix = cg_structlit_fill array arm + def_isstructdef
// LOAD widening (ADDQ $field_off). cstage build+run was T1; cs==ww .s byte-id
// rides T2 (test-lang-byteid). The def row has a [3]u8 pad ahead of encmap, so
// the read exercises a non-zero field offset (the base64 std_encoding shape).
package structlit_arrfield_test;
type e1 = struct { encmap: [4]u8 };
let GE: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] };
type e2 = struct { pad: [3]u8, encmap: [4]u8 };
def GD: e2 = e2 { pad = [9u8, 9u8, 9u8], encmap = [65u8, 66u8, 67u8, 68u8] };
@test fn global_let_read() void = {
assert(GE.encmap[0]: i32 == 65);
};
@test fn global_def_read_off() void = {
assert(GD.encmap[2]: i32 == 67);
};
@test fn local_lit_read0() void = {
let g: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] };
assert(g.encmap[0]: i32 == 65);
};
@test fn local_lit_read3() void = {
let g: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] };
assert(g.encmap[3]: i32 == 68);
};

View File

@@ -0,0 +1,70 @@
// valstruct_subsize_test — sub-8 nested value-struct zero-init extent, local +
// global, distinct byte asserts. Migrated from
// test/wcc/949_valstruct_subsize_run.c. A nested {[N]u8} value-struct of ABI
// size 1/2/4 once emitted a stray MOVQ $0 (local) / 8 zero DATA bytes (global)
// on wwstage that cstage didn't. cstage build+run was T1; cs==ww .s byte-id
// rides T2 (test-lang-byteid).
//
// The D1/D2 rows WRITE then READ a byte so the value is deterministic (the
// robust falsifiable dimension). The ctl_*_16 rows are the negative control: a
// >8 multi-word value-struct still zero-inits — a wrongly-suppressed >8 zero arm
// would read stack garbage (and diverge from the still-zeroing cstage on the T2
// byte-id, which is the real guarantee for the unwritten read).
package valstruct_subsize_test;
type in4 = struct { m: [4]u8 };
type ov4 = struct { i: in4 };
type in2 = struct { m: [2]u8 };
type ov2 = struct { i: in2 };
type in1 = struct { m: [1]u8 };
type ov1 = struct { i: in1 };
type in16 = struct { m: [16]u8 };
type ov16 = struct { i: in16 };
let G4: ov4;
let G2: ov2;
let G1: ov1;
let G16: ov16;
@test fn d1_local_4() void = {
let o: ov4;
o.i.m[0] = 66u8;
assert(o.i.m[0]: i32 == 66);
};
@test fn d1_local_2() void = {
let o: ov2;
o.i.m[1] = 55u8;
assert(o.i.m[1]: i32 == 55);
};
@test fn d1_local_1() void = {
let o: ov1;
o.i.m[0] = 44u8;
assert(o.i.m[0]: i32 == 44);
};
@test fn d2_global_4() void = {
G4.i.m[0] = 66u8;
assert(G4.i.m[0]: i32 == 66);
};
@test fn d2_global_2() void = {
G2.i.m[1] = 55u8;
assert(G2.i.m[1]: i32 == 55);
};
@test fn d2_global_1() void = {
G1.i.m[0] = 44u8;
assert(G1.i.m[0]: i32 == 44);
};
@test fn ctl_local_16() void = {
let o: ov16;
assert(o.i.m[7]: i32 == 0);
};
@test fn ctl_global_16() void = {
assert(G16.i.m[7]: i32 == 0);
};

View File

@@ -11,8 +11,9 @@
* negative literal should have produced 0xFF... (link succeeded;
* runtime read 0). The array arm hit the same gap.
*
* Both 923_signed_data_emit_run and the broader bootstrap byte-id
* (995_self_rebuild) would catch a future regression, but this row
* Both test/lang/signed_data_emit_test.ww (the migrated runtime rows)
* and the broader bootstrap byte-id (995_self_rebuild) would catch a
* future regression, but this row
* pins the *asm shape* itself — a future cgen refactor that emits
* the slot via a different directive (e.g. via DATA + DATAR rather
* than DATAW) would silently divergent even with green semantics.

View File

@@ -1,217 +0,0 @@
/*
* 914_arr_u16_store_run — runtime + byte-id net for #128a: array-
* literal init into [N]u16 (or any [N]T where esz==2) must store with
* MOVW, not MOVQ. Pre-fix cstage's cgen.c:7180-7222 array-init dispatch
* routed esz==2 to MOVQ fall-through (the comment at 7194-7198
* documented + deferred this until A_MOVW landed in w6a); the MOVQ
* wrote 8 bytes into a 2-byte slot, overlapping the next 6 bytes of
* stack. Adjacent fully-init writes accident-corrected via overlap
* (each MOVQ rewrote the prior MOVQ's trailing 6B), but a PARTIAL
* init left high garbage in slots that should have been default-zero.
*
* Fix is the now-unblocked dispatch: `else if (esz == 2) op = A_MOVW;`
* The wwstage emitter was already correct (uses MOVW); the cstage gap
* was the deferred TODO. Both stages now emit byte-identical MOVW for
* [N]u16 (and any aliased-narrow-element [N]T whose tinfo.size == 2).
*
* Rows cover (the bug is caught via the rule-10 cs==ww byte-id gate;
* ww doesn't accept truly-partial init literals, and adjacent MOVQ
* writes accident-correct the runtime values, so byte-id is the lever):
* - u16_full_init: fully-init [4]u16, regression guard (pre-fix
* accident-correct at runtime via MOVQ overlap; .s shifts
* MOVQ→MOVW, cs==ww BYTE-IDENTICAL now)
* - u16_small_values: small u16 values, summed (regression guard)
* - u8_control: [4]u8 baseline (already MOVB pre-fix, no shift)
* - i16_signed: signed-narrow [N]i16, same dispatch — verifies the
* fix isn't gated on unsignedness
*
* TY_NAMED alias of u16 (`type myw = u16; let a: [4]myw = …`) is a
* sibling miscompile filed separately: wwstage's array-init element-
* size dispatch reads `primsize(elemn.str)` which returns 0 for an
* alias name, leaving esz at 8 (wrong slot, wrong stride). Out of
* scope for #128a (cstage MOVW landing).
*
* Each row carries (a) cstage `ww build` + run asserting the exit
* code and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id). Post-#128a
* the partial-init row's cstage emission gains MOVW; both stages
* unchanged everywhere else.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
/* Fully-init [4]u16: pre-fix MOVQ overlap accident-corrected;
* post-fix proper MOVW per slot. Sum of last bytes = 0xBE = 190;
* mod 256 = 190. We assert per-element to catch any value drift. */
{ "u16_full_init",
"package main;\n"
"export fn main() i32 = {\n"
" let a: [4]u16 = [0xABCDu16, 0xBEEFu16, 0xC0DEu16, 0xDEADu16];\n"
" if (a[0] != 0xABCDu16) { return 1; };\n"
" if (a[1] != 0xBEEFu16) { return 2; };\n"
" if (a[2] != 0xC0DEu16) { return 3; };\n"
" if (a[3] != 0xDEADu16) { return 4; };\n"
" return 0;\n"
"};\n", 0 },
/* Same shape with smaller values — pin that the dispatch fires
* on values that don't need the upper 16 bits. */
{ "u16_small_values",
"package main;\n"
"export fn main() i32 = {\n"
" let a: [4]u16 = [10u16, 20u16, 30u16, 40u16];\n"
" let s: i32 = 0;\n"
" s += a[0]: i32; s += a[1]: i32;\n"
" s += a[2]: i32; s += a[3]: i32;\n"
" return s;\n"
"};\n", 100 },
/* [4]u8 control: already correct (MOVB pre-fix). Regression
* guard — asm should be unchanged. */
{ "u8_control",
"package main;\n"
"export fn main() i32 = {\n"
" let a: [4]u8 = [10u8, 20u8, 30u8, 40u8];\n"
" let s: i32 = 0;\n"
" s += a[0]: i32; s += a[1]: i32;\n"
" s += a[2]: i32; s += a[3]: i32;\n"
" return s;\n"
"};\n", 100 },
/* [4]i16: signed-narrow, same MOVW dispatch (op chosen by esz,
* not signedness). Verifies the fix isn't gated. */
{ "i16_signed",
"package main;\n"
"export fn main() i32 = {\n"
" let a: [4]i16 = [10i16, 20i16, 30i16, -5i16];\n"
" let s: i32 = 0;\n"
" s += a[0]: i32; s += a[1]: i32;\n"
" s += a[2]: i32; s += a[3]: i32;\n"
" return s;\n"
"};\n", 55 /* 10+20+30+(-5) = 55 */ },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "arru16store: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwau16_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char src[128], outbin[128], rmcmd[160];
snprintf(src, sizeof src, "%s/wwau16_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwau16_%d_%d",
tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (f == NULL) { runwait(rmcmd); fail++; continue; }
fputs(rows[i].src, f);
fclose(f);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
char cs_s[128], ws_s[128];
snprintf(cs_s, sizeof cs_s, "%s/wwau16_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwau16_%d_%d_ww.s",
tmpdir, getpid(), i);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d arr-u16-store tests failed\n", fail, n);
return 1;
}
printf("arru16store: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,231 +0,0 @@
/*
* 917_def_float_lit_run — runtime + byte-id net for #129 Phase A.1:
* module-level `def NAME: f64 = literal;` (and `def: f32 = …`)
* silently fell through emit_defs's int-only `fold_int_literal` gate,
* so no DATAW row landed in the .data section — `w6l` failed link
* with `undefined reference to 'main.NAME'`. Symmetric latent bug in
* emit_lets's float arm: it only handled bare N_FLOATLIT, never
* peeled N_UN(MINUS/PLUS, N_FLOATLIT), so `let g: f64 = -1.5;`
* silently zero-emitted into the same undef-ref shape.
*
* Phase A.1 fix (rule-12 sea-of-stars consolidation):
* - cstage: extract `emit_floatlit_data(out, c, dir, name, T, rhs)`
* helper, called by emit_lets's float arm (now collapsed) AND
* emit_defs (new float arm). N_CAST + N_UN(MINUS/PLUS,
* N_FLOATLIT) peeled inside the helper.
* - wwstage: parallel `emitfloatlitdata` helper. Negation via
* IEEE-754 sign-bit XOR (avoids dragging the math bitcast helpers
* into cgen).
* - LOAD side: cstage's N_IDENT float-let arm and wwstage's cgident
* def-branch both gated on let_islet/deflookup-but-not-float; the
* gate widens to also catch float defs (they emit through the
* same mod_mangle / emitsymname symbol).
*
* Bootstrap NEUTRAL: zero current `def: f{32,64} = lit` consumers in
* lib/ or selfhost/. The N_UN-peel collateral fix for lets has no
* shipped consumers either (audit: no `let g: f64 = -lit;` anywhere).
*
* Rows cover both fix sides (DATA emit + LOAD) and the N_UN collateral:
* - f64_def_pos: `def K: f64 = 1.5;` — was undef-ref pre-fix, exit
* 1 (1.5 → i32 truncates to 1).
* - f64_def_neg: `def K: f64 = -1.5;` — was undef-ref pre-fix; exit
* 255 (sign-bit flip via XOR; -1.5 → i32 truncates to -1 → 255
* in unsigned exit byte).
* - f32_def_pos: `def K: f32 = 1.5f32; …` — same shape, f32 width.
* - f64_let_neg: `let g: f64 = -1.5;` — pre-existing latent bug
* (N_UN peel never added to emit_lets); now fixed by the same
* helper.
* - f64_let_pos: `let g: f64 = 1.5;` — regression guard (existing
* bare-N_FLOATLIT path).
* - f32_let_pos: `let g: f32 = 1.5f32;` — regression guard, f32 path.
*
* Each row carries (a) cstage `ww build` + run asserting exit code
* and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
{ "f64_def_pos",
"package main;\n"
"def K: f64 = 1.5;\n"
"export fn main() i32 = {\n"
" let x: f64 = K;\n"
" return (x: i32);\n"
"};\n", 1 },
{ "f64_def_neg",
"package main;\n"
"def K: f64 = -1.5;\n"
"export fn main() i32 = {\n"
" let x: f64 = K;\n"
" return (x: i32);\n"
"};\n", 255 /* -1 as unsigned exit byte */ },
{ "f32_def_pos",
"package main;\n"
"def K: f32 = 1.5f32;\n"
"export fn main() i32 = {\n"
" let x: f32 = K;\n"
" return (x: i32);\n"
"};\n", 1 },
/* Matrix-closure: f32 + neg combined directly. Exercises the
* f32-narrow path PLUS the top-byte-XOR negation in one row.
* The other rows cover each leg individually (f64_def_neg for
* negation, f32_def_pos for f32 narrow); this row pins they
* compose correctly. */
{ "f32_def_neg",
"package main;\n"
"def K: f32 = -1.5f32;\n"
"export fn main() i32 = {\n"
" let x: f32 = K;\n"
" return (x: i32);\n"
"};\n", 255 /* -1 as exit byte */ },
/* Pre-existing latent: emit_lets's float arm never peeled
* N_UN(MINUS,N_FLOATLIT). The class-closure consolidation
* fix in emit_floatlit_data heals this too. */
{ "f64_let_neg",
"package main;\n"
"let g: f64 = -1.5;\n"
"export fn main() i32 = {\n"
" return (g: i32);\n"
"};\n", 255 },
{ "f64_let_pos",
"package main;\n"
"let g: f64 = 1.5;\n"
"export fn main() i32 = {\n"
" return (g: i32);\n"
"};\n", 1 },
{ "f32_let_pos",
"package main;\n"
"let g: f32 = 1.5f32;\n"
"export fn main() i32 = {\n"
" return (g: i32);\n"
"};\n", 1 },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "deflitf: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwdflf_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char rmcmd[128];
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
char src[128], outbin[128], cs_s[128], ws_s[128];
snprintf(src, sizeof src, "%s/wwdflf_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwdflf_%d_%d",
tmpdir, getpid(), i);
snprintf(cs_s, sizeof cs_s, "%s/wwdflf_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwdflf_%d_%d_ww.s",
tmpdir, getpid(), i);
FILE *f = fopen(src, "wb");
if (f == NULL) { fail++; runwait(rmcmd); continue; }
fputs(rows[i].src, f);
fclose(f);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d def-float-lit tests failed\n", fail, n);
return 1;
}
printf("deflitf: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,241 +0,0 @@
/*
* 918_struct_composite_init_run — runtime + byte-id net for #129
* Phase A.2: module-level `let`/`def` with composite-struct
* initializer silently emitted undefined ref OR wrong bytes pre-fix.
*
* Pre-A.2 failure modes:
* - cstage emit_lets / wwstage emitletdataw skipped struct-typed lets
* entirely (`if (is_struct) continue;` / parallel) — link surfaced
* `undefined reference to 'main.NAME'`.
* - cstage emit_defs / wwstage emitdefconstants had no struct arm —
* same undef ref for def, plus a SEPARATE LOAD-side cgen bug
* emitting `MOVSXD (BP), AX` (reading stack frame byte 0) when the
* LOAD did get past the link.
*
* Phase A.2 fix (per A.1 SSoT-helper precedent):
* - cstage: emit_struct_data + emit_struct_lit_bytes helpers walk
* Tfield list in declaration order, zero-fill padding via per-
* field offsets (rule 13), dispatch per field type. Float-field
* bytes inlined (mirroring A.1's emit_floatlit_data shape but
* localised so the byte loop covers padding too). Nested struct
* recurses. Out-of-scope field kinds (array / str / slice / ptr)
* fatal loud per rule-7.
* - cstage: emit_lets + emit_defs gain struct arms routing through
* the helper.
* - cstage: LOAD-side widening at `if (u && u->kind == TY_STRUCT
* && lhs->kind == N_IDENT)` arm — the `let_islet`-gated LEAQ
* name(SB) shape now also fires for struct defs via the new
* `def_isstructdef` registry (mirror of letvars).
* - wwstage: parallel emitstructdata + emitstructlitbytes helpers,
* defent.dtnode field, defvarstructinfo (cgdot LOAD widening).
*
* Bootstrap NEUTRAL: zero `let/def: T = T{...}` consumers in lib/ or
* selfhost/. γ-cleanup is the first consumer (lib/math:floatinfo).
*
* Rows cover all A.2-scope shapes:
* - (a) `let CFG: cfg_t = cfg_t{a=1, b=2u64};` — plain mixed-int let
* - (b) `def CFG: cfg_t = cfg_t{a=1, b=2u64};` — plain mixed-int def
* (exercises LOAD-widening; both stages)
* - (c) `let F: ft = ft{a=1.5, b=99u32};` — let with float field
* - (d) `def F: ft = ft{a=1.5, b=99u32};` — def with float field
* (storage + LOAD + float-narrow path together)
* - (e) `let Z: zt = zt{};` — empty struct-lit zero-fill
* - (f) `let CFG: cfg_t;` — regression: no-rhs (pre-existing path
* unchanged)
*
* Each row carries (a) cstage `ww build` + run asserting exit code
* and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id).
*
* Nested-struct shape (#3 in design report) is OMITTED here — the
* helper implements the recursion but #145 (parser/checker inner-
* literal field-name leak) blocks end-to-end correctness; nested
* row deferred until #145 lands.
*
* Array-in-struct shape parked to Phase A.3 boundary.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
{ "let_int_struct",
"package main;\n"
"type cfg_t = struct { a: i32, b: u64 };\n"
"let CFG: cfg_t = cfg_t{a=1, b=2u64};\n"
"export fn main() i32 = {\n"
" return CFG.a;\n"
"};\n", 1 },
{ "def_int_struct",
"package main;\n"
"type cfg_t = struct { a: i32, b: u64 };\n"
"def CFG: cfg_t = cfg_t{a=1, b=2u64};\n"
"export fn main() i32 = {\n"
" return CFG.a;\n"
"};\n", 1 },
{ "let_float_field",
"package main;\n"
"type ft = struct { a: f64, b: u32 };\n"
"let F: ft = ft{a=1.5, b=99u32};\n"
"export fn main() i32 = {\n"
" return (F.a: i32);\n"
"};\n", 1 },
{ "def_float_field",
"package main;\n"
"type ft = struct { a: f64, b: u32 };\n"
"def F: ft = ft{a=1.5, b=99u32};\n"
"export fn main() i32 = {\n"
" return (F.a: i32);\n"
"};\n", 1 },
{ "let_empty_struct",
"package main;\n"
"type zt = struct { a: i32, b: u64 };\n"
"let Z: zt = zt{};\n"
"export fn main() i32 = {\n"
" return Z.a;\n"
"};\n", 0 },
/* 8B struct hits the cstage emit_lets scalar-8B short-circuit
* (sz==8 fold_int_literal arm) — without the `!let_isstruct`
* gate the struct lit fold-fails and the let drops entirely,
* emitting no DATA. Both stages now route via the struct arm. */
{ "let_int_struct_8b",
"package main;\n"
"type s8 = struct { a: i32, b: i32 };\n"
"let X: s8 = s8{a=7, b=42};\n"
"export fn main() i32 = {\n"
" return X.a;\n"
"};\n", 7 },
/* Regression: no-rhs path unchanged (emit_data_row_zero / wwstage
* parallel). */
{ "let_norhs_struct",
"package main;\n"
"type cfg_t = struct { a: i32, b: u64 };\n"
"let CFG: cfg_t;\n"
"export fn main() i32 = {\n"
" return CFG.a;\n"
"};\n", 0 },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "strcomp: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwstrc_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char src[128], outbin[128], cs_s[128], ws_s[128], rmcmd[160];
snprintf(src, sizeof src, "%s/wwstrc_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwstrc_%d_%d",
tmpdir, getpid(), i);
snprintf(cs_s, sizeof cs_s, "%s/wwstrc_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwstrc_%d_%d_ww.s",
tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (f == NULL) { fail++; runwait(rmcmd); continue; }
fputs(rows[i].src, f);
fclose(f);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d struct-composite tests failed\n", fail, n);
return 1;
}
printf("strcomp: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,354 +0,0 @@
/*
* 919_array_static_init_run — runtime + byte-id net for #129 Phase
* A.3: module-level let/def with array initializer.
*
* Pre-A.3 state:
* - Int-element arrays (u8/i8/u16/u32/u64/i32 etc) already worked
* in both stages via fold_int_literal.
* - Float-element arrays ([N]f64, [N]f32) → undef-ref at link
* (emit_lets array arm fold_int_literal fails on FLOATLIT).
* - Array DEFs (def A: [N]T = [...]) → emit_defs no array arm
* (storage missing) AND cgindex broken (reads LEAQ (BP), BX —
* stack frame, not data section).
* - Array-in-struct field (`def D: dt = dt{tag=42, buf=[...]}`) →
* #129 A.2 rule-7 fatal "array field rhs not foldable" — the
* shape parked in A.2 awaiting A.3.
*
* Phase A.3 fix (mirror A.1/A.2 SSoT-helper precedent):
* - cstage: emit_array_data + emit_array_lit_bytes helpers with
* element-kind dispatch (int via fold_int_literal preserving
* bootstrap byte-id, float via inline bitcast + sign-XOR byte-
* loop mirror of A.1, struct via emit_struct_lit_bytes recursion
* mirror of A.2). Two-pass validate-then-emit avoids partial-byte
* corruption on rhs-fold-failure.
* - cstage: emit_lets array arm routes through helper; emit_defs
* gains array arm.
* - cstage: DefArray registry + def_isarraydef populated in
* let_collect; cgindex N_INDEX direct-ident `isglobal` gate
* widened to (let_islet || def_isarraydef).
* - cstage: emit_struct_lit_bytes (A.2 helper) gains TY_ARRAY field
* arm calling emit_array_lit_bytes recursively (closes A.2 parked
* shape 15).
* - wwstage: parallel emitarraydata + emitarraylitbytes; emitstruct
* litbytes TY_ARRAY arm; defvartnode helper; cgindex falls through
* to defvartnode after letvartnode nil.
*
* Bootstrap RISK: live consumers in lib/os, lib/bufio, lib/strings,
* lib/encoding/utf8 (dfa + masks), lib/strconv/stof_data
* (left_shift_table). All use typed-int-literal elements; the int-elem
* helper path is byte-for-byte preserved → bootstrap NEUTRAL.
*
* Rows (size strata 1B/2B/4B/8B × count strata 1/2/4 × int/float/struct/
* empty/no-rhs/def-variant, avoiding the 16B-evade pattern from A.2):
*
* - (a) `let A: [4]u8 = [1u8, 2u8, 3u8, 4u8]` — 1B regression
* - (b) `let A: [4]u32 = [1u32, 2u32, 3u32, 4u32]` — 4B regression
* - (c) `let A: [2]u64 = [1u64, 2u64]` — 8B regression
* - (d) `let A: [4]i32 = [-1, -2, -3, -4]` — N_UN peel regression
* - (e) `let A: [4]f64 = [1.5, -2.5, 3.5, -4.5]` — NEW float-elem
* - (f) `let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32]` — NEW
* f32 narrow + sign-XOR per element
* - (g) `def A: [4]u32 = [11u32, 22u32, 33u32, 44u32]` — NEW
* def-storage + LOAD-widening
* - (h) `def A: [4]f64 = [1.5, 2.5, 3.5, 4.5]` — NEW def-variant of
* float
* - (i) `def D: dt = dt{tag=42, buf=[1u8,2u8,3u8,4u8]}` — NEW
* closes A.2 shape 15 (struct-with-array-field)
* - (j) `let A: [4]u8 = [0u8, 0u8, 0u8, 0u8]` — explicit-zero
* regression
* - (k) `let A: [1]u8 = [0u8]` — single-elem (matches lib/os/
* emptypath pattern)
*
* Each row: cstage `ww build` + run asserting exit code + w6c vs
* w6c_ww `.s` cmp (rule-10 byte-id).
*
* #156 (PREREQ-1) extends this with 2D `[N][M]T` static-init (a) +
* double-index read (b) — the A.3 shape-14 capstone, consumer-driven by
* fold-4's powers_of_ten[596][2]u64. emit_array_lit_bytes gains a
* TY_ARRAY-element arm (recurse; esz=etype->size); cgindex leaves the
* sub-array ADDRESS for an array element (sister of #135). Rows
* let_2d_x, def_2d_u64 and let_struct_2d_field + the nested-`...`
* loud-reject (rule-7) below. The D.m[i][j] global-struct-field-array
* READ stays a
* pre-existing gap (#160, 1D+2D, cs≠ww) out of scope here.
*
* Deferred:
* - Pointer-element arrays `[N]*T = [&G, &H]` — needs DATAR per
* element (own task/fold).
* - `...` repeat with a nested-array element — loud-reject (#156
* rule-7); no consumer (powers_of_ten is fully enumerated).
* - Bare-int `[N]u8 = [1, 2, 3, 4]` — #130 (checker issue).
* - Partial init `[4]u8 = [1u8]` — checker rejects (parser/checker
* decision).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
{ "let_u8_arr",
"package main;\n"
"let A: [4]u8 = [1u8, 2u8, 3u8, 4u8];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 1 },
{ "let_u32_arr",
"package main;\n"
"let A: [4]u32 = [1u32, 2u32, 3u32, 4u32];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 1 },
{ "let_u64_arr",
"package main;\n"
"let A: [2]u64 = [1u64, 2u64];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 1 },
{ "let_i32_neg_arr",
"package main;\n"
"let A: [4]i32 = [-1, -2, -3, -4];\n"
"export fn main() i32 = { return A[0]; };\n", 255 /* -1 */ },
/* Float-element array — NEW in A.3. Includes both signs to exercise
* the sign-XOR byte-loop per element. */
{ "let_f64_arr",
"package main;\n"
"let A: [4]f64 = [1.5, -2.5, 3.5, -4.5];\n"
"export fn main() i32 = { return (A[0]: i32); };\n", 1 },
{ "let_f32_arr",
"package main;\n"
"let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32];\n"
"export fn main() i32 = { return (A[0]: i32); };\n", 1 },
/* def-variant exercises the LOAD-widening (def_isarraydef) at
* cgindex/cgident. Storage emit also new. */
{ "def_u32_arr",
"package main;\n"
"def A: [4]u32 = [11u32, 22u32, 33u32, 44u32];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 11 },
{ "def_f64_arr",
"package main;\n"
"def A: [4]f64 = [1.5, 2.5, 3.5, 4.5];\n"
"export fn main() i32 = { return (A[0]: i32); };\n", 1 },
/* The A.2-parked shape-15 — closes via emit_struct_lit_bytes
* TY_ARRAY field arm. */
{ "let_struct_with_arr_field",
"package main;\n"
"type dt = struct { tag: i32, buf: [4]u8 };\n"
"let D: dt = dt{tag=42, buf=[1u8, 2u8, 3u8, 4u8]};\n"
"export fn main() i32 = { return D.tag; };\n", 42 },
{ "let_u8_zero_arr",
"package main;\n"
"let A: [4]u8 = [0u8, 0u8, 0u8, 0u8];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 0 },
{ "let_u8_single",
"package main;\n"
"let A: [1]u8 = [7u8];\n"
"export fn main() i32 = { return A[0]: i32; };\n", 7 },
/* #156 (PREREQ-1): 2D [N][M]T static-init (a) + double-index read
* (b) — the A.3 shape-14 capstone, consumer-driven by fold-4's
* powers_of_ten[596][2]u64. emit_array_lit_bytes recurses on the
* TY_ARRAY element (esz=etype->size, rule-13); cgindex leaves the
* sub-array ADDRESS (not a value) for an array element so the outer
* index dereferences the right cell (sister of #135). */
{ "let_2d_u64",
"package main;\n"
"let A: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];\n"
"export fn main() i32 = { return A[1][0]: i32; };\n", 3 },
{ "def_2d_u64",
"package main;\n"
"def A: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];\n"
"export fn main() i32 = { return A[2][1]: i32; };\n", 6 },
/* variable-index read — the exact fold-4 access pattern
* (powers_of_ten[i][0]/[i][1]). 21 + 30 = 51. */
{ "let_2d_varidx",
"package main;\n"
"let A: [3][2]u64 = [[10u64,11u64],[20u64,21u64],[30u64,31u64]];\n"
"fn at(i: i32, j: i32) u64 = { return A[i][j]; };\n"
"export fn main() i32 = { return (at(1, 1) + at(2, 0)): i32; };\n",
51 },
/* 8-byte 2D: must NOT hit the sz==8 scalar short-circuit (the
* isarr8/N_TARRAY guard, #128 lesson) — routes to the array arm. */
{ "let_2d_u32_8byte",
"package main;\n"
"let A: [2][1]u32 = [[7u32],[9u32]];\n"
"export fn main() i32 = { return A[1][0]: i32; };\n", 9 },
/* 2D write to one cell, sum all four — verifies the lvalue address
* targets the exact cell with no neighbour clobber. 1+2+99+4=106. */
{ "let_2d_write",
"package main;\n"
"let A: [2][2]u64 = [[1u64,2u64],[3u64,4u64]];\n"
"export fn main() i32 = { A[1][0] = 99u64; return "
"(A[0][0]+A[0][1]+A[1][0]+A[1][1]): i32; };\n", 106 },
/* struct field that is itself a 2D array — static-init emit +
* layout (read D.tag). The D.m[i][j] field-array READ exercises a
* pre-existing global-struct-field-base bug (#137/#150 family,
* 1D+2D, cs≠ww) out of PREREQ-1 scope — the array bytes are
* covered by the cs==ww byte-id gate below. */
{ "let_struct_2d_field",
"package main;\n"
"type dt = struct { tag: i32, m: [2][2]u64 };\n"
"let D: dt = dt{tag=42, m=[[1u64,2u64],[3u64,4u64]]};\n"
"export fn main() i32 = { return D.tag; };\n", 42 },
/* 3D — locks recursion-depth>2 in both emit (nested TY_ARRAY arm
* recurses twice) and read (double-then-single index, two
* address-leaves). [[[1,2],[3,4]],[[5,6],[7,8]]]; A[1][1][0] = 7. */
{ "let_3d_u8",
"package main;\n"
"let A: [2][2][2]u8 = "
"[[[1u8,2u8],[3u8,4u8]],[[5u8,6u8],[7u8,8u8]]];\n"
"export fn main() i32 = { return A[1][1][0]: i32; };\n", 7 },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "arrinit: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwari_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char rmcmd[160];
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
char src[128];
snprintf(src, sizeof src, "%s/wwari_%d_%d.ww",
tmpdir, getpid(), i);
FILE *f = fopen(src, "wb");
if (f == NULL) { fail++; runwait(rmcmd); continue; }
fputs(rows[i].src, f);
fclose(f);
char outbin[128];
snprintf(outbin, sizeof outbin, "%s/wwari_%d_%d",
tmpdir, getpid(), i);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
char cs_s[128], ws_s[128];
snprintf(cs_s, sizeof cs_s, "%s/wwari_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwari_%d_%d_ww.s",
tmpdir, getpid(), i);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
/* #156 rule-7: a `...` repeat marker with a nested-array element is
* a loud reject in BOTH stages (no consumer needs it; powers_of_ten
* is fully enumerated). The compile must FAIL, not silently emit
* wrong bytes. Separate from the rows table (which asserts build
* success). */
{
char src[64];
snprintf(src, sizeof src, "/tmp/wwari_%d_rej.ww", getpid());
FILE *f = fopen(src, "wb");
if (f != NULL) {
fputs("package main;\n"
"let A: [4][2]u64 = [[1u64, 2u64]...];\n"
"export fn main() i32 = { return 0; };\n", f);
fclose(f);
}
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s -o /dev/null %s 2>/dev/null",
w6c, src);
int rc_cs = runwait(cmd);
snprintf(cmd, sizeof cmd, "%s -o /dev/null %s 2>/dev/null",
w6c_ww, src);
int rc_ww = runwait(cmd);
n++;
if (rc_cs == 0 || rc_ww == 0) {
fprintf(stderr, "row[nested_ellipsis_reject]: expected "
"BOTH stages to reject (cs=%d ww=%d), want nonzero "
"(#156 rule-7)\n", rc_cs, rc_ww);
fail++;
}
unlink(src);
}
if (fail) {
fprintf(stderr, "%d/%d array-static-init tests failed\n", fail, n);
return 1;
}
printf("arrinit: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,204 +0,0 @@
/*
* 919_strarray_static_run — BUG #18. Runtime + cs==ww byte-id net for a
* module-level `let xs: [N]str = ["a","b",…];` static table.
*
* THE BUG (BOTH stages dropped it — shared-logic gap, not rule-10):
* A module-level [N]str static init emitted NO .data at all. The
* per-element str header carries a ptr→rodata relocation (not just
* bytes), so it can't ride emit_array_lit_bytes (byte-only): the str-
* element case fell through to fold_int_literal, returned 0, and
* emit_lets zero-init'd / skipped — leaving `main.<tab>` undefined.
* `w6l: undefined reference` at link. Function-LOCAL [N]str worked
* (runtime element stores); only the module-level STATIC DATA form was
* broken.
*
* THE FIX (#18): emit_strarray_data / emitstrarraydata apply the scalar-
* str-global pattern (DATAW header with a zero ptr placeholder + inline
* LE len, then a per-element `DATAR sym+idx*esz(SB),_S_n(SB)`) at each
* element offset. let_pre_intern / letpreintern pre-intern each element
* strlit so the _S_ rodata rows precede the DATAR references. Scoped to
* the DATAW (`let`) directive — A_DATAR requires a DATAW holder.
*
* EACH ROW CARRIES BOTH DIMENSIONS (801 model):
* (a) cstage `ww build` + run, asserting the exit — proves the table's
* .len bytes are correct AND each element's .ptr relocation
* resolves to the right rodata label (the rows deref a NON-zero
* element's first byte, so a dropped/wrong reloc gives a wrong
* char — built-in negative control).
* (b) w6c vs w6c_ww `.s` cmp — FAILS if the stages diverge.
*
* GATE POLARITY: must stay GREEN. A wrong exit means the static table
* relocations regressed; a byte-id FAIL means the stages diverged.
*
* NB: the rows read elements via the `.ptr`/`.len` pseudo-fields, NOT
* the `len()` builtin — `len(xs[i])` on an indexed str element is a
* separate pre-existing read-side miscompile (returns the ptr; filed
* alongside #18), orthogonal to the emission fix under test here.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
/* .len bytes: 2+3+1 == 6. A dropped table would fail to link. */
{ "strtab_len",
"package main;\n"
"let t: [3]str = [\"ab\",\"cde\",\"f\"];\n"
"export fn main() i32 = { return (t[0].len + t[1].len + t[2].len): i32; };\n",
6 },
/* element-2 .ptr reloc: *(t[2].ptr) == 'C' (67), NOT 'A' — proves
* the +2*esz relocation resolves to "C", not element 0. */
{ "strtab_ptr_elem2",
"package main;\n"
"let t: [3]str = [\"A\",\"B\",\"C\"];\n"
"export fn main() i32 = { let p: *u8 = t[2].ptr; return (*p): i32; };\n",
67 },
/* runtime-indexed .ptr: i=1, *(t[i].ptr) == 'y' (121) — the
* LEAQ tab(SB)+i*esz addressing reaches the right element's reloc. */
{ "strtab_ptr_varindex",
"package main;\n"
"let t: [3]str = [\"xx\",\"yyy\",\"z\"];\n"
"export fn main() i32 = { let i: i32 = 1; let p: *u8 = t[i].ptr; "
"return (*p): i32; };\n",
121 },
/* empty-element (no reloc, len 0) followed by a real element: t[0]
* len==0, *(t[1].ptr) == 'Z' (90) — the empty slot must not shift
* the following element's reloc offset. */
{ "strtab_empty_then_ptr",
"package main;\n"
"let t: [2]str = [\"\",\"Z\"];\n"
"export fn main() i32 = { if (t[0].len != 0) { return 88; }; "
"let p: *u8 = t[1].ptr; return (*p): i32; };\n",
90 },
/* repeat suffix `[X, Y...]` — the trailing `...` fills the rest of
* [3]str with the last explicit element ("Y"). t[2] is a repeat-
* filled slot: *(t[2].ptr) == 'Y' (89), NOT 'X' — proves the +48
* fill row's DATAR resolves to last_ev ("Y"), exercising the
* repeat branch (its own len-fill + DATAR loop) the other rows skip. */
{ "strtab_repeat_suffix",
"package main;\n"
"let t: [3]str = [\"X\",\"Y\"...];\n"
"export fn main() i32 = { let p: *u8 = t[2].ptr; return (*p): i32; };\n",
89 },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "strarray_static: w6c_ww missing — cannot run "
"the cs==ww byte-id gate\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwsas_%d_d_%d", getpid(), i);
mkdir(tmpdir, 0755);
char rmcmd[160];
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
char src[128], outbin[128];
snprintf(src, sizeof src, "%s/wwsas_%d_%d.ww", tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwsas_%d_%d", tmpdir, getpid(), i);
FILE *f = fopen(src, "wb");
if (f == NULL) { runwait(rmcmd); fail++; continue; }
fputs(rows[i].src, f);
fclose(f);
/* (a) cstage build + run. */
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
/* (b) cs==ww byte-id gate. */
char cs_s[128], ws_s[128];
snprintf(cs_s, sizeof cs_s, "%s/wwsas_%d_%d_cs.s", tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwsas_%d_%d_ww.s", tmpdir, getpid(), i);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr, "row[%s]: cstage/wwstage .s DIFFER "
"(rule-10 byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d strarray static-init tests failed\n",
fail, n);
return 1;
}
printf("strarray_static: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,221 +0,0 @@
/*
* 923_signed_data_emit_run — top-level `let` bindings of signed
* integer types must emit a module-scope DATA slot whose initialiser
* is the literal's two's-complement bytes (#19).
*
* Pre-fix both stages skipped the scalar DATAW arm when the rhs was
* N_UN(TK_MINUS, INTLIT). cstage's emit_lets fell through to the
* default `else continue;` so `let x: i8 = -1i8;` produced no DATAW
* row and the link failed with "undefined reference to x". Wwstage's
* emitletdataw silently left the slot at zero — link succeeded but
* the read returned 0 instead of -1, a corpus-coverage-blind bug.
*
* The array arm carried the same defect on both stages. cstage's
* walker bailed on the first non-foldable element (then dropped the
* whole DATAW row for the array via the `is_array continue` fall-
* through); wwstage emitted zeros at every unfoldable index, again
* silently. The utf8 DFA shape (`let dfa: [8]i8 = [0i8, -1i8, ...]`)
* is the canonical real-source trigger.
*
* Sister to #24, which fixed the same N_UN-fold gap on the `def`-
* emit side (emit_defs / emitdefconstants) via the shared
* fold_int_literal / foldintliteral helper. Task #19 routes the
* `let`-emit paths (scalar + array) through the same helper.
*
* Rows pin the full signed-int matrix (i8/i16/i32/i64) for both
* scalar and 1D array shapes, plus positive controls so a future
* regression of the gate that affects only the negative arm still
* leaves the positive rows green. The negative-zero (TK_MINUS over
* 0) and TK_TILDE rows pin the other two N_UN ops the helper covers.
*
* Stage matrix: cstage always; wwstage gated on `ww_ww` existing.
* Runtime checks all read through cast-strip + literal compare so a
* cgen-side narrow-load regression surfaces here rather than hiding
* behind the DATA slot's wider-than-elem padding.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want; };
static const struct row rows[] = {
{ "i8_neg_scalar",
"let x: i8 = -1i8;\n"
"fn main() i32 = { if (x != -1i8) { return 1; }; return 0; };\n",
0 },
{ "i8_pos_scalar",
"let x: i8 = 42i8;\n"
"fn main() i32 = { if (x != 42i8) { return 1; }; return 0; };\n",
0 },
{ "i16_neg_scalar",
"let x: i16 = -2i16;\n"
"fn main() i32 = { if (x != -2i16) { return 1; }; return 0; };\n",
0 },
{ "i16_pos_scalar",
"let x: i16 = 1000i16;\n"
"fn main() i32 = { if (x != 1000i16) { return 1; }; return 0; };\n",
0 },
{ "i32_neg_scalar",
"let x: i32 = -100i32;\n"
"fn main() i32 = { if (x != -100i32) { return 1; }; return 0; };\n",
0 },
{ "i32_pos_scalar",
"let x: i32 = 100000i32;\n"
"fn main() i32 = { if (x != 100000i32) { return 1; }; return 0; };\n",
0 },
{ "i64_neg_scalar",
"let x: i64 = -1000i64;\n"
"fn main() i32 = { if (x != -1000i64) { return 1; }; return 0; };\n",
0 },
{ "i64_pos_scalar",
"let x: i64 = 1000000i64;\n"
"fn main() i32 = { if (x != 1000000i64) { return 1; }; return 0; };\n",
0 },
/* TK_TILDE over a literal — the other N_UN op fold_int_literal
* covers. ~0u64 == 0xFFFFFFFFFFFFFFFF == -1i64. */
{ "i64_tilde_scalar",
"let x: i64 = (~0u64): i64;\n"
"fn main() i32 = { if (x != -1i64) { return 1; }; return 0; };\n",
0 },
/* Array of i8: utf8 DFA shape. The negative entries silently
* zeroed pre-fix on wwstage; cstage emitted nothing at all and
* the link failed before this row could even build. */
{ "i8_arr_dfa",
"let dfa: [8]i8 = [0i8, -1i8, 1i8, 2i8, 0i8, 0i8, -1i8, -1i8];\n"
"fn main() i32 = {\n"
" if (dfa[0] != 0i8) { return 1; };\n"
" if (dfa[1] != -1i8) { return 2; };\n"
" if (dfa[2] != 1i8) { return 3; };\n"
" if (dfa[3] != 2i8) { return 4; };\n"
" if (dfa[6] != -1i8) { return 5; };\n"
" if (dfa[7] != -1i8) { return 6; };\n"
" return 0;\n"
"};\n",
0 },
{ "i16_arr_mixed",
"let a: [4]i16 = [1i16, -2i16, 3i16, -4i16];\n"
"fn main() i32 = {\n"
" if (a[0] != 1i16) { return 1; };\n"
" if (a[1] != -2i16) { return 2; };\n"
" if (a[2] != 3i16) { return 3; };\n"
" if (a[3] != -4i16) { return 4; };\n"
" return 0;\n"
"};\n",
0 },
{ "i32_arr_mixed",
"let a: [4]i32 = [10i32, -20i32, 30i32, -40i32];\n"
"fn main() i32 = {\n"
" if (a[0] != 10i32) { return 1; };\n"
" if (a[1] != -20i32) { return 2; };\n"
" if (a[2] != 30i32) { return 3; };\n"
" if (a[3] != -40i32) { return 4; };\n"
" return 0;\n"
"};\n",
0 },
{ "i64_arr_mixed",
"let a: [4]i64 = [100i64, -200i64, 300i64, -400i64];\n"
"fn main() i32 = {\n"
" if (a[0] != 100i64) { return 1; };\n"
" if (a[1] != -200i64) { return 2; };\n"
" if (a[2] != 300i64) { return 3; };\n"
" if (a[3] != -400i64) { return 4; };\n"
" return 0;\n"
"};\n",
0 },
};
static int
run_driver(const char *driver, const struct row *r, int i)
{
char src[128], tmpdir[64], outbin[128], rmcmd[160], cmd[1024];
snprintf(tmpdir, sizeof tmpdir, "/tmp/sde_%d_d_%d", getpid(), i);
mkdir(tmpdir, 0755);
snprintf(src, sizeof src, "%s/sde_%d_%d.ww", tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/sde_%d_%d", tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: build via %s failed\n",
r->label, driver);
runwait(rmcmd);
return -1;
}
int got = runwait(outbin);
runwait(rmcmd);
return got;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[512];
if (bin[0] != '/') {
char cwd[256];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cdrv[640];
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
char wdrv[640];
snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin);
struct { const char *name; const char *path; int gated_on_existence; }
drivers[] = {
{ "cstage", cdrv, 0 },
{ "wwstage", wdrv, 1 },
{ NULL, NULL, 0 },
};
int n = (int)(sizeof rows / sizeof rows[0]);
int total = 0, fail = 0;
for (int d = 0; drivers[d].name; d++) {
if (drivers[d].gated_on_existence
&& access(drivers[d].path, X_OK) != 0) {
fprintf(stderr, "signed_data_emit: skip %s (no %s)\n",
drivers[d].name, drivers[d].path);
continue;
}
for (int i = 0; i < n; i++) {
int got = run_driver(drivers[d].path, &rows[i], i);
total++;
if (got != rows[i].want) {
fprintf(stderr,
"signed_data_emit[%s][%s]: exit=%d want=%d\n",
drivers[d].name, rows[i].label,
got, rows[i].want);
fail++;
}
}
}
if (fail) {
fprintf(stderr,
"signed_data_emit: %d/%d fixtures failed\n", fail, total);
return 1;
}
printf("signed_data_emit: %d/%d ok\n", total, total);
return 0;
}

View File

@@ -1,303 +0,0 @@
/*
* 946_const_slice_aggregate_run — #117/#119: const slice of (str,*fn)
* tuple rows + scalar &fn globals emit DATA (was both-stage LOUD at
* emit_slice_data / silent-no-DATA for the scalar &fn).
*
* #117: a `const [](str,*fn)` (fold-6's charclass_map shape) emitted NO
* DATA — emit_slice_data rode the scalar emit_array_lit_bytes backing and
* loud-stopped on the str/tuple/fn elements. Now the backing is k tuple
* rows (emit_tuple_row_*): each str element a 24B header + ptr→char DATAR,
* each &fn element an 8B slot + the BRAND-NEW &fn→DATAR reloc, at the 8B
* tuple-slot offsets (str@row+0/24B, *fn@row+24/8B = 32B/row, ken-confirmed
* layout). #119: a scalar `let p: *fn = &f` global wires the same reloc
* helper at the emit_lets 8B-scalar site (pre-#119: no DATA → undefined
* ref / garbage deref).
*
* POLARITY: align-BOTH — both stages were LOUD at base, no runtime
* reference. byte-id is BLIND (#263): the runtime READ-BACK is the net.
* The fn-reloc (the genuinely new machinery) is pinned at runtime with
* DISTINCT fns per row, so a wrong reloc is caught.
*
* READ-PATH NOTE (honest boundary): the indexed/ptr tuple-element FIELD
* reads off a const slice (`tbl[i].0`, `(&tbl[i]).0`) and the whole-element
* register-cursor read are pre-existing-broken (the #37/#58 index-cursor
* truncation + "unsupported field-read shape" — separate mechanisms, filed
* siblings; fold-6's compile arm also needs them). The one runtime
* observation available of the BACKING is the whole-element bind's word0
* (loaded correctly even by the truncating cursor): so the fn-reloc rows
* put the *fn FIRST (word0) to read it back, and the consumer-ordering
* (str,*fn) rows pin `len(tbl)` (header) + cs==ww byte-id on the DATA. The
* str-element header+reloc reuses the proven emit_tuple_data machinery
* (941 t3_global_elem runtime-pinned) — verified here by byte-id.
*
* NNN<950, self-contained (/tmp, no imports) — rule-14's selfhost-sibling
* race does not apply (941/944/945 precedent). Every K_RUN row also pins
* cstage/wwstage asm byte-id.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa), cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
#define K_RUN 0 /* build+run both drivers, exit==want, + cs==ww byte-id */
#define K_BUILDERR 1 /* build must FAIL with experr on BOTH drivers (rule 7) */
struct row { const char *label; const char *src; int want;
int kind; const char *experr; };
static int
errlog_has(const char *path, const char *needle)
{
FILE *f = fopen(path, "rb");
if (!f) return 0;
char buf[8192];
size_t got = fread(buf, 1, sizeof buf - 1, f);
fclose(f);
buf[got] = '\0';
return strstr(buf, needle) != NULL;
}
static const struct row rows[] = {
/* #117 fn-reloc readback: *fn FIRST so the whole-element bind's
* word0 (the only backing word the truncating index-cursor loads
* correctly) IS the fn ptr. DISTINCT fns per row — a wrong reloc
* (or a swapped per-row offset) is caught by calling each back. */
{ "fnfirst_reloc",
"package main;\n"
"fn fa(c: rune) bool = { return c == 'a'; };\n"
"fn fz(c: rune) bool = { return c == 'z'; };\n"
"const tbl: [](*fn(c: rune) bool, str) = [(&fa, \"aa\"), (&fz, \"zzz\")];\n"
"export fn main() i32 = {\n"
" let e0 = tbl[0];\n"
" let e1 = tbl[1];\n"
" let f0 = e0.0;\n"
" let f1 = e1.0;\n"
" if (!(*f0)('a')) { return 1; };\n"
" if ((*f0)('z')) { return 2; };\n"
" if (!(*f1)('z')) { return 3; };\n"
" if ((*f1)('a')) { return 4; };\n"
" if (len(tbl) != 2) { return 5; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* fold-6's exact consumer ordering: (str,*fn). The str + fn element
* relocs at the consumer-ordering slot offsets are pinned by cs==ww
* byte-id on the DATA; len(tbl) confirms the slice header resolves. */
{ "consumer_str_fn",
"package main;\n"
"fn fa(c: rune) bool = { return c == 'a'; };\n"
"fn fz(c: rune) bool = { return c == 'z'; };\n"
"const tbl: [](str, *fn(c: rune) bool) = [(\"aa\", &fa), (\"zzz\", &fz)];\n"
"export fn main() i32 = {\n"
" if (len(tbl) != 2) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* multi-row str backing: 3 rows of distinct str lengths — pins the
* per-row 32B stride of the str-header backing (byte-id) + header. */
{ "consumer_3row",
"package main;\n"
"fn fa(c: rune) bool = { return c == 'a'; };\n"
"const tbl: [](str, *fn(c: rune) bool) = "
"[(\"a\", &fa), (\"bb\", &fa), (\"ccc\", &fa)];\n"
"export fn main() i32 = {\n"
" if (len(tbl) != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* #117 broad-arm pin (rob): the TY_TUPLE arm also backs an ACCEPTED
* non-(str,*fn) scalar-tuple slice — (i64,str) with a TYPED i64 (a bare
* untyped int is ww-checker-rejected, #120). Scalar FIRST so the i64
* reads back via the word0-correct whole-element cursor (#121 read-path:
* .1/word3 is truncated, same constraint as the fn-first row). DISTINCT
* values catch a wrong per-row stride/offset; len(t) pins the header; the
* str element rides the 32B backing (its DATAR + len pinned by cs==ww
* byte-id). Base f8be2ae has no TY_TUPLE arm → louds (broad arm is new). */
{ "scalar_tuple_slice",
"package main;\n"
"const t: [](i64, str) = [(10i64, \"a\"), (20i64, \"bb\")];\n"
"export fn main() i32 = {\n"
" let e0 = t[0];\n"
" let e1 = t[1];\n"
" let v0 = e0.0;\n"
" let v1 = e1.0;\n"
" if (v0 != 10) { return 1; };\n"
" if (v1 != 20) { return 2; };\n"
" if (len(t) != 2) { return 3; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* #119: scalar &fn module-globals — DISTINCT fns, each called back
* through the reloc (pre-#119: no DATA → undefined ref / garbage). */
{ "scalar_fnptr",
"package main;\n"
"fn fa(c: rune) bool = { return c == 'a'; };\n"
"fn fz(c: rune) bool = { return c == 'z'; };\n"
"let pf: *fn(c: rune) bool = &fa;\n"
"let pg: *fn(c: rune) bool = &fz;\n"
"export fn main() i32 = {\n"
" if (!(*pf)('a')) { return 1; };\n"
" if ((*pf)('z')) { return 2; };\n"
" if (!(*pg)('z')) { return 3; };\n"
" if ((*pg)('a')) { return 4; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* honest boundary (rule 7): a non-tuple aggregate element (here a
* bare []str) stays LOUD, symmetric both stages — #117 is NARROW to
* the (str,*fn) tuple form, not the full slice-of-aggregate family. */
{ "loud_slice_of_str",
"package main;\n"
"const xs: []str = [\"a\", \"b\"];\n"
"export fn main() i32 = { return len(xs): i32; };\n", 0,
K_BUILDERR, "slice-of-{str,slice,tagged}" },
};
static int
run_driver(const char *driver, const struct row *r, int i)
{
char tmpdir[96], src[128], outbin[128], errf[128], rmcmd[160], cmd[1024];
snprintf(tmpdir, sizeof tmpdir, "/tmp/csa_%d_d_%d", getpid(), i);
mkdir(tmpdir, 0755);
snprintf(src, sizeof src, "%s/csa_%d_%d.ww", tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/csa_%d_%d", tmpdir, getpid(), i);
snprintf(errf, sizeof errf, "%s/err", tmpdir);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s >/dev/null 2>%s",
driver, outbin, src, errf);
int brc = runwait(cmd);
if (r->kind == K_BUILDERR) {
int ok = (brc != 0)
&& (r->experr == NULL || errlog_has(errf, r->experr));
if (!ok)
fprintf(stderr, "row[%s]: %s expected loud builderr "
"\"%s\" (brc=%d)\n", r->label, driver,
r->experr ? r->experr : "", brc);
runwait(rmcmd);
return ok ? 0 : 1;
}
if (brc != 0) {
fprintf(stderr, "row[%s]: build via %s failed\n",
r->label, driver);
runwait(rmcmd);
return -1;
}
int got = runwait(outbin);
runwait(rmcmd);
if (got != r->want) {
fprintf(stderr, "row[%s]: %s exit %d, want %d\n",
r->label, driver, got, r->want);
return 1;
}
return 0;
}
static int
asm_byte_identical(const char *bin, const struct row *r, int i)
{
char src[96], cs[96], ws[96], cmd[1024];
snprintf(src, sizeof src, "/tmp/csa_asm_%d_%d.ww", getpid(), i);
snprintf(cs, sizeof cs, "/tmp/csa_asm_%d_%d_c.s", getpid(), i);
snprintf(ws, sizeof ws, "/tmp/csa_asm_%d_%d_w.s", getpid(), i);
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c errored\n", r->label);
unlink(src);
return -1;
}
snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null",
bin, ws, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label);
unlink(src); unlink(cs);
return -1;
}
int rc = slurp_eq(cs, ws);
if (rc != 0)
fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n",
r->label);
unlink(src); unlink(cs); unlink(ws);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[2080];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cdrv[2120], wdrv[2120];
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin);
int n = (int)(sizeof rows / sizeof rows[0]);
int total = 0, fail = 0;
for (int i = 0; i < n; i++) {
total++;
if (run_driver(cdrv, &rows[i], i) != 0) fail++;
}
if (access(wdrv, X_OK) == 0) {
for (int i = 0; i < n; i++) {
total++;
if (run_driver(wdrv, &rows[i], i) != 0) fail++;
}
for (int i = 0; i < n; i++) {
if (rows[i].kind == K_BUILDERR)
continue;
total++;
if (asm_byte_identical(bin, &rows[i], i) != 0) fail++;
}
}
if (fail) {
fprintf(stderr, "const_slice_aggregate: %d/%d checks failed\n",
fail, total);
return 1;
}
printf("const_slice_aggregate: %d/%d ok\n", total, total);
return 0;
}

View File

@@ -1,276 +0,0 @@
/*
* 947_inferred_scalar_global_run — runtime + byte-id net for #66(b-i): an
* INFERRED int-literal module-global `let s = 42;` (no type annotation) was
* wwstage SILENT-WRONG. The checker stamps such a global with an
* N_TNAME("untyped_int") annotation; letemitsize / emitletdataw / the cgident
* global-read arm key on that annotation's name, which letscalarprim doesn't
* recognise — so the global was dropped from collectlets (no DATAW emitted)
* AND the read fell to the silent module-leaf (no `MOVQ main.s(SB)`), leaving
* `MOVSXD` to sign-extend a STALE AX. cstage instead type_default's the untyped
* int to the 8B machine word before emit, so it produced the correct
* `DATAW main.s` + `MOVQ main.s(SB), AX` (exit 42). cs≠ww, ww silent-wrong.
*
* Fix (wwstage only, cgen.ww defaultinferredlets, one choke-point before
* collectlets): rewrite the untyped_int annotation to the concrete machine
* word `int` — NOT i32 (that's the #108 truncation trap, opposite polarity) —
* so all three consumers resolve it as an 8B int global. The emitted DATAW +
* MOVQ then match cstage byte-for-byte (align ww UP). Guarded to N_INTLIT rhs
* ONLY: a const-EXPR inferred global (`let s = 7*6`) is #66(b-ii), a SEPARATE
* loud both-stage no-DATA gap, and must stay on its loud route.
*
* Each row carries (a) a cstage `ww build` + run asserting the exit code (R1
* pre-fix: wwstage exit 136 / asm differs), and (b) a w6c vs w6c_ww `.s` cmp
* (rule-10 byte-id). R2 is the typed-annotation control (already cs==ww/42),
* locking no regression on the annotated path.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; int want_err; };
static const struct row rows[] = {
/* R1 — the #66(b-i) repro: inferred int-literal module-global, read
* back from main. Pre-fix wwstage emitted neither the DATAW nor the
* MOVQ → MOVSXD on stale AX → exit 136. Post-fix cs==ww, exit 42. */
{ "inferred",
"package main;\n"
"let s = 42;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 42, 0 },
/* R2 — typed-annotation control: `let s: i64 = 42;` already worked
* (cs==ww, DATA emitted). Regression guard for the annotated path. */
{ "typed_ctrl",
"package main;\n"
"let s: i64 = 42;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 42, 0 },
/* R3 — #134 neg leg: inferred unary-over-int-literal module-global
* `let s = -42;` (rhs N_UN(TK_MINUS) over N_INTLIT). Pre-fix wwstage
* emitted neither DATAW nor MOVQ (un-defaulted untyped_int annotation)
* → exit 168 (garbage). cstage folds the unary, emits DATAW + load
* (exit 214 = -42 low-8). Post-fix defaultinferredlets peels the unary
* and defaults to `int`, so cs==ww and both run -42 (exit 214). */
{ "neg_inferred",
"package main;\n"
"let s = -42;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 214, 0 },
/* R4 — #134 neg typed control: `let s: int = -42;` (TYPED). Already
* cs==ww today (concrete annotation → letscalarprim fires). Locks the
* construction proof: R3's emitted .s is byte-identical to this typed
* control (the inferred decl IS the typed decl after defaulting). */
{ "neg_typed_ctrl",
"package main;\n"
"let s: int = -42;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 214, 0 },
/* #133 — const-EXPR scalar module-global. The let pass-2 arm now
* const-folds an N_BIN / unary-over-N_BIN / def-ref rhs and stamps it
* to an N_INTLIT (mirroring the N_DEF arm), so cgen's literal-only
* DATA emitter lays the row in BOTH stages. Pre-fix: cstage LINK-FAILed
* (`undefined main.s` — read emitted, no DATA word) and wwstage was
* SILENT-WRONG (no DATA, no load, MOVSXD on stale AX → exit 152). */
/* C1 — inferred const-expr `let s = 7*6;` → 42 (N_BIN rhs). */
{ "const_inferred",
"package main;\n"
"let s = 7 * 6;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 42, 0 },
/* C2 — typed const-expr (b-ii) `let s: i64 = 7*6;` → 42. Pre-fix this
* LINK-FAILed BOTH stages (annotation-independent no-DATA gap); the
* same stamp supplies the foldable value. */
{ "const_typed",
"package main;\n"
"let s: i64 = 7 * 6;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 42, 0 },
/* C3 — def-ref through let `def K: int = 6; let s = K*7;` → 42. Proves
* eval_def_const's N_IDENT def-resolution reaches through the new let
* hook. */
{ "const_defref",
"package main;\n"
"def K: int = 6;\n"
"let s = K * 7;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 42, 0 },
/* C4 — unary-over-binop `let s = -(2*3);` → -6 (low byte 250). Proves
* the N_UN ∘ N_BIN composition folds through eval_def_const. */
{ "const_unary_binop",
"package main;\n"
"let s = -(2 * 3);\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 250, 0 },
/* C5 — loud guard: a div-by-zero const-expr module-global init stays a
* compile ERROR in BOTH stages, NOT silently zeroed. Asserts the
* eval_def_const error path is preserved through the let hook. */
{ "const_divzero",
"package main;\n"
"let s = 7 / 0;\n"
"export fn main() i32 = {\n"
" return s: i32;\n"
"};\n", 0, 1 },
{ NULL, NULL, 0, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "infglobal: w6c_ww missing — cannot run the "
"cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwisg_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char src[128], rmcmd[160];
snprintf(src, sizeof src, "%s/wwisg_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (f == NULL) { runwait(rmcmd); fail++; continue; }
fputs(rows[i].src, f);
fclose(f);
char cs_s[128], ws_s[128];
snprintf(cs_s, sizeof cs_s, "%s/wwisg_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwisg_%d_%d_ww.s",
tmpdir, getpid(), i);
/* Loud-guard rows (#133 R5): both stages must REJECT the
* source at compile (e.g. a div-by-zero const-expr init). No
* value to run / no byte-id — only the error-path preservation
* matters. Assert raw w6c AND w6c_ww both emit non-zero. */
if (rows[i].want_err) {
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) == 0) {
fprintf(stderr, "row[%s]: w6c accepted a source "
"that must be rejected (loud guard)\n",
rows[i].label);
fail++;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) == 0) {
fprintf(stderr, "row[%s]: w6c_ww accepted a "
"source that must be rejected (loud "
"guard)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
continue;
}
/* (a) cstage build + run. */
char outbin[128];
snprintf(outbin, sizeof outbin, "%s/wwisg_%d_%d",
tmpdir, getpid(), i);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
/* (b) cs==ww byte-id gate. */
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d inferred-scalar-global tests failed\n",
fail, n);
return 1;
}
printf("infglobal: %d/%d ok (cstage run + cs==ww byte-id)\n", n, n);
return 0;
}

View File

@@ -1,206 +0,0 @@
/*
* 949_structlit_arrfield_run — runtime + byte-id net for #249: struct
* array-field init/read silent miscompiles. Two distinct roots, both
* gate-blind (cs==ww broken identically pre-fix):
*
* BUG B — reading an array field of a module-GLOBAL struct value
* (`G.arr[i]`). The N_INDEX fallback's cg_dotbase_addr / dotbaseaddr
* helper (the #135 sibling) had no module-global-struct base arm:
* cstage emitted `LEAQ (BP)` (read the stack → 0), wwstage fell to
* cgexpr(N_DOT) which loaded the field VALUE as a pointer → SEGFAULT.
* The .data was already correct (emit_struct_lit_bytes #129 A.3); only
* the READ base address was wrong. Fix: a global value-struct base
* emits `LEAQ name(SB) (+ ADDQ field_off)`, mirroring the scalar
* global-field read (cgen.c:7532). const globals are def_isstructdef.
*
* BUG A — initializing an array field from a struct literal
* (`e{ arr = [..] }`) as a local. cg_structlit_fill / cgstructlitfill
* had no TY_ARRAY field arm; the array field fell to the generic
* scalar tail (cgexpr the N_ARRLIT → AX, store one sized word) which
* silently DROPPED every element. Fix: a TY_ARRAY field arm element-
* wise stores the N_ARRLIT at base+field_off+i*esz, reusing the proven
* N_LET array-init shape. The GLOBAL literal-init path is unaffected
* (it goes through emit_struct_lit_bytes, already correct).
*
* cstage `ww build` + run for exit code; w6c vs w6c_ww `.s` cmp for the
* rule-10 byte-id gate. u8 element rows only (a `[N]u8` read cast to i32
* is byte-id; wider widths hit the i32-return MOVL/MOVSXD cs/ww
* divergence — see 949_dotbase_arr_run's deferral note).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
/* BUG B: read [4]u8 field of a module-global `let` struct at idx 0
* (field_off 0). Pre-fix cstage→0, wwstage→SEGFAULT. encmap[0]='A'
* (65). */
{ "global_let_read",
"package main;\n"
"type e = struct { encmap: [4]u8 };\n"
"let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n"
"export fn main() i32 = { return g.encmap[0]: i32; };\n", 65 },
/* BUG B: read [4]u8 field of a module-global `def` (const) struct
* at idx 2, with a non-zero field offset (a [3]u8 pad ahead of it) —
* exercises def_isstructdef + the ADDQ $field_off arm. The base64
* `const std_encoding` shape. pad ahead, encmap[2]='C' (67). */
{ "global_def_read_off",
"package main;\n"
"type e = struct { pad: [3]u8, encmap: [4]u8 };\n"
"def G: e = e { pad = [9u8, 9u8, 9u8],"
" encmap = [65u8, 66u8, 67u8, 68u8] };\n"
"export fn main() i32 = { return G.encmap[2]: i32; };\n", 67 },
/* BUG A: local struct-literal init of a [4]u8 field, read idx 0.
* Pre-fix the array field fell to the generic scalar tail (cgexpr
* the N_ARRLIT → AX, store one word) and silently dropped every
* element → 0. encmap[0]='A' (65). */
{ "local_lit_read0",
"package main;\n"
"type e = struct { encmap: [4]u8 };\n"
"export fn main() i32 = {\n"
" let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n"
" return g.encmap[0]: i32;\n"
"};\n", 65 },
/* BUG A: same init, read idx 3 — asserts the LAST element landed
* (the pre-fix single-word store would never reach it). 'D' (68). */
{ "local_lit_read3",
"package main;\n"
"type e = struct { encmap: [4]u8 };\n"
"export fn main() i32 = {\n"
" let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n"
" return g.encmap[3]: i32;\n"
"};\n", 68 },
/* NB: a trailing `...` repeat in a struct-LITERAL array field
* (`encmap = [7u8...]`) is rejected by the CHECKER ("[1]u8 not
* assignable to [4]u8") — the field type-check doesn't apply the
* repeat-length inference that bare `let a: [N]T = [v...]` gets.
* The cg_structlit_fill array arm mirrors the N_LET `...` handling
* for symmetry, but that path is checker-unreachable today (separate
* checker gap, not #249). No row exercises it. */
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "structlit_arrfield: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwsaf_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char src[128], outbin[128], cs_s[160], ws_s[160], rmcmd[160];
snprintf(src, sizeof src, "%s/wwsaf_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwsaf_%d_%d",
tmpdir, getpid(), i);
snprintf(cs_s, sizeof cs_s, "%s/wwsaf_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwsaf_%d_%d_ww.s",
tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (f == NULL) { fail++; runwait(rmcmd); continue; }
fputs(rows[i].src, f);
fclose(f);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d structlit-arrfield tests failed\n",
fail, n);
return 1;
}
printf("structlit_arrfield: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,251 +0,0 @@
/*
* 949_valstruct_subsize_run — runtime + byte-id net for #254: a sub-8
* (non-8-multiple) nested value-struct must size its zero-init extent
* from the type table's natural ABI size (cstage lu->size), NOT the
* slot-padded register-struct width.
*
* Root: wwstage conflated SLOT-size (round-to-8, for frame layout) with
* ABI-size (true). A nested value-struct field was sized via fieldsize()
* (cgenutil.ww TY_STRUCT -> ti.slotsize = 8), poisoning structabisize +
* registerstruct si.totsize to 8 for a struct whose true ABI size is 4.
* Two emission sites then over-sized:
* D1 (local): cglet zsz = structabisize = 8 hit the `zsz == 8` zero
* arm (cgenstmt.ww #213) -> a stray `MOVQ $0, off(BP)` that cstage
* (ABI 4 is sub-8 -> left uninit per the shared no-rhs policy)
* never emits.
* D2 (global): emitletdataw struct arm wrote si.totsize = 8 zero bytes
* of DATAW; cstage cg_let_emit_size returns u->size = 4.
* Both were SILENT cs!=ww divergences (gate-blind: a standalone wwstage
* is self-consistent; only the cs==ww .s cmp catches it).
*
* Fix (rule-13 SSoT): both sites source the extent from tinfo.size
* (peeling TY_NAMED), the same value cstage reads. fieldsize /
* registerstruct / frame slot-padding stay UNTOUCHED — moving the fix
* into the size helpers would shift nested-struct field offsets and
* re-diverge other byte-id.
*
* Rows cover the whole sub-8 class (ABI size 1/2/4) in both the local
* (D1) and global (D2) emission contexts, plus a >8 NEGATIVE control
* proving the fix didn't disable legitimate multi-word zero-init. Each
* row: cstage `ww build` + run for the exit code (correctness) AND
* w6c vs w6c_ww `.s` cmp for rule-10 byte-id (the silent-divergence net).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row { const char *label; const char *src; int want_exit; };
static const struct row rows[] = {
/* D1 local, ABI size 4 (inner {[4]u8}). Pre-fix wwstage emitted a
* stray MOVQ $0 cstage didn't -> .s differ. Write+read a byte so
* the exit is deterministic (sub-8 is left uninit by BOTH stages,
* matching cstage's no-rhs policy). */
{ "d1_local_4",
"package main;\n"
"type inner = struct { m: [4]u8 };\n"
"type outv = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outv;\n"
" o.i.m[0] = 66u8;\n"
" return o.i.m[0]: i32;\n"
"};\n", 66 },
/* D1 local, ABI size 2 ([2]u8). */
{ "d1_local_2",
"package main;\n"
"type inner = struct { m: [2]u8 };\n"
"type outv = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outv;\n"
" o.i.m[1] = 55u8;\n"
" return o.i.m[1]: i32;\n"
"};\n", 55 },
/* D1 local, ABI size 1 ([1]u8) — the tightest sub-8 case. */
{ "d1_local_1",
"package main;\n"
"type inner = struct { m: [1]u8 };\n"
"type outv = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outv;\n"
" o.i.m[0] = 44u8;\n"
" return o.i.m[0]: i32;\n"
"};\n", 44 },
/* D2 global, ABI size 4. Pre-fix wwstage emitted DATAW of 8 zero
* bytes vs cstage's 4 -> .s differ. */
{ "d2_global_4",
"package main;\n"
"type inner = struct { m: [4]u8 };\n"
"type outv = struct { i: inner };\n"
"let g: outv;\n"
"export fn main() i32 = {\n"
" g.i.m[0] = 66u8;\n"
" return g.i.m[0]: i32;\n"
"};\n", 66 },
/* D2 global, ABI size 2. */
{ "d2_global_2",
"package main;\n"
"type inner = struct { m: [2]u8 };\n"
"type outv = struct { i: inner };\n"
"let g: outv;\n"
"export fn main() i32 = {\n"
" g.i.m[1] = 55u8;\n"
" return g.i.m[1]: i32;\n"
"};\n", 55 },
/* D2 global, ABI size 1. */
{ "d2_global_1",
"package main;\n"
"type inner = struct { m: [1]u8 };\n"
"type outv = struct { i: inner };\n"
"let g: outv;\n"
"export fn main() i32 = {\n"
" g.i.m[0] = 44u8;\n"
" return g.i.m[0]: i32;\n"
"};\n", 44 },
/* NEGATIVE control — a >8 (multi-word) value-struct still zero-
* inits. Read an UNWRITTEN byte: a working multi-word zero-init
* fill makes it 0. If the fix had wrongly suppressed the >8 zero
* arm, this would read stack garbage (and byte-id would diff
* against the still-zeroing cstage). Local + global both proven. */
{ "ctl_local_16",
"package main;\n"
"type inner = struct { m: [16]u8 };\n"
"type outv = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outv;\n"
" return o.i.m[7]: i32;\n"
"};\n", 0 },
{ "ctl_global_16",
"package main;\n"
"type inner = struct { m: [16]u8 };\n"
"type outv = struct { i: inner };\n"
"let g: outv;\n"
"export fn main() i32 = {\n"
" return g.i.m[7]: i32;\n"
"};\n", 0 },
{ NULL, NULL, 0 }
};
static int
slurp_eq(const char *a, const char *b)
{
FILE *fa = fopen(a, "rb");
FILE *fb = fopen(b, "rb");
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; }
int rc = 0;
for (;;) {
int ca = fgetc(fa);
int cb = fgetc(fb);
if (ca != cb) { rc = -1; break; }
if (ca == EOF) break;
}
fclose(fa); fclose(fb);
return rc;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char w6c[1100], w6c_ww[1100];
snprintf(w6c, sizeof w6c, "%s/w6c", bin);
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
if (access(w6c_ww, X_OK) != 0) {
fprintf(stderr, "valstruct_subsize: w6c_ww missing — cannot run "
"the cs==ww byte-id gate (the whole point of this test)\n");
return 1;
}
int n = 0, fail = 0;
for (int i = 0; rows[i].src; i++, n++) {
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwvss_%d_d_%d",
getpid(), i);
mkdir(tmpdir, 0755);
char rmcmd[160];
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
char src[128], outbin[128], cs_s[128], ws_s[128];
snprintf(src, sizeof src, "%s/wwvss_%d_%d.ww",
tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/wwvss_%d_%d",
tmpdir, getpid(), i);
snprintf(cs_s, sizeof cs_s, "%s/wwvss_%d_%d_cs.s",
tmpdir, getpid(), i);
snprintf(ws_s, sizeof ws_s, "%s/wwvss_%d_%d_ww.s",
tmpdir, getpid(), i);
FILE *f = fopen(src, "wb");
if (f == NULL) { fail++; runwait(rmcmd); continue; }
fputs(rows[i].src, f);
fclose(f);
char cmd[2048];
snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s",
bin, outbin, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: cstage build failed\n",
rows[i].label);
fail++;
runwait(rmcmd);
continue;
}
int got = runwait(outbin);
if (got != rows[i].want_exit) {
fprintf(stderr, "row[%s]: cstage exit %d, want %d\n",
rows[i].label, got, rows[i].want_exit);
fail++;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c, cs_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label);
fail++; runwait(rmcmd); continue;
}
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null",
w6c_ww, ws_s, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "row[%s]: w6c_ww failed\n",
rows[i].label);
fail++; runwait(rmcmd); continue;
}
if (slurp_eq(cs_s, ws_s) != 0) {
fprintf(stderr,
"row[%s]: cstage/wwstage .s DIFFER (rule-10 "
"byte-id violation)\n", rows[i].label);
fail++;
}
runwait(rmcmd);
}
if (fail) {
fprintf(stderr, "%d/%d valstruct-subsize tests failed\n",
fail, n);
return 1;
}
printf("valstruct_subsize: %d/%d ok (cstage run + cs==ww byte-id)\n",
n, n);
return 0;
}

View File

@@ -1,202 +0,0 @@
/*
* 989_nestfield_run — #44/#55 struct-layout SSoT: a struct with a nested
* sub-8 composite field plus a successor must address EVERY field at the
* checker's natural offset, identically on the write (construction) and
* read (field-access) paths.
*
* THE BUG (cat-A silent miscompile, gate-blind): wwstage had TWO struct-
* layout sources. `registerstruct` (selfhost/cmd/wcc/cgenutil.ww) rebuilt
* each field's `fi.foff` via `fieldsize` — SLOT-padded, so a nested
* `inner{x:u8,y:u8}` (size 2, slotsize 8) pushed every successor to an 8B
* boundary. The READ path (cgplaceaddr/dotbaseaddr) reads the checker's
* tfield.offset — NATURAL (inner align 1 → p at offset 1, z packed right
* after). So ww WROTE p/z at the slot-padded offset and READ them at the
* natural offset → garbage. The shape (nested sub-8 composite + a field
* after it) is corpus-ABSENT — ww uses both sources on its OWN structs, so
* if such a struct existed the bootstrap would mis-address itself and
* 400-green would be impossible; the gate cannot see it, this repro is the
* proof. cstage has no structinfo — it reads tfield directly, self-
* consistently natural (cmd/w6c/cgen.c). THE FIX: make ww's `fi.foff` a
* VIEW of tfield.offset (lock-step walk tstruct.list + ti.fields), so the
* second source collapses onto cstage's natural one (cs==ww preserved).
*
* Each program self-checks every field (write 1/2/3/.., read back, return
* the 1-based index of the first mismatch, 0 on all-correct). Pre-fix ww
* constructs at slot offsets and reads at natural → a non-zero return on
* the first composite-or-successor field, so cs(=0) != ww(!=0) AND ww !=
* want. Both stages build+run (rule-10); the want is the absolute 0.
*
* This is a RUNTIME cs==ww check (both stages exit 0): it proves field
* offsets are natural and instruction-correct RELATIVE TO the struct base.
* It deliberately does NOT gate the absolute .s frame, which is still
* cs!=ww on this shape via a SEPARATE pre-existing producer — wwstage
* reserves the struct LOCAL's stack slot at slot-padded slotsize, cstage
* at natural (task #75). The frame-absolute teeth belong to #75's fix.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return -1;
}
struct row {
const char *label;
const char *src;
int want_exit; /* >= 0: pin the absolute value; -1: cs==ww only */
};
static const struct row rows[] = {
/* (1) nested2 — outer2{a:u8, p:inner}: the core divergence. Natural
* p at offset 1; pre-fix slot-padded p at offset 8. Construction
* (write) vs field-access (read) disagree → o.p.x / o.p.y read wrong.
* Returns the 1-based index of the first mismatched field, 0 on ok. */
{ "nested2",
"package main;\n"
"type inner = struct { x: u8, y: u8 };\n"
"type outer2 = struct { a: u8, p: inner };\n"
"export fn main() int = {\n"
" let o: outer2 = outer2 { a = 5, p = inner { x = 6, y = 7 } };\n"
" if (o.a: int != 5) { return 1; };\n"
" if (o.p.x: int != 6) { return 2; };\n"
" if (o.p.y: int != 7) { return 3; };\n"
" return 0;\n"
"};\n",
0 },
/* (2) nested3 — outer{a:u8, p:inner, z:i64}: z proves post-composite
* accumulation stays natural. Pre-fix z sat at the slot-padded offset
* past the 8B-padded inner; the natural read undershoots. The wide z
* value (0x44444444) is verified inside the program (the exit channel
* is 8-bit), so a truncated/mis-addressed z fails the in-program cmp. */
{ "nested3",
"package main;\n"
"type inner = struct { x: u8, y: u8 };\n"
"type outer = struct { a: u8, p: inner, z: i64 };\n"
"export fn main() int = {\n"
" let o: outer = outer { a = 1, p = inner { x = 2, y = 3 }, z = 0x44444444i64 };\n"
" if (o.a: int != 1) { return 1; };\n"
" if (o.p.x: int != 2) { return 2; };\n"
" if (o.p.y: int != 3) { return 3; };\n"
" if (o.z != 0x44444444i64) { return 4; };\n"
" return 0;\n"
"};\n",
0 },
/* (3) control — flat struct {a:u8, b:i64}, no sub-8 composite field.
* Natural and slot-padded layouts coincide (b lands at 8 either way);
* proves the fix leaves the common case unmoved. */
{ "flat_ctl",
"package main;\n"
"type flat = struct { a: u8, b: i64 };\n"
"export fn main() int = {\n"
" let o: flat = flat { a = 9, b = 0x33333333i64 };\n"
" if (o.a: int != 9) { return 1; };\n"
" if (o.b != 0x33333333i64) { return 2; };\n"
" return 0;\n"
"};\n",
0 },
};
/* run_build — build+run `src` via `driver`; returns the binary's exit
* code, or -1 on a build failure. */
static int
run_build(const char *driver, const struct row *r, int i)
{
char tmpdir[64], src[128], outbin[128], rmcmd[160], cmd[1024];
snprintf(tmpdir, sizeof tmpdir, "/tmp/nestfld_%d_d_%d", getpid(), i);
mkdir(tmpdir, 0755);
snprintf(src, sizeof src, "%s/nestfld_%d_%d.ww", tmpdir, getpid(), i);
snprintf(outbin, sizeof outbin, "%s/nestfld_%d_%d", tmpdir, getpid(), i);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -2; }
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
driver, outbin, src);
int brc = runwait(cmd);
int got = -1;
if (brc == 0) got = runwait(outbin);
runwait(rmcmd);
return brc == 0 ? got : -1;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cdrv[1024], wdrv[1024];
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin);
int have_ww = (access(wdrv, X_OK) == 0);
int n = (int)(sizeof rows / sizeof rows[0]);
int total = 0, fail = 0;
for (int i = 0; i < n; i++) {
total++;
int gc = run_build(cdrv, &rows[i], i);
/* cstage must build+run */
if (gc < 0) {
fprintf(stderr, "nestfield_run[cstage][%s]: build/run "
"failed (got %d)\n", rows[i].label, gc);
fail++;
continue;
}
if (rows[i].want_exit >= 0 && gc != rows[i].want_exit) {
fprintf(stderr, "nestfield_run[cstage][%s]: exit=%d "
"want=%d (field mismatch)\n",
rows[i].label, gc, rows[i].want_exit);
fail++;
}
if (!have_ww) {
fprintf(stderr, "nestfield_run: skip wwstage (no %s)\n",
wdrv);
continue;
}
int gw = run_build(wdrv, &rows[i], i);
/* rule-10: the cat-A invariant is cs == ww */
if (gw != gc) {
fprintf(stderr, "nestfield_run[%s]: cs=%d != ww=%d "
"(struct field-offset divergence — #44/#55)\n",
rows[i].label, gc, gw);
fail++;
}
if (rows[i].want_exit >= 0 && gw != rows[i].want_exit) {
fprintf(stderr, "nestfield_run[wwstage][%s]: exit=%d "
"want=%d (field mismatch)\n",
rows[i].label, gw, rows[i].want_exit);
fail++;
}
}
if (fail) {
fprintf(stderr, "nestfield_run: %d/%d checks failed\n",
fail, total);
return 1;
}
printf("nestfield_run: %d/%d ok\n", total, total);
return 0;
}

View File

@@ -25,9 +25,9 @@
* 683 asm_byte_identical pattern). Byte-identity subsumes the frame:
* pre-fix nested3 differs at `TEXT main,$32` vs `$16`, `SUBQ $32` vs
* `$16`, and every `-24(BP)` vs `-16(BP)`; post-fix the two .s are
* byte-for-byte equal. The sibling 989_nestfield_run is the RUNTIME
* exit-code proof (deliberately NOT frame-gated — see its header); this
* file is the .s/frame-absolute one #75 owes.
* byte-for-byte equal. The sibling RUNTIME exit-code proof migrated to
* test/lang/nestfield_test.ww (@test field-read rows, cs==ww via the T2
* byte-id gate); this file is the .s/frame-absolute one #75 owes.
*/
#include <stdio.h>
#include <stdlib.h>

View File

@@ -0,0 +1,7 @@
//ww:error "repeat with nested-array elements"
// #156/rule-7 carrier: a `...` repeat marker with a nested-array element must
// REJECT on both stages (no consumer needs it; powers_of_ten is fully
// enumerated). From test/wcc/919_array_static_init_run.c nested_ellipsis_reject.
package main;
let A: [4][2]u64 = [[1u64, 2u64]...];
export fn main() i32 = { return 0; };

View File

@@ -0,0 +1,8 @@
//ww:error "division by zero"
// #133/rule-7 carrier: a div-by-zero const-expr module-global init stays a
// COMPILE error in BOTH stages, NOT silently zeroed (the eval_def_const error
// path survives the let-hook). From test/wcc/947_inferred_scalar_global_run.c
// const_divzero.
package main;
let s = 7 / 0;
export fn main() i32 = { return s: i32; };

View File

@@ -0,0 +1,8 @@
//ww:error "slice-of-{str,slice,tagged}"
// #117/rule-7 carrier: a non-tuple aggregate element (a bare []str) in a
// const-slice static-init stays a LOUD reject in BOTH stages — #117 is narrow
// to the (str,*fn) tuple form. From test/wcc/946_const_slice_aggregate_run.c
// loud_slice_of_str.
package main;
const xs: []str = ["a", "b"];
export fn main() i32 = { return len(xs): i32; };