test: retire owned observers 989_sepdotpath + 989_syntaxexport

This commit is contained in:
2026-08-08 13:48:18 +09:00
parent 51f8c615d8
commit dc93bcee76
2 changed files with 0 additions and 645 deletions

View File

@@ -1,339 +0,0 @@
/*
* 989_sepdotpath_run — sep-build of a DOTTED-path (multi-component) package
* (#57). Commit-6 broad-soak prereq: the real toolchain sep-builds packages
* like `encoding.utf8`, whose body must mangle on the full dotted import path
* (`encoding.utf8.X`), not the leaf `package` clause (`utf8.X`).
*
* Root cause it guards: the sep producer splices a package's own body under
* `//ww:module-reset` (so `-c` keeps imported==0). Pre-#57 that reset carried
* NO path, so the body's `package <leaf>;` clause set curmod to the LEAF —
* the DEFINER mangled `b.val` while every importer (spliced under
* `//ww:module a.b`) referenced `a.b.val` → unresolved at link. #57 threads
* the dotted path through the reset (`//ww:module-reset a.b`), demoting the
* leaf clause to an assertion. Single-COMPONENT packages were always clean
* (leaf == dotted path) — that invariant is the regression guard below.
*
* Graph (smallest that mixes both kinds): root -> { a.b (dotted), c (single) }.
*
* Asserts (fresh output stems under an invocation-owned root; retained
* `<stem>.sepwork` is inspected, then removed by final carrier cleanup):
* 1. Build + run, BOTH stages → exit EXPECT_EXIT (the dotted-package symbol
* resolves + links; the program runs). Pre-#57 the link failed.
* 2. cs==ww (rule 10): per-package `.s`/`.wwi`/`.unit.ww` AND the final
* binary are byte-identical between `ww` and `ww_ww`.
* 3. NON-VACUITY (a) — definer==importer on the DOTTED form: the producer's
* `a.b.s` DEFINES `a.b.val` and the root's `__root.s` REFERENCES
* `a.b.val`. Pre-#57 the definer emitted the leaf `b.val` → the strings
* mismatched; this row would fail (and assert 1's link would fail).
* The reset directive in `a.b.unit.ww` carries the dotted path.
* 4. NON-VACUITY (b) — single-component regression guard: package `c`
* sep-builds in the SAME graph, defines `c.cval` (leaf == dotted), and
* cs==ww (covered by assert 2). Cross-commit byte-id of single-component
* output is additionally pinned by 989_sepbuild_run + the 990-997 gates.
*
* All intermediates are `-o`-redirected to /tmp for isolation. Models
* 989_sepbuild_run.c conventions; 989 prefix per the sep-gate precedent.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#define EXPECT_EXIT 37
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 *
absbin(void)
{
const char *b = getenv("BIN");
if (!b) b = "out/bin";
if (b[0] == '/') return b;
static char buf[2048];
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return NULL;
snprintf(buf, sizeof buf, "%s/%s", cwd, b);
return buf;
}
static int
slurp(const char *path, char **outbuf, size_t *outlen)
{
FILE *f = fopen(path, "rb");
if (!f) return -1;
fseek(f, 0, SEEK_END);
long n = ftell(f);
fseek(f, 0, SEEK_SET);
if (n < 0) { fclose(f); return -1; }
char *b = malloc((size_t)n + 1);
if (!b) { fclose(f); return -1; }
if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; }
b[n] = '\0';
fclose(f);
*outbuf = b;
*outlen = (size_t)n;
return 0;
}
static int
files_eq(const char *a, const char *b)
{
char *ba = NULL, *bb = NULL;
size_t na = 0, nb = 0;
if (slurp(a, &ba, &na) < 0 || slurp(b, &bb, &nb) < 0) {
free(ba); free(bb);
return -1;
}
int eq = (na == nb && memcmp(ba, bb, na) == 0);
free(ba); free(bb);
return eq ? 0 : 1;
}
/* 0 if `needle` occurs in the file at `path`, 1 if absent, -1 on read err. */
static int
file_contains(const char *path, const char *needle)
{
char *b = NULL;
size_t n = 0;
if (slurp(path, &b, &n) < 0) return -1;
int found = (strstr(b, needle) != NULL);
free(b);
return found ? 0 : 1;
}
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 = absbin();
if (!bin) return 1;
char td[64], cmd[8192], p[1024];
int fail = 0, have_lib = 0, have_a = 0, have_ab = 0, have_c = 0;
snprintf(td, sizeof td, "/tmp/wwsepdot_%d", getpid());
if (mkdir(td, 0755) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot acquire %s\n", td);
return 1;
}
/* lib/a/b — a 2-level dotted package (clause `package b;`, dir a/b). */
snprintf(p, sizeof p, "%s/lib", td);
if (mkdir(p, 0755) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot create %s\n", p);
fail++; goto out;
}
have_lib = 1;
snprintf(p, sizeof p, "%s/lib/a", td);
if (mkdir(p, 0755) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot create %s\n", p);
fail++; goto out;
}
have_a = 1;
snprintf(p, sizeof p, "%s/lib/a/b", td);
if (mkdir(p, 0755) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot create %s\n", p);
fail++; goto out;
}
have_ab = 1;
snprintf(p, sizeof p, "%s/lib/c", td);
if (mkdir(p, 0755) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot create %s\n", p);
fail++; goto out;
}
have_c = 1;
snprintf(p, sizeof p, "%s/lib/a/b/mod.ww", td);
if (write_file(p, "package b;\nexport fn val() i32 = { return 42; };\n"))
{ fail++; goto out; }
snprintf(p, sizeof p, "%s/lib/c/mod.ww", td);
if (write_file(p, "package c;\nexport fn cval() i32 = { return 5; };\n"))
{ fail++; goto out; }
char rootww[1024];
snprintf(rootww, sizeof rootww, "%s/root.ww", td);
if (write_file(rootww,
"package main;\n"
"import a.b;\n"
"import c;\n"
"fn main() i32 = { return b.val() - c.cval(); };\n"))
{ fail++; goto out; }
/* Two driver stages and their scratch dirs (paths rebuilt from the
* small fixed `td` + stage tag → provably non-truncating snprintfs). */
struct { const char *drv, *tag; char prog[1024]; }
stg[] = { { "ww", "cs", {0} }, { "ww_ww", "ww", {0} } };
for (int s = 0; s < 2; s++) {
snprintf(stg[s].prog, sizeof stg[s].prog, "%s/prog.%s", td, stg[s].tag);
/* Each direct build produces the `.s`/`.unit.ww` artifacts this
* gate inspects. */
snprintf(cmd, sizeof cmd,
"timeout 240 %s/%s build "
"-I %s/lib -o %s %s >/dev/null 2>&1",
bin, stg[s].drv, td, stg[s].prog, rootww);
if (runwait(cmd) != 0) {
fprintf(stderr, "sepdotpath FAIL: %s build\n", stg[s].drv);
fail++;
continue;
}
int rc = runwait(stg[s].prog);
if (rc != EXPECT_EXIT) {
fprintf(stderr, "sepdotpath FAIL: %s prog exit=%d expected %d\n",
stg[s].drv, rc, EXPECT_EXIT);
fail++;
}
}
/* The discovered package set materialized (dotted + single + root). */
const char *pkgs[] = { "a.b", "c", "__root" };
for (int i = 0; i < 3; i++) {
/* #69: the root is compiled WITHOUT `-I`, so it produces no `.wwi`;
* assert its `.s` materialized instead. Deps still emit a `.wwi`. */
int is_root = (strcmp(pkgs[i], "__root") == 0);
snprintf(p, sizeof p, "%s/prog.cs.sepwork/%s%s", td, pkgs[i],
is_root ? ".s" : ".wwi");
if (access(p, 0) != 0) {
fprintf(stderr, "sepdotpath FAIL: missing %s%s (discovery)\n",
pkgs[i], is_root ? ".s" : ".wwi");
fail++;
}
}
/* cs==ww (rule 10): per-package .s/.wwi/.unit.ww + final binary. The
* root has no `.wwi` post-#69, so it is excluded from the .wwi compare. */
for (int i = 0; i < 3; i++) {
const char *suf[] = { ".s", ".wwi", ".unit.ww" };
for (int k = 0; k < 3; k++) {
if (strcmp(pkgs[i], "__root") == 0 && strcmp(suf[k], ".wwi") == 0)
continue;
char a[1024], b[1024];
snprintf(a, sizeof a, "%s/prog.%s.sepwork/%s%s",
td, stg[0].tag, pkgs[i], suf[k]);
snprintf(b, sizeof b, "%s/prog.%s.sepwork/%s%s",
td, stg[1].tag, pkgs[i], suf[k]);
if (files_eq(a, b) != 0) {
fprintf(stderr, "sepdotpath FAIL: cs!=ww for %s%s (rule 10)\n",
pkgs[i], suf[k]);
fail++;
}
}
}
if (files_eq(stg[0].prog, stg[1].prog) != 0) {
fprintf(stderr, "sepdotpath FAIL: cs exe != ww exe (rule 10)\n");
fail++;
}
/* NON-VACUITY (a): definer == importer on the DOTTED qualification.
* Pre-#57 the definer emitted the leaf `b.val` while the importer
* referenced `a.b.val` → mismatch + unresolved link. */
{
char def_s[1024], ref_s[1024], unit[1024];
snprintf(def_s, sizeof def_s, "%s/prog.cs.sepwork/a.b.s", td);
snprintf(ref_s, sizeof ref_s, "%s/prog.cs.sepwork/__root.s", td);
snprintf(unit, sizeof unit, "%s/prog.cs.sepwork/a.b.unit.ww", td);
if (file_contains(def_s, "TEXT a.b.val") != 0) {
fprintf(stderr, "sepdotpath FAIL: definer a.b.s lacks dotted "
"`TEXT a.b.val` (leaf-clause regression)\n");
fail++;
}
if (file_contains(ref_s, "a.b.val") != 0) {
fprintf(stderr, "sepdotpath FAIL: importer __root.s lacks "
"reference to a.b.val\n");
fail++;
}
if (file_contains(unit, "//ww:module-reset a.b") != 0) {
fprintf(stderr, "sepdotpath FAIL: a.b.unit.ww reset directive "
"does not carry the dotted path\n");
fail++;
}
}
/* NON-VACUITY (b): single-component `c` sep-builds in the SAME graph and
* defines its leaf==dotted symbol `c.cval` (curmod resolves to the same
* string with or without #57 → byte-id preserved). cs==ww already
* asserted above; cross-commit byte-id pinned by 989_sepbuild + 990-997. */
{
char c_s[1024];
snprintf(c_s, sizeof c_s, "%s/prog.cs.sepwork/c.s", td);
if (file_contains(c_s, "TEXT c.cval") != 0) {
fprintf(stderr, "sepdotpath FAIL: single-component c.s lacks "
"`TEXT c.cval` (regression)\n");
fail++;
}
}
out:
snprintf(cmd, sizeof cmd,
"rm -rf -- '%s/prog.cs.sepwork' '%s/prog.ww.sepwork'", td, td);
if (runwait(cmd) != 0) {
fprintf(stderr, "sepdotpath FAIL: cannot clean .sepwork trees\n");
fail++;
}
{
char path[1200];
snprintf(path, sizeof path, "%s/root.ww", td);
if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", path); fail++; }
snprintf(path, sizeof path, "%s/prog.cs", td);
if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", path); fail++; }
snprintf(path, sizeof path, "%s/prog.ww", td);
if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", path); fail++; }
}
if (have_ab) {
snprintf(p, sizeof p, "%s/lib/a/b", td);
{
char path[1200];
snprintf(path, sizeof path, "%s/mod.ww", p);
if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", path); fail++; }
}
if (rmdir(p) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", p); fail++; }
}
if (have_a) {
snprintf(p, sizeof p, "%s/lib/a", td);
if (rmdir(p) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", p); fail++; }
}
if (have_c) {
snprintf(p, sizeof p, "%s/lib/c", td);
{
char path[1200];
snprintf(path, sizeof path, "%s/mod.ww", p);
if (unlink(path) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", path); fail++; }
}
if (rmdir(p) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", p); fail++; }
}
if (have_lib) {
snprintf(p, sizeof p, "%s/lib", td);
if (rmdir(p) != 0 && errno != ENOENT) { fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", p); fail++; }
}
if (rmdir(td) != 0 && errno != ENOENT) {
fprintf(stderr, "sepdotpath FAIL: cannot remove %s\n", td);
fail++;
}
if (fail) {
fprintf(stderr, "sepdotpath: %d check(s) failed\n", fail);
return 1;
}
printf("sepdotpath: dotted `a.b` + single `c` via build_one_sep — "
"build+run (exit %d) + cs==ww per-pkg .s/.wwi/.unit + final binary "
"+ definer==importer on a.b.val + single-component c.cval intact\n",
EXPECT_EXIT);
return 0;
}

View File

@@ -1,306 +0,0 @@
/*
* 989_syntaxexport_run — BUG-A residual at the surviving syntax->wcc
* package boundary (#72), post the #74 frontend consolidation.
*
* Root cause it guards: `lib/ww/syntax/` exports the fns wcc calls, and
* those fns' signatures name frontend types (tok, tinfo, tctx, ...). When
* the separate-compilation producer emits syntax's `.wwi`,
* check_exported_type recurses every exported decl — and, for an exported
* struct, its FIELDS too (the
* harec STORAGE_STRUCT precedent, wwi.c wwi_check_type N_TSTRUCT). Any
* referenced type that is itself unexported aborts the producer with
* "exported declaration references unexported type". Pre-fix, syntax's
* surface left 16 such types unexported, so syntax's `.wwi` never produced
* -> every wcc sep-build was blocked. Fix: `export` those 16 type decls
* (10 fn-signature-direct + 6 surfaced by the struct-field recursion:
* tykind/tfield/tparam/ttupleelem via tinfo, tctx via typesinit, and
* tinfocacheent via tctx). Exporting a TYPE emits no code -> the bug is
* byte-id-neutral; this gate proves the PRODUCER residual is closed.
*
* The consumer here uses QUALIFIED refs (`syntax.tokname`, `syntax.tkind`)
* to isolate the producer fix from the separate unqualified-ref question
* (#75). It happens to link + run end-to-end, which also shows the
* qualified-ref path resolves across the sep boundary.
*
* Asserts (direct builds compile every package):
* 1. Build + run, BOTH stages -> exit EXPECT_EXIT (`syntax.tokname(
* TK_INT)` == "int", len 3). Pre-fix the syntax producer exited 1, so
* the build never produced a binary.
* 2. syntax's `.wwi` is produced and carries the 16 `export type` decls.
* 3. cs==ww (rule 10): syntax's `.wwi`/`.s`/`.unit.ww` AND the final
* binary are byte-identical between `ww` and `ww_ww`.
* 4. NON-VACUITY (the bug, isolated, BOTH compilers): replay the producer
* `w6c -c -I` on the produced `syntax.unit.ww` -> exits 0 (exports
* present). On a copy with `export ` stripped from the type decls ->
* MUST exit non-zero (the export-check fires). Proven for w6c + w6c_ww.
*
* All intermediates are `-o`-redirected to /tmp; it only reads
* the in-tree `lib/ww/syntax`. Models 989_seproot_export_run.c.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#define EXPECT_EXIT 3
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 *
absbin(void)
{
const char *b = getenv("BIN");
if (!b) b = "out/bin";
if (b[0] == '/') return b;
static char buf[2048];
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return NULL;
snprintf(buf, sizeof buf, "%s/%s", cwd, b);
return buf;
}
static int
slurp(const char *path, char **outbuf, size_t *outlen)
{
FILE *f = fopen(path, "rb");
if (!f) return -1;
fseek(f, 0, SEEK_END);
long n = ftell(f);
fseek(f, 0, SEEK_SET);
if (n < 0) { fclose(f); return -1; }
char *b = malloc((size_t)n + 1);
if (!b) { fclose(f); return -1; }
if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; }
b[n] = '\0';
fclose(f);
*outbuf = b;
*outlen = (size_t)n;
return 0;
}
static int
files_eq(const char *a, const char *b)
{
char *ba = NULL, *bb = NULL;
size_t na = 0, nb = 0;
if (slurp(a, &ba, &na) < 0 || slurp(b, &bb, &nb) < 0) {
free(ba); free(bb);
return -1;
}
int eq = (na == nb && memcmp(ba, bb, na) == 0);
free(ba); free(bb);
return eq ? 0 : 1;
}
/* 0 if `needle` occurs in the file at `path`, 1 if absent, -1 on read err. */
static int
file_contains(const char *path, const char *needle)
{
char *b = NULL;
size_t n = 0;
if (slurp(path, &b, &n) < 0) return -1;
int found = (strstr(b, needle) != NULL);
free(b);
return found ? 0 : 1;
}
static int
write_file(const char *path, const char *body)
{
FILE *f = fopen(path, "wb");
if (!f) return -1;
if (fputs(body, f) == EOF) { fclose(f); return -1; }
return fclose(f);
}
int
main(void)
{
const char *bin = absbin();
if (!bin) return 1;
char root[1024];
if (getcwd(root, sizeof root) == NULL) return 1;
char td[] = "/tmp/wwsynexp_XXXXXX";
char cmd[8192];
int fail = 0, cleanup_fail = 0;
if (mkdtemp(td) == NULL) return 1;
/* Root: QUALIFIED refs into the real syntax package — `syntax.tokname`
* over `syntax.tkind`. The producer must serialize syntax's `.wwi`
* (exported fns over frontend types) WITHOUT the unexported-type abort. */
char rootww[1024];
snprintf(rootww, sizeof rootww, "%s/root.ww", td);
if (write_file(rootww,
"package main;\n"
"import syntax;\n"
"fn main() i32 = {\n"
"\tlet s: str = syntax.tokname(syntax.tkind.TK_INT);\n"
"\treturn s.len: i32;\n"
"};\n"))
{ fail++; goto out; }
struct { const char *drv, *tag; char prog[1024]; }
stg[] = { { "ww", "cs", {0} }, { "ww_ww", "ww", {0} } };
for (int s = 0; s < 2; s++) {
snprintf(stg[s].prog, sizeof stg[s].prog, "%s/prog.%s", td, stg[s].tag);
/* Direct builds produce the `.wwi`/`.s`/`.unit.ww` artifacts this
* gate inspects. */
snprintf(cmd, sizeof cmd,
"timeout 240 %s/%s build "
"-I %s/lib/ww -o %s %s >%s/build.%s.log 2>&1",
bin, stg[s].drv, root, stg[s].prog, rootww,
td, stg[s].tag);
if (runwait(cmd) != 0) {
fprintf(stderr, "syntaxexport FAIL: %s build (pre-fix: syntax "
"producer rejects export-fn-over-unexported-type)\n", stg[s].drv);
fail++;
continue;
}
/* the producer abort must not appear in the build log. */
char log[1024], wwi[1024];
snprintf(log, sizeof log, "%s/build.%s.log", td, stg[s].tag);
if (file_contains(log, "unexported type") == 0) {
fprintf(stderr, "syntaxexport FAIL: %s build log shows "
"'unexported type' (producer residual not closed)\n", stg[s].drv);
fail++;
}
snprintf(wwi, sizeof wwi, "%s/prog.%s.sepwork/syntax.wwi", td, stg[s].tag);
if (access(wwi, 0) != 0) {
fprintf(stderr, "syntaxexport FAIL: %s produced no syntax.wwi\n",
stg[s].drv);
fail++;
}
int rc = runwait(stg[s].prog);
if (rc != EXPECT_EXIT) {
fprintf(stderr, "syntaxexport FAIL: %s prog exit=%d expected %d\n",
stg[s].drv, rc, EXPECT_EXIT);
fail++;
}
}
/* syntax's `.wwi` carries the now-exported frontend types — spot-check
* a representative set spanning each surfacing path (fn-direct + the
* struct-field and tctx-field cascades). */
{
char wwi[1024];
snprintf(wwi, sizeof wwi, "%s/prog.cs.sepwork/syntax.wwi", td);
const char *want[] = {
"export type tok ", "export type tkind ", "export type node ",
"export type nkind ", "export type tinfo ", "export type tfield ",
"export type tctx ", "export type tinfocacheent ",
};
for (int i = 0; i < (int)(sizeof want / sizeof want[0]); i++)
if (file_contains(wwi, want[i]) != 0) {
fprintf(stderr, "syntaxexport FAIL: syntax.wwi lacks '%s'\n",
want[i]);
fail++;
}
}
/* cs==ww (rule 10): syntax's per-package artefacts + the final binary. */
{
const char *suf[] = { ".wwi", ".s", ".unit.ww" };
for (int k = 0; k < 3; k++) {
char a[1024], b[1024];
snprintf(a, sizeof a, "%s/prog.cs.sepwork/syntax%s", td, suf[k]);
snprintf(b, sizeof b, "%s/prog.ww.sepwork/syntax%s", td, suf[k]);
if (files_eq(a, b) != 0) {
fprintf(stderr, "syntaxexport FAIL: cs!=ww for syntax%s "
"(rule 10)\n", suf[k]);
fail++;
}
}
if (files_eq(stg[0].prog, stg[1].prog) != 0) {
fprintf(stderr, "syntaxexport FAIL: cs exe != ww exe (rule 10)\n");
fail++;
}
}
/* NON-VACUITY (the bug, isolated): replay the producer on the produced
* `syntax.unit.ww`. With the exports present `w6c -c -I` exits 0; with
* `export ` stripped from the type decls it MUST exit non-zero (the
* export-check fires). Proven for BOTH compilers. */
{
char unit[1024], ne[1024];
snprintf(unit, sizeof unit, "%s/prog.cs.sepwork/syntax.unit.ww", td);
snprintf(ne, sizeof ne, "%s/syntax.noexport.ww", td);
snprintf(cmd, sizeof cmd,
"sed 's/export type /type /g' %s > %s", unit, ne);
if (runwait(cmd) != 0) { fail++; goto out; }
struct { const char *comp; } cc[] = { { "w6c" }, { "w6c_ww" } };
for (int j = 0; j < 2; j++) {
char wwi[1024], asmf[1024];
snprintf(wwi, sizeof wwi, "%s/nv.%s.wwi", td, cc[j].comp);
snprintf(asmf, sizeof asmf, "%s/nv.%s.s", td, cc[j].comp);
snprintf(cmd, sizeof cmd, "%s/%s -c -I %s -o %s %s >/dev/null 2>&1",
bin, cc[j].comp, wwi, asmf, unit);
if (runwait(cmd) != 0) {
fprintf(stderr, "syntaxexport FAIL: %s -c -I rejected the "
"EXPORTED unit (post-fix producer must succeed)\n",
cc[j].comp);
fail++;
}
snprintf(cmd, sizeof cmd, "%s/%s -c -I %s -o %s %s >/dev/null 2>&1",
bin, cc[j].comp, wwi, asmf, ne);
if (runwait(cmd) == 0) {
fprintf(stderr, "syntaxexport FAIL: %s -c -I accepted the "
"UNEXPORTED-type unit (bug not reproduced -> vacuous "
"gate)\n", cc[j].comp);
fail++;
}
}
}
out:
for (int s = 0; s < 2; s++) {
const char *tag = s == 0 ? "cs" : "ww";
char path[1200];
snprintf(path, sizeof path, "%s/prog.%s.sepwork", td, tag);
snprintf(cmd, sizeof cmd, "rm -rf -- '%s'", path);
if (runwait(cmd) != 0) cleanup_fail = 1;
snprintf(path, sizeof path, "%s/prog.%s", td, tag);
if (unlink(path) != 0 && errno != ENOENT) cleanup_fail = 1;
snprintf(path, sizeof path, "%s/build.%s.log", td, tag);
if (unlink(path) != 0 && errno != ENOENT) cleanup_fail = 1;
}
{
const char *files[] = {
"root.ww", "syntax.noexport.ww",
"nv.w6c.wwi", "nv.w6c.s",
"nv.w6c_ww.wwi", "nv.w6c_ww.s",
};
for (size_t i = 0; i < sizeof files / sizeof files[0]; i++) {
char path[1200];
snprintf(path, sizeof path, "%s/%s", td, files[i]);
if (unlink(path) != 0 && errno != ENOENT) cleanup_fail = 1;
}
}
if (rmdir(td) != 0) cleanup_fail = 1;
if (cleanup_fail) {
fprintf(stderr, "syntaxexport FAIL: cleanup incomplete under %s\n", td);
fail++;
}
if (fail) {
fprintf(stderr, "syntaxexport: %d check(s) failed\n", fail);
return 1;
}
printf("syntaxexport: syntax->wcc boundary sep-PRODUCES clean (16 export "
"type decls) + qualified-ref consumer build+run (exit %d) + cs==ww "
"syntax.wwi/.s/.unit.ww/binary + non-vacuity (export strip rejects, "
"both compilers)\n", EXPECT_EXIT);
return 0;
}