cgen: type-key wwstage struct-layout at 3 sites via stamped tinfo (#21)
wwstage cgen resolved struct LAYOUT by bare-leaf name (structlookup / structparamsize) at three caller-side sites — the by-value arg push (cgenutil), the let-receive copy width (cgenstmt), and the field-read offset (cgenexpr). Under a cross-module same-leaf collision (two modules each exporting a `pair`, 16B vs 24B) the name lookup first-matches the WRONG type, so the push dropped the 2nd eightbyte, the receive over-copied, and the field read the wrong offset. cstage type-keys off the stamped tinfo and is correct; this aligns wwstage UP to it (ww-only change). Route all three sites through the stamped node.type_ via a new structabisizetn(*tinfo) accessor (push + receive) and tichase(type_).fields (field-read, structlookupchain removed). One commit (rule-11 carve-out): the collision drives all three at once and no per-site fixture isolates, so it cannot bisect-split. A scoped slice of the #209/#211 name-keyed-cgen cluster retirement; the cgdot *struct-ptr/global and let-copy siblings stay name-keyed and are filed (#31). New table-driven test 793_xmod_struct_argpush_collide_run (4 scenarios: push/recv/field over 16B and 12B tails) reddens under a revert of the three cgen files. Full make test green (336 passed); make sizelint clean.
This commit is contained in:
@@ -2583,29 +2583,38 @@ fn cgletbody(c: *cgen, n: *syntax.node, off: i32) void = {
|
||||
};
|
||||
};
|
||||
if (rhs.kind == syntax.nkind.N_CALL) {
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (tn != nil) {
|
||||
if (tn.kind == syntax.nkind.N_TNAME) {
|
||||
sname = tn.str;
|
||||
};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let lsi: *structinfo = structlookup(c, sname);
|
||||
if (lsi != nil) {
|
||||
// ≤24B register RECV: the value arrives packed
|
||||
// in AX/DX/CX, so size by the maxalign-rounded
|
||||
// ABI size (cstage lu->size), not the natural
|
||||
// extent — see structabisize (#169).
|
||||
let lsz: i32 = structabisize(lsi);
|
||||
let tlm: i32 = lsz - (lsz / 8) * 8;
|
||||
if (lsz <= 24) {
|
||||
if (tlm == 0 || tlm == 1
|
||||
|| tlm == 2 || tlm == 4) {
|
||||
cgexpr(c, rhs);
|
||||
cgaggregstore(c, "BP", off, lsz, true);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
//
|
||||
// #21/#224: size off the checker-STAMPED tinfo
|
||||
// (structabisizetn = tichase(tn.type_).size, the
|
||||
// maxalign-rounded ABI size = check.ww:2467),
|
||||
// NOT structlookup(tn.str). On a cross-module
|
||||
// same-leaf collision the inferred-let's tn.str
|
||||
// is a bare leaf that structlookup mis-resolves to
|
||||
// a FOREIGN same-leaf struct → the recv copied that
|
||||
// struct's word count (a 24B foreign over-copies a
|
||||
// 16B local, spilling into a neighbour slot). The
|
||||
// stamped tinfo carries the right size regardless of
|
||||
// collision; byte-id with structabisize on a
|
||||
// resolving lookup. Mirrors the sibling array arm
|
||||
// below (already tn.type_-keyed). cstage is
|
||||
// type-keyed (lu->size) — align ww UP.
|
||||
let lsz: i32 = structabisizetn(tn.type_: *syntax.tinfo);
|
||||
if (lsz > 0) {
|
||||
let tlm: i32 = lsz - (lsz / 8) * 8;
|
||||
if (lsz <= 24) {
|
||||
if (tlm == 0 || tlm == 1
|
||||
|| tlm == 2 || tlm == 4) {
|
||||
cgexpr(c, rhs);
|
||||
cgaggregstore(c, "BP", off, lsz, true);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user