wcc/check: #24 reject composite-element tuple (array/struct/tuple), declared+inferred, both stages

A tuple whose element chases to TY_ARRAY/STRUCT/TUPLE (>8B) silently
miscompiled both stages: t.0[i] read segfaulted and construction dropped
the payload into the 8B slot. Reject the type at resolution (DISP-B);
faithful inline layout deferred to #60. cstage resolve_type N_TTUPLE
(declared) + N_TUPLE expr (inferred literal, was a cstage-only silent
miscompile + cs!=ww asymmetry); wwstage tinfofornode covers both.
test/wcc/832 + 941 migrated.
This commit is contained in:
2026-06-09 17:29:11 +09:00
parent f1cd0a3555
commit 785fe342fa
6 changed files with 144 additions and 33 deletions

View File

@@ -1964,6 +1964,18 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
let pt: *tinfo = tinfofornode(c, p.lhs);
// #62/#69: tuple-member value cycle — loud, cstage twin.
if (circularnamed(c, pt, p.lhs)) { pt = c.tc.tyerr; };
// #24: a composite element (array/struct/nested tuple
// >8B) cannot ride the 8B cursor slot — the #60 layout
// drops it on construction and segvs on t.N[i] read.
// Reject until #60/DISP-A inlines it; cstage twin.
let cu: *tinfo = tichase(pt);
if (cu != nil && (cu.kind == tykind.TY_ARRAY
|| cu.kind == tykind.TY_STRUCT
|| cu.kind == tykind.TY_TUPLE)) {
cerr("error: tuple element must be a scalar, str, slice, or tagged-union (composite element deferred to task #60)\n");
c.errs += 1;
pt = c.tc.tyerr;
};
let te: *ttupleelem = alloc(ttupleelem{type_=pt, offset=slottotal, tnext=nil})!;
if (teh == nil) { teh = te; } else { tet.tnext = te; };
tet = te;