wcc/ww: match on a global value-struct tagged field reads g(SB) (#29)
A match whose scrutinee is a tagged field of a GLOBAL value-struct read the tag/payload from the BP region (saved-BP + return-addr) instead of g(SB) and returned garbage. Both stages were identical-wrong, so the byte-id gate could not see it -- a gate-blind regression introduced by M1 (#25): M1's in-place N_DOT match arm uses localfind(base), which returns the 0 not-found sentinel for a global base, so 0+field.offset landed in the frame. Gate the in-place arm on a confirmed-local base -- `localfind(base)==0 && let_islet/isletvar(base)`, verbatim from cstage's own global test at cgen.c:2000 (both stages, same spelling). A global base now falls through to the existing spill path, which cgexprs the scrutinee and resolves g(SB). M1's local-field in-place ($32) path is untouched. Regenerates the w6c and wwdump combined.ww. Table-driven 841 test (global int/reassign/str-payload + a local-field M1 regression row), runtime-discriminating: pre-fix returns garbage, post-fix 42 on both stages; rob's direct-global-field spill caveat confirmed at runtime.
This commit is contained in:
@@ -10243,7 +10243,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* `match (p.field)` — point sl_off at the field's slot
|
||||
* inside the parent struct. The slot layout (tag at +0,
|
||||
* value words at +8/+16) is contiguous within the struct,
|
||||
* so no spill is needed. */
|
||||
* so no spill is needed. #29: gated below on a
|
||||
* CONFIRMED-LOCAL base — a global base (`match (g.field)`)
|
||||
* has localfind==0, so 0+field.offset would land in the
|
||||
* saved-BP/return-addr region; it falls through to the
|
||||
* spill `else`, which resolves g(SB). */
|
||||
Type *bt = s->lhs->type;
|
||||
Type *bu = type_chase_named(bt);
|
||||
Tfield *f = NULL;
|
||||
@@ -10254,8 +10258,8 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f) {
|
||||
int boff = localfind(locals, s->lhs->str);
|
||||
int boff = f ? localfind(locals, s->lhs->str) : 0;
|
||||
if (f && !(boff == 0 && let_islet(s->lhs->str))) {
|
||||
sl_off = boff + (int)f->offset;
|
||||
} else {
|
||||
/* fall back to spill — `match (h.e)` where
|
||||
|
||||
Reference in New Issue
Block a user