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:
@@ -14791,10 +14791,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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -21273,6 +21282,25 @@ fn fnparamslookup(c: *cgen, name: str) *node = {
|
||||
return nil;
|
||||
};
|
||||
|
||||
// samemodfn — true iff `name` is registered as a fn in c.curmod. Used
|
||||
// by cgcall to suppress the bare-name Hare-style builtins (`alloc(x)`,
|
||||
// future free/append/len audits) when the current module declares its
|
||||
// own decl by that name. Mirrors cstage's same-module check at
|
||||
// cmd/wcc/check.c (alloc gate, task #23) — `scope_lookup_prefer` over
|
||||
// the flat scope would also match `use os;`-imported decls in a primary,
|
||||
// suppressing the builtin spuriously; the same-module-tag filter here
|
||||
// (and `c.curmod && ...` on the cstage side) keeps the gate strict.
|
||||
fn samemodfn(c: *cgen, name: str) bool = {
|
||||
let f: *fnret = c.fnrets;
|
||||
for (f != nil) {
|
||||
if (streq(f.fname, name)) {
|
||||
if (streq(f.fmod, c.curmod)) { return true; };
|
||||
};
|
||||
f = f.frnext;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// fnparamslookupmod — same-module-first leaf walk. Module-qualified
|
||||
// `mod.fn(...)` calls go through this so a leaf collision (multiple
|
||||
// modules export the same name, e.g. `os.read` and `io.read`) resolves
|
||||
|
||||
@@ -1703,6 +1703,25 @@ fn fnparamslookup(c: *cgen, name: str) *node = {
|
||||
return nil;
|
||||
};
|
||||
|
||||
// samemodfn — true iff `name` is registered as a fn in c.curmod. Used
|
||||
// by cgcall to suppress the bare-name Hare-style builtins (`alloc(x)`,
|
||||
// future free/append/len audits) when the current module declares its
|
||||
// own decl by that name. Mirrors cstage's same-module check at
|
||||
// cmd/wcc/check.c (alloc gate, task #23) — `scope_lookup_prefer` over
|
||||
// the flat scope would also match `use os;`-imported decls in a primary,
|
||||
// suppressing the builtin spuriously; the same-module-tag filter here
|
||||
// (and `c.curmod && ...` on the cstage side) keeps the gate strict.
|
||||
fn samemodfn(c: *cgen, name: str) bool = {
|
||||
let f: *fnret = c.fnrets;
|
||||
for (f != nil) {
|
||||
if (streq(f.fname, name)) {
|
||||
if (streq(f.fmod, c.curmod)) { return true; };
|
||||
};
|
||||
f = f.frnext;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// fnparamslookupmod — same-module-first leaf walk. Module-qualified
|
||||
// `mod.fn(...)` calls go through this so a leaf collision (multiple
|
||||
// modules export the same name, e.g. `os.read` and `io.read`) resolves
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14791,10 +14791,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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -21273,6 +21282,25 @@ fn fnparamslookup(c: *cgen, name: str) *node = {
|
||||
return nil;
|
||||
};
|
||||
|
||||
// samemodfn — true iff `name` is registered as a fn in c.curmod. Used
|
||||
// by cgcall to suppress the bare-name Hare-style builtins (`alloc(x)`,
|
||||
// future free/append/len audits) when the current module declares its
|
||||
// own decl by that name. Mirrors cstage's same-module check at
|
||||
// cmd/wcc/check.c (alloc gate, task #23) — `scope_lookup_prefer` over
|
||||
// the flat scope would also match `use os;`-imported decls in a primary,
|
||||
// suppressing the builtin spuriously; the same-module-tag filter here
|
||||
// (and `c.curmod && ...` on the cstage side) keeps the gate strict.
|
||||
fn samemodfn(c: *cgen, name: str) bool = {
|
||||
let f: *fnret = c.fnrets;
|
||||
for (f != nil) {
|
||||
if (streq(f.fname, name)) {
|
||||
if (streq(f.fmod, c.curmod)) { return true; };
|
||||
};
|
||||
f = f.frnext;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// fnparamslookupmod — same-module-first leaf walk. Module-qualified
|
||||
// `mod.fn(...)` calls go through this so a leaf collision (multiple
|
||||
// modules export the same name, e.g. `os.read` and `io.read`) resolves
|
||||
|
||||
Reference in New Issue
Block a user