From e784968dd8167cc8ff6816e7f03d5981c210e214 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 25 May 2026 14:45:04 +0900 Subject: [PATCH] test: 954 add struct-exclusion control row (#102 over-catch guard) The fix's new cglet branch is gated on sz==16 AND rettupleof != nil. The existing rows prove it CATCHES 16B tuple receives but nothing pinned that it does NOT catch a 16B struct{i64,i64} receive (same sz==16, but rettupleof returns nil for a non-tuple return). A future rettupleof refactor returning non-nil for a struct would silently route the struct through the AX/DX tuple spill and miscompile it, gate-blind. The new ctl_struct row is byte-id and runs correctly (exit 12) both pre- and post-fix, pinning the tuple/struct discrimination. --- test/wcc/954_tuprecv_run.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/test/wcc/954_tuprecv_run.c b/test/wcc/954_tuprecv_run.c index 1f064bf0..aa4eb89f 100644 --- a/test/wcc/954_tuprecv_run.c +++ b/test/wcc/954_tuprecv_run.c @@ -28,10 +28,16 @@ * diverge by exactly one dropped `MOVQ DX, -8(BP)`; post-fix all * are byte-identical. * - * Two CONTROL rows pin that the fix touches nothing else: the - * destructure form `let (a,b) = mk()` (cgmlet + tupstore cursor) and a - * 32B wide/str-element single-var tuple stay byte-id both pre- and - * post-fix (the fix is in cglet/N_LET, gated on sz==16). + * Three CONTROL rows pin that the fix touches nothing else: the + * destructure form `let (a,b) = mk()` (cgmlet + tupstore cursor), a + * 32B wide/str-element single-var tuple, and a 16B struct{i64,i64} + * single-var receive — all stay byte-id both pre- and post-fix. The fix + * is in cglet/N_LET, gated on sz==16 AND rettupleof != nil; the struct + * row is the over-catch guard: sz IS 16 but rettupleof returns nil for a + * non-tuple return, so the new branch must NOT hijack the struct's + * generic store. Without that guard a struct receive would route through + * the AX/DX tuple spill and miscompile any struct whose layout differs + * from {word0,word1}. */ #include #include @@ -110,6 +116,20 @@ static const struct row rows[] = { "\tlet t: (i64, str) = mk();\n" "\treturn t.0: i32;\n" "};\n", 7 }, + /* CONTROL — over-catch guard. A 16B struct{i64,i64} from-call receive + * is sz==16 like the bug rows, but rettupleof returns nil for a + * non-tuple return, so the fix's new branch must NOT hijack it; it + * stays on the generic struct store and byte-id pre- and post-fix. + * Pins that the fix's tuple/struct discrimination (#102) holds. a=5, + * b=7, 5+7 = 12. */ + { "ctl_struct", + "package main;\n" + "type pair = struct { a: i64, b: i64 };\n" + "fn mk() pair = { return pair { a = 5, b = 7 }; };\n" + "export fn main() i32 = {\n" + "\tlet t = mk();\n" + "\treturn (t.a: i32) + (t.b: i32);\n" + "};\n", 12 }, { NULL, NULL, 0 } };