cmd+selfhost+test: gate alloc builtin behind same-module fn alloc

Mirrors the existing abort/assert gates in cstage check.c (strict
same-module lookup rather than scope_lookup_prefer, since lib/os.alloc
under a `use os;` import must not suppress the bare-alloc builtin in
client code). cgen.c shadows the resolution: only fire the rt_alloc
path when the typer left N_CALL.lhs->type == ty_err. wwstage gets a
new samemodfn helper for the matching gate.

Test fixtures: package-main repair for the 3 alloc rows in 700_e2e.c
that the parser was inheriting curmod="os" from the concat'd os.ww;
new shadow-test row asserts a same-module `fn alloc(n: i64) i64`
beats the builtin in cgen.
This commit is contained in:
2026-05-19 18:51:07 +09:00
parent 58e6d349a2
commit 3fe968c8a0
7 changed files with 148 additions and 18 deletions

View File

@@ -2938,10 +2938,19 @@ fn cgcall(c: *cgen, n: *node) void = {
// value's bytes. For struct literals, lower to rt_alloc
// + per-field stores. Mirrors cmd/w6c/cgen.c's N_CALL
// alloc path.
//
// Same-module-scope guard: skip the builtin when a fn
// `alloc` is declared in the current module (lib/os and
// rt/ensure both shadow it). Mirrors cstage check.c's
// scope_lookup_prefer gating on the `abort` precedent;
// without it, the bare same-module call lands in the
// typed-builtin path and shadows the user decl. Task #23.
if (streq(callee.str, "alloc")) {
if (n.list != nil) {
cgalloc(c, n);
return;
if (!samemodfn(c, "alloc")) {
cgalloc(c, n);
return;
};
};
};
};