wcc_ww/cgen: #63 alias-named struct-lit fill via structlookupchain (let-init + sret-return)
cglet's N_STRUCTLIT init arm resolved the struct by a bare
structlookup(c, sname). For an alias-NAMED literal
(`type rep2 = rep; let r = rep2{id=6}`) the type ref carries the
alias name "rep2" but only the base `rep` is registered, so the
lookup returned nil and the field-fill never fired. The nil then
split by slot size into two symptoms of one root:
- <=8B: the small-let scalar default zeroed the slot and DROPPED
the literal (SILENT wrong — the field read 0), and
- >8B: no fill arm matched, falling to the cglet "unhandled rhs
shape" LOUD (task #7/rule-7).
Route the arm through structlookupchain (the #92/W2 SSoT already
adopted at cgenstmt:1974/:2687), which chases the alias chain to the
base struct. trefn (rhs.lhs) is already the N_IDENT/N_TNAME type ref
structlookupchain accepts, so the bare sname extraction is dropped.
cstage operates on the resolved Type* via type_chase_named and was
always correct: ww-only align-UP, cs UNTOUCHED.
ROUTED (the two reachable silent sites, one class):
:2421 local N_STRUCTLIT let-init — the #63 repro hits it for
both the <=8B silent-zero and the >24B loud symptoms.
:1250 >24B sret RETURN twin (reviewer-63). sretretsize chases
the alias for the size GATE so this sret arm fires, but
the fill used the same bare structlookup(sname) — for an
alias-named >24B literal it returned nil and the fill was
SKIPPED, so the callee returned an uninitialised sret
buffer (SILENT wrong, runtime-0; cs correct). Same root,
same symptom, sibling site → folded by construction.
DECLINED (traced, not blind-routed; rule-11 + the #101 precedent):
:2625 N_IDENT struct-copy — also bare-structlookup but the copy
falls through to a generic path byte-identical with cstage;
both stages run correct. The post-copy field-READ diverges
(cs direct-offset vs ww LEAQ-indirect) = the #81/#65 alias
field-read class, out of #63 scope.
:2511 N_CALL struct-recv — blocked UPSTREAM by the aggregate-
return shape (#272/#277); ww louds at the sender.
:1363 <=24B register RETURN — alias case louds via the same
scalar-default catch (#277), not silently wrong.
The 2 already-chasing sites (1974/2687) untouched.
CONVERGENCE: m3_letinit_typed + m3_letinit_untyped (ww silent-zero ->
6/6 byte-id) + m6_letlit_alias (ww loud -> 7 byte-id) + sret_return_-
alias32 (ww silent-0 -> 10 byte-id), plus a non-alias control
(no-regress). Bootstrap byte-id NEUTRAL (selfhost has no
alias-struct-litinit/return; all 4 selfhost tools cs==ww confirmed).
Test: 944_alias_structlit_init_run (5 rows x cs-run + ww-run +
cs==ww byte-id = 15 checks), Makefile-wired.
This commit is contained in:
@@ -33730,14 +33730,20 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (okrhs) {
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: the >24B sret RETURN twin of the :2421
|
||||
// let-init fix. sretretsize chases the alias for
|
||||
// the size GATE (so this sret arm fires for a >24B
|
||||
// alias struct), but the field-fill resolved the
|
||||
// struct by a bare structlookup(c, sname): for an
|
||||
// alias-NAMED literal (`type biga = big; return
|
||||
// biga{...}`) sname is "biga", unregistered, so
|
||||
// sret_si was nil and the fill was SKIPPED — the
|
||||
// callee returned an uninitialised sret buffer
|
||||
// (SILENT wrong, runtime-0). structlookupchain chases
|
||||
// to the base struct; cs fills via the resolved
|
||||
// Type*, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let sret_si: *structinfo = structlookup(c, sname);
|
||||
let sret_si: *structinfo = structlookupchain(c, trefn);
|
||||
if (sret_si != nil) {
|
||||
let emptys: str;
|
||||
emptys.ptr = nil; emptys.len = 0;
|
||||
@@ -34898,14 +34904,17 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// (the #17 silent-zero fix). Mirror of cstage cgen.c N_LET
|
||||
// structlit branch.
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: an alias-NAMED struct literal (`type rep2 = rep;
|
||||
// let r = rep2{id=6}`) parses its type ref as N_IDENT/N_TNAME
|
||||
// "rep2", but only the base `rep` is registered — bare
|
||||
// structlookup(c, "rep2") returns nil, so the fill never
|
||||
// fired: the slot zeroed + the lit DROPPED (≤8B silent) or
|
||||
// fell to the :2920 LOUD (>8B). structlookupchain chases the
|
||||
// alias chain to the base struct, the #92/W2 SSoT already
|
||||
// adopted at cgenstmt:1974/:2687. cs chases via
|
||||
// type_chase_named, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
let si: *structinfo = structlookupchain(c, trefn);
|
||||
if (si != nil) {
|
||||
cgstructlitfillbp(c, si, rhs, off);
|
||||
c.lastwasreturn = 0;
|
||||
|
||||
@@ -1240,14 +1240,20 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (okrhs) {
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: the >24B sret RETURN twin of the :2421
|
||||
// let-init fix. sretretsize chases the alias for
|
||||
// the size GATE (so this sret arm fires for a >24B
|
||||
// alias struct), but the field-fill resolved the
|
||||
// struct by a bare structlookup(c, sname): for an
|
||||
// alias-NAMED literal (`type biga = big; return
|
||||
// biga{...}`) sname is "biga", unregistered, so
|
||||
// sret_si was nil and the fill was SKIPPED — the
|
||||
// callee returned an uninitialised sret buffer
|
||||
// (SILENT wrong, runtime-0). structlookupchain chases
|
||||
// to the base struct; cs fills via the resolved
|
||||
// Type*, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let sret_si: *structinfo = structlookup(c, sname);
|
||||
let sret_si: *structinfo = structlookupchain(c, trefn);
|
||||
if (sret_si != nil) {
|
||||
let emptys: str;
|
||||
emptys.ptr = nil; emptys.len = 0;
|
||||
@@ -2408,14 +2414,17 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// (the #17 silent-zero fix). Mirror of cstage cgen.c N_LET
|
||||
// structlit branch.
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: an alias-NAMED struct literal (`type rep2 = rep;
|
||||
// let r = rep2{id=6}`) parses its type ref as N_IDENT/N_TNAME
|
||||
// "rep2", but only the base `rep` is registered — bare
|
||||
// structlookup(c, "rep2") returns nil, so the fill never
|
||||
// fired: the slot zeroed + the lit DROPPED (≤8B silent) or
|
||||
// fell to the :2920 LOUD (>8B). structlookupchain chases the
|
||||
// alias chain to the base struct, the #92/W2 SSoT already
|
||||
// adopted at cgenstmt:1974/:2687. cs chases via
|
||||
// type_chase_named, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
let si: *structinfo = structlookupchain(c, trefn);
|
||||
if (si != nil) {
|
||||
cgstructlitfillbp(c, si, rhs, off);
|
||||
c.lastwasreturn = 0;
|
||||
|
||||
@@ -33730,14 +33730,20 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (okrhs) {
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: the >24B sret RETURN twin of the :2421
|
||||
// let-init fix. sretretsize chases the alias for
|
||||
// the size GATE (so this sret arm fires for a >24B
|
||||
// alias struct), but the field-fill resolved the
|
||||
// struct by a bare structlookup(c, sname): for an
|
||||
// alias-NAMED literal (`type biga = big; return
|
||||
// biga{...}`) sname is "biga", unregistered, so
|
||||
// sret_si was nil and the fill was SKIPPED — the
|
||||
// callee returned an uninitialised sret buffer
|
||||
// (SILENT wrong, runtime-0). structlookupchain chases
|
||||
// to the base struct; cs fills via the resolved
|
||||
// Type*, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let sret_si: *structinfo = structlookup(c, sname);
|
||||
let sret_si: *structinfo = structlookupchain(c, trefn);
|
||||
if (sret_si != nil) {
|
||||
let emptys: str;
|
||||
emptys.ptr = nil; emptys.len = 0;
|
||||
@@ -34898,14 +34904,17 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// (the #17 silent-zero fix). Mirror of cstage cgen.c N_LET
|
||||
// structlit branch.
|
||||
if (rhs.kind == nkind.N_STRUCTLIT) {
|
||||
// #63: an alias-NAMED struct literal (`type rep2 = rep;
|
||||
// let r = rep2{id=6}`) parses its type ref as N_IDENT/N_TNAME
|
||||
// "rep2", but only the base `rep` is registered — bare
|
||||
// structlookup(c, "rep2") returns nil, so the fill never
|
||||
// fired: the slot zeroed + the lit DROPPED (≤8B silent) or
|
||||
// fell to the :2920 LOUD (>8B). structlookupchain chases the
|
||||
// alias chain to the base struct, the #92/W2 SSoT already
|
||||
// adopted at cgenstmt:1974/:2687. cs chases via
|
||||
// type_chase_named, runtime-correct.
|
||||
let trefn: *node = rhs.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (trefn != nil) {
|
||||
if (trefn.kind == nkind.N_IDENT) { sname = trefn.str; }
|
||||
else { if (trefn.kind == nkind.N_TNAME) { sname = trefn.str; }; };
|
||||
};
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
let si: *structinfo = structlookupchain(c, trefn);
|
||||
if (si != nil) {
|
||||
cgstructlitfillbp(c, si, rhs, off);
|
||||
c.lastwasreturn = 0;
|
||||
|
||||
Reference in New Issue
Block a user