wcc: reject module-scope alloc/call let initializers at check time
A module-scope let whose rhs runs code (alloc, call — peeled through
cast/?/! wrappers) emitted no DATAW slot: emit_lets' fold-fail
silently skipped the definition and every reference died at LINK
time with 'undefined reference', the one unacceptable failure mode
(rule 7). Hare's model rejects at check time (ref/harec/src/
check.c:4360 'Unable to evaluate initializer at compile time') and
routes runtime init through @init, which ww does not have — so both
frontends now reject at the declaration with identical wording.
alias_infptr_global flips compile->error as the alloc pin (its
letvartnode N_TPTR-over-N_TSTRUCT coverage lives on in the local
alias_infptr_{nest,slicecap} siblings); callinit_global_reject pins
the call shape. Corpus pin 1741/345/21/209/1166/3482.
This commit is contained in:
@@ -3126,6 +3126,26 @@ check_file(Checker *c, Node *file)
|
|||||||
if (t)
|
if (t)
|
||||||
require_sized(c, t, d->pos, "a variable");
|
require_sized(c, t, d->pos, "a variable");
|
||||||
d->type = t;
|
d->type = t;
|
||||||
|
/* A module-scope initializer must be link-time data:
|
||||||
|
* an alloc/call rhs runs code, emit_lets' fold-fail
|
||||||
|
* skipped the DATAW slot silently, and every
|
||||||
|
* reference died at LINK time ("undefined reference")
|
||||||
|
* — reject at the declaration instead (rule 7).
|
||||||
|
* Hare rejects at check time too (ref/harec/src/
|
||||||
|
* check.c:4360 "Unable to evaluate initializer at
|
||||||
|
* compile time"); ww has no @init path. */
|
||||||
|
{
|
||||||
|
Node *r = d->rhs;
|
||||||
|
while (r != NULL && (r->kind == N_CAST
|
||||||
|
|| r->kind == N_TRYPROP
|
||||||
|
|| r->kind == N_TRYUNW))
|
||||||
|
r = r->lhs;
|
||||||
|
if (r != NULL && (r->kind == N_ALLOC
|
||||||
|
|| r->kind == N_CALL))
|
||||||
|
err(c, d->pos, "module-scope let %s: "
|
||||||
|
"runtime initializer unsupported "
|
||||||
|
"(alloc/call; rule 7)", d->str);
|
||||||
|
}
|
||||||
if (d->str && d->str[0]) {
|
if (d->str && d->str[0]) {
|
||||||
Sym *prev = scope_lookup_local(c->cur, d->str);
|
Sym *prev = scope_lookup_local(c->cur, d->str);
|
||||||
const char *mod = decl_mod(file, d);
|
const char *mod = decl_mod(file, d);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package wwfixture;
|
package wwfixture;
|
||||||
|
|
||||||
def protocolversion: i32 = 1;
|
def protocolversion: i32 = 1;
|
||||||
def corpuscount: i32 = 1740;
|
def corpuscount: i32 = 1741;
|
||||||
def errorcount: i32 = 343;
|
def errorcount: i32 = 345;
|
||||||
def compilecount: i32 = 22;
|
def compilecount: i32 = 21;
|
||||||
def runcount: i32 = 209;
|
def runcount: i32 = 209;
|
||||||
def runexitcount: i32 = 1166;
|
def runexitcount: i32 = 1166;
|
||||||
def nativecount: i32 = 3480;
|
def nativecount: i32 = 3482;
|
||||||
def corpushash: str = "a2f2514f07ca4e20457331e30f051394da3e59fcfa8f5f6ec3b33d9c14490354";
|
def corpushash: str = "bad5b37d555f3f4d742f7a6fcfa857ff46315757233819a19eb9bc1da2800ce7";
|
||||||
|
|
||||||
type directive = enum i32 {
|
type directive = enum i32 {
|
||||||
ERROR = 0,
|
ERROR = 0,
|
||||||
|
|||||||
@@ -343,7 +343,32 @@ fn installdecl(c: *checker, file: *syntax.node, d: *syntax.node) void = {
|
|||||||
if (k == syntax.nkind.N_DEF) { installtop(c, d, nm, mod, syntax.skind.SK_DEF, "def"); return; };
|
if (k == syntax.nkind.N_DEF) { installtop(c, d, nm, mod, syntax.skind.SK_DEF, "def"); return; };
|
||||||
if (k == syntax.nkind.N_TYPEDECL) { installtop(c, d, nm, mod, syntax.skind.SK_TYPE, "type"); return; };
|
if (k == syntax.nkind.N_TYPEDECL) { installtop(c, d, nm, mod, syntax.skind.SK_TYPE, "type"); return; };
|
||||||
if (k == syntax.nkind.N_FNDECL) { installtop(c, d, nm, mod, syntax.skind.SK_FN, "fn"); return; };
|
if (k == syntax.nkind.N_FNDECL) { installtop(c, d, nm, mod, syntax.skind.SK_FN, "fn"); return; };
|
||||||
if (k == syntax.nkind.N_LET) { installtop(c, d, nm, mod, syntax.skind.SK_VAR, "let"); return; };
|
if (k == syntax.nkind.N_LET) {
|
||||||
|
// A module-scope initializer must be link-time data: an
|
||||||
|
// alloc/call rhs runs code, emitletdataw's fold-fail
|
||||||
|
// skipped the DATAW slot silently, and every reference
|
||||||
|
// died at LINK time ("undefined reference") — reject at
|
||||||
|
// the declaration instead (rule 7). Hare rejects at check
|
||||||
|
// time too (ref/harec/src/check.c:4360); ww has no @init
|
||||||
|
// path. Mirrors cstage check_file N_LET.
|
||||||
|
let rr: *syntax.node = d.rhs;
|
||||||
|
for (rr != nil) {
|
||||||
|
if (rr.kind == syntax.nkind.N_CAST) { rr = rr.lhs; continue; };
|
||||||
|
if (rr.kind == syntax.nkind.N_TRYPROP) { rr = rr.lhs; continue; };
|
||||||
|
if (rr.kind == syntax.nkind.N_TRYUNW) { rr = rr.lhs; continue; };
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (rr != nil) {
|
||||||
|
if (rr.kind == syntax.nkind.N_ALLOC || rr.kind == syntax.nkind.N_CALL) {
|
||||||
|
cerr(d.file); cerr(": error: module-scope let ");
|
||||||
|
cerr(nm);
|
||||||
|
cerr(": runtime initializer unsupported (alloc/call; rule 7)\n");
|
||||||
|
c.errs += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
installtop(c, d, nm, mod, syntax.skind.SK_VAR, "let");
|
||||||
|
return;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// installtop — install a top-level decl name into c.top, rejecting a
|
// installtop — install a top-level decl name into c.top, rejecting a
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
//ww:compile
|
//ww:error "runtime initializer unsupported (alloc/call; rule 7)"
|
||||||
// INFERRED-global *struct root: the letvartnode gate must accept the
|
// Module-scope alloc initializer: no DATAW slot exists for a
|
||||||
// checker-synthesized N_TPTR-over-N_TSTRUCT exactly as the local arm.
|
// runtime-computed global, so pre-reject every reference died at
|
||||||
|
// LINK time ("undefined reference to 'main.gp'") — the checker now
|
||||||
|
// rejects at the declaration on both frontends (Hare model:
|
||||||
|
// ref/harec/src/check.c:4360 rejects non-compile-time-evaluable
|
||||||
|
// global initializers; ww has no @init path).
|
||||||
package main;
|
package main;
|
||||||
type box = struct { s: str, n: int };
|
type box = struct { s: str, n: int };
|
||||||
let gp = alloc(box { s = "hi", n = 1 })!;
|
let gp = alloc(box { s = "hi", n = 1 })!;
|
||||||
|
|||||||
7
test/wcc/data/callinit_global_reject/case.ww
Normal file
7
test/wcc/data/callinit_global_reject/case.ww
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//ww:error "runtime initializer unsupported (alloc/call; rule 7)"
|
||||||
|
// The call sibling of alias_infptr_global's alloc reject: a
|
||||||
|
// module-scope call initializer has no link-time data either.
|
||||||
|
package main;
|
||||||
|
fn mk() i64 = { return 7; };
|
||||||
|
let gc: i64 = mk();
|
||||||
|
export fn main() i32 = { return gc: i32; };
|
||||||
Reference in New Issue
Block a user