From c78bf6ebcac7dc34b4d4241dd9a1ba9b9f8ae246 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 8 Aug 2026 14:29:28 +0900 Subject: [PATCH] test: port the xmod same-leaf collision carriers to corpus fixtures 752_modparam_callee.c -> r752_modparam_xmod_variadic_vs_scalar, r752_modparam_variadic_no_collision (run; alpha/beta module dirs) 784_xmod_alias_struct_collide_run.c -> r784_xmod_alias_struct_collide (run-exit 42), r784_xmod_alias_struct_symmetric (21), r784_xmod_alias_control (30) (sa/sb module dirs) 793_xmod_struct_argpush_collide_run.c -> r793_xmod_argpush_ {recvpush_t16 107, fieldread_t16 107, combined_t16 114, recvpush_t12 6} (m1/m2 module dirs) 797_xmod_struct_field_layout_collide_run.c -> r797_xmod_layout_ {ptrread_t16 107, letcopy_t16 107, addrptr_pq 10, addrval_pq 10, ptrwrite_t16 109, valwrite_t16 109} (m1/m2) + r797_nestfill_box (66) r770-style sibling module dirs express the trees; the fixture corpus runs both drivers natively (784's wwstage-build-only leg upgrades to build+run) and test-data-byteid owns each carrier's aggregated per- package .s compare (letcopy_t16's real discriminator). All 16 probed green on both stages including per-package byte identity. --- internal/wwfixture/types.ww | 10 +- test/wcc/752_modparam_callee.c | 298 ------------ test/wcc/784_xmod_alias_struct_collide_run.c | 393 --------------- .../wcc/793_xmod_struct_argpush_collide_run.c | 343 ------------- ...797_xmod_struct_field_layout_collide_run.c | 452 ------------------ .../alpha/alpha.ww | 8 + .../case.ww | 9 + .../alpha/alpha.ww | 5 + .../beta/beta.ww | 9 + .../case.ww | 11 + test/wcc/data/r784_xmod_alias_control/case.ww | 12 + .../wcc/data/r784_xmod_alias_control/sa/sa.ww | 21 + .../r784_xmod_alias_struct_collide/case.ww | 17 + .../r784_xmod_alias_struct_collide/sa/sa.ww | 25 + .../r784_xmod_alias_struct_collide/sb/sb.ww | 7 + .../r784_xmod_alias_struct_symmetric/case.ww | 11 + .../r784_xmod_alias_struct_symmetric/sa/sa.ww | 15 + .../r784_xmod_alias_struct_symmetric/sb/sb.ww | 8 + .../r793_xmod_argpush_combined_t16/case.ww | 12 + .../r793_xmod_argpush_combined_t16/m1/m1.ww | 5 + .../r793_xmod_argpush_combined_t16/m2/m2.ww | 4 + .../r793_xmod_argpush_fieldread_t16/case.ww | 11 + .../r793_xmod_argpush_fieldread_t16/m1/m1.ww | 4 + .../r793_xmod_argpush_fieldread_t16/m2/m2.ww | 4 + .../r793_xmod_argpush_recvpush_t12/case.ww | 11 + .../r793_xmod_argpush_recvpush_t12/m1/m1.ww | 5 + .../r793_xmod_argpush_recvpush_t12/m2/m2.ww | 4 + .../r793_xmod_argpush_recvpush_t16/case.ww | 11 + .../r793_xmod_argpush_recvpush_t16/m1/m1.ww | 5 + .../r793_xmod_argpush_recvpush_t16/m2/m2.ww | 4 + test/wcc/data/r797_nestfill_box/case.ww | 14 + .../data/r797_xmod_layout_addrptr_pq/case.ww | 13 + .../data/r797_xmod_layout_addrptr_pq/m1/m1.ww | 10 + .../data/r797_xmod_layout_addrptr_pq/m2/m2.ww | 5 + .../data/r797_xmod_layout_addrval_pq/case.ww | 13 + .../data/r797_xmod_layout_addrval_pq/m1/m1.ww | 10 + .../data/r797_xmod_layout_addrval_pq/m2/m2.ww | 5 + .../data/r797_xmod_layout_letcopy_t16/case.ww | 12 + .../r797_xmod_layout_letcopy_t16/m1/m1.ww | 10 + .../r797_xmod_layout_letcopy_t16/m2/m2.ww | 5 + .../data/r797_xmod_layout_ptrread_t16/case.ww | 11 + .../r797_xmod_layout_ptrread_t16/m1/m1.ww | 10 + .../r797_xmod_layout_ptrread_t16/m2/m2.ww | 5 + .../r797_xmod_layout_ptrwrite_t16/case.ww | 12 + .../r797_xmod_layout_ptrwrite_t16/m1/m1.ww | 10 + .../r797_xmod_layout_ptrwrite_t16/m2/m2.ww | 5 + .../r797_xmod_layout_valwrite_t16/case.ww | 12 + .../r797_xmod_layout_valwrite_t16/m1/m1.ww | 10 + .../r797_xmod_layout_valwrite_t16/m2/m2.ww | 5 + 49 files changed, 420 insertions(+), 1491 deletions(-) delete mode 100644 test/wcc/752_modparam_callee.c delete mode 100644 test/wcc/784_xmod_alias_struct_collide_run.c delete mode 100644 test/wcc/793_xmod_struct_argpush_collide_run.c delete mode 100644 test/wcc/797_xmod_struct_field_layout_collide_run.c create mode 100644 test/wcc/data/r752_modparam_variadic_no_collision/alpha/alpha.ww create mode 100644 test/wcc/data/r752_modparam_variadic_no_collision/case.ww create mode 100644 test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/alpha/alpha.ww create mode 100644 test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/beta/beta.ww create mode 100644 test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/case.ww create mode 100644 test/wcc/data/r784_xmod_alias_control/case.ww create mode 100644 test/wcc/data/r784_xmod_alias_control/sa/sa.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_collide/case.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_collide/sa/sa.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_collide/sb/sb.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_symmetric/case.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_symmetric/sa/sa.ww create mode 100644 test/wcc/data/r784_xmod_alias_struct_symmetric/sb/sb.ww create mode 100644 test/wcc/data/r793_xmod_argpush_combined_t16/case.ww create mode 100644 test/wcc/data/r793_xmod_argpush_combined_t16/m1/m1.ww create mode 100644 test/wcc/data/r793_xmod_argpush_combined_t16/m2/m2.ww create mode 100644 test/wcc/data/r793_xmod_argpush_fieldread_t16/case.ww create mode 100644 test/wcc/data/r793_xmod_argpush_fieldread_t16/m1/m1.ww create mode 100644 test/wcc/data/r793_xmod_argpush_fieldread_t16/m2/m2.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t12/case.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t12/m1/m1.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t12/m2/m2.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t16/case.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t16/m1/m1.ww create mode 100644 test/wcc/data/r793_xmod_argpush_recvpush_t16/m2/m2.ww create mode 100644 test/wcc/data/r797_nestfill_box/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrptr_pq/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrptr_pq/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrptr_pq/m2/m2.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrval_pq/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrval_pq/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_addrval_pq/m2/m2.ww create mode 100644 test/wcc/data/r797_xmod_layout_letcopy_t16/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_letcopy_t16/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_letcopy_t16/m2/m2.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrread_t16/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrread_t16/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrread_t16/m2/m2.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrwrite_t16/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrwrite_t16/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_ptrwrite_t16/m2/m2.ww create mode 100644 test/wcc/data/r797_xmod_layout_valwrite_t16/case.ww create mode 100644 test/wcc/data/r797_xmod_layout_valwrite_t16/m1/m1.ww create mode 100644 test/wcc/data/r797_xmod_layout_valwrite_t16/m2/m2.ww diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index 254211de..8701b322 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1643; +def corpuscount: i32 = 1659; def errorcount: i32 = 338; def compilecount: i32 = 18; -def runcount: i32 = 198; -def runexitcount: i32 = 1089; -def nativecount: i32 = 3286; -def corpushash: str = "c2bfc683a76c7bffa727612f102893c7dbfdb9e73e56212eed8687b8087d7870"; +def runcount: i32 = 200; +def runexitcount: i32 = 1103; +def nativecount: i32 = 3318; +def corpushash: str = "c9c9361b3f799c1439fb9009f8c6edfc7dbf36a263b789e65f239b3984661ffd"; type directive = enum i32 { ERROR = 0, diff --git a/test/wcc/752_modparam_callee.c b/test/wcc/752_modparam_callee.c deleted file mode 100644 index 3e947255..00000000 --- a/test/wcc/752_modparam_callee.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * 752_modparam_callee — sentinel for task #16 (sub-bug of #4d): - * wwstage's callee_variadic_param helper (selfhost/cmd/wcc/ - * cgenutil.ww) took an N_DOT callee but routed both arms through - * bare-leaf fnparamslookup. Post-#4d that walk is same-module-first - * then head-walk fallback — for a cross-module N_DOT call from a - * caller whose c.curmod doesn't match either side, the head-walk - * returns whichever module's same-leaf fn sits at the head of - * c.fnrets. When that head-side fn has a divergent variadic-vs- - * non-variadic shape the callee_variadic_param result fires the - * gather machinery against the wrong-module shape: arg-prep - * builds a slice for `xs: T...` while the CALL still targets the - * non-variadic module-qualified label. Label correct, ABI wrong. - * - * Surfaced by attempting strings.contains' Hare-shaped - * `(needles: (str | rune)...)` graduation while bytes.contains - * stays at `(needle: (u8 | []u8))` — caller's - * `bytes.contains(b, n)` site picked strings.contains' variadic - * params for arg-prep. - * - * Cstage carries no sister bug: cmd/w6c/cgen.c reads the callee - * fn-type from the typed `n->lhs->type` (TY_FN sig) and walks - * `callee_params->variadic` directly, module-aware via the typed - * AST. Mirror of #4d / #28 / #31 / #34: cstage sidesteps every - * bare-leaf table. - * - * Fix: route the N_DOT arm through fnparamslookupmod(c, leaf, - * callee.lhs.str). The N_IDENT arm stays on bare fnparamslookup - * (already same-module-first post-#4d). - * - * row | what it pins - * ---------------------------------------|------------------------- - * cross_module_same_leaf_variadic_vs_scalar - * | primary wedge. A.foo - * | variadic, B.foo scalar - * | same leaf. Caller in - * | a third package calls - * | B.foo with a tagged - * | arg; pre-fix wwstage - * | preps the call site as - * | variadic gather and - * | mis-marshals — rc=11. - * | Post-fix both stages - * | rc=0. - * bare_leaf_no_collision | control: variadic fn - * | declared in only one - * | module, called via - * | bare leaf (N_IDENT) - * | from the same module. - * | Confirms the N_IDENT - * | arm still graduates - * | through bare - * | fnparamslookup - * | (post-#4d). - * - * The standalone same_module_same_leaf runtime control now lives in - * test/wcc/data/r75_modparam_same_module_same_leaf/case.ww. This wrapper - * retains only the two package-layout rows that require separately named - * imported source files and therefore are not expressible by case.ww. - */ -#include -#include -#include -#include -#include -#include -#include - -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; - int want_exit; - int n_files; - const char *files[8]; /* {path, src, path, src, ...} */ - const char *entry; /* file to `ww build` (relative) */ -}; - -static const struct row rows[] = { - /* Primary wedge. alpha.foo is variadic (i32...), beta.foo is - * non-variadic with a tagged-union param. Caller in `main` - * imports both and calls beta.foo with a tagged (u8|[]u8). The - * combined-source layout puts `beta` after `alpha` so beta.foo - * sits at the head of c.fnrets among non-main fns; with - * c.curmod="main" the bare-leaf walk falls through same-module - * to head-walk and picks beta.foo here — but reverse the import - * order or any other ordering perturbation flips it to alpha.foo. - * Either fnparamslookup result is wrong half the time; the - * N_DOT arm must route through fnparamslookupmod to be stable. - * Pre-#16 the head-pick happens to be the variadic side and - * arg-prep builds an `i32...` gather slice while CALL targets - * beta.foo's scalar ABI. */ - { "cross_module_same_leaf_variadic_vs_scalar", 0, 3, - { "alpha/alpha.ww", - "package alpha;\n" - "export fn foo(a: i32, xs: i32...) i32 = {\n" - "\treturn a + xs.len;\n" - "};\n", - "beta/beta.ww", - "package beta;\n" - "export fn foo(a: i32, n: (u8 | []u8)) i32 = {\n" - "\tmatch (n) {\n" - "\tcase let c: u8 => return a + (c: i32);\n" - "\tcase let s: []u8 => return a + s.len;\n" - "\t};\n" - "\treturn 0;\n" - "};\n", - "main.ww", - "package main;\n" - "import alpha;\n" - "import beta;\n" - "export fn main() i32 = {\n" - "\tlet n: (u8 | []u8) = 7u8;\n" - "\tlet r: i32 = beta.foo(10, n);\n" - "\tif (r != 17) { return 11; };\n" - "\treturn 0;\n" - "};\n" }, - "main.ww" }, - - /* Control. A variadic fn exists in only one imported module; - * the caller calls it via N_DOT. No same-leaf collision, so - * fnparamslookupmod's same-module hint and the head-walk - * fallback agree. Pre+post fix both stages rc=0. */ - { "bare_leaf_no_collision", 0, 2, - { "alpha/alpha.ww", - "package alpha;\n" - "export fn sum(a: i32, xs: i32...) i32 = {\n" - "\tlet t: i32 = a;\n" - "\tlet i: i32 = 0;\n" - "\tfor (i < xs.len) { t += xs[i]; i += 1; };\n" - "\treturn t;\n" - "};\n", - "main.ww", - "package main;\n" - "import alpha;\n" - "export fn main() i32 = {\n" - "\tlet r: i32 = alpha.sum(1, 2, 3, 4);\n" - "\tif (r != 10) { return 40; };\n" - "\treturn 0;\n" - "};\n" }, - "main.ww" }, -}; - -static int -write_one(const char *dir, const char *rel, const char *src, - int *parent_owned) -{ - char path[512]; - snprintf(path, sizeof path, "%s/%s", dir, rel); - char *slash = strchr(path + strlen(dir) + 1, '/'); - if (slash) { - *slash = '\0'; - if (mkdir(path, 0755) != 0) return -1; - *parent_owned = 1; - *slash = '/'; - } - FILE *f = fopen(path, "wb"); - if (!f) return -1; - int rc = fputs(src, f) == EOF ? -1 : 0; - if (fclose(f) != 0) rc = -1; - return rc; -} - -static int -cleanup_row(const char *tmpdir, const struct row *r, - const int *parent_owned) -{ - char path[512], cmd[640], entry[512]; - int rc = 0; - - for (int k = 0; k < r->n_files; k++) { - snprintf(path, sizeof path, "%s/%s", tmpdir, r->files[2 * k]); - char *slash = strchr(path + strlen(tmpdir) + 1, '/'); - if (slash && !parent_owned[k]) continue; - if (unlink(path) != 0 && errno != ENOENT) rc = -1; - } - - snprintf(entry, sizeof entry, "%s/%s", tmpdir, r->entry); - char *dot = strrchr(entry, '.'); - if (dot && strcmp(dot, ".ww") == 0) *dot = '\0'; - if (unlink(entry) != 0 && errno != ENOENT) rc = -1; - snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork", entry); - if (runwait(cmd) != 0) rc = -1; - - for (int k = 0; k < r->n_files; k++) { - snprintf(path, sizeof path, "%s/%s", tmpdir, r->files[2 * k]); - char *slash = strchr(path + strlen(tmpdir) + 1, '/'); - if (slash && parent_owned[k]) { - *slash = '\0'; - if (rmdir(path) != 0 && errno != ENOENT) rc = -1; - } - } - if (rmdir(tmpdir) != 0) rc = -1; - return rc; -} - -static int -run_row(const char *driver, const struct row *r, int idx, const char *tag) -{ - (void)idx; - char tmpdir[] = "/tmp/modparam_XXXXXX"; - if (mkdtemp(tmpdir) == NULL) { - fprintf(stderr, "modparam_callee[%s][%s]: mkdtemp failed\n", - tag, r->label); - return 1; - } - int fail = 0; - int parent_owned[4] = { 0 }; - - for (int k = 0; k < r->n_files; k++) { - if (write_one(tmpdir, r->files[2 * k], - r->files[2 * k + 1], &parent_owned[k]) != 0) { - fprintf(stderr, - "modparam_callee[%s][%s]: write %s failed\n", - tag, r->label, r->files[2 * k]); - fail++; - goto cleanup; - } - } - - char cmd[2048]; - snprintf(cmd, sizeof cmd, - "cd %s && %s build %s >/dev/null 2>&1", tmpdir, driver, r->entry); - if (runwait(cmd) != 0) { - fprintf(stderr, - "modparam_callee[%s][%s]: build failed\n", - tag, r->label); - fail++; - goto cleanup; - } - - char entry_bin[512]; - snprintf(entry_bin, sizeof entry_bin, "%s/%s", tmpdir, r->entry); - char *dot = strrchr(entry_bin, '.'); - if (dot && strcmp(dot, ".ww") == 0) *dot = '\0'; - int got = runwait(entry_bin); - if (got != r->want_exit) { - fprintf(stderr, - "modparam_callee[%s][%s]: rc=%d want=%d\n", - tag, r->label, got, r->want_exit); - fail++; - } - -cleanup: - if (cleanup_row(tmpdir, r, parent_owned) != 0) { - fprintf(stderr, "modparam_callee[%s][%s]: cleanup failed\n", - tag, r->label); - if (fail == 0) fail++; - } - return fail; -} - -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], wdrv[640]; - 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++; - fail += run_row(cdrv, &rows[i], i, "cs"); - if (have_ww) { - total++; - fail += run_row(wdrv, &rows[i], i, "ws"); - } - } - - if (fail) { - fprintf(stderr, - "modparam_callee: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("modparam_callee: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/784_xmod_alias_struct_collide_run.c b/test/wcc/784_xmod_alias_struct_collide_run.c deleted file mode 100644 index b80aca13..00000000 --- a/test/wcc/784_xmod_alias_struct_collide_run.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 784_xmod_alias_struct_collide_run — project #223 runtime + byte-id - * net. A struct-field access through a pointer-ALIAS receiver - * (`s.` where `s` is a `type s = *vtable` alias) miscompiled in - * wwstage when the alias leaf collided with a DIFFERENT module's - * same-leaf STRUCT (the eFinal io.stream = *vtable alias vs the - * memio.stream struct). cgen's #191 alias-peel loop - * (selfhost/cmd/wcc/cgenexpr.ww cgdot) broke on the name-keyed - * structlookup's any-module fallback — it found the FOREIGN struct, - * halted the peel with the receiver still N_TNAME, skipped the - * pointer-to-struct field-load arm, and the field load fell through to - * the SB-global fallback: `MOVQ (SB), AX` (an undefined symbol → - * w6l link-fail / garbage). cstage is correct — type_chase_named - * (cmd/w6c/cgen.c) follows the resolved NAMED.under POINTER chain - * (module-correct), never a name re-lookup. Sibling of #208 (lossy - * name-keyed resolution leaking to a global leaf, but in the CHECKER). - * - * Fix (wwstage-only align-down, cgenexpr.ww:1769 peel loop): the - * struct-break is now MODULE-AWARE — break ONLY on a struct that THIS - * module defines (structsamemod), a same-module ALIAS keeps peeling - * (aliassamemod), and a foreign leaf falls back to the prior - * any-module heuristic. - * - * GATE-BLIND in the bootstrap: the io.stream-alias vs memio.stream- - * struct collision is the only same-leaf alias-vs-struct cross-module - * pair, and it only entered the corpus at the #94 eFinal FLIP (master - * never had it). A single-module synthetic does NOT trigger — the - * collision needs a SECOND module contributing the same-leaf struct - * into the corpus. Hence this 2-module probe. - * - * row | shape | exit | byte-id - * -----------+----------------------------------------+------+-------- - * collision | sa: type s=*vtable + vtable{reader} + | 42 | cs==ww - * | dispatcher `read(x:s) match(x.reader)`| | - * | sb: type s=struct{} (same leaf, NO | | - * | reader field) — the #223 trigger | | - * symmetric | sa: type s=struct{} + value-receiver | 21 | cs==ww - * | `geta(x:s)`; sb: type s=*vtable alias | | - * | — guards the same-module-struct break | | - * | still fires (a naive alias-first | | - * | reorder would mis-peel A's struct) | | - * control | sa: alias+vtable+dispatcher, NO foreign | 30 | cs==ww - * | same-leaf struct — common io-like case| | - * - * The dispatcher uses a BRANCHED callee (void arm → -1, fn-ptr arm → - * v+100) so the field load actually feeds control flow (gate-blind - * discipline). cstage `ww build` + run pins runtime; raw w6c vs w6c_ww - * `.s` cmp on the self-built two-module unit pins rule-10 byte-id - * (the discriminating net for #223 — pre-fix the dispatcher diverges - * `MOVQ reader(SB)` vs the pointer-field load). - * - * Filed-not-fixed here: #224 (the broader cross-module same-leaf STRUCT - * name-keying at structlookupchain) — distinct, not FLIP-triggered. - */ -#include -#include -#include -#include -#include -#include - -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); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - if (ferror(fa) || ferror(fb)) rc = -1; - if (fclose(fa) != 0) rc = -1; - if (fclose(fb) != 0) rc = -1; - return rc; -} - -struct file { const char *name; const char *src; }; - -struct scenario { - const char *label; - const struct file *files; /* name==NULL terminates */ - int want_exit; -}; - -/* ---- collision: the #223 bug ------------------------------------- */ -static const struct file collision_files[] = { - { "sa.ww", - "package sa;\n" - "\n" - "export type reader = fn(x: s, v: i32) i32;\n" - "\n" - "export type vtable = struct {\n" - " reader: (*reader | void),\n" - "};\n" - "\n" - "export type s = *vtable;\n" - "\n" - "export fn read(x: s, v: i32) i32 = {\n" - " match (x.reader) {\n" - " case void => return -1;\n" - " case let f: *reader => return (*f)(x, v);\n" - " };\n" - "};\n" - "\n" - "export fn mkvt(f: *reader) vtable = {\n" - " return vtable { reader = f };\n" - "};\n" - "\n" - "export fn mkempty() vtable = {\n" - " return vtable { reader = void };\n" - "};\n" }, - /* sb's `s` is a STRUCT sharing the leaf `s` with sa's alias — the - * name-keyed structlookup any-module fallback used to halt sa.read's - * alias-peel here. No `reader` field, so the mis-resolved field walk - * fell through to `MOVQ reader(SB)`. */ - { "sb.ww", - "package sb;\n" - "\n" - "export type s = struct {\n" - " a: i32,\n" - " b: i32,\n" - "};\n" }, - { "main.ww", - "package main;\n" - "\n" - "import sa;\n" - "import sb;\n" - "\n" - "fn cb(x: sa.s, v: i32) i32 = { return v + 100; };\n" - "\n" - "export fn main() i32 = {\n" - " let vt = sa.mkvt((&cb): *sa.reader);\n" - " let st: sa.s = &vt;\n" - " let r = sa.read(st, 5);\n" - " let vt2 = sa.mkempty();\n" - " let st2: sa.s = &vt2;\n" - " let r2 = sa.read(st2, 5);\n" - " if (r != 105) { return 11; };\n" - " if (r2 != -1) { return 12; };\n" - " return 42;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- symmetric: A struct, B alias; receiver is A's struct value -- */ -static const struct file symmetric_files[] = { - { "sa.ww", - "package sa;\n" - "\n" - "export type s = struct {\n" - " a: i32,\n" - " b: i32,\n" - "};\n" - "\n" - "export fn mk(av: i32, bv: i32) s = {\n" - " return s { a = av, b = bv };\n" - "};\n" - "\n" - "export fn geta(x: s) i32 = {\n" - " return x.a;\n" - "};\n" }, - { "sb.ww", - "package sb;\n" - "\n" - "export type vtable = struct {\n" - " q: i32,\n" - "};\n" - "\n" - "export type s = *vtable;\n" }, - { "main.ww", - "package main;\n" - "\n" - "import sa;\n" - "import sb;\n" - "\n" - "export fn main() i32 = {\n" - " let o = sa.mk(21, 8);\n" - " let r = sa.geta(o);\n" - " if (r != 21) { return 11; };\n" - " return 21;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- control: same-module alias+vtable, no foreign same-leaf ----- */ -static const struct file control_files[] = { - { "sa.ww", - "package sa;\n" - "\n" - "export type reader = fn(x: s, v: i32) i32;\n" - "\n" - "export type vtable = struct {\n" - " reader: (*reader | void),\n" - "};\n" - "\n" - "export type s = *vtable;\n" - "\n" - "export fn read(x: s, v: i32) i32 = {\n" - " match (x.reader) {\n" - " case void => return -1;\n" - " case let f: *reader => return (*f)(x, v);\n" - " };\n" - "};\n" - "\n" - "export fn mkvt(f: *reader) vtable = {\n" - " return vtable { reader = f };\n" - "};\n" }, - { "main.ww", - "package main;\n" - "\n" - "import sa;\n" - "\n" - "fn cb(x: sa.s, v: i32) i32 = { return v + 100; };\n" - "\n" - "export fn main() i32 = {\n" - " let vt = sa.mkvt((&cb): *sa.reader);\n" - " let st: sa.s = &vt;\n" - " let r = sa.read(st, 5);\n" - " if (r != 105) { return 11; };\n" - " return 30;\n" - "};\n" }, - { NULL, NULL } -}; - -static const struct scenario scenarios[] = { - { "collision", collision_files, 42 }, - { "symmetric", symmetric_files, 21 }, - { "control", control_files, 30 }, -}; - -static int -run_scenario(const char *bin, const char *cdrv, const char *wdrv, - const struct scenario *sc) -{ - (void)bin; - /* Private fixture dir — #215: srcd is this dir (not shared /tmp), - * so the driver's srcd-first import search can't pick up a - * polluting same-name file. mkdtemp gives a unique path. */ - char dir[] = "/tmp/ww784_XXXXXX"; - if (mkdtemp(dir) == NULL) { - fprintf(stderr, "784[%s]: mkdtemp failed\n", sc->label); - return -1; - } - - char path[1024], cmd[4096]; - int rc = 0; - - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - FILE *f = fopen(path, "wb"); - if (!f) { fprintf(stderr, "784[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - int bad = fputs(sc->files[i].src, f) == EOF; - if (fclose(f) != 0) bad = 1; - if (bad) { fprintf(stderr, "784[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - } - - /* #94 sep layout: cstage build + run pins runtime; pin - * all outputs stay under the scratch dir. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/main %s/main.ww", - dir, cdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "784[%s]: cstage build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(path, sizeof path, "%s/main", dir); - int got = runwait(path); - if (got != sc->want_exit) { - fprintf(stderr, "784[%s]: cstage exit %d, want %d\n", - sc->label, got, sc->want_exit); - rc = -1; - } - - /* Byte-id net (the #223 discriminator): the wwstage driver's - * build emits per-package w6c_ww asm; pre-fix the dispatcher diverges. - * The root + each imported pkg compile to separate .sepwork/.s; - * concat (sorted glob, identical set both stages) for the compare. */ - char cs_s[1024], ws_s[1024]; - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/mainww %s/main.ww", - dir, wdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "784[%s]: ww_ww build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(cs_s, sizeof cs_s, "%s/all_cs.s", dir); - snprintf(ws_s, sizeof ws_s, "%s/all_ww.s", dir); - snprintf(cmd, sizeof cmd, - "cat %s/main.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, cs_s, cs_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "784[%s]: cstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - snprintf(cmd, sizeof cmd, - "cat %s/mainww.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, ws_s, ws_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "784[%s]: wwstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, "784[%s]: cs.s/ww.s DIFFER (rule-10 byte-id " - "violation — #223 regression)\n", sc->label); - rc = -1; - } - -done: - snprintf(cmd, sizeof cmd, "rm -rf %s/main.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "784[%s]: cleanup main.sepwork\n", - sc->label); rc = -1; } - snprintf(cmd, sizeof cmd, "rm -rf %s/mainww.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "784[%s]: cleanup mainww.sepwork\n", - sc->label); rc = -1; } - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "784[%s]: cleanup %s\n", sc->label, - sc->files[i].name); - rc = -1; - } - } - const char *children[] = { "main", "mainww", "all_cs.s", "all_ww.s", NULL }; - for (int i = 0; children[i]; i++) { - snprintf(path, sizeof path, "%s/%s", dir, children[i]); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "784[%s]: cleanup %s\n", sc->label, - children[i]); - rc = -1; - } - } - if (rmdir(dir) != 0) { - fprintf(stderr, "784[%s]: cleanup directory\n", sc->label); - rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2048]; - 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[2100], wdrv[2100]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - if (access(wdrv, X_OK) != 0) { - fprintf(stderr, "784: ww_ww missing — cannot run the cs==ww " - "byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = (int)(sizeof scenarios / sizeof scenarios[0]); - int fail = 0; - for (int i = 0; i < n; i++) { - if (run_scenario(bin, cdrv, wdrv, &scenarios[i]) != 0) - fail++; - } - - if (fail) { - fprintf(stderr, "784 xmod_alias_struct_collide: %d/%d " - "scenarios failed\n", fail, n); - return 1; - } - printf("xmod_alias_struct_collide: %d/%d ok (cstage run + cs==ww " - "byte-id)\n", n, n); - return 0; -} diff --git a/test/wcc/793_xmod_struct_argpush_collide_run.c b/test/wcc/793_xmod_struct_argpush_collide_run.c deleted file mode 100644 index 0cbde27b..00000000 --- a/test/wcc/793_xmod_struct_argpush_collide_run.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * 793_xmod_struct_argpush_collide_run — project #21/#224 runtime + byte-id - * net. An inferred-let struct LOCAL whose type leaf collides with a - * DIFFERENT module's same-leaf struct miscompiled in wwstage at THREE - * caller-side register-ABI sites, all keyed off the name-resolved - * (collision-prone) struct instead of the checker-STAMPED tinfo: - * - * - push (cgenutil.ww pushargsrev): the by-value struct call-arg - * COUNT came from name-keyed structparamsize(lc.tnode). On the - * collision lc.tnode is a bare leaf structlookup mis-resolves to the - * foreign same-leaf struct (>16B → 0), so the fast path was skipped - * and the arg dropped to a scalar single-PUSHQ — the 2nd eightbyte - * (the sub-8 tail) was lost. [the original #21 site] - * - recv (cgenstmt.ww cgletbody): `let s = m1.mk()` sized the - * register receive via structlookup(tn.str) → the foreign struct's - * word count, OVER-copying a 24B foreign over a 16B local (spilling - * CX into a neighbour slot). - * - field (cgenexpr.ww cgdot direct-struct arm): `s.` resolved - * the offset via structlookupchain(tn) → the foreign struct's layout, - * reading the field at the WRONG offset + wrong load-op. [#224, filed - * not-fixed by 784/#223] - * - * cstage is correct at all three — it keys on args[i]->type / lu->size / - * t->fields (the checker-STAMPED type), never a name re-lookup. Fix - * (wwstage-only align-UP, #21/#224, ONE commit): route all three off the - * stamped tinfo — structabisizetn(arg/tn.type_) for the push+recv COUNT, - * tichase(dotlhs.type_).fields (tfield) for the field offset+type. - * - * GATE-BLIND in the bootstrap (same class as 784/#223): the trigger needs - * a SECOND module contributing a same-leaf struct of a DIFFERENT size, so - * the name-keyed lookup mis-resolves. A single-module synthetic resolves - * correctly (structlookup's same-module pass) and stays byte-id — it does - * NOT redden. Hence this 2-module probe. - * - * row | m1.pair (local) | m2.pair (foreign) | site(s) | exit - * -----------------+----------------------+-------------------+---------------+----- - * recvpush_t16 | {u64,u16} 16B | 24B | recv + push | 107 - * fieldread_t16 | {u64,u16} 16B | 24B | recv + field | 107 - * combined_t16 | {u64,u16} 16B | 24B | recv+field+push| 114 - * recvpush_t12 | {u32,u32,u32} 12B | 24B | recv + push | 6 - * - * cstage `ww build` + run pins runtime; the wwstage binary is run - * too (the bug WAS a wrong wwstage runtime value); raw cs.s vs ww.s cmp - * over the driver-produced per-package asm pins rule-10 byte-id (the - * discriminating net — pre-fix __root.s diverges at the push/recv/field). - */ -#include -#include -#include -#include -#include -#include - -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); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - if (ferror(fa) || ferror(fb)) rc = -1; - if (fclose(fa) != 0) rc = -1; - if (fclose(fb) != 0) rc = -1; - return rc; -} - -struct file { const char *name; const char *src; }; - -struct scenario { - const char *label; - const struct file *files; /* name==NULL terminates */ - int want_exit; -}; - -/* m2.pair is a 24B struct sharing the leaf `pair` with m1.pair — the - * name-keyed lookup's any-module fallback mis-resolves m1.pair to it. */ -static const char m2_24[] = - "package m2;\n" - "export type pair = struct { hi: u64, mid: u64, lo: u64 };\n" - "export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; };\n"; - -/* ---- recvpush_t16: inferred-let recv + by-value push (the #21 site) -- */ -static const struct file recvpush_t16_files[] = { - { "m1.ww", - "package m1;\n" - "export type pair = struct { hi: u64, lo: u16 };\n" - "export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; };\n" - "export fn consume(p: pair) i32 = { return (p.hi + (p.lo: u64)): i32; };\n" }, - { "m2.ww", m2_24 }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let s = m1.mk();\n" - " return m1.consume(s);\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- fieldread_t16: inferred-let recv + direct field read (#224) ----- */ -static const struct file fieldread_t16_files[] = { - { "m1.ww", - "package m1;\n" - "export type pair = struct { hi: u64, lo: u16 };\n" - "export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; };\n" }, - { "m2.ww", m2_24 }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let s = m1.mk();\n" - " return (s.hi + (s.lo: u64)): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- combined_t16: recv + field + push in one fn -------------------- */ -static const struct file combined_t16_files[] = { - { "m1.ww", - "package m1;\n" - "export type pair = struct { hi: u64, lo: u16 };\n" - "export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; };\n" - "export fn consume(p: pair) i32 = { return (p.hi + (p.lo: u64)): i32; };\n" }, - { "m2.ww", m2_24 }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let s = m1.mk();\n" - " let x: i32 = (s.lo: i32);\n" - " return m1.consume(s) + x;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- recvpush_t12: a maxalign-4 12B sub-8-tail tail shape ----------- */ -static const struct file recvpush_t12_files[] = { - { "m1.ww", - "package m1;\n" - "export type pair = struct { a: u32, b: u32, c: u32 };\n" - "export fn mk() pair = { return pair { a = 1: u32, b = 2: u32, c = 3: u32 }; };\n" - "export fn consume(p: pair) i32 = { return (p.a + p.b + p.c): i32; };\n" }, - { "m2.ww", m2_24 }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let s = m1.mk();\n" - " return m1.consume(s);\n" - "};\n" }, - { NULL, NULL } -}; - -static const struct scenario scenarios[] = { - { "recvpush_t16", recvpush_t16_files, 107 }, - { "fieldread_t16", fieldread_t16_files, 107 }, - { "combined_t16", combined_t16_files, 114 }, - { "recvpush_t12", recvpush_t12_files, 6 }, -}; - -static int -run_scenario(const char *cdrv, const char *wdrv, const struct scenario *sc) -{ - /* Private fixture dir — the driver's srcd-first import search can't - * pick up a polluting same-name file (mirrors 784/#215). */ - char dir[] = "/tmp/ww793_XXXXXX"; - if (mkdtemp(dir) == NULL) { - fprintf(stderr, "793[%s]: mkdtemp failed\n", sc->label); - return -1; - } - - char path[1024], cmd[4096]; - int rc = 0; - - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - FILE *f = fopen(path, "wb"); - if (!f) { fprintf(stderr, "793[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - int bad = fputs(sc->files[i].src, f) == EOF; - if (fclose(f) != 0) bad = 1; - if (bad) { fprintf(stderr, "793[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - } - - /* cstage build + run pins runtime; all outputs remain under the - * scratch dir. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/main %s/main.ww", - dir, cdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "793[%s]: cstage build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(path, sizeof path, "%s/main", dir); - int gotc = runwait(path); - if (gotc != sc->want_exit) { - fprintf(stderr, "793[%s]: cstage exit %d, want %d\n", - sc->label, gotc, sc->want_exit); - rc = -1; - } - - /* wwstage build + run: the bug WAS a wrong wwstage runtime - * value (a dropped/over-copied field), so run the wwstage binary too. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/mainww %s/main.ww", - dir, wdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "793[%s]: ww_ww build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(path, sizeof path, "%s/mainww", dir); - int gotw = runwait(path); - if (gotw != sc->want_exit) { - fprintf(stderr, "793[%s]: wwstage exit %d, want %d\n", - sc->label, gotw, sc->want_exit); - rc = -1; - } - - /* Byte-id net (the discriminator): per-package asm under - * .sepwork/.s; concat (sorted glob, identical set both - * stages) for the compare. Pre-fix __root.s diverges. */ - char cs_s[1024], ws_s[1024]; - snprintf(cs_s, sizeof cs_s, "%s/all_cs.s", dir); - snprintf(ws_s, sizeof ws_s, "%s/all_ww.s", dir); - snprintf(cmd, sizeof cmd, - "cat %s/main.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, cs_s, cs_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "793[%s]: cstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - snprintf(cmd, sizeof cmd, - "cat %s/mainww.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, ws_s, ws_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "793[%s]: wwstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, "793[%s]: cs.s/ww.s DIFFER (rule-10 byte-id " - "violation — #21/#224 regression)\n", sc->label); - rc = -1; - } - -done: - snprintf(cmd, sizeof cmd, "rm -rf %s/main.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "793[%s]: cleanup main.sepwork\n", - sc->label); rc = -1; } - snprintf(cmd, sizeof cmd, "rm -rf %s/mainww.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "793[%s]: cleanup mainww.sepwork\n", - sc->label); rc = -1; } - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "793[%s]: cleanup %s\n", sc->label, - sc->files[i].name); - rc = -1; - } - } - const char *children[] = { "main", "mainww", "all_cs.s", "all_ww.s", NULL }; - for (int i = 0; children[i]; i++) { - snprintf(path, sizeof path, "%s/%s", dir, children[i]); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "793[%s]: cleanup %s\n", sc->label, - children[i]); - rc = -1; - } - } - if (rmdir(dir) != 0) { - fprintf(stderr, "793[%s]: cleanup directory\n", sc->label); - rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2048]; - 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[2100], wdrv[2100]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - if (access(wdrv, X_OK) != 0) { - fprintf(stderr, "793: ww_ww missing — cannot run the cs==ww " - "byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = (int)(sizeof scenarios / sizeof scenarios[0]); - int fail = 0; - for (int i = 0; i < n; i++) { - if (run_scenario(cdrv, wdrv, &scenarios[i]) != 0) - fail++; - } - - if (fail) { - fprintf(stderr, "793 xmod_struct_argpush_collide: %d/%d " - "scenarios failed\n", fail, n); - return 1; - } - printf("xmod_struct_argpush_collide: %d/%d ok (cstage+wwstage run + " - "cs==ww byte-id)\n", n, n); - return 0; -} diff --git a/test/wcc/797_xmod_struct_field_layout_collide_run.c b/test/wcc/797_xmod_struct_field_layout_collide_run.c deleted file mode 100644 index 40724042..00000000 --- a/test/wcc/797_xmod_struct_field_layout_collide_run.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * 797_xmod_struct_field_layout_collide_run — project #31 (RULING R2, - * commit-1: the OFFSET/SIZE align-up arms) runtime + byte-id net. The - * direct continuation of 793 (#21): #21 type-keyed the THREE caller-side - * sites the 793 collision drove (push/recv/field-read); #31 closes the - * field-LAYOUT *receiver* arms #21 left name-keyed. Commit-1 covers the - * offset/size half: - * - * - R1 (cgenexpr cgdot, local *struct READ): `p.f` where p is an - * inferred-let *struct resolved the field OFFSET via - * structlookupchain(inner) → the FOREIGN same-leaf struct's layout - * (wrong offset + wrong load-op). Now tichase(dotlhs.type_)->.sub - * ->fields (the #21 R0 tfield template), via the shared read - * choke-point cgptrfieldloadtf. - * - C1 (cgenstmt cgletbody, let-COPY size): `let p2 = p1` sized the - * struct memcpy run via structlookup(tn.str) → the foreign 24B - * struct, OVER-reading a 16B source + OVER-writing p2's slot (a - * SILENT OOB whose *value* coincidentally round-trips — the asm - * diverges, cs!=ww). Now structabisizetn(rhs.type_) (the COPY - * source's stamped tinfo). - * - A1/A2 (cgenexpr cgun, addr-of `&p.f` / `&o.f`): the LEAQ field - * offset came from structlookupchain → wrong offset. Now - * tichase(opnd.lhs.type_) (->.sub for the *struct A1 arm). - * - * cstage is correct at all of them — it keys on type_chase_named(base-> - * type)->fields / lu->size (the checker-STAMPED type), never a name - * re-lookup. #31 aligns wwstage UP (ww-only change; cstage cgen.c is the - * untouched oracle). - * - * GATE-BLIND in the bootstrap (same class as 793/784): the trigger needs - * a SECOND module contributing a same-leaf struct of a DIFFERENT size so - * the name-keyed lookup mis-resolves. The reddening surface is INFERRED - * LOCALS (a global struct decl is always explicitly qualified, so its - * qualifier resolves correctly — non-reddenable; the global value/ptr - * arms R2/R3/A3/W3/W4a are converted-for-construction and ride the - * corpus byte-id, not pinned here). - * - * row | m1 (local) | m2 (foreign) | arm | exit - * ----------------+-------------------+--------------+-----+----- - * ptrread_t16 | pair{u64,u16} 16B | pair 24B | R1 | 107 - * letcopy_t16 | pair{u64,u16} 16B | pair 24B | C1 | 107 (value coincides; byte-id is the net) - * addrptr_pq | pq{u64,u64} 16B | pq 24B | A1 | 10 - * addrval_pq | pq{u64,u64} 16B | pq 24B | A2 | 10 - * ptrwrite_t16 | pair{u64,u16} 16B | pair 24B | W1 | 109 (commit-2 STORE) - * valwrite_t16 | pair{u64,u16} 16B | pair 24B | W2 | 109 (commit-2 STORE) - * nestfill_box | box{tag,ir:nst} 32B | box 24B | W2 | 66 (commit-2 cgstructlitfilltn nested recursion) - * - * Commit-2 (RULING R2 / Opt-2) converts the W1/W2/W5/W4b store-loop arms - * off the name-keyed receiver walk to a tinfo-native fill (cgstructlitfilltn - * + sretretsizetn), closing the in-loop #32 nested struct-receive/structlit/ - * ident sub-arms by construction. The two scalar WRITE rows STORE through the - * mis-resolved offset: at commit-1 (R1 read already fixed) wwstage stored at - * the FOREIGN offset 16 while reading off 8 -> 100+7=107 WRONG vs cstage 109. - * They reach only the scalar storeopsz arm, NOT cgstructlitfilltn; the - * nestfill_box row is the cgstructlitfilltn fill + nested-recursion value pin - * (a struct-literal stored into a struct-typed field, whose own field is a - * nested struct literal) — the riskiest new helper, which no bootstrap - * construct exercises. - * - * Each row reddens under an INDEPENDENT revert of its arm (verified - * impl-side: R1 ww=101, C1 cs!=ww OOB, A1/A2 ww=8, W1/W2 ww=107 cs!=ww). - * cstage `ww build` + run pins runtime; the wwstage binary is run too - * (the bug WAS a wrong wwstage runtime value / OOB); raw cs.s vs ww.s over - * the driver-produced per-package asm pins rule-10 byte-id. - * - * NOTE the addr rows use an all-u64 `pq` (offset-only collision): the - * canonical {u64,u16} field would, after `&p.lo`, force a `*q = v:u16` - * narrow deref-STORE which wwstage currently emits as MOVQ where cstage - * emits MOVW — a SEPARATE pre-existing wwstage narrow-deref-store-width - * divergence (NOT #31; surfaced + filed by impl-31). An all-u64 store is - * MOVQ in both stages, so the row isolates the #31 offset fix. - */ -#include -#include -#include -#include -#include -#include - -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); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - if (ferror(fa) || ferror(fb)) rc = -1; - if (fclose(fa) != 0) rc = -1; - if (fclose(fb) != 0) rc = -1; - return rc; -} - -struct file { const char *name; const char *src; }; - -struct scenario { - const char *label; - const struct file *files; /* name==NULL terminates */ - int want_exit; -}; - -/* m2 contributes 24B same-leaf `pair` and `pq` — the name-keyed lookup's - * any-module fallback mis-resolves m1's 16B versions to these. */ -static const char m2_src[] = - "package m2;\n" - "export type pair = struct { hi: u64, mid: u64, lo: u64 };\n" - "export type pq = struct { a: u64, b: u64, v: u64 };\n" - "export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; };\n"; - -/* m1: 16B `pair` (sub-8 tail) + 16B all-u64 `pq` (offset-only). */ -static const char m1_src[] = - "package m1;\n" - "export type pair = struct { hi: u64, lo: u16 };\n" - "export type pq = struct { a: u64, v: u64 };\n" - "let g: pair = pair { hi = 100: u64, lo = 7: u16 };\n" - "let gq: pq = pq { a = 1: u64, v = 7: u64 };\n" - "export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; };\n" - "export fn mkp() *pair = { return &g; };\n" - "export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; };\n" - "export fn mkpq() *pq = { return &gq; };\n"; - -/* ---- ptrread_t16 (R1): inferred-let *struct field read ------------- */ -static const struct file ptrread_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let p = m1.mkp();\n" - " return (p.hi + (p.lo: u64)): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- letcopy_t16 (C1): inferred-let local-to-local struct copy ----- */ -static const struct file letcopy_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let p1 = m1.mk();\n" - " let p2 = p1;\n" - " return (p2.hi + (p2.lo: u64)): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- addrptr_pq (A1): &p.f over an inferred-let *struct ------------ */ -static const struct file addrptr_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pq;\n" - " dummy.a = 0: u64;\n" - " let p = m1.mkpq();\n" - " let q = &p.v;\n" - " *q = 9: u64;\n" - " return (p.a + p.v): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- addrval_pq (A2): &o.f over an inferred-let value struct ------- */ -static const struct file addrval_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pq;\n" - " dummy.a = 0: u64;\n" - " let s = m1.mkq();\n" - " let q = &s.v;\n" - " *q = 9: u64;\n" - " return (s.a + s.v): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- ptrwrite_t16 (W1, commit-2): inferred-let *struct field STORE. - * `p.lo = 9: u16` resolved the field OFFSET via the name-keyed lookup -> - * the FOREIGN 24B pair (lo @ off 16, u64) -> the store landed at off 16 - * (a u64 MOVQ into g's DATA neighbour) while the read (R1, fixed in - * commit-1) reads off 8 -> p.lo stays 7 -> 100+7=107 WRONG (cstage 109, - * cs!=ww). The {u64,u16} field stores MOVW in both stages (a direct - * field store, NOT the addr-of `*q=v:u16` narrow-deref-store divergence - * the A1/A2 pq rows dodge), so it isolates the #31 W1 offset/width fix. */ -static const struct file ptrwrite_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let p = m1.mkp();\n" - " p.lo = 9: u16;\n" - " return (p.hi + (p.lo: u64)): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- valwrite_t16 (W2, commit-2): inferred-let value-struct field STORE. - * `s.lo = 9: u16` resolved the OFFSET via the FOREIGN 24B pair -> stored - * 8 bytes at off 16 (past s's 16B slot) while s.lo (off 8) stays 7 -> - * 100+7=107 WRONG (cstage 109). The write-twin #21 missed. */ -static const struct file valwrite_files[] = { - { "m1.ww", m1_src }, - { "m2.ww", m2_src }, - { "main.ww", - "package main;\n" - "import m1;\n" - "import m2;\n" - "fn main() i32 = {\n" - " let dummy: m2.pair;\n" - " dummy.hi = 0: u64;\n" - " let s = m1.mk();\n" - " s.lo = 9: u16;\n" - " return (s.hi + (s.lo: u64)): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -/* ---- nestfill_box (W2 -> cgstructlitfilltn, commit-2): the nested- - * recursion VALUE pin for the new fill helper. `s.ir = nst{...}` stores a - * struct-LITERAL into a struct-typed field of a value-struct local, - * driving cgstructlitfilltn (the W2 N_STRUCTLIT sub-arm, mode 0); the - * literal's `dp = deep{...}` field is itself a struct literal, so - * cgstructlitfilltn RECURSES — cgstructlitfilltn(tichase(tf.type_)) at - * the inner offset (box.ir.dp @ +16). This is the riskiest new code and - * is exercised by NO bootstrap construct (the corpus has zero `x.f = - * Y{...}` struct-lit field stores) and by NO other 797 row (they all - * store scalars/idents/calls, hitting only the storeopsz scalar arm). - * Want = i0 + dp.d0 + dp.d1 = 11 + 22 + 33 = 66; a broken recursion - * drops dp -> 11, a mis-offset -> a wrong sum. - * - * COLLISION-FREE by necessity (NOT an oversight): a cross-module - * same-leaf box collision CANNOT drive this pin because TWO pre-existing - * wwstage CHECKER gaps (orthogonal to #31, which is cgen-only) block the - * wwstage readback under collision — (a) the checker mis-resolves a - * nested value-struct field read to the FOREIGN field type (`u64 -> nst - * not assignable`); (b) a chained `s.ir.dp.d0` read trips `asserttyped: - * dot`. So the value is read back via single-dot-through-param helpers - * (sumnst/sumdeep), the only nested-read shape wwstage accepts. The pin - * still catches every cgstructlitfilltn fill/recursion miscompile (cs == - * ww runtime + cs.s == ww.s byte-id); the collision surface for the - * SCALAR store stays covered by ptrwrite/valwrite above. */ -static const struct file nestfill_files[] = { - { "main.ww", - "package main;\n" - "type deep = struct { d0: u64, d1: u64 };\n" - "type nst = struct { i0: u64, dp: deep };\n" - "type box = struct { tag: u64, ir: nst };\n" - "fn mkbox() box = { return box { tag = 0: u64, ir = nst { i0 = 0: u64, dp = deep { d0 = 0: u64, d1 = 0: u64 } } }; };\n" - "fn sumdeep(d: deep) u64 = { return d.d0 + d.d1; };\n" - "fn sumnst(n: nst) u64 = { return n.i0 + sumdeep(n.dp); };\n" - "fn main() i32 = {\n" - " let s = mkbox();\n" - " s.ir = nst { i0 = 11: u64, dp = deep { d0 = 22: u64, d1 = 33: u64 } };\n" - " return sumnst(s.ir): i32;\n" - "};\n" }, - { NULL, NULL } -}; - -static const struct scenario scenarios[] = { - { "ptrread_t16", ptrread_files, 107 }, - { "letcopy_t16", letcopy_files, 107 }, - { "addrptr_pq", addrptr_files, 10 }, - { "addrval_pq", addrval_files, 10 }, - { "ptrwrite_t16", ptrwrite_files, 109 }, - { "valwrite_t16", valwrite_files, 109 }, - { "nestfill_box", nestfill_files, 66 }, -}; - -static int -run_scenario(const char *cdrv, const char *wdrv, const struct scenario *sc) -{ - char dir[] = "/tmp/ww797_XXXXXX"; - if (mkdtemp(dir) == NULL) { - fprintf(stderr, "797[%s]: mkdtemp failed\n", sc->label); - return -1; - } - - char path[1024], cmd[4096]; - int rc = 0; - - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - FILE *f = fopen(path, "wb"); - if (!f) { fprintf(stderr, "797[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - int bad = fputs(sc->files[i].src, f) == EOF; - if (fclose(f) != 0) bad = 1; - if (bad) { fprintf(stderr, "797[%s]: write %s\n", sc->label, - sc->files[i].name); rc = -1; goto done; } - } - - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/main %s/main.ww", - dir, cdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "797[%s]: cstage build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(path, sizeof path, "%s/main", dir); - int gotc = runwait(path); - if (gotc != sc->want_exit) { - fprintf(stderr, "797[%s]: cstage exit %d, want %d\n", - sc->label, gotc, sc->want_exit); - rc = -1; - } - - snprintf(cmd, sizeof cmd, - "cd %s && %s build -I %s -o %s/mainww %s/main.ww", - dir, wdrv, dir, dir, dir); - if (runwait(cmd) != 0) { - fprintf(stderr, "797[%s]: ww_ww build failed\n", sc->label); - rc = -1; goto done; - } - snprintf(path, sizeof path, "%s/mainww", dir); - int gotw = runwait(path); - if (gotw != sc->want_exit) { - fprintf(stderr, "797[%s]: wwstage exit %d, want %d\n", - sc->label, gotw, sc->want_exit); - rc = -1; - } - - char cs_s[1024], ws_s[1024]; - snprintf(cs_s, sizeof cs_s, "%s/all_cs.s", dir); - snprintf(ws_s, sizeof ws_s, "%s/all_ww.s", dir); - snprintf(cmd, sizeof cmd, - "cat %s/main.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, cs_s, cs_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "797[%s]: cstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - snprintf(cmd, sizeof cmd, - "cat %s/mainww.sepwork/*.s > %s 2>/dev/null && test -s %s", - dir, ws_s, ws_s); - if (runwait(cmd) != 0) { - fprintf(stderr, "797[%s]: wwstage asm aggregation failed\n", - sc->label); - rc = -1; goto done; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, "797[%s]: cs.s/ww.s DIFFER (rule-10 byte-id " - "violation — #31 regression)\n", sc->label); - rc = -1; - } - -done: - snprintf(cmd, sizeof cmd, "rm -rf %s/main.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "797[%s]: cleanup main.sepwork\n", - sc->label); rc = -1; } - snprintf(cmd, sizeof cmd, "rm -rf %s/mainww.sepwork", dir); - if (runwait(cmd) != 0) { fprintf(stderr, "797[%s]: cleanup mainww.sepwork\n", - sc->label); rc = -1; } - for (int i = 0; sc->files[i].name; i++) { - snprintf(path, sizeof path, "%s/%s", dir, sc->files[i].name); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "797[%s]: cleanup %s\n", sc->label, - sc->files[i].name); - rc = -1; - } - } - const char *children[] = { "main", "mainww", "all_cs.s", "all_ww.s", NULL }; - for (int i = 0; children[i]; i++) { - snprintf(path, sizeof path, "%s/%s", dir, children[i]); - if (unlink(path) != 0 && errno != ENOENT) { - fprintf(stderr, "797[%s]: cleanup %s\n", sc->label, - children[i]); - rc = -1; - } - } - if (rmdir(dir) != 0) { - fprintf(stderr, "797[%s]: cleanup directory\n", sc->label); - rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2048]; - 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[2100], wdrv[2100]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - if (access(wdrv, X_OK) != 0) { - fprintf(stderr, "797: ww_ww missing — cannot run the cs==ww " - "byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = (int)(sizeof scenarios / sizeof scenarios[0]); - int fail = 0; - for (int i = 0; i < n; i++) { - if (run_scenario(cdrv, wdrv, &scenarios[i]) != 0) - fail++; - } - - if (fail) { - fprintf(stderr, "797 xmod_struct_field_layout_collide: %d/%d " - "scenarios failed\n", fail, n); - return 1; - } - printf("xmod_struct_field_layout_collide: %d/%d ok (cstage+wwstage run + " - "cs==ww byte-id)\n", n, n); - return 0; -} diff --git a/test/wcc/data/r752_modparam_variadic_no_collision/alpha/alpha.ww b/test/wcc/data/r752_modparam_variadic_no_collision/alpha/alpha.ww new file mode 100644 index 00000000..c1f1e1a0 --- /dev/null +++ b/test/wcc/data/r752_modparam_variadic_no_collision/alpha/alpha.ww @@ -0,0 +1,8 @@ +// sole variadic callee for the r752 no-collision control. +package alpha; +export fn sum(a: i32, xs: i32...) i32 = { + let t: i32 = a; + let i: i32 = 0; + for (i < xs.len) { t += xs[i]; i += 1; }; + return t; +}; diff --git a/test/wcc/data/r752_modparam_variadic_no_collision/case.ww b/test/wcc/data/r752_modparam_variadic_no_collision/case.ww new file mode 100644 index 00000000..053054d4 --- /dev/null +++ b/test/wcc/data/r752_modparam_variadic_no_collision/case.ww @@ -0,0 +1,9 @@ +//ww:run +// migrated from test/wcc/752_modparam_callee.c: control — variadic callee in one module only; the N_IDENT arm stays on bare fnparamslookup. +package main; +import alpha; +export fn main() i32 = { + let r: i32 = alpha.sum(1, 2, 3, 4); + if (r != 10) { return 40; }; + return 0; +}; diff --git a/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/alpha/alpha.ww b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/alpha/alpha.ww new file mode 100644 index 00000000..d8ed874d --- /dev/null +++ b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/alpha/alpha.ww @@ -0,0 +1,5 @@ +// same-leaf variadic side of the r752 collision pair. +package alpha; +export fn foo(a: i32, xs: i32...) i32 = { + return a + xs.len; +}; diff --git a/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/beta/beta.ww b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/beta/beta.ww new file mode 100644 index 00000000..3b3ae670 --- /dev/null +++ b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/beta/beta.ww @@ -0,0 +1,9 @@ +// same-leaf scalar-tagged side of the r752 collision pair. +package beta; +export fn foo(a: i32, n: (u8 | []u8)) i32 = { + match (n) { + case let c: u8 => return a + (c: i32); + case let s: []u8 => return a + s.len; + }; + return 0; +}; diff --git a/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/case.ww b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/case.ww new file mode 100644 index 00000000..77d5c2cc --- /dev/null +++ b/test/wcc/data/r752_modparam_xmod_variadic_vs_scalar/case.ww @@ -0,0 +1,11 @@ +//ww:run +// migrated from test/wcc/752_modparam_callee.c: N_DOT callee param lookup must be module-keyed — alpha.foo variadic vs beta.foo scalar same leaf (#16). +package main; +import alpha; +import beta; +export fn main() i32 = { + let n: (u8 | []u8) = 7u8; + let r: i32 = beta.foo(10, n); + if (r != 17) { return 11; }; + return 0; +}; diff --git a/test/wcc/data/r784_xmod_alias_control/case.ww b/test/wcc/data/r784_xmod_alias_control/case.ww new file mode 100644 index 00000000..35a56d80 --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_control/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 30 +// migrated from test/wcc/784_xmod_alias_struct_collide_run.c: control — alias+vtable dispatcher with NO foreign same-leaf struct in the closure. +package main; +import sa; +fn cb(x: sa.s, v: i32) i32 = { return v + 100; }; +export fn main() i32 = { + let vt = sa.mkvt((&cb): *sa.reader); + let st: sa.s = &vt; + let r = sa.read(st, 5); + if (r != 105) { return 11; }; + return 30; +}; diff --git a/test/wcc/data/r784_xmod_alias_control/sa/sa.ww b/test/wcc/data/r784_xmod_alias_control/sa/sa.ww new file mode 100644 index 00000000..9488648c --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_control/sa/sa.ww @@ -0,0 +1,21 @@ +// alias+vtable dispatcher, collision-free control for r784. +package sa; + +export type reader = fn(x: s, v: i32) i32; + +export type vtable = struct { + reader: (*reader | void), +}; + +export type s = *vtable; + +export fn read(x: s, v: i32) i32 = { + match (x.reader) { + case void => return -1; + case let f: *reader => return (*f)(x, v); + }; +}; + +export fn mkvt(f: *reader) vtable = { + return vtable { reader = f }; +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_collide/case.ww b/test/wcc/data/r784_xmod_alias_struct_collide/case.ww new file mode 100644 index 00000000..7066a573 --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_collide/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 42 +// migrated from test/wcc/784_xmod_alias_struct_collide_run.c: #223 trigger — sa's *vtable alias peel must not halt on sb's same-leaf foreign struct. +package main; +import sa; +import sb; +fn cb(x: sa.s, v: i32) i32 = { return v + 100; }; +export fn main() i32 = { + let vt = sa.mkvt((&cb): *sa.reader); + let st: sa.s = &vt; + let r = sa.read(st, 5); + let vt2 = sa.mkempty(); + let st2: sa.s = &vt2; + let r2 = sa.read(st2, 5); + if (r != 105) { return 11; }; + if (r2 != -1) { return 12; }; + return 42; +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_collide/sa/sa.ww b/test/wcc/data/r784_xmod_alias_struct_collide/sa/sa.ww new file mode 100644 index 00000000..48728a50 --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_collide/sa/sa.ww @@ -0,0 +1,25 @@ +// alias-side of the r784 #223 pair: s = *vtable with a branched dispatcher. +package sa; + +export type reader = fn(x: s, v: i32) i32; + +export type vtable = struct { + reader: (*reader | void), +}; + +export type s = *vtable; + +export fn read(x: s, v: i32) i32 = { + match (x.reader) { + case void => return -1; + case let f: *reader => return (*f)(x, v); + }; +}; + +export fn mkvt(f: *reader) vtable = { + return vtable { reader = f }; +}; + +export fn mkempty() vtable = { + return vtable { reader = void }; +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_collide/sb/sb.ww b/test/wcc/data/r784_xmod_alias_struct_collide/sb/sb.ww new file mode 100644 index 00000000..518a5eca --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_collide/sb/sb.ww @@ -0,0 +1,7 @@ +// foreign same-leaf STRUCT `s` (no reader field) — the #223 mis-peel bait. +package sb; + +export type s = struct { + a: i32, + b: i32, +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_symmetric/case.ww b/test/wcc/data/r784_xmod_alias_struct_symmetric/case.ww new file mode 100644 index 00000000..fec778db --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_symmetric/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 21 +// migrated from test/wcc/784_xmod_alias_struct_collide_run.c: symmetric guard — sa's same-module STRUCT break must still fire with sb's same-leaf alias present. +package main; +import sa; +import sb; +export fn main() i32 = { + let o = sa.mk(21, 8); + let r = sa.geta(o); + if (r != 21) { return 11; }; + return 21; +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_symmetric/sa/sa.ww b/test/wcc/data/r784_xmod_alias_struct_symmetric/sa/sa.ww new file mode 100644 index 00000000..90bd8c27 --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_symmetric/sa/sa.ww @@ -0,0 +1,15 @@ +// struct-side receiver for the r784 symmetric guard. +package sa; + +export type s = struct { + a: i32, + b: i32, +}; + +export fn mk(av: i32, bv: i32) s = { + return s { a = av, b = bv }; +}; + +export fn geta(x: s) i32 = { + return x.a; +}; diff --git a/test/wcc/data/r784_xmod_alias_struct_symmetric/sb/sb.ww b/test/wcc/data/r784_xmod_alias_struct_symmetric/sb/sb.ww new file mode 100644 index 00000000..b86f5d7f --- /dev/null +++ b/test/wcc/data/r784_xmod_alias_struct_symmetric/sb/sb.ww @@ -0,0 +1,8 @@ +// foreign same-leaf pointer ALIAS `s` — a naive alias-first reorder would mis-peel sa's struct. +package sb; + +export type vtable = struct { + q: i32, +}; + +export type s = *vtable; diff --git a/test/wcc/data/r793_xmod_argpush_combined_t16/case.ww b/test/wcc/data/r793_xmod_argpush_combined_t16/case.ww new file mode 100644 index 00000000..db2bbf4d --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_combined_t16/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 114 +// migrated from test/wcc/793_xmod_struct_argpush_collide_run.c: recv+field+push in one fn under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let s = m1.mk(); + let x: i32 = (s.lo: i32); + return m1.consume(s) + x; +}; diff --git a/test/wcc/data/r793_xmod_argpush_combined_t16/m1/m1.ww b/test/wcc/data/r793_xmod_argpush_combined_t16/m1/m1.ww new file mode 100644 index 00000000..737e8934 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_combined_t16/m1/m1.ww @@ -0,0 +1,5 @@ +// 16B sub-8-tail pair — the local side of the r793 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn consume(p: pair) i32 = { return (p.hi + (p.lo: u64)): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_combined_t16/m2/m2.ww b/test/wcc/data/r793_xmod_argpush_combined_t16/m2/m2.ww new file mode 100644 index 00000000..17b4da37 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_combined_t16/m2/m2.ww @@ -0,0 +1,4 @@ +// 24B same-leaf foreign pair — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_fieldread_t16/case.ww b/test/wcc/data/r793_xmod_argpush_fieldread_t16/case.ww new file mode 100644 index 00000000..2f0583ef --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_fieldread_t16/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 107 +// migrated from test/wcc/793_xmod_struct_argpush_collide_run.c: #224 site — direct field read off the inferred-let recv under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let s = m1.mk(); + return (s.hi + (s.lo: u64)): i32; +}; diff --git a/test/wcc/data/r793_xmod_argpush_fieldread_t16/m1/m1.ww b/test/wcc/data/r793_xmod_argpush_fieldread_t16/m1/m1.ww new file mode 100644 index 00000000..9df0c55a --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_fieldread_t16/m1/m1.ww @@ -0,0 +1,4 @@ +// 16B sub-8-tail pair — the local side of the r793 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; diff --git a/test/wcc/data/r793_xmod_argpush_fieldread_t16/m2/m2.ww b/test/wcc/data/r793_xmod_argpush_fieldread_t16/m2/m2.ww new file mode 100644 index 00000000..17b4da37 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_fieldread_t16/m2/m2.ww @@ -0,0 +1,4 @@ +// 24B same-leaf foreign pair — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t12/case.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t12/case.ww new file mode 100644 index 00000000..0cb98822 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t12/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 6 +// migrated from test/wcc/793_xmod_struct_argpush_collide_run.c: maxalign-4 12B {u32,u32,u32} sub-8 tail under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let s = m1.mk(); + return m1.consume(s); +}; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t12/m1/m1.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t12/m1/m1.ww new file mode 100644 index 00000000..b4763f5a --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t12/m1/m1.ww @@ -0,0 +1,5 @@ +// 12B maxalign-4 triple — the local side of the r793 t12 collision. +package m1; +export type pair = struct { a: u32, b: u32, c: u32 }; +export fn mk() pair = { return pair { a = 1: u32, b = 2: u32, c = 3: u32 }; }; +export fn consume(p: pair) i32 = { return (p.a + p.b + p.c): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t12/m2/m2.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t12/m2/m2.ww new file mode 100644 index 00000000..17b4da37 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t12/m2/m2.ww @@ -0,0 +1,4 @@ +// 24B same-leaf foreign pair — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t16/case.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t16/case.ww new file mode 100644 index 00000000..b6f731d0 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t16/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 107 +// migrated from test/wcc/793_xmod_struct_argpush_collide_run.c: #21 push+recv sites — 16B m1.pair vs 24B foreign same-leaf; count must come from stamped tinfo. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let s = m1.mk(); + return m1.consume(s); +}; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t16/m1/m1.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t16/m1/m1.ww new file mode 100644 index 00000000..737e8934 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t16/m1/m1.ww @@ -0,0 +1,5 @@ +// 16B sub-8-tail pair — the local side of the r793 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn consume(p: pair) i32 = { return (p.hi + (p.lo: u64)): i32; }; diff --git a/test/wcc/data/r793_xmod_argpush_recvpush_t16/m2/m2.ww b/test/wcc/data/r793_xmod_argpush_recvpush_t16/m2/m2.ww new file mode 100644 index 00000000..17b4da37 --- /dev/null +++ b/test/wcc/data/r793_xmod_argpush_recvpush_t16/m2/m2.ww @@ -0,0 +1,4 @@ +// 24B same-leaf foreign pair — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_nestfill_box/case.ww b/test/wcc/data/r797_nestfill_box/case.ww new file mode 100644 index 00000000..d1f17fd9 --- /dev/null +++ b/test/wcc/data/r797_nestfill_box/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 66 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: cgstructlitfilltn nested-recursion pin — struct-literal field store with a nested literal; single-dot readback helpers per the open wwstage chained-read gaps. +package main; +type deep = struct { d0: u64, d1: u64 }; +type nst = struct { i0: u64, dp: deep }; +type box = struct { tag: u64, ir: nst }; +fn mkbox() box = { return box { tag = 0: u64, ir = nst { i0 = 0: u64, dp = deep { d0 = 0: u64, d1 = 0: u64 } } }; }; +fn sumdeep(d: deep) u64 = { return d.d0 + d.d1; }; +fn sumnst(n: nst) u64 = { return n.i0 + sumdeep(n.dp); }; +fn main() i32 = { + let s = mkbox(); + s.ir = nst { i0 = 11: u64, dp = deep { d0 = 22: u64, d1 = 33: u64 } }; + return sumnst(s.ir): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_addrptr_pq/case.ww b/test/wcc/data/r797_xmod_layout_addrptr_pq/case.ww new file mode 100644 index 00000000..1cf8246f --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrptr_pq/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 10 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: A1 arm — &p.v LEAQ offset over *struct; all-u64 pq isolates offset from the narrow-deref-store width family. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pq; + dummy.a = 0: u64; + let p = m1.mkpq(); + let q = &p.v; + *q = 9: u64; + return (p.a + p.v): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_addrptr_pq/m1/m1.ww b/test/wcc/data/r797_xmod_layout_addrptr_pq/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrptr_pq/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_addrptr_pq/m2/m2.ww b/test/wcc/data/r797_xmod_layout_addrptr_pq/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrptr_pq/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_xmod_layout_addrval_pq/case.ww b/test/wcc/data/r797_xmod_layout_addrval_pq/case.ww new file mode 100644 index 00000000..6ec87e92 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrval_pq/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 10 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: A2 arm — &s.v over a value struct under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pq; + dummy.a = 0: u64; + let s = m1.mkq(); + let q = &s.v; + *q = 9: u64; + return (s.a + s.v): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_addrval_pq/m1/m1.ww b/test/wcc/data/r797_xmod_layout_addrval_pq/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrval_pq/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_addrval_pq/m2/m2.ww b/test/wcc/data/r797_xmod_layout_addrval_pq/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_addrval_pq/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_xmod_layout_letcopy_t16/case.ww b/test/wcc/data/r797_xmod_layout_letcopy_t16/case.ww new file mode 100644 index 00000000..c0280a69 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_letcopy_t16/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 107 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: C1 arm — let-copy size from the COPY source's stamped tinfo (value coincides; byte-id is the net). +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let p1 = m1.mk(); + let p2 = p1; + return (p2.hi + (p2.lo: u64)): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_letcopy_t16/m1/m1.ww b/test/wcc/data/r797_xmod_layout_letcopy_t16/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_letcopy_t16/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_letcopy_t16/m2/m2.ww b/test/wcc/data/r797_xmod_layout_letcopy_t16/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_letcopy_t16/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_xmod_layout_ptrread_t16/case.ww b/test/wcc/data/r797_xmod_layout_ptrread_t16/case.ww new file mode 100644 index 00000000..194e9835 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrread_t16/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 107 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: R1 arm — *struct field read offset must come from stamped tinfo, not the foreign layout. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let p = m1.mkp(); + return (p.hi + (p.lo: u64)): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_ptrread_t16/m1/m1.ww b/test/wcc/data/r797_xmod_layout_ptrread_t16/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrread_t16/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_ptrread_t16/m2/m2.ww b/test/wcc/data/r797_xmod_layout_ptrread_t16/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrread_t16/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_xmod_layout_ptrwrite_t16/case.ww b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/case.ww new file mode 100644 index 00000000..959b5069 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 109 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: W1 arm — p.lo store offset/width through *struct under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let p = m1.mkp(); + p.lo = 9: u16; + return (p.hi + (p.lo: u64)): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m1/m1.ww b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m2/m2.ww b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_ptrwrite_t16/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; }; diff --git a/test/wcc/data/r797_xmod_layout_valwrite_t16/case.ww b/test/wcc/data/r797_xmod_layout_valwrite_t16/case.ww new file mode 100644 index 00000000..7346f1b2 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_valwrite_t16/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 109 +// migrated from test/wcc/797_xmod_struct_field_layout_collide_run.c: W2 arm — s.lo store into a value struct under the same-leaf collision. +package main; +import m1; +import m2; +fn main() i32 = { + let dummy: m2.pair; + dummy.hi = 0: u64; + let s = m1.mk(); + s.lo = 9: u16; + return (s.hi + (s.lo: u64)): i32; +}; diff --git a/test/wcc/data/r797_xmod_layout_valwrite_t16/m1/m1.ww b/test/wcc/data/r797_xmod_layout_valwrite_t16/m1/m1.ww new file mode 100644 index 00000000..158dcf9b --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_valwrite_t16/m1/m1.ww @@ -0,0 +1,10 @@ +// 16B pair + 16B all-u64 pq providers — the local side of the r797 collision. +package m1; +export type pair = struct { hi: u64, lo: u16 }; +export type pq = struct { a: u64, v: u64 }; +let g: pair = pair { hi = 100: u64, lo = 7: u16 }; +let gq: pq = pq { a = 1: u64, v = 7: u64 }; +export fn mk() pair = { return pair { hi = 100: u64, lo = 7: u16 }; }; +export fn mkp() *pair = { return &g; }; +export fn mkq() pq = { return pq { a = 1: u64, v = 7: u64 }; }; +export fn mkpq() *pq = { return &gq; }; diff --git a/test/wcc/data/r797_xmod_layout_valwrite_t16/m2/m2.ww b/test/wcc/data/r797_xmod_layout_valwrite_t16/m2/m2.ww new file mode 100644 index 00000000..413167e3 --- /dev/null +++ b/test/wcc/data/r797_xmod_layout_valwrite_t16/m2/m2.ww @@ -0,0 +1,5 @@ +// 24B same-leaf pair + pq — the name-keyed lookup's mis-resolution bait. +package m2; +export type pair = struct { hi: u64, mid: u64, lo: u64 }; +export type pq = struct { a: u64, b: u64, v: u64 }; +export fn use2(p: pair) i32 = { return (p.hi + p.mid + p.lo): i32; };