w6c: fall to the place resolver for indexed dot-chain aggregate sources
The dot-chain SOURCE-address walkers (cg_dotchain_addr / dotchainaddr) deliberately have no index hop — their AX-clean spill contract serves the chained dotbase arm — so an aggregate copy from elem[k].field (N_DOT over N_INDEX) fell out of the walk. Every aggarg_srcaddr consumer loud-stopped (arg push #271, aggregate return #272, field assign, structlit fill, ident reassign) EXCEPT the indexed element-store arm, which left the walker's result UNCHECKED and copied through a stale SI — a silent both-stage miscompile (out[j] = hs[k].result read garbage). Task #6. Both stages, two twin edits each: the aggarg_srcaddr N_DOT arm falls back to cgplaceaddr (the C4/#40 place resolver, emission-free-on- failure so the fallback starts clean), and the indexed store site checks the walker before the same fallback. Still loud (filed follow-ups): auto-deref pointer-to-array indexed bases (hs: *[4]T; hs[k].field — cgplaceaddr's index arm takes no deref hop; the explicit (*hs)[k].field form works), and the bare N_INDEX slice-element aggregate source.
This commit is contained in:
@@ -1689,7 +1689,13 @@ fn aggargsrcaddr(c: *cgen, src: *syntax.node, dst: str) bool = {
|
||||
return false;
|
||||
};
|
||||
if (src.kind == syntax.nkind.N_DOT) {
|
||||
return dotchainaddr(c, src, dst);
|
||||
if (dotchainaddr(c, src, dst)) { return true; };
|
||||
// task #6: an N_INDEX link inside the dot chain
|
||||
// (handles[k].result) — the chain walker has no index hop
|
||||
// (AX-clean spill contract for dotbaseaddr); the place
|
||||
// resolver is the C4/#40 fallback, and the failed walk is
|
||||
// emission-free so the fallback starts clean.
|
||||
return cgplaceaddr(c, src, dst);
|
||||
};
|
||||
if (src.kind == syntax.nkind.N_INDEX) {
|
||||
let base: *syntax.node = src.lhs;
|
||||
@@ -9778,15 +9784,26 @@ fn cgassign(c: *cgen, n: *syntax.node) void = {
|
||||
emitsymname(c, n.rhs.str);
|
||||
emitline("(SB), SI\n");
|
||||
};
|
||||
} else { if (n.rhs.kind == syntax.nkind.N_DOT) {
|
||||
dotchainaddr(c, n.rhs, "SI");
|
||||
} else {
|
||||
if (!cgplaceaddr(c, n.rhs, "SI")) {
|
||||
let msrc: str = "indexed aggregate assignment source unresolved\n";
|
||||
os.write(2, msrc.ptr, msrc.len: u64);
|
||||
os.exit(1);
|
||||
// task #6: the chain walker
|
||||
// declines an N_INDEX link
|
||||
// (emission-free) — its result
|
||||
// was unchecked here, so the
|
||||
// copy below read through a
|
||||
// stale SI. Fall to the
|
||||
// generic place resolver.
|
||||
let dok: bool = false;
|
||||
if (n.rhs.kind == syntax.nkind.N_DOT) {
|
||||
dok = dotchainaddr(c, n.rhs, "SI");
|
||||
};
|
||||
};};};
|
||||
if (!dok) {
|
||||
if (!cgplaceaddr(c, n.rhs, "SI")) {
|
||||
let msrc: str = "indexed aggregate assignment source unresolved\n";
|
||||
os.write(2, msrc.ptr, msrc.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
};};
|
||||
emitline("\tPOPQ\tBX\n"); // dest
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
|
||||
Reference in New Issue
Block a user