wwstage: register error-structs in collectstructs so large-union struct-variant returns widen (#9)
collectstructs registered a struct only when the typedecl body is N_TSTRUCT, so an error-struct (type X = !struct{...}, whose body is N_TBANG{N_TSTRUCT}) never entered wwstage's c.structs table. The name-keyed structlookup then missed at the return-widen sites, and wwstage dropped the struct construction when returning a struct variant of a large (>4-eightbyte) union -- wrong runtime value and cs!=ww. cstage has no struct name-table (pure tinfo) and was correct. Peel the N_TBANG body in collectstructs so error-structs register; both existing cstage-mirrored widen arms then fire. Provably byte-id-inert: no committed source defines a !struct today. Adds test/wcc/785 (struct-variant return + named-void control, both-stage byte-id + runtime). The >4-eightbyte 5th-word truncation on return remains, symmetric (cs==ww) and unread by the tag/early-word path; #222's sret hidden-pointer cutover is the committed fix (table-retirement tracked as the wwstage->tinfo SSoT arc). Aligns wwstage up to cstage (rule-10).
This commit is contained in:
@@ -435,6 +435,17 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
cgwidentaggedstore(c, c.fnret.type_: *tinfo, rhs, "BP",
|
||||
scroff, rsz);
|
||||
// Tagged-return ABI loads at most 4 eightbytes
|
||||
// (AX/DX/CX/R8). A union whose slot exceeds 32B
|
||||
// (tag + >3 payload words, e.g. a 32B struct
|
||||
// variant = 40B slot) drops its 5th+ word here —
|
||||
// SYMMETRICALLY with cstage, so byte-id holds and
|
||||
// the tag/early-word read paths are correct. The
|
||||
// dropped tail is #222 (the >4-eightbyte sret ABI
|
||||
// asymmetry); its real fix routes large unions
|
||||
// through a hidden-pointer sret on both paths.
|
||||
// Sound only while consumers never read the tail
|
||||
// (errno's tag/strerror path does not).
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scroff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
|
||||
Reference in New Issue
Block a user