wcc/ww: reject a duplicate top-level main (F-D)
A second top-level decl named `main` (fn/let/def/type) collides with the entry main on the single bare `main` symbol: today both lower to a bare `main`, w6l silently accepts the duplicate, and the program links rc=0 then segfaults (or runs wrong), in both stages. The existing duplicate-decl rejects key on (name, module), so a cross-module `foo.main` vs the bare entry `main` read as distinct and slip through. Add a program-global, name-only, cross-module uniqueness check on `main` in the checker (both stages), colocated with the duplicate-decl rejects and counting user decls before the -T synthesized test main. Corpus-safe: a lone `fn main` in any package stays legal (ww has no package-main convention -- cmatrix/lisp/mandelbrot are non-main-package entries and keep building). This converts the silent segfault to a loud compile error and subsumes the w6l silent-dup-main case (#31); correct package-aware mangling of a non-entry main is deferred to the root-unit entry-detection work (#22/#32). Regenerates the w6c and wwdump combined.ww. Table-driven 842 test: reject rows for let/fn/def/type main (genuine cross-module import form) plus a negative single-main corpus-safe row that must still build+run.
This commit is contained in:
@@ -6227,6 +6227,35 @@ export fn checkfile(c: *checker, file: *node) void = {
|
||||
d = d.next;
|
||||
};
|
||||
|
||||
// Program-global, name-only, cross-module uniqueness on `main`.
|
||||
// `main` lowers to ONE bare entry symbol, so a second top-level
|
||||
// decl named `main` (any kind, any package) collides with the
|
||||
// entry at link time — today a silent segfault / link-fail in
|
||||
// both stages. The (name, module) duplicate rejects in installtop
|
||||
// read a cross-package `foo.main` and the bare entry as distinct,
|
||||
// so they miss this. Correct multi-main mangling (entry stays bare,
|
||||
// the rest qualify) is deferred (task #32); reject loudly meanwhile
|
||||
// (rule 7). Walks USER decls only — runs before the -T synth main
|
||||
// is appended below — so a hosted-test build never false-counts.
|
||||
// Twin of cmd/wcc/check.c.
|
||||
let firstmain: *node = nil;
|
||||
let mm: *node = file.list;
|
||||
for (mm != nil) {
|
||||
let ismain: bool = (mm.kind == nkind.N_FNDECL
|
||||
|| mm.kind == nkind.N_LET || mm.kind == nkind.N_DEF
|
||||
|| mm.kind == nkind.N_TYPEDECL) && streq(mm.str, "main");
|
||||
if (ismain) {
|
||||
if (firstmain == nil) {
|
||||
firstmain = mm;
|
||||
} else {
|
||||
cerr(mm.file);
|
||||
cerr(": error: duplicate top-level main: only the entry main may exist (task #32)\n");
|
||||
c.errs += 1;
|
||||
};
|
||||
};
|
||||
mm = mm.next;
|
||||
};
|
||||
|
||||
// #15 @test harness — under `w6c_ww -T`, synthesize the entry the
|
||||
// driver would otherwise hand-wire. We sit at the seam between
|
||||
// fn-install (Pass 1, all names now in scope so the synth callees
|
||||
|
||||
Reference in New Issue
Block a user