wcc: cgdot/cgident dead-end paths are loud (rule 7)

cgdot's local-ident arm silently emitted nothing for a receiver
whose local record carries no type node (inference miss upstream),
leaving the consumer reading stale AX. cgident's tail silently
emitted nothing for any ident that resolved to no local/fn/def/let;
that silence is load-bearing ONLY for the #140 !void error-singleton
value (tag-only, the widen arm stamps the tag) -- keep exactly that
case, mirroring the cstage #140 guard, and hard-stop the rest.
This commit is contained in:
2026-08-09 00:15:10 +09:00
parent 57d33acd1f
commit f0029227b5

View File

@@ -1388,7 +1388,19 @@ fn cgident(c: *cgen, n: *syntax.node) void = {
};
return;
};
return;
// #140: a `!void` error-singleton spelled as a VALUE (`return
// toolong;`) is tag-only — the void payload has size 0 and no
// storage, so it is neither a local, def, nor let. Emit NOTHING;
// the enclosing widen arm stamps the variant tag. Mirrors cstage
// cgen.c N_IDENT #140 guard. Every other unresolvable ident is
// checker-rejected upstream — loud, never the old silent return.
{
let vu: *syntax.tinfo = tichase(n.type_: *syntax.tinfo);
if (vu != nil && vu.kind == syntax.tykind.TY_VOID) { return; };
};
let mur: str = "cgident: unresolvable identifier (rule 7)\n";
os.write(2, mur.ptr, mur.len: u64);
os.exit(1);
};
// cgslicehdr — load the 24B slice/str header at base+0 into the
@@ -3707,7 +3719,16 @@ fn cgdot(c: *cgen, n: *syntax.node) void = {
};
tn = nx;
};
if (tn == nil) { return; };
// A registered local with NO type node means
// inference missed upstream — emitting nothing
// leaves the consumer reading stale AX, and
// falling through would emit a bogus
// `MOVQ <fld>(SB)` (the #191 hazard). Loud.
if (tn == nil) {
let mdt: str = "cgdot: local receiver has no type node (rule 7)\n";
os.write(2, mdt.ptr, mdt.len: u64);
os.exit(1);
};
let lkind: syntax.nkind = tn.kind;
// Pointer-to-struct: deref then field load.
if (lkind == syntax.nkind.N_TPTR) {