wcc/ww: compound OP= on a tagged index/ident is a loud reject (#20/#21)
Compound `OP=` through an index (gs[i]/a[i]) or a bare ident (g) on a tagged union silently misbehaved: cstage dropped the index compound and plain-stored, and BOTH stages compiled an ident compound into an add on the tag word -- byte-identical, so the gate stayed green while the tag was corrupted. A compound op on a whole union is nonsense. Gate the index plain-store arm on TK_ASSIGN so a compound falls to the existing #133 reject (wwstage's byte-id twin); add a dedicated #21 ident reject in both stages. This closes the compound half of the tagged-payload write class (deref #18, dot #34 already reject). #19 (global tagged-array static-init DATA) is a separate emitter, still open.
This commit is contained in:
@@ -6483,8 +6483,16 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* the full cg_widen_tagged_store machinery — scalar /
|
||||
* str / struct / subset payloads, tag remap, nullable
|
||||
* fold — without duplicating it. The scratch lives in
|
||||
* the function frame; no cleanup needed. */
|
||||
if ((is_arr || is_sl || is_ptr) && elem_tagged) {
|
||||
* the function frame; no cleanup needed.
|
||||
* #20: only a PLAIN `=` widens. A COMPOUND `gs[i] OP= v`
|
||||
* on a tagged element is nonsense — without the
|
||||
* TK_ASSIGN gate it dropped the OP and plain-stored the
|
||||
* RHS (silent miscompile, cs!=ww). The gate lets a
|
||||
* compound fall to the #133 indexed-compound arm below,
|
||||
* whose elem_tagged guard rejects loud (the byte-id
|
||||
* twin of wwstage, which already rejected via #133). */
|
||||
if ((is_arr || is_sl || is_ptr) && elem_tagged
|
||||
&& n->op == TK_ASSIGN) {
|
||||
int ssz = esz;
|
||||
int scr = cg_tagscr_slot(c, &locals, ssz);
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
@@ -6972,6 +6980,20 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* #21: a COMPOUND op on a whole tagged-union IDENT (`g OP= v`
|
||||
* with g:(int|bool)) is nonsense — the ident load-combine-
|
||||
* store tail below (the N_IDENT compound arm) reads and writes
|
||||
* one word of the {payload,tag} box, corrupting the tag. Reject
|
||||
* loud here, the ident twin of the #18 deref / #133 index
|
||||
* rejects; the byte-id twin of the wwstage guard. Plain `=`
|
||||
* (the tagged-ident reassign arm just below) is untouched. */
|
||||
if (n->lhs && n->lhs->kind == N_IDENT && n->op != TK_ASSIGN
|
||||
&& n->lhs->type) {
|
||||
Type *itu = type_chase_named(n->lhs->type);
|
||||
if (itu && itu->kind == TY_TAGGED)
|
||||
fatal("ident compound on tagged not wired "
|
||||
"(#21/rule-7)");
|
||||
}
|
||||
/* Plain `r = expr;` where r is a tagged-union local.
|
||||
* Delegates to cg_widen_tagged_store: covers nullable fold,
|
||||
* tagged→tagged (with tag remap), struct payload (ident or
|
||||
|
||||
Reference in New Issue
Block a user