wcc/cgen: #119 scalar &fn global DATA via the #117 reloc helper (both-stage)

This commit is contained in:
2026-06-06 20:28:50 +09:00
parent 942abf0482
commit 1b4f25ac45
5 changed files with 94 additions and 9 deletions

View File

@@ -15359,6 +15359,25 @@ emit_lets(Cg *c, FILE *out, Node *file)
Node *r = d->rhs;
while (r != NULL && r->kind == N_CAST) r = r->lhs;
if (r == NULL) continue;
/* #119: a scalar `&fn` global — 8B zero ptr
* placeholder + the &fn->DATAR reloc (the #117
* helper at its second consumer). Pre-#119 this
* fell through fold_int_literal -> continue -> no
* DATA -> undefined ref / garbage deref. */
{
const char *fsym = node_fnptr_sym(c, r);
if (fsym != NULL) {
const char *sym = mod_mangle_value(c,
d->str, d->module);
fprintf(out, "DATAW %s(SB),\"", sym);
for (int i = 0; i < 8; i++)
emit_data_byte(out, 0);
fputs("\"\n", out);
fprintf(out, "DATAR %s+0(SB),%s(SB)\n",
sym, fsym);
continue;
}
}
/* Same helper as emit_defs (#24): widens
* the gate to cover N_UN(TK_MINUS/TILDE/PLUS,
* leaf) so `let x: i8 = -1i8;` and friends

View File

@@ -40247,8 +40247,10 @@ fn emitletdataw(c: *cgen, file: *node) void = {
if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) {
let v: u64 = 0u64;
let ok: bool = true;
let fnp: bool = false;
let r: *node = nil;
if (d.rhs != nil) {
let r: *node = d.rhs;
r = d.rhs;
for (r != nil) {
if (r.kind != nkind.N_CAST) { break; };
r = r.lhs;
@@ -40258,9 +40260,24 @@ fn emitletdataw(c: *cgen, file: *node) void = {
// int leaf folds. `let x: i8 = -1i8;`
// arrives as N_UN(TK_MINUS, N_INTLIT)
// after the typed-AST cast peel.
ok = foldintliteral(r, &v);
// #119: a scalar `&fn` global — the &fn->DATAR
// reloc (the #117 helper at its second consumer).
if (nodefnptr(c, r)) { fnp = true; }
else { ok = foldintliteral(r, &v); };
};
if (ok) {
if (fnp) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");
let zi: i32 = 0;
for (zi < 8) { emitdatawbyte(0u8); zi += 1; };
emitline("\"\n");
emitline("DATAR ");
emitsymnamehint(c, nm, d.nmod);
emitline("+0(SB),");
emitfnname(c, r.lhs.str, c.curmod);
emitline("(SB)\n");
} else if (ok) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");

View File

@@ -2693,8 +2693,10 @@ fn emitletdataw(c: *cgen, file: *node) void = {
if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) {
let v: u64 = 0u64;
let ok: bool = true;
let fnp: bool = false;
let r: *node = nil;
if (d.rhs != nil) {
let r: *node = d.rhs;
r = d.rhs;
for (r != nil) {
if (r.kind != nkind.N_CAST) { break; };
r = r.lhs;
@@ -2704,9 +2706,24 @@ fn emitletdataw(c: *cgen, file: *node) void = {
// int leaf folds. `let x: i8 = -1i8;`
// arrives as N_UN(TK_MINUS, N_INTLIT)
// after the typed-AST cast peel.
ok = foldintliteral(r, &v);
// #119: a scalar `&fn` global — the &fn->DATAR
// reloc (the #117 helper at its second consumer).
if (nodefnptr(c, r)) { fnp = true; }
else { ok = foldintliteral(r, &v); };
};
if (ok) {
if (fnp) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");
let zi: i32 = 0;
for (zi < 8) { emitdatawbyte(0u8); zi += 1; };
emitline("\"\n");
emitline("DATAR ");
emitsymnamehint(c, nm, d.nmod);
emitline("+0(SB),");
emitfnname(c, r.lhs.str, c.curmod);
emitline("(SB)\n");
} else if (ok) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");

View File

@@ -40247,8 +40247,10 @@ fn emitletdataw(c: *cgen, file: *node) void = {
if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) {
let v: u64 = 0u64;
let ok: bool = true;
let fnp: bool = false;
let r: *node = nil;
if (d.rhs != nil) {
let r: *node = d.rhs;
r = d.rhs;
for (r != nil) {
if (r.kind != nkind.N_CAST) { break; };
r = r.lhs;
@@ -40258,9 +40260,24 @@ fn emitletdataw(c: *cgen, file: *node) void = {
// int leaf folds. `let x: i8 = -1i8;`
// arrives as N_UN(TK_MINUS, N_INTLIT)
// after the typed-AST cast peel.
ok = foldintliteral(r, &v);
// #119: a scalar `&fn` global — the &fn->DATAR
// reloc (the #117 helper at its second consumer).
if (nodefnptr(c, r)) { fnp = true; }
else { ok = foldintliteral(r, &v); };
};
if (ok) {
if (fnp) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");
let zi: i32 = 0;
for (zi < 8) { emitdatawbyte(0u8); zi += 1; };
emitline("\"\n");
emitline("DATAR ");
emitsymnamehint(c, nm, d.nmod);
emitline("+0(SB),");
emitfnname(c, r.lhs.str, c.curmod);
emitline("(SB)\n");
} else if (ok) {
emitline("DATAW ");
emitsymnamehint(c, nm, d.nmod);
emitline("(SB),\"");

View File

@@ -129,6 +129,21 @@ static const struct row rows[] = {
" if (len(tbl) != 3) { return 1; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* #119: scalar &fn module-globals — DISTINCT fns, each called back
* through the reloc (pre-#119: no DATA → undefined ref / garbage). */
{ "scalar_fnptr",
"package main;\n"
"fn fa(c: rune) bool = { return c == 'a'; };\n"
"fn fz(c: rune) bool = { return c == 'z'; };\n"
"let pf: *fn(c: rune) bool = &fa;\n"
"let pg: *fn(c: rune) bool = &fz;\n"
"export fn main() i32 = {\n"
" if (!(*pf)('a')) { return 1; };\n"
" if ((*pf)('z')) { return 2; };\n"
" if (!(*pg)('z')) { return 3; };\n"
" if ((*pg)('a')) { return 4; };\n"
" return 0;\n"
"};\n", 0, K_RUN, NULL },
/* honest boundary (rule 7): a non-tuple aggregate element (here a
* bare []str) stays LOUD, symmetric both stages — #117 is NARROW to
* the (str,*fn) tuple form, not the full slice-of-aggregate family. */