w6c+w6c_ww: box [N]tagged array-literal elements via the tagged-store path (fix #12)
A [N]tagged-union array-literal element fell through the is_agg multi-word-copy path (STRUCT/ARRAY/TUPLE/str/slice only) to the scalar 1-word store: the raw value landed in word 0 (the tag slot) with no tag written and no payload boxed, so a later match found no variant. Both stages under-copied identically, so the copy-depth bug was byte-id-blind — a stride-only fix would still store 1 word and pass the gate green on both-wrong. Route each tagged element through cg_widen_tagged_store / the N_LET "BP" tagged-store wrapper — the same choke-point let-init, vararg gather and struct-field stores already use — so boxing, tag-remap and zero-pad-to- slot come for free. esz now comes from the stamped slot size (rule-13); the wwstage narrow override only covered widths 1/2/4, leaving a 16/24B tagged element on the wrong 8-byte sentinel stride. rule-7 loud-stops the unwired `[N]tagged=[x...]` repeat-fill (the widen call consumes the node and trashes AX). test/wcc/685: table-driven runtime readback (106/42/13) + a build-fail row for the repeat-fill loud-stop, both stages.
This commit is contained in:
@@ -29634,6 +29634,17 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
let isslicel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_SLICE;
|
||||
if (isslicel) { esz = esubti.size: i32; };
|
||||
// #12: a tagged-union element. NOT folded into isagg —
|
||||
// isagg's body word-copies/fatals and never boxes the
|
||||
// tag+payload; route through the cgwidentaggedstore
|
||||
// choke-point the N_LET tagged path (cgenstmt.ww:1627)
|
||||
// uses. esz must come from the stamped slot size (#8-class
|
||||
// trap, rule-13): the narrow override below only rescues
|
||||
// 1/2/4, so a tagged 16/24B element keeps the wrong 8
|
||||
// sentinel stride without this.
|
||||
let istaggedel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_TAGGED;
|
||||
if (istaggedel) { 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
|
||||
@@ -29721,6 +29732,8 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else { if (istaggedel) {
|
||||
cgwidentaggedstore(c, esubti, e, "BP", off + idx * esz, esz);
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel || isslicel) {
|
||||
@@ -29746,7 +29759,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
};
|
||||
}; };
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
@@ -29756,6 +29769,14 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// #12: `...` re-stores from AX, but cgwidentaggedstore consumed
|
||||
// the node and trashed AX — the repeat-fill would write garbage.
|
||||
// No consumer needs `[N]tagged=[x,...]`.
|
||||
if (repeat && istaggedel) {
|
||||
let m12r: str = "#12: `...` repeat of a tagged-union array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m12r.ptr, m12r.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
|
||||
Reference in New Issue
Block a user