selfhost/cmd+test: run check before cgen in wwstage drivers
w6c_ww and wwdump_ww (-c mode) silently passed source into cgen without type-checking it; any type error flowed through as broken asm with exit 0. Mirror cstage cmd/w6c/main.c:73-75: between the parse-error gate and cgeninit, install typesinit + checkinit + checkfile + `if (ck.errs > 0) return 1;`. Cgen path unchanged — drivers own check, cgen owns emit (checkfile not idempotent due to installdecl scopedefine). The wire-up was blocked by five latent check.ww divergences from cstage, all landed first: cross-module type refs (#51), enum-int reinterprets (#52), per-block scoping (#53), nominal-first tagged-variant inclusion (#55), and same-module N_IDENT callee preference (#56). With those clear, the broader exercise of check across every selfhost driver reaches 131/131 first try. 994_w6c_ww grows by one row: a trivially-wrong `let x: i32 = "hello";` smoke pins both stages to exit-non-zero. Pre-#50 it emitted 202 bytes of broken asm with exit=0. Unblocks #42 (size/align/offset wwstage intercepts) and the audit-§1.8 UP-polarity refactor (node.type_ population can now land in the same check pass we just wired up).
This commit is contained in:
@@ -22442,6 +22442,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// cgen and emits junk asm with a zero exit (silent miscompile).
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
|
||||
// #50: run check before cgen so AST mutations from #42 (size/align/
|
||||
// offset fold) and the audit §1.8 node.type_ population land before
|
||||
// cgen walks the file. Mirrors cmd/w6c/main.c:73-75. Five precondition
|
||||
// fixes for fixture cleanliness: #51 cross-module type refs, #52
|
||||
// enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant
|
||||
// compare, #56 bare-leaf same-module preference.
|
||||
let tc: tctx;
|
||||
typesinit(&tc, ar);
|
||||
let ck: checker;
|
||||
checkinit(&ck, ar, &tc);
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
|
||||
let cg: cgen;
|
||||
cgeninit(&cg, ar);
|
||||
cgfile(&cg, f);
|
||||
|
||||
@@ -147,6 +147,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// cgen and emits junk asm with a zero exit (silent miscompile).
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
|
||||
// #50: run check before cgen so AST mutations from #42 (size/align/
|
||||
// offset fold) and the audit §1.8 node.type_ population land before
|
||||
// cgen walks the file. Mirrors cmd/w6c/main.c:73-75. Five precondition
|
||||
// fixes for fixture cleanliness: #51 cross-module type refs, #52
|
||||
// enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant
|
||||
// compare, #56 bare-leaf same-module preference.
|
||||
let tc: tctx;
|
||||
typesinit(&tc, ar);
|
||||
let ck: checker;
|
||||
checkinit(&ck, ar, &tc);
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
|
||||
let cg: cgen;
|
||||
cgeninit(&cg, ar);
|
||||
cgfile(&cg, f);
|
||||
|
||||
@@ -22454,6 +22454,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, a, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #50: mirror w6c — run check before cgen so AST mutations
|
||||
// from #42 (size/align/offset fold) and audit §1.8 (node.type_
|
||||
// population) land before cgen walks. Without this, wwdump -c
|
||||
// (the byte-identity probe for 994) would diverge from w6c_ww
|
||||
// on any program that uses the size/align/offset typed builtins.
|
||||
let tc: tctx;
|
||||
typesinit(&tc, a);
|
||||
let ck: checker;
|
||||
checkinit(&ck, a, &tc);
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
let cg: cgen;
|
||||
cgeninit(&cg, a);
|
||||
cgfile(&cg, f);
|
||||
|
||||
@@ -159,6 +159,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, a, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #50: mirror w6c — run check before cgen so AST mutations
|
||||
// from #42 (size/align/offset fold) and audit §1.8 (node.type_
|
||||
// population) land before cgen walks. Without this, wwdump -c
|
||||
// (the byte-identity probe for 994) would diverge from w6c_ww
|
||||
// on any program that uses the size/align/offset typed builtins.
|
||||
let tc: tctx;
|
||||
typesinit(&tc, a);
|
||||
let ck: checker;
|
||||
checkinit(&ck, a, &tc);
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
let cg: cgen;
|
||||
cgeninit(&cg, a);
|
||||
cgfile(&cg, f);
|
||||
|
||||
@@ -248,6 +248,45 @@ main(void)
|
||||
n++;
|
||||
}
|
||||
|
||||
/* #50: the check pass is wired into both wwdump_ww -c and
|
||||
* w6c_ww in front of cgen. Pre-#50, a hard type error parsed
|
||||
* cleanly and reached cgen, which would emit asm with a zero
|
||||
* exit (silent miscompile). Pin the rejection by giving each
|
||||
* driver a trivially-broken file and demanding non-zero exit. */
|
||||
struct { const char *label; const char *src; } bad[] = {
|
||||
{ "let_str_to_i32",
|
||||
"package main;\n"
|
||||
"fn main() i32 = {\n"
|
||||
" let x: i32 = \"hello\";\n"
|
||||
" return x;\n"
|
||||
"};\n" },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
for (int i = 0; bad[i].label; i++) {
|
||||
char src[64], wcmd[2048], dcmd[2048], s[64];
|
||||
snprintf(src, sizeof src, "/tmp/wwc6_bad_%d_%d.ww", getpid(), i);
|
||||
snprintf(s, sizeof s, "/tmp/wwc6_bad_%d_%d.s", getpid(), i);
|
||||
if (write_file(src, bad[i].src) != 0) { fail++; n++; continue; }
|
||||
snprintf(wcmd, sizeof wcmd,
|
||||
"%s/w6c_ww -o %s %s >/dev/null 2>&1", bin, s, src);
|
||||
snprintf(dcmd, sizeof dcmd,
|
||||
"%s/wwdump_ww -c %s >%s 2>/dev/null", bin, src, s);
|
||||
if (runwait(wcmd) == 0) {
|
||||
fprintf(stderr,
|
||||
"w6c_ww FAIL: %s slipped past check (silent miscompile)\n",
|
||||
bad[i].label);
|
||||
fail++;
|
||||
}
|
||||
if (runwait(dcmd) == 0) {
|
||||
fprintf(stderr,
|
||||
"wwdump_ww -c FAIL: %s slipped past check (silent miscompile)\n",
|
||||
bad[i].label);
|
||||
fail++;
|
||||
}
|
||||
unlink(src); unlink(s);
|
||||
n++;
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
fprintf(stderr, "w6c_ww: %d/%d diff(s) failed\n", fail, n);
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user