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;
|
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.
|
// Top-level `def` constant — load from its DATA symbol.
|
||||||
// Str defs (rhs N_STRLIT) aren't laid out at a SB symbol; the
|
// Str defs (rhs N_STRLIT) aren't laid out at a SB symbol; the
|
||||||
// MOVQ symname(SB) fallback below would emit a bogus reference
|
// 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");
|
emitline("(SB), AX\n");
|
||||||
return;
|
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
|
// Top-level mutable `let` — RIP-relative load from its DATAW
|
||||||
// slot. Mirrors C cgen's catch-all `MOVQ masym(s), AX` for
|
// slot. Mirrors C cgen's catch-all `MOVQ masym(s), AX` for
|
||||||
// scalar lets, plus the (LEAQ, MOVQ, MOVQ[, MOVQ]) sequence
|
// 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
|
// lhs.str is the explicit module hint so a same-leaf
|
||||||
// def in another module (head of c.fnrets) can't shadow
|
// def in another module (head of c.fnrets) can't shadow
|
||||||
// the explicit qualifier (#17 N_DOT-arm omission audit).
|
// the explicit qualifier (#17 N_DOT-arm omission audit).
|
||||||
let frt: *syntax.node = fnretlookupmod(c, fld, usehint(c, lhs.str));
|
// Fn value vs data read: classified by the STAMPED
|
||||||
if (frt != nil) {
|
// 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");
|
emitline("\tLEAQ\t");
|
||||||
emitfnname(c, fld, usehint(c, lhs.str));
|
emitfnname(c, fld, usehint(c, lhs.str));
|
||||||
emitline("(SB), AX\n");
|
emitline("(SB), AX\n");
|
||||||
@@ -5286,7 +5297,12 @@ fn cgun(c: *cgen, n: *syntax.node) void = {
|
|||||||
// (LEAQ + emitfnname(c, nm, c.curmod)). Previously
|
// (LEAQ + emitfnname(c, nm, c.curmod)). Previously
|
||||||
// fell through silently — the AX-store at the
|
// fell through silently — the AX-store at the
|
||||||
// assign site picked up whatever AX held.
|
// 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");
|
emitline("\tLEAQ\t");
|
||||||
emitfnname(c, nm, c.curmod);
|
emitfnname(c, nm, c.curmod);
|
||||||
emitline("(SB), AX\n");
|
emitline("(SB), AX\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user