cgen: route non-named callee to indirect CALL AX (wwstage #181-cgen)

Discovered while verifying #181's checker fix end-to-end: wwstage's
cgcall pre-computes `isfnptrcall` only for N_IDENT (local) and
N_DOT (struct fn-ptr field) callees. For a non-named callee — the
deref-call `(*f)(...)` shape (N_UN TK_STAR) most prominently — the
flag stayed false, the IDENT/DOT name-emit branches both missed,
and the emit produced `CALL (SB)` with an empty symbol.

Cstage handles this naturally via its default-fallthrough at
cmd/w6c/cgen.c:5918-5921 — `else { cgexpr(c, n->lhs, locals);
ins1(c, A_CALL, areg(D_AX)); }` catches every callee shape that
isn't bare-IDENT module-fn or N_DOT module-qualified call. The
fix here mirrors that fallthrough: any callee whose kind is
neither N_IDENT nor N_DOT sets isfnptrcall = true, routing
through the existing cgexpr-into-AX + CALL AX path.

Combined.ww regenerated for selfhost/cmd/{w6c,wwdump}/main
.combined.ww per #110 freshness gate.

Lands as a follow-up to the #181 checker bail-lift: the checker
now stamps the deref-call N_CALL (so cgen runs), and with this
fix the wwstage cgen lowers it correctly. test/wcc/766's wwstage
+byte-id rows go green; runtime symmetry with cstage holds.
This commit is contained in:
2026-05-28 20:13:07 +09:00
parent ba044e206d
commit 595577f606
3 changed files with 39 additions and 0 deletions

View File

@@ -21659,6 +21659,19 @@ fn cgcall(c: *cgen, n: *node) void = {
isfnptrcall = true;
};
};
// #181-cgen: a non-named callee (`(*f)(...)` → N_UN TK_STAR,
// or any other expression-valued fn) is an indirect call.
// cgexpr the callee into AX; CALL AX. Mirrors cstage's
// default-fallthrough at cmd/w6c/cgen.c:5918-5921 which
// catches every callee shape that isn't a bare-IDENT module
// fn or N_DOT module-qualified call. Pre-fix wwstage emitted
// `CALL (SB)` (empty symbol) for the N_UN-callee shape — the
// IDENT/DOT name-emit branches missed and isfnptrcall stayed
// false.
if (callee.kind != nkind.N_IDENT
&& callee.kind != nkind.N_DOT) {
isfnptrcall = true;
};
if (callee.kind == nkind.N_DOT) {
let base: *node = callee.lhs;
let fld: str = callee.str;

View File

@@ -4099,6 +4099,19 @@ fn cgcall(c: *cgen, n: *node) void = {
isfnptrcall = true;
};
};
// #181-cgen: a non-named callee (`(*f)(...)` → N_UN TK_STAR,
// or any other expression-valued fn) is an indirect call.
// cgexpr the callee into AX; CALL AX. Mirrors cstage's
// default-fallthrough at cmd/w6c/cgen.c:5918-5921 which
// catches every callee shape that isn't a bare-IDENT module
// fn or N_DOT module-qualified call. Pre-fix wwstage emitted
// `CALL (SB)` (empty symbol) for the N_UN-callee shape — the
// IDENT/DOT name-emit branches missed and isfnptrcall stayed
// false.
if (callee.kind != nkind.N_IDENT
&& callee.kind != nkind.N_DOT) {
isfnptrcall = true;
};
if (callee.kind == nkind.N_DOT) {
let base: *node = callee.lhs;
let fld: str = callee.str;

View File

@@ -21659,6 +21659,19 @@ fn cgcall(c: *cgen, n: *node) void = {
isfnptrcall = true;
};
};
// #181-cgen: a non-named callee (`(*f)(...)` → N_UN TK_STAR,
// or any other expression-valued fn) is an indirect call.
// cgexpr the callee into AX; CALL AX. Mirrors cstage's
// default-fallthrough at cmd/w6c/cgen.c:5918-5921 which
// catches every callee shape that isn't a bare-IDENT module
// fn or N_DOT module-qualified call. Pre-fix wwstage emitted
// `CALL (SB)` (empty symbol) for the N_UN-callee shape — the
// IDENT/DOT name-emit branches missed and isfnptrcall stayed
// false.
if (callee.kind != nkind.N_IDENT
&& callee.kind != nkind.N_DOT) {
isfnptrcall = true;
};
if (callee.kind == nkind.N_DOT) {
let base: *node = callee.lhs;
let fld: str = callee.str;