wwdump: -c/-r gate on parse errors
wwdump's -c/-r modes emitted output from a garbage parse silently. Gate on the parse-error count first (the w6c main gate, main.ww:162); wwstage-only — the C wwdump has no -c/-r modes.
This commit is contained in:
8
Makefile
8
Makefile
@@ -263,6 +263,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
||||
$(BIN)/test_defercap_run \
|
||||
$(BIN)/test_loopcap_run \
|
||||
$(BIN)/test_enumcap_run \
|
||||
$(BIN)/test_wwdumpgate_run \
|
||||
$(BIN)/test_ampfncollide_run \
|
||||
$(BIN)/test_trycallcollide_run \
|
||||
$(BIN)/test_gunsigned_run \
|
||||
@@ -829,6 +830,13 @@ $(BIN)/test_enumcap_run: test/wcc/989_enumcap_run.c \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# 989_wwdumpgate_run (#52, F15 c4): wwdump_ww's -c/-r arms gate on parse-stage
|
||||
# errors instead of silently emitting asm / a resolve report on a broken AST.
|
||||
# Runs wwdump + wwdump_ww directly (rule-10). See the test header.
|
||||
$(BIN)/test_wwdumpgate_run: test/wcc/989_wwdumpgate_run.c \
|
||||
$(BIN)/wwdump $(BIN)/wwdump_ww | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# 989_ampfncollide_run (#4, c2): `&fn` synthesis (unoptype TK_AMP +
|
||||
# assignableaddrfn) prefers the current module's fn when a same-leaf fn is
|
||||
# declared in a later module. Builds/rejects on BOTH driver twins (rule-10).
|
||||
|
||||
@@ -44685,6 +44685,11 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #52: gate the resolve report on parse-stage errors. Without
|
||||
// this a parse-errored decl is silently dropped from the AST
|
||||
// and the report is printed with rc=0. Mirrors w6c main.ww:162
|
||||
// / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
let tc: tctx;
|
||||
typesinit(&tc);
|
||||
let ck: checker;
|
||||
@@ -44708,6 +44713,12 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #52: gate cgen on parse-stage errors BEFORE check/cgen.
|
||||
// A parse-errored decl is silently dropped from the AST; the
|
||||
// remaining file would otherwise emit asm with rc=0 (silent
|
||||
// miscompile, and the 994 byte-identity probe ships wrong asm
|
||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
// #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
|
||||
|
||||
@@ -135,6 +135,11 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #52: gate the resolve report on parse-stage errors. Without
|
||||
// this a parse-errored decl is silently dropped from the AST
|
||||
// and the report is printed with rc=0. Mirrors w6c main.ww:162
|
||||
// / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
let tc: tctx;
|
||||
typesinit(&tc);
|
||||
let ck: checker;
|
||||
@@ -158,6 +163,12 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
let f: *node = parsefile(&ps);
|
||||
// #52: gate cgen on parse-stage errors BEFORE check/cgen.
|
||||
// A parse-errored decl is silently dropped from the AST; the
|
||||
// remaining file would otherwise emit asm with rc=0 (silent
|
||||
// miscompile, and the 994 byte-identity probe ships wrong asm
|
||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
// #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
|
||||
|
||||
139
test/wcc/989_wwdumpgate_run.c
Normal file
139
test/wcc/989_wwdumpgate_run.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 989_wwdumpgate_run (#52, F15 c4) — wwdump_ww's `-c` and `-r` arms must gate
|
||||
* on parse-stage errors instead of silently emitting on a broken AST.
|
||||
*
|
||||
* THE BUG (wwstage wwdump_ww only, cat-A silent wrong output under rc=0): the
|
||||
* `-c` codegen arm ran checkfile+cgfile with NO parse-error gate — ps.errs
|
||||
* was never read — so a parse-errored decl was silently dropped from the AST
|
||||
* and the rest of the file compiled to asm with exit 0 (and `-c` IS the 994
|
||||
* byte-identity probe, so the gate tool itself could ship wrong asm silently).
|
||||
* The `-r` resolve report arm was likewise ungated. THE FIX: add the
|
||||
* `l.errs>0 || ps.errs>0` gate after parsefile in both arms, mirroring the
|
||||
* w6c compiler gate (selfhost/cmd/w6c/main.ww:162 / cmd/w6c/main.c).
|
||||
*
|
||||
* WWSTAGE-ONLY: the C wwdump (cstage) implements only -t/-a, not -c/-r — the
|
||||
* codegen/resolve dump arms are a wwstage-wwdump_ww feature, so there is no
|
||||
* cstage -c/-r twin to diff against; the gate reference is the w6c compiler.
|
||||
*
|
||||
* row | mode | input | result
|
||||
* -------+------+---------------+----------------------------------
|
||||
* bad_c | -c | parse error | rc != 0, zero asm bytes
|
||||
* bad_r | -r | parse error | rc != 0
|
||||
* ok_c | -c | valid file | rc == 0, asm emitted (control)
|
||||
*
|
||||
* bad_c / bad_r were RED pre-c4 (rc=0 with truncated asm / a resolve report).
|
||||
* ok_c pins the healthy emission path unperturbed.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int
|
||||
runwait(const char *cmd)
|
||||
{
|
||||
int rc = system(cmd);
|
||||
if (rc == -1) return -1;
|
||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *BAD =
|
||||
"package main;\n\n"
|
||||
"export fn main(argc: i32, argv: **u8) i32 = {\n\treturn 0;\n};\n\n"
|
||||
"fn broken( {\n";
|
||||
static const char *OK =
|
||||
"package main;\nexport fn main() i32 = { return 0; };\n";
|
||||
|
||||
/* Run `<tool> <mode> <src>` capturing asm on stdout; returns rc, sets
|
||||
* *asmbytes to the stdout byte count when non-NULL. */
|
||||
static int
|
||||
run_dump(const char *tool, const char *mode, const char *src, long *asmbytes)
|
||||
{
|
||||
char outp[128], cmd[1024];
|
||||
snprintf(outp, sizeof outp, "/tmp/wwdg_%d_out", getpid());
|
||||
snprintf(cmd, sizeof cmd, "%s %s %s > %s 2>/dev/null",
|
||||
tool, mode, src, outp);
|
||||
int rc = runwait(cmd);
|
||||
if (asmbytes) {
|
||||
FILE *f = fopen(outp, "rb");
|
||||
long n = 0;
|
||||
if (f) { fseek(f, 0, SEEK_END); n = ftell(f); fclose(f); }
|
||||
*asmbytes = n;
|
||||
}
|
||||
unlink(outp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
write_file(const char *path, const char *body)
|
||||
{
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (!f) return -1;
|
||||
fputs(body, f);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = getenv("BIN");
|
||||
if (!bin) bin = "out/bin";
|
||||
char absbin[1024];
|
||||
if (bin[0] != '/') {
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
|
||||
bin = absbin;
|
||||
}
|
||||
|
||||
char wtool[1024];
|
||||
snprintf(wtool, sizeof wtool, "%s/wwdump_ww", bin);
|
||||
if (access(wtool, X_OK) != 0) {
|
||||
/* wwdump_ww is the unit under test; absence is a wiring fault. */
|
||||
fprintf(stderr, "wwdumpgate: missing %s\n", wtool);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char badp[64], okp[64];
|
||||
snprintf(badp, sizeof badp, "/tmp/wwdg_bad_%d.ww", getpid());
|
||||
snprintf(okp, sizeof okp, "/tmp/wwdg_ok_%d.ww", getpid());
|
||||
if (write_file(badp, BAD) || write_file(okp, OK)) return 1;
|
||||
|
||||
int fail = 0, total = 0;
|
||||
long ab;
|
||||
|
||||
/* bad_c: loud, zero asm */
|
||||
total++;
|
||||
if (run_dump(wtool, "-c", badp, &ab) == 0 || ab != 0) {
|
||||
fprintf(stderr, "wwdumpgate[bad_c]: emitted asm with rc=0 on "
|
||||
"parse-errored input (#52); asm=%ld\n", ab);
|
||||
fail++;
|
||||
}
|
||||
|
||||
/* bad_r: loud */
|
||||
total++;
|
||||
if (run_dump(wtool, "-r", badp, NULL) == 0) {
|
||||
fprintf(stderr, "wwdumpgate[bad_r]: resolve report with rc=0 on "
|
||||
"parse-errored input (#52)\n");
|
||||
fail++;
|
||||
}
|
||||
|
||||
/* ok_c control: rc=0 with asm */
|
||||
total++;
|
||||
if (run_dump(wtool, "-c", okp, &ab) != 0 || ab <= 0) {
|
||||
fprintf(stderr, "wwdumpgate[ok_c]: healthy file rejected/no asm "
|
||||
"(asm=%ld)\n", ab);
|
||||
fail++;
|
||||
}
|
||||
|
||||
unlink(badp); unlink(okp);
|
||||
|
||||
if (fail) {
|
||||
fprintf(stderr, "wwdumpgate_run: %d/%d check(s) failed\n", fail, total);
|
||||
return 1;
|
||||
}
|
||||
printf("wwdumpgate_run: %d/%d ok\n", total, total);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user