w6c: classify fn-value idents by the stamped TY_FN, not the leaf table
wwstage cgen re-derived fn-ness by NAME: cgident's fn arm gated on fnretlookup, whose cross-module leaf fallback matches a foreign same-leaf fn — inside aa.getv the bare `v` (aa's i32 global, stamped by the #55 prefer fix) took the fn-address arm for main's `fn v` and emitted LEAQ aa.v(SB) with no deref; the ww_ww-built 794 program exited 0 instead of 7. cstage reads the checker-stamped type (cgen.c:4315). Convert the three value-position sites to the stamp (same predicate-to-stamp conversion as the #14 F7-c7 `&fn` arm): cgident (now TY_FN -> def -> let, cstage's order — the def-first order also mis-read a foreign scalar def shadowed by a curmod fn), the cgdot module-qualified value arm, and the `&ident` #180 arm. Call-position fnretlookup consumers are unchanged. The 794 two-file program is now cs==ww byte-identical and both drivers run exit 7; the carrier retires in the follow-up.
This commit is contained in:
@@ -1227,6 +1227,25 @@ fn cgident(c: *cgen, n: *syntax.node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
// Fn-name used as a value (e.g. `let f = some_fn;`) — LEAQ the
|
||||
// symbol address into AX. Classified by the checker-STAMPED
|
||||
// TY_FN type, never by a name lookup: the unit-wide fnrets
|
||||
// table matches a foreign same-leaf fn (main.v shadowing aa's
|
||||
// i32 global while cgen'ing aa.getv — the #55 cgen-side
|
||||
// sibling), where the stamp already resolved via
|
||||
// scopelookupprefer. Arm order TY_FN → def → let mirrors
|
||||
// cstage cgexpr N_IDENT (cmd/w6c/cgen.c:4315-4374); same
|
||||
// predicate-to-stamp conversion as the #14 F7-c7 `&fn` arm
|
||||
// (cgen.ww nodefnptr). emitfnname still handles ffiresolve +
|
||||
// module-mangling, so a body-less FFI binding emits its
|
||||
// @symbol() name.
|
||||
let fu: *syntax.tinfo = tichase(n.type_: *syntax.tinfo);
|
||||
if (fu != nil && fu.kind == syntax.tykind.TY_FN) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, nm, c.curmod);
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
// Top-level `def` constant — load from its DATA symbol.
|
||||
// Str defs (rhs N_STRLIT) aren't laid out at a SB symbol; the
|
||||
// MOVQ symname(SB) fallback below would emit a bogus reference
|
||||
@@ -1274,19 +1293,6 @@ fn cgident(c: *cgen, n: *syntax.node) void = {
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
// Fn-name used as a value (e.g. `let f = some_fn;` or
|
||||
// `... = some_fn;`). LEAQ the symbol address into AX. The
|
||||
// emitfnname helper handles ffiresolve and module-mangling
|
||||
// in one go, so a body-less FFI binding emits the C symbol
|
||||
// it was declared with via @symbol(), not the ww-side ident.
|
||||
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
||||
let rtyp: *syntax.node = fnretlookup(c, nm);
|
||||
if (rtyp != nil) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, nm, c.curmod);
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
// Top-level mutable `let` — RIP-relative load from its DATAW
|
||||
// slot. Mirrors C cgen's catch-all `MOVQ masym(s), AX` for
|
||||
// scalar lets, plus the (LEAQ, MOVQ, MOVQ[, MOVQ]) sequence
|
||||
@@ -4652,8 +4658,13 @@ fn cgdot(c: *cgen, n: *syntax.node) void = {
|
||||
// lhs.str is the explicit module hint so a same-leaf
|
||||
// def in another module (head of c.fnrets) can't shadow
|
||||
// the explicit qualifier (#17 N_DOT-arm omission audit).
|
||||
let frt: *syntax.node = fnretlookupmod(c, fld, usehint(c, lhs.str));
|
||||
if (frt != nil) {
|
||||
// Fn value vs data read: classified by the STAMPED
|
||||
// TY_FN type, not fnretlookupmod — its leaf fallback
|
||||
// matches a curmod fn against a foreign scalar def
|
||||
// (`mod.MSG` under a curmod `fn MSG`) and emits LEAQ
|
||||
// where cstage MOVQs the data. #55 cgen-side class.
|
||||
let du: *syntax.tinfo = tichase(n.type_: *syntax.tinfo);
|
||||
if (du != nil && du.kind == syntax.tykind.TY_FN) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, fld, usehint(c, lhs.str));
|
||||
emitline("(SB), AX\n");
|
||||
@@ -5286,7 +5297,12 @@ fn cgun(c: *cgen, n: *syntax.node) void = {
|
||||
// (LEAQ + emitfnname(c, nm, c.curmod)). Previously
|
||||
// fell through silently — the AX-store at the
|
||||
// assign site picked up whatever AX held.
|
||||
if (fnretlookup(c, nm) != nil) {
|
||||
// Gate on the stamped TY_FN (cstage cgen.c amp
|
||||
// arm parity), not the name table — the leaf
|
||||
// fallback matches a foreign same-leaf fn
|
||||
// (#55 cgen-side class).
|
||||
let ou: *syntax.tinfo = tichase(opnd.type_: *syntax.tinfo);
|
||||
if (ou != nil && ou.kind == syntax.tykind.TY_FN) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, nm, c.curmod);
|
||||
emitline("(SB), AX\n");
|
||||
|
||||
Reference in New Issue
Block a user