w6c+wwstage: struct-array-field slice as call-arg via dotbaseaddr (#257)
An inline slice of a struct `[N]T`-field passed DIRECTLY as a call argument (`rd(x.o[lo:hi])`) materialized the slice .ptr from the field VALUE, not its ADDRESS: the pushargs/pushargsrev N_SLICE inline builder's non-ident else-arm did plain cgexpr(base), so the N_DOT field auto-derefs (MOVL field,AX used as .ptr) -> callee derefs garbage -> SEGFAULT. The let-init / assign-rhs / return / hoist-to-local contexts already routed through the cgslice #252 choke-point; only this call-arg builder kept a private duplicate. cs==ww both segfaulted identically pre-fix (gate-blind). Fix (symmetric both stages): - route the else-arm through cg_dotbase_addr / dotbaseaddr (the cgslice #252 choke-point: array-field-gated, so `[]T`/str/`*T` fields fall through to cgexpr; chained inner `o.p.m` handled via its #253 arm); - extend the N_IDENT-only esz gate to N_DOT bases, taking the element width from the checker-stamped base->type (rule-13 type table), so non-u8 call-arg slices scale stride. Before: `MOVL -8(BP),AX; PUSHQ AX` (field value as .ptr). After: `LEAQ -8(BP),AX; PUSHQ AX` (field address). cs==ww byte-identical. Helper note: used dotbaseaddr (not dotchainaddr as first scoped) — it is the established cgslice choke-point and is array-field-gated, so a slice/ str-typed field base keeps the correct cgexpr header-ptr load; bare dotchainaddr lacks that gate and would mis-emit the field address for those. dotbaseaddr already handles the chained `o.p.m` inner via #253. Tests: test/wcc/949 gains 6 call-arg rows (u8, i32-esz-stride, via-*struct, chained, + hoist-to-local and bare-local-array controls), each run- correctness AND cs==ww byte-id. PROOF-GREP residual: the tagged-union-element indexed-STORE arm (cgen.c:~4972 / cgenexpr.ww:~5024) is the same N_DOT-base auto-deref shape, still unrouted in BOTH stages (symmetric, segfaults) — a distinct consumption axis filed separately; NOT fixed here.
This commit is contained in:
@@ -15624,15 +15624,30 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #257: an N_DOT `[N]T`-field base (`x.o[lo:hi]` as a call
|
||||
// arg) carries no tnode — resolve esz / base-address from the
|
||||
// checker-stamped element tinfo on base.type_ instead. Cstage
|
||||
// twin reads base->type (cgen.c pushargs N_SLICE esz). Mirror
|
||||
// of the cgslice #252 site.
|
||||
let dotbu: *tinfo = nil;
|
||||
if (base != nil) { if (base.kind == nkind.N_DOT) {
|
||||
dotbu = base.type_: *tinfo;
|
||||
for (dotbu != nil && dotbu.kind == tykind.TY_NAMED) {
|
||||
dotbu = dotbu.under;
|
||||
};
|
||||
};};
|
||||
// esz from the type table for an N_IDENT base (#76; mirrors
|
||||
// the cgindex idiom). Non-ident base stays esz=1 -> ptr
|
||||
// unscaled, matching cstage's base->kind==N_IDENT gate.
|
||||
// the cgindex idiom) or an N_DOT array/slice-field base (#257:
|
||||
// scale by the field's element width, not esz=1 -> silently
|
||||
// wrong for non-u8). Other non-ident bases stay esz=1.
|
||||
let esz: i32 = 1;
|
||||
if (baselocal != nil) {
|
||||
esz = elemsizeofc(c, baselocal.tnode);
|
||||
} else { if (globaltn != nil) {
|
||||
esz = elemsizeofc(c, globaltn);
|
||||
};};
|
||||
} else { if (dotbu != nil && dotbu.sub != nil) {
|
||||
esz = dotbu.sub.size: i32;
|
||||
};};};
|
||||
// base address → push
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
@@ -15661,9 +15676,14 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitsymname(c, globalname);
|
||||
emitline("(SB), AX\n");
|
||||
};
|
||||
} else { if (dotbaseaddr(c, base, "AX")) {
|
||||
// #257: N_DOT `[N]T`-field base as a call arg → field
|
||||
// ADDRESS (LEAQ), not the auto-deref VALUE load cgexpr
|
||||
// emits. Same choke-point as the cgslice #252 site;
|
||||
// `[]T`/str/`*T` fields fall through to cgexpr.
|
||||
} else {
|
||||
cgexpr(c, base);
|
||||
};};
|
||||
};};};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
// hi (default base length) → push
|
||||
if (hi != nil) {
|
||||
|
||||
Reference in New Issue
Block a user