diff --git a/selfhost/cmd/ww/main.combined.ww b/selfhost/cmd/ww/main.combined.ww index 32961e17..cc9c93cd 100644 --- a/selfhost/cmd/ww/main.combined.ww +++ b/selfhost/cmd/ww/main.combined.ww @@ -2986,8 +2986,11 @@ fn joinpathlit(dir: *u8, name: str) *u8 = { // ---- Subprocess plumbing ---------------------------------------------- // procrun — fork, execve `path` with `argv` (NULL-terminated), wait. -// Returns 0 on clean exit-0, 1 on any non-zero exit or signal kill, -// -1 on fork/wait failure. +// Returns the child's real exit code on clean exit, 1 on signal kill, +// -1 on fork/wait failure. Mirrors cmd/ww/main.c:do_run WEXITSTATUS: +// the build-step callers only test `!= 0`, so propagating the exact +// non-zero code leaves them unaffected while `dorun` reports the true +// program exit status (was collapsing every non-zero exit to 1; fix #16). fn procrun(path: *u8, argv: **u8) i32 = { let pid: i32 = os.fork(); if (pid < 0) { @@ -3009,8 +3012,7 @@ fn procrun(path: *u8, argv: **u8) i32 = { // next byte = exit code. if ((status & 127i32) != 0) { return 1; }; let code: i32 = (status >> 8i32) & 255i32; - if (code != 0) { return 1; }; - return 0; + return code; }; // ---- `use` resolution + source concatenation -------------------------- diff --git a/selfhost/cmd/ww/main.ww b/selfhost/cmd/ww/main.ww index 344a5930..e9136ea4 100644 --- a/selfhost/cmd/ww/main.ww +++ b/selfhost/cmd/ww/main.ww @@ -152,8 +152,11 @@ fn joinpathlit(dir: *u8, name: str) *u8 = { // ---- Subprocess plumbing ---------------------------------------------- // procrun — fork, execve `path` with `argv` (NULL-terminated), wait. -// Returns 0 on clean exit-0, 1 on any non-zero exit or signal kill, -// -1 on fork/wait failure. +// Returns the child's real exit code on clean exit, 1 on signal kill, +// -1 on fork/wait failure. Mirrors cmd/ww/main.c:do_run WEXITSTATUS: +// the build-step callers only test `!= 0`, so propagating the exact +// non-zero code leaves them unaffected while `dorun` reports the true +// program exit status (was collapsing every non-zero exit to 1; fix #16). fn procrun(path: *u8, argv: **u8) i32 = { let pid: i32 = os.fork(); if (pid < 0) { @@ -175,8 +178,7 @@ fn procrun(path: *u8, argv: **u8) i32 = { // next byte = exit code. if ((status & 127i32) != 0) { return 1; }; let code: i32 = (status >> 8i32) & 255i32; - if (code != 0) { return 1; }; - return 0; + return code; }; // ---- `use` resolution + source concatenation -------------------------- diff --git a/test/wcc/993_ww_ww.c b/test/wcc/993_ww_ww.c index c215eb2e..fccb0581 100644 --- a/test/wcc/993_ww_ww.c +++ b/test/wcc/993_ww_ww.c @@ -113,6 +113,27 @@ diff_one(const char *bin, const char *cwd, const char *label, return rc; } +/* Stage a program whose main() returns `code`, build+exec it via the + * named driver's `run` subcommand, and return the propagated exit code + * (-1 on staging/spawn failure). #16: ww_ww must report the child's real + * exit code, not collapse every non-zero exit to 1. */ +static int +run_exit_code(const char *bin, const char *driver, int code) +{ + char src[64]; + snprintf(src, sizeof src, "/tmp/ww_rc_%d_%d.ww", getpid(), code); + FILE *f = fopen(src, "w"); + if (!f) return -1; + fprintf(f, "export fn main() i32 = {\n\treturn %d;\n};\n", code); + fclose(f); + + char cmd[256]; + snprintf(cmd, sizeof cmd, "%s/%s run %s 2>/dev/null", bin, driver, src); + int rc = runwait(cmd); + unlink(src); + return rc; +} + int main(void) { @@ -171,11 +192,38 @@ main(void) n++; } unlink(hello_src); - if (fail) { - fprintf(stderr, "ww_ww: %d/%d diff(s) failed\n", fail, n); + + /* #16: `ww_ww run` must propagate the child program's real exit code + * (the shared procrun helper was collapsing every non-zero exit to 1). + * Table-driven; the non-zero rows fail under the old collapse-to-1. + * The C ww driver is the reference (do_run -> WEXITSTATUS); assert + * ww_ww matches it row-for-row. */ + static const int exit_codes[] = { 0, 7, 42 }; + int nrc = (int)(sizeof exit_codes / sizeof exit_codes[0]); + int rcfail = 0; + for (int i = 0; i < nrc; i++) { + int want = exit_codes[i]; + int cww = run_exit_code(bin, "ww", want); + int wwww = run_exit_code(bin, "ww_ww", want); + if (cww != want) { + fprintf(stderr, "ww_ww FAIL: C ww run returned %d, " + "want %d\n", cww, want); + rcfail++; + } + if (wwww != want) { + fprintf(stderr, "ww_ww FAIL: ww_ww run returned %d, " + "want %d (exit-code propagation, #16)\n", wwww, want); + rcfail++; + } + } + + if (fail || rcfail) { + fprintf(stderr, "ww_ww: %d/%d diff(s) failed, %d exit-code " + "row(s) failed\n", fail, n, rcfail); return 1; } printf("ww_ww: byte-identical to C ww on %d corpus builds " - "(single-file + selfhost/wwdump multi-import)\n", n); + "(single-file + selfhost/wwdump multi-import); " + "run exit-code propagated on %d rows (#16)\n", n, nrc); return 0; }