/* * 742_parse_error — both stages of w6c must exit non-zero on a parse * error. Pins rule 10 symmetry on the failure path. * * Predecessor symptom: wwstage `w6c_ww` ran cgen on the broken AST and * exited 0 (stderr noise only). Drivers downstream of w6c (`ww build`, * make rules) saw no signal and proceeded. * * cstage `w6c` checks `l.errs || p.errs` before cgen and returns 1. * This test pins the same exit-code contract on both binaries against a * known-bad fixture. */ #include #include #include #include #include static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static int write_file(const char *path, const char *content) { FILE *f = fopen(path, "wb"); if (!f) return -1; fputs(content, f); fclose(f); return 0; } static int filehas(const char *path, const char *needle) { char buf[8192]; FILE *f = fopen(path, "rb"); if (!f) return 0; size_t n = fread(buf, 1, sizeof buf - 1, f); fclose(f); buf[n] = '\0'; return strstr(buf, needle) != NULL; } /* check_fail — the tool must exit non-zero AND emit a parse diagnostic. * Both stages report "expected identifier" first on this fixture; a crash * exits non-zero with no diagnostic, so the substring distinguishes a * clean reject from a segfault (#20). */ static int check_fail(const char *tool, const char *src) { char cmd[4096], errf[64]; snprintf(errf, sizeof errf, "/tmp/parse_err_e_%d.txt", getpid()); snprintf(cmd, sizeof cmd, "%s %s >/dev/null 2>%s", tool, src, errf); int rc = runwait(cmd); int hasmsg = filehas(errf, "expected identifier"); unlink(errf); if (rc == 0) { fprintf(stderr, "742 FAIL: %s exited 0 on parse-error fixture\n", tool); return -1; } if (!hasmsg) { fprintf(stderr, "742 FAIL: %s nonzero exit but missing parse " "diagnostic (a crash, not a clean reject)\n", tool); return -1; } return 0; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[2048]; 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 src[64], outs[64]; snprintf(src, sizeof src, "/tmp/parse_err_%d.ww", getpid()); snprintf(outs, sizeof outs, "/tmp/parse_err_%d.s", getpid()); if (write_file(src, "fn fn fn ;\n") != 0) { fprintf(stderr, "742: cannot write fixture\n"); return 1; } char w6c[2240], w6c_ww[2240], w6c_ww_bin[2240]; snprintf(w6c, sizeof w6c, "%s/w6c -o %s", bin, outs); snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww -o %s", bin, outs); snprintf(w6c_ww_bin, sizeof w6c_ww_bin, "%s/w6c_ww", bin); int total = 0, fail = 0; total++; if (check_fail(w6c, src) != 0) fail++; if (access(w6c_ww_bin, X_OK) == 0) { total++; if (check_fail(w6c_ww, src) != 0) fail++; } unlink(src); unlink(outs); if (fail) { fprintf(stderr, "742_parse_error: %d/%d failed\n", fail, total); return 1; } printf("742_parse_error: %d/%d ok\n", total, total); return 0; }