w6c_ww/cgen: size [N]enum element from tinfo not slotsize (fix #8)
wwstage sized a named-enum array element (`[N]tk`, tk = enum i32) as a
raw 8-byte slot instead of its i32 backing (4), via two sibling code
paths that both derived the element width structurally and missed the
enum's underlying size:
- elemsizeofc (cgenutil.ww) was the odd-one-out among the elem*c
helpers: elemissignedc/elemisfloatc already read the checker-stamped
tinfo (t.type_.sub), but elemsizeofc went elemsizeof->primsize->
slotsize, and primsize("tk")=0 fell through to 8. This drove the
cgindex READ: `a[i]` strode by 8 (MOVQ) where cstage strode by 4
(MOVSXD), reading the wrong/out-of-bounds element for i>=1.
- the array-literal init STORE (cgenstmt.ww) computed its own esz the
same way (primsize=0 -> stayed at the 8 sentinel, enum is not an
aggregate), so a local `[N]enum` literal stored at stride 8 into a
stride-4 frame slot, overrunning it and smashing the saved BP /
return addr -> wwstage-built binary SEGFAULTED.
Both align UP to cstage, which reads the stamped element size uniformly
(N_INDEX idx_eff(bt)->sub->size; N_LET array-init lu->sub->size,
cgen.c:6387). The read fix brings all four elem*c helpers onto the same
tinfo SSoT; the store fix takes the stamped element size for a narrow
scalar. Closing both close-by-construction at the size source.
No in-tree [N]enum / aliased-narrow element existed before kwtab, so
this was byte-id-gate-blind until now. test/wcc/682_arr_enum_elem.c
pins it table-driven: global+local reads, local init-store, signed
sign-extend, and a frame-smash row, each run through both stages with
exit-code and cstage==wwstage asm-byte-id checks.
This commit is contained in:
@@ -16757,6 +16757,26 @@ fn elemsizeofc(c: *cgen, t: *node) i32 = {
|
||||
};
|
||||
let direct: i32 = elemsizeof(t);
|
||||
if (direct != 8) { return direct; };
|
||||
// #8: direct==8 is elemsizeof's "unresolved alias/aggregate" sentinel.
|
||||
// Read the element width off the checker-stamped tinfo, mirroring the
|
||||
// sibling elem*c helpers (elemissignedc :915, elemisfloatc :939, which
|
||||
// already read t.type_.sub) and cstage idx_eff(bt)->sub->size
|
||||
// (cmd/w6c/cgen.c N_INDEX). elemsizeofc was the odd-one-out among the
|
||||
// elem*c family — it derived size purely structurally, so a named-narrow
|
||||
// element (`[N]tkind`, tkind = enum i32) slipped through to a raw 8B slot
|
||||
// instead of its i32 backing (4), wrong-striding both the cgindex READ
|
||||
// and the local-array-init STORE (frame-smash). Peel TY_NAMED on the
|
||||
// indexable and on its element, matching the #270-2 nested-array block
|
||||
// above. Structural slotsize fallback stays for the t.type_==nil case.
|
||||
let ti: *tinfo = t.type_: *tinfo;
|
||||
if (ti != nil) {
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti != nil) {
|
||||
let esub: *tinfo = ti.sub;
|
||||
for (esub != nil && esub.kind == tykind.TY_NAMED) { esub = esub.under; };
|
||||
if (esub != nil) { return esub.size: i32; };
|
||||
};
|
||||
};
|
||||
let k: nkind = t.kind;
|
||||
let elem: *node = nil;
|
||||
if (k == nkind.N_TPTR) { elem = t.lhs; };
|
||||
@@ -29491,6 +29511,20 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
// #8: a named-narrow element (`[N]tk`, tk = enum i32) is
|
||||
// neither a builtin prim (primsize=0 above, so esz stayed
|
||||
// the 8 sentinel) nor an aggregate, so the scalar store kept
|
||||
// an 8B stride/MOVQ and overran the stride-4 frame slot —
|
||||
// smashing the saved BP / return addr (SEGFAULT). Mirror
|
||||
// cstage's uniform lu->sub->size (cgen.c:6387) and the
|
||||
// elemsizeofc read-side fix: take the stamped element tinfo's
|
||||
// size for a narrow scalar (1/2/4). Wider non-prim elements
|
||||
// (tagged/slice/str two-half) stay the documented follow-up
|
||||
// at :1742-1744 — the single-MOVx store below is scalar-only.
|
||||
if (!isstrel && !isagg && esz == 8 && esubti != nil) {
|
||||
let es: i32 = esubti.size: i32;
|
||||
if (es == 1 || es == 2 || es == 4) { esz = es; };
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
|
||||
Reference in New Issue
Block a user