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.
This commit is contained in:
2026-05-25 14:45:04 +09:00
parent 734c0c36e5
commit e784968dd8

View File

@@ -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 <stdio.h>
#include <stdlib.h>
@@ -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 }
};