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:
@@ -9059,6 +9059,13 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
int is_agg = esubu && (esubu->kind == TY_STRUCT
|
||||
|| esubu->kind == TY_ARRAY
|
||||
|| esubu->kind == TY_TUPLE);
|
||||
/* #12: a tagged-union element. NOT folded into is_agg —
|
||||
* is_agg's body does N_STRUCTLIT/N_IDENT word-copy and
|
||||
* FATALs on the literal/scalar case, never boxing the
|
||||
* tag+payload. Route each element through the same
|
||||
* cg_widen_tagged_store choke-point every other tagged
|
||||
* store uses (let-init, vararg gather, struct-field). */
|
||||
int is_tagged_el = esubu && esubu->kind == TY_TAGGED;
|
||||
int is_str_el = type_isstr(esub);
|
||||
/* #20/#270 str-slice arm: a slice element is a 24B
|
||||
* {ptr,len,cap} header just like str; cgexpr lowers it
|
||||
@@ -9144,6 +9151,13 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
if (is_tagged_el) {
|
||||
cg_widen_tagged_store(c, locals, esub,
|
||||
e, D_BP, base, esz);
|
||||
last = e;
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
cgexpr(c, e, *locals);
|
||||
if (is_str_el || is_slice_el) {
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
@@ -9165,6 +9179,12 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
if (repeat && is_agg)
|
||||
fatal("#270-1c: `...` repeat of an aggregate "
|
||||
"array-literal element not wired (rule-7)");
|
||||
/* #12: `...` re-stores from AX, but cg_widen_tagged_store
|
||||
* consumed the node and trashed AX — a repeat-fill would
|
||||
* write garbage. No consumer needs `[N]tagged=[x,...]`. */
|
||||
if (repeat && is_tagged_el)
|
||||
fatal("#12: `...` repeat of a tagged-union "
|
||||
"array-literal element not wired (rule-7)");
|
||||
if (repeat && last) {
|
||||
/* fill remaining slots with the value still in
|
||||
* AX (and BX for str). */
|
||||
|
||||
Reference in New Issue
Block a user