test: delete dead @test gates 910/997 — coverage re-hosted in E2-C2 (M4 E3-C2, #22)
910_at_test.c and 997_at_test_ww.c build via `ww build` then read <stem>.combined.ww as a driver side-effect; the E3 flip removes that side-effect, so they cannot pass post-flip. Their coverage was fully re-hosted in E2-C2 -- every axis (run-exit, -T cs/ww byte-id, the userman/badsig/undefbody/linkfail rejects, the dup-decl family, modfn coexist, user `fn run` coexist) has a live home in 989_septest_run, 911_attest_drop, or 989_declns_sep, several strengthened. Deleting them before the flip keeps `make test` bisect-clean. Also retargets a stale 'Sibling of 910_at_test' doc comment in 911_attest_record.c to the surviving gates.
This commit is contained in:
12
Makefile
12
Makefile
@@ -232,7 +232,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
||||
$(BIN)/test_w6l_manyflags \
|
||||
$(BIN)/test_arch \
|
||||
$(BIN)/test_e2e $(BIN)/test_ffi $(BIN)/test_dyn $(BIN)/test_stdlib \
|
||||
$(BIN)/test_at_test $(BIN)/test_selfimport $(BIN)/test_missingpkg \
|
||||
$(BIN)/test_selfimport $(BIN)/test_missingpkg \
|
||||
$(BIN)/test_driver_flagargs \
|
||||
$(BIN)/test_let_global $(BIN)/test_def_neg_global \
|
||||
$(BIN)/test_def_const_fold \
|
||||
@@ -535,7 +535,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
||||
$(BIN)/test_field_signed $(BIN)/test_frame_argcount \
|
||||
$(BIN)/test_selfhost $(BIN)/test_w6a_ww $(BIN)/test_w6l_ww \
|
||||
$(BIN)/test_w6c_ww $(BIN)/test_ww_ww $(BIN)/test_self_rebuild \
|
||||
$(BIN)/test_dyn_ww $(BIN)/test_selfcheck $(BIN)/test_at_test_ww \
|
||||
$(BIN)/test_dyn_ww $(BIN)/test_selfcheck \
|
||||
$(BIN)/test_attest_record $(BIN)/test_attest_drop \
|
||||
$(BIN)/test_declns_sep \
|
||||
$(BIN)/test_fmt_run $(BIN)/test_log_run $(BIN)/test_fnmatch_run \
|
||||
@@ -688,10 +688,6 @@ $(BIN)/test_dyn: test/wcc/810_dyn.c $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||
$(BIN)/test_stdlib: test/wcc/900_stdlib.c $(BIN)/w6c | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BIN)/test_at_test: test/wcc/910_at_test.c $(BIN)/ww $(BIN)/w6c $(BIN)/w6a \
|
||||
$(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BIN)/test_selfimport: test/wcc/948_selfimport.c $(BIN)/w6c $(BIN)/w6c_ww \
|
||||
| $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
@@ -2951,10 +2947,6 @@ $(BIN)/test_dyn_ww: test/wcc/996_dyn_ww.c $(BIN)/ww $(BIN)/w6l $(BIN)/w6l_ww \
|
||||
$(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BIN)/test_at_test_ww: test/wcc/997_at_test_ww.c $(BIN)/ww_ww $(BIN)/w6c_ww \
|
||||
$(BIN)/w6a_ww $(BIN)/w6l_ww $(BIN)/w6c $(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BIN)/test_attest_record: test/wcc/911_attest_record.c $(BIN)/ww $(BIN)/w6c \
|
||||
$(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
@@ -1,452 +0,0 @@
|
||||
/*
|
||||
* 910_at_test — drives the compiler's `-T` @test mode (task #15).
|
||||
*
|
||||
* Under `w6c -T`, the checker collects every @test fn and synthesizes
|
||||
* `export fn main() i32 { t0(); t1(); ...; return 0; }`, calling each in
|
||||
* source order; a test that runs to completion passes, an abort/div0/
|
||||
* nonzero exit FAILS the run. This replaces the old driver-side regex
|
||||
* scan (find_attest) — the @test set now comes from the AST, the single
|
||||
* source of truth (rob #15 ruling). cgen is untouched: the synthesized
|
||||
* entry rides the existing cgfn path.
|
||||
*
|
||||
* Probes:
|
||||
* 1. RUN — `w6c -T` the @test-only fixture, assemble, link, run; the
|
||||
* synthesized entry must exit 0 (every @test passed). Imports are
|
||||
* resolved by `ww build` into a *.combined.ww (the fixture uses
|
||||
* `alloc`, whose rt_malloc symbol the driver concatenates); we then
|
||||
* compile that combined unit with `-T`.
|
||||
* 2. REJECT — `-T` of a fixture that also defines a user `main` must
|
||||
* exit nonzero (the synth entry owns main).
|
||||
* 3. GUARD — `-T` of a fixture whose @test fn is not `fn() void` must
|
||||
* exit nonzero (rule-7 loud, no silent skip/coerce).
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 *
|
||||
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;
|
||||
}
|
||||
|
||||
/* run_fixture — `<comp> -T` the @test fixture (import-resolved into a
|
||||
* combined unit by <drv> build), assemble, link, run; the synthesized
|
||||
* entry must exit 0. Returns 0 on success. */
|
||||
static int
|
||||
run_fixture(const char *bin, const char *comp, const char *drv)
|
||||
{
|
||||
int pid = getpid();
|
||||
char src[256], comb[256], binout[256], asmf[256], obj[256], exe[256];
|
||||
char rt[1024], cmd[4096];
|
||||
snprintf(src, sizeof src, "/tmp/at910_%s_%d.ww", comp, pid);
|
||||
snprintf(binout, sizeof binout, "/tmp/at910_%s_%d", comp, pid);
|
||||
snprintf(comb, sizeof comb, "/tmp/at910_%s_%d.combined.ww", comp, pid);
|
||||
snprintf(asmf, sizeof asmf, "/tmp/at910_%s_%d.s", comp, pid);
|
||||
snprintf(obj, sizeof obj, "/tmp/at910_%s_%d.o", comp, pid);
|
||||
snprintf(exe, sizeof exe, "/tmp/at910_%s_%d.exe", comp, pid);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
|
||||
snprintf(cmd, sizeof cmd, "cp test/wcc/data/attest_pass.ww %s", src);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "910 FAIL: cp\n"); return 1; }
|
||||
|
||||
/* `test -c -o <stem>` (compile-only) resolves imports AND auto-bundles
|
||||
* lib/test (#17) into <stem>.combined.ww — the synth's run() callee
|
||||
* must link below — WITHOUT running the harness. We depend on the
|
||||
* combined ARTIFACT; `-o` keeps the binary off the CWD. */
|
||||
snprintf(cmd, sizeof cmd, "%s/%s test -c -o %s %s > /dev/null 2>&1",
|
||||
bin, drv, binout, src);
|
||||
runwait(cmd);
|
||||
if (access(comb, 0) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s build produced no %s\n", drv, comb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof cmd, "%s/%s -T %s -o %s 2>/dev/null", bin, comp, comb, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s -T errored\n", comp);
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "910 FAIL: w6a\n"); return 1; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null", bin, exe, obj, rt);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "910 FAIL: w6l\n"); return 1; }
|
||||
|
||||
int rc = runwait(exe);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "910 FAIL: synth entry exited %d (a @test failed)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
unlink(src); unlink(comb); unlink(asmf); unlink(obj); unlink(exe);
|
||||
unlink(binout);
|
||||
char tmp[300];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", binout); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", binout); unlink(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reject — `<comp> -T <fixture>` must exit nonzero. */
|
||||
static int
|
||||
reject(const char *bin, const char *comp, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/%s -T %s -o /dev/null 2>/dev/null",
|
||||
bin, comp, fixture);
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "910 FAIL: %s -T accepted %s (expected reject)\n",
|
||||
comp, what);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Each row: a fixture `-T` must loud-reject, and why. */
|
||||
static const struct {
|
||||
const char *fixture;
|
||||
const char *what;
|
||||
} rejects[] = {
|
||||
{ "test/wcc/data/attest_userman.ww", "user main" },
|
||||
{ "test/wcc/data/attest_badsig.ww", "non-void @test" },
|
||||
};
|
||||
|
||||
/*
|
||||
* #6: each row asserts whether a symbol's TEXT def appears in the asm
|
||||
* `<comp>` emits for attest_nondrop.ww in a given mode. A @test fn is
|
||||
* spliced out of a non-test build (harec ref/harec/src/check.c:3941 —
|
||||
* checked but never emitted) and kept under -T (the synth entry calls
|
||||
* it); a plain fn is always emitted.
|
||||
*/
|
||||
static const struct {
|
||||
const char *sym; /* TEXT label to grep for */
|
||||
int testmode; /* 1 => -T, 0 => plain build */
|
||||
int present; /* expected: 1 present, 0 absent */
|
||||
const char *what;
|
||||
} nondrop_rows[] = {
|
||||
{ "data.nondrop_keep", 0, 1, "plain fn kept non-T" },
|
||||
{ "data.nondrop_test_a", 0, 0, "head @test dropped non-T" },
|
||||
{ "data.nondrop_test_b", 0, 0, "mid @test dropped non-T" },
|
||||
{ "data.nondrop_test_c", 0, 0, "consecutive @test dropped non-T" },
|
||||
{ "data.nondrop_keep", 1, 1, "plain fn kept under -T" },
|
||||
{ "data.nondrop_test_a", 1, 1, "head @test kept under -T" },
|
||||
{ "data.nondrop_test_b", 1, 1, "mid @test kept under -T" },
|
||||
{ "data.nondrop_test_c", 1, 1, "consecutive @test kept under -T" },
|
||||
};
|
||||
|
||||
/* nondrop — compile attest_nondrop.ww plain and `-T`, then assert each
|
||||
* row's TEXT def is present/absent. */
|
||||
static int
|
||||
nondrop(const char *bin, const char *comp)
|
||||
{
|
||||
int pid = getpid();
|
||||
char plain[256], tee[256], cmd[4096];
|
||||
snprintf(plain, sizeof plain, "/tmp/at910nd_%s_p_%d.s", comp, pid);
|
||||
snprintf(tee, sizeof tee, "/tmp/at910nd_%s_t_%d.s", comp, pid);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/%s test/wcc/data/attest_nondrop.ww -o %s 2>/dev/null",
|
||||
bin, comp, plain);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s non-T nondrop compile\n", comp);
|
||||
return 1;
|
||||
}
|
||||
/* The -T compile synthesizes a main that calls lib/test's run(), so it
|
||||
* needs the lib/test-inclusive combined `ww test -c` writes (the plain
|
||||
* compile above has no synth, so it stays on the raw fixture). */
|
||||
char stem[256], comb[300];
|
||||
snprintf(stem, sizeof stem, "/tmp/at910nd_%s_c_%d", comp, pid);
|
||||
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/ww test -c -o %s test/wcc/data/attest_nondrop.ww > /dev/null 2>&1",
|
||||
bin, stem);
|
||||
runwait(cmd);
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/%s -T %s -o %s 2>/dev/null", bin, comp, comb, tee);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s -T nondrop compile\n", comp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
for (size_t i = 0; i < sizeof nondrop_rows / sizeof nondrop_rows[0]; i++) {
|
||||
const char *f = nondrop_rows[i].testmode ? tee : plain;
|
||||
snprintf(cmd, sizeof cmd, "grep -q '^TEXT %s,' %s",
|
||||
nondrop_rows[i].sym, f);
|
||||
int found = runwait(cmd) == 0;
|
||||
if (found != nondrop_rows[i].present) {
|
||||
fprintf(stderr, "910 FAIL: %s — %s: %s %s (expected %s)\n",
|
||||
comp, nondrop_rows[i].what, nondrop_rows[i].sym,
|
||||
found ? "present" : "absent",
|
||||
nondrop_rows[i].present ? "present" : "absent");
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlink(plain); unlink(tee); unlink(comb);
|
||||
char tmp[300];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
||||
unlink(stem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* reject_plain — `<comp> <fixture>` (NON-T) must exit nonzero. Pins that
|
||||
* a @test body is type-checked before the #6 splice drops it: an
|
||||
* undefined symbol in the body is caught loud even though the fn never
|
||||
* reaches codegen (harec checks at :3913, drops at :3941). */
|
||||
static int
|
||||
reject_plain(const char *bin, const char *comp, const char *fixture,
|
||||
const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/%s %s -o /dev/null 2>/dev/null",
|
||||
bin, comp, fixture);
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "910 FAIL: %s (non-T) accepted %s "
|
||||
"(expected reject)\n", comp, what);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* linkfail — a plain fn calling a @test fn, built non-T: compile +
|
||||
* assemble succeed, but the link MUST fail (the dropped @test def leaves
|
||||
* the call's symbol dangling — harec-faithful loud failure, never a
|
||||
* silent mis-link). Linker behavior is stage-independent, so cstage
|
||||
* suffices; 997's byte-id proves the wwstage .s is identical. */
|
||||
static int
|
||||
linkfail(const char *bin, const char *comp)
|
||||
{
|
||||
int pid = getpid();
|
||||
char asmf[256], obj[256], exe[256], rt[1024], cmd[4096];
|
||||
snprintf(asmf, sizeof asmf, "/tmp/at910lf_%s_%d.s", comp, pid);
|
||||
snprintf(obj, sizeof obj, "/tmp/at910lf_%s_%d.o", comp, pid);
|
||||
snprintf(exe, sizeof exe, "/tmp/at910lf_%s_%d.exe", comp, pid);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/%s test/wcc/data/attest_calldropped.ww -o %s 2>/dev/null",
|
||||
bin, comp, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s non-T calldropped compile\n", comp);
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: w6a calldropped\n");
|
||||
unlink(asmf);
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null",
|
||||
bin, exe, obj, rt);
|
||||
int rc = 0;
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "910 FAIL: calldropped linked (expected "
|
||||
"undefined-reference to the dropped @test sym)\n");
|
||||
rc = 1;
|
||||
}
|
||||
unlink(asmf); unlink(obj); unlink(exe);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* accept — `<comp> <fixture>` (NON-T) must exit zero. The #23 cross-package
|
||||
* legal control: distinct-mod same-leaf decls coexist, so the dup reject
|
||||
* keyed on (name, mod) must NOT fire. */
|
||||
static int
|
||||
accept(const char *bin, const char *comp, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/%s %s -o /dev/null 2>/dev/null",
|
||||
bin, comp, fixture);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s rejected %s (expected accept)\n",
|
||||
comp, what);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* count_text — number of `TEXT <sym>,` directive lines in an asm file
|
||||
* (Plan-9 `TEXT name,$frame`), -1 on open failure. A COUNT (not presence)
|
||||
* is what distinguishes the #84 dead-dup: the bug yields 0x `TEXT run` +
|
||||
* 2x `TEXT test.run`, which a mere presence check would miss. */
|
||||
static int
|
||||
count_text(const char *path, const char *sym)
|
||||
{
|
||||
char want[128];
|
||||
snprintf(want, sizeof want, "TEXT %s,", sym);
|
||||
size_t wlen = strlen(want);
|
||||
FILE *f = fopen(path, "r");
|
||||
if (f == NULL) return -1;
|
||||
char line[8192];
|
||||
int n = 0;
|
||||
while (fgets(line, sizeof line, f) != NULL)
|
||||
if (strncmp(line, want, wlen) == 0) n++;
|
||||
fclose(f);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* coexist_run — a @test unit that ALSO defines a user `fn run` must
|
||||
* COEXIST with lib/test's bound runner, not collide. Post-#80 the synth
|
||||
* `use test;` is prepended before binding, so lib/test's `run` keys under
|
||||
* "test" (not "") and no longer duplicate-collides with the user's bare
|
||||
* `run` (which mangles bare via #84). `<comp> -T` of the `<drv> test -c`
|
||||
* combined now ACCEPTS; the -T asm carries EXACTLY 1 `TEXT run` (user,
|
||||
* bare) + 1 `TEXT test.run` (lib runner) — the static-label proof that the
|
||||
* user run is distinct in the real @test/-T path where #84 lives; then,
|
||||
* assembled, linked and run, the synth entry exits 0 (the user `run` did
|
||||
* not hijack the runner and the @test passes). Pre-#80 this loud-rejected
|
||||
* "duplicate fn run". */
|
||||
static int
|
||||
coexist_run(const char *bin, const char *comp, const char *drv)
|
||||
{
|
||||
int pid = getpid();
|
||||
char stem[256], comb[300], asmf[320], obj[320], exe[320];
|
||||
char rt[1024], cmd[4096];
|
||||
snprintf(stem, sizeof stem, "/tmp/at910cr_%s_%d", comp, pid);
|
||||
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
||||
snprintf(asmf, sizeof asmf, "%s.run.s", stem);
|
||||
snprintf(obj, sizeof obj, "%s.run.o", stem);
|
||||
snprintf(exe, sizeof exe, "%s.exe", stem);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/%s test -c -o %s test/wcc/data/attest_userrun.ww > /dev/null 2>&1",
|
||||
bin, drv, stem);
|
||||
runwait(cmd);
|
||||
if (access(comb, 0) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s build produced no %s\n", drv, comb);
|
||||
return 1;
|
||||
}
|
||||
int rc = 0;
|
||||
snprintf(cmd, sizeof cmd, "%s/%s -T %s -o %s 2>/dev/null",
|
||||
bin, comp, comb, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "910 FAIL: %s -T rejected user `fn run` coexist "
|
||||
"(expected accept post-#80)\n", comp);
|
||||
rc = 1;
|
||||
}
|
||||
if (rc == 0) {
|
||||
int nr = count_text(asmf, "run");
|
||||
int nt = count_text(asmf, "test.run");
|
||||
if (nr != 1 || nt != 1) {
|
||||
fprintf(stderr, "910 FAIL: %s -T asm label count run=%d "
|
||||
"test.run=%d (want 1/1) — user `fn run` not distinct from "
|
||||
"lib runner (a #84 dead-dup gives run=0/test.run=2)\n",
|
||||
comp, nr, nt);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "910 FAIL: coexist w6a\n"); rc = 1; }
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null",
|
||||
bin, exe, obj, rt);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "910 FAIL: coexist w6l\n"); rc = 1; }
|
||||
}
|
||||
if (rc == 0 && runwait(exe) != 0) {
|
||||
fprintf(stderr, "910 FAIL: coexist synth entry nonzero — user "
|
||||
"`fn run` hijacked the runner or the @test failed\n");
|
||||
rc = 1;
|
||||
}
|
||||
unlink(comb); unlink(asmf); unlink(obj); unlink(exe);
|
||||
char tmp[320];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
||||
unlink(stem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* modfn_run — `<drv> run <fixture>` and assert exit 6 (#30). The fixture's
|
||||
* main returns `aa() + aa.helper()` = 1 + 5: the bare `aa()` must resolve to
|
||||
* the fn (1) and the qualified `aa.helper()` to the module member (5). A
|
||||
* mis-resolution that still compiled would run to a different code; this
|
||||
* pins the resolved TARGETS, not just acceptance. */
|
||||
static int
|
||||
modfn_run(const char *bin, const char *drv, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/%s run %s > /dev/null 2>&1", bin, drv, fixture);
|
||||
int rc = runwait(cmd);
|
||||
if (rc != 6) {
|
||||
fprintf(stderr, "910 FAIL: %s run %s exited %d (expected 6 — bare fn "
|
||||
"+ qualified module resolution)\n", drv, what, rc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = absbin();
|
||||
if (!bin) { fprintf(stderr, "910 FAIL: getcwd\n"); return 1; }
|
||||
|
||||
if (run_fixture(bin, "w6c", "ww") != 0) return 1;
|
||||
for (size_t i = 0; i < sizeof rejects / sizeof rejects[0]; i++)
|
||||
if (reject(bin, "w6c", rejects[i].fixture, rejects[i].what) != 0)
|
||||
return 1;
|
||||
if (nondrop(bin, "w6c") != 0) return 1;
|
||||
if (reject_plain(bin, "w6c", "test/wcc/data/attest_undefbody.ww",
|
||||
"undefined symbol in @test body") != 0) return 1;
|
||||
if (linkfail(bin, "w6c") != 0) return 1;
|
||||
|
||||
/* #23 — top-level duplicate-decl reject (one row per kind: all four
|
||||
* route through installtop, so each deserves its own pin) + legal
|
||||
* cross-package control + the builtin-redecl carve-out accept. */
|
||||
if (reject_plain(bin, "w6c", "test/wcc/data/dup_fn.ww",
|
||||
"same-module duplicate fn") != 0) return 1;
|
||||
if (reject_plain(bin, "w6c", "test/wcc/data/dup_type.ww",
|
||||
"same-module duplicate type") != 0) return 1;
|
||||
if (reject_plain(bin, "w6c", "test/wcc/data/dup_def.ww",
|
||||
"same-module duplicate def") != 0) return 1;
|
||||
if (reject_plain(bin, "w6c", "test/wcc/data/dup_let.ww",
|
||||
"same-module duplicate let") != 0) return 1;
|
||||
if (accept(bin, "w6c", "test/wcc/data/dup_xpkg_ok.ww",
|
||||
"cross-package same-name") != 0) return 1;
|
||||
if (accept(bin, "w6c", "test/wcc/data/builtin_redecl_ok.ww",
|
||||
"builtin nomem redecl (carve-out)") != 0) return 1;
|
||||
/* #30 — a top-level fn whose leaf matches an imported module name
|
||||
* coexists with the module bareword (different namespaces). Accept
|
||||
* proves both the bare `aa()` (fn) and qualified `aa.helper()`
|
||||
* (module) resolve; a mis-resolution would fail to compile. Both
|
||||
* decl orders are pinned (use-before-value AND value-before-use): the
|
||||
* order-dependence is exactly what regresses silently — cstage is
|
||||
* order-independent, wwstage closes both directions via the symmetric
|
||||
* promotes in installtop + installdecl's N_USE arm. */
|
||||
if (accept(bin, "w6c", "test/wcc/data/modfn_coexist_ok.ww",
|
||||
"fn named like imported module (use-before-value)") != 0) return 1;
|
||||
if (accept(bin, "w6c", "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
||||
"fn named like imported module (value-before-use)") != 0) return 1;
|
||||
/* runtime-resolve: both orders run to exit 6 (bare fn=1 + module
|
||||
* member=5), pinning the resolved targets on the cstage driver. */
|
||||
if (modfn_run(bin, "ww", "test/wcc/data/modfn_coexist_ok.ww",
|
||||
"use-before-value") != 0) return 1;
|
||||
if (modfn_run(bin, "ww", "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
||||
"value-before-use") != 0) return 1;
|
||||
if (coexist_run(bin, "w6c", "ww") != 0) return 1;
|
||||
|
||||
printf("@test -T: run ok + user-main and bad-signature rejected + "
|
||||
"non-T @test drop + checked-body + dangling-call link-fail (#6) + "
|
||||
"dup fn/type/def/let reject + xpkg + builtin-redecl accept + "
|
||||
"modfn coexist (#30) + fn-run coexist (#80)\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* 911_attest_record — #17 record-and-continue harness (lib/test + the
|
||||
* table-synth -T entry). Sibling of 910_at_test (which pins the synth
|
||||
* itself + the #6 non-T drop); this one pins the RUNTIME behaviour the
|
||||
* fork+wait4 runner adds:
|
||||
* table-synth -T entry). Sibling of 989_septest_run + 911_attest_drop
|
||||
* (which pin the synth entry itself + the #6 non-T drop); this one pins
|
||||
* the RUNTIME behaviour the fork+wait4 runner adds:
|
||||
*
|
||||
* 1. RECORD-AND-CONTINUE — `ww test` the mixed fixture (one pass, then
|
||||
* assert-fail/SIGSEGV/SIGFPE, then a final pass). The runner must
|
||||
|
||||
@@ -1,523 +0,0 @@
|
||||
/*
|
||||
* 997_at_test_ww — the wwstage twin of 910_at_test, driving the `-T`
|
||||
* @test mode through `w6c_ww` (the ww-built compiler) instead of `w6c`
|
||||
* (the C bootstrap). Task #15.
|
||||
*
|
||||
* Probes:
|
||||
* 1. RUN — `w6c_ww -T` the @test-only fixture (import-resolved by
|
||||
* `ww_ww build` into a combined unit), assemble, link, run; the
|
||||
* synthesized entry must exit 0.
|
||||
* 2. BYTE-ID (rule 10) — `w6c -T` and `w6c_ww -T` must emit
|
||||
* byte-identical asm for the same source. The synthesized entry
|
||||
* rides cgfn at the gated choke point, so the @test set + the
|
||||
* collection-order calls are identical by construction. This is
|
||||
* the new entry-synth byte-id gate.
|
||||
* 3. REJECT — `-T` of a user-main fixture exits nonzero.
|
||||
* 4. GUARD — `-T` of a non-`fn() void` @test exits nonzero.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 *
|
||||
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
|
||||
run_fixture(const char *bin)
|
||||
{
|
||||
int pid = getpid();
|
||||
char src[256], comb[256], binout[256], asmf[256], obj[256], exe[256];
|
||||
char rt[1024], cmd[4096];
|
||||
snprintf(src, sizeof src, "/tmp/at997_%d.ww", pid);
|
||||
snprintf(binout, sizeof binout, "/tmp/at997_%d", pid);
|
||||
snprintf(comb, sizeof comb, "/tmp/at997_%d.combined.ww", pid);
|
||||
snprintf(asmf, sizeof asmf, "/tmp/at997_%d.s", pid);
|
||||
snprintf(obj, sizeof obj, "/tmp/at997_%d.o", pid);
|
||||
snprintf(exe, sizeof exe, "/tmp/at997_%d.exe", pid);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
|
||||
snprintf(cmd, sizeof cmd, "cp test/wcc/data/attest_pass.ww %s", src);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: cp\n"); return 1; }
|
||||
|
||||
/* `ww_ww test -c -o <stem>` (compile-only) resolves imports AND auto-
|
||||
* bundles lib/test (#17) into <stem>.combined.ww — the synth's run()
|
||||
* callee must link below — WITHOUT running the harness. We gate on the
|
||||
* combined ARTIFACT existing; `-o` keeps the binary off the CWD. */
|
||||
snprintf(cmd, sizeof cmd, "%s/ww_ww test -c -o %s %s > /dev/null 2>&1",
|
||||
bin, binout, src);
|
||||
runwait(cmd);
|
||||
if (access(comb, 0) != 0) {
|
||||
fprintf(stderr, "997 FAIL: ww_ww build produced no %s\n", comb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c_ww -T errored\n"); return 1; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a_ww -o %s %s 2>/dev/null", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6a_ww\n"); return 1; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6l_ww -o %s %s %s 2>/dev/null", bin, exe, obj, rt);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6l_ww\n"); return 1; }
|
||||
|
||||
int rc = runwait(exe);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "997 FAIL: synth entry exited %d (a @test failed)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
unlink(src); unlink(comb); unlink(asmf); unlink(obj); unlink(exe);
|
||||
unlink(binout);
|
||||
char tmp[300];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", binout); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", binout); unlink(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* byteid — `w6c -T` and `w6c_ww -T` on the same unit must agree. The #17
|
||||
* synth's run() callee only resolves against the auto-bundled lib/test, so
|
||||
* we byte-compare the lib/test-INCLUSIVE combined (raw -T of the fixture
|
||||
* would loud-reject the undefined run); `ww test -c` writes that combined. */
|
||||
static int
|
||||
byteid(const char *bin)
|
||||
{
|
||||
int pid = getpid();
|
||||
char stem[256], comb[256], cs[256], ws[256], cmd[4096];
|
||||
snprintf(stem, sizeof stem, "/tmp/at997_bid_%d", pid);
|
||||
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
||||
snprintf(cs, sizeof cs, "/tmp/at997_bid_c_%d.s", pid);
|
||||
snprintf(ws, sizeof ws, "/tmp/at997_bid_w_%d.s", pid);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/ww test -c -o %s test/wcc/data/attest_pass.ww > /dev/null 2>&1",
|
||||
bin, stem);
|
||||
runwait(cmd);
|
||||
if (access(comb, 0) != 0) {
|
||||
fprintf(stderr, "997 FAIL: ww test -c produced no %s\n", comb);
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c -T %s -o %s 2>/dev/null", bin, comb, cs);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c -T (byteid)\n"); return 1; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, ws);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c_ww -T (byteid)\n"); return 1; }
|
||||
|
||||
char *bc = NULL, *bw = NULL;
|
||||
size_t nc = 0, nw = 0;
|
||||
int rc = 0;
|
||||
if (slurp(cs, &bc, &nc) < 0 || slurp(ws, &bw, &nw) < 0) {
|
||||
fprintf(stderr, "997 FAIL: slurp byteid asm\n");
|
||||
rc = 1;
|
||||
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
||||
fprintf(stderr, "997 FAIL: -T asm differs (cs %zu, ww %zu)\n", nc, nw);
|
||||
rc = 1;
|
||||
}
|
||||
free(bc); free(bw);
|
||||
unlink(comb); unlink(cs); unlink(ws);
|
||||
char tmp[300];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
||||
unlink(stem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
reject(const char *bin, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o /dev/null 2>/dev/null", bin, fixture);
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww -T accepted %s (expected reject)\n", what);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Each row: a fixture `w6c_ww -T` must loud-reject, and why. */
|
||||
static const struct {
|
||||
const char *fixture;
|
||||
const char *what;
|
||||
} rejects[] = {
|
||||
{ "test/wcc/data/attest_userman.ww", "user main" },
|
||||
{ "test/wcc/data/attest_badsig.ww", "non-void @test" },
|
||||
};
|
||||
|
||||
/* #6: TEXT-def present/absent rows for attest_nondrop.ww (mirror 910). */
|
||||
static const struct {
|
||||
const char *sym;
|
||||
int testmode; /* 1 => -T, 0 => plain build */
|
||||
int present;
|
||||
const char *what;
|
||||
} nondrop_rows[] = {
|
||||
{ "data.nondrop_keep", 0, 1, "plain fn kept non-T" },
|
||||
{ "data.nondrop_test_a", 0, 0, "head @test dropped non-T" },
|
||||
{ "data.nondrop_test_b", 0, 0, "mid @test dropped non-T" },
|
||||
{ "data.nondrop_test_c", 0, 0, "consecutive @test dropped non-T" },
|
||||
{ "data.nondrop_keep", 1, 1, "plain fn kept under -T" },
|
||||
{ "data.nondrop_test_a", 1, 1, "head @test kept under -T" },
|
||||
{ "data.nondrop_test_b", 1, 1, "mid @test kept under -T" },
|
||||
{ "data.nondrop_test_c", 1, 1, "consecutive @test kept under -T" },
|
||||
};
|
||||
|
||||
/* nondrop — drive the #6 splice through w6c_ww (rows) AND assert the
|
||||
* non-T asm is cs/ww byte-identical (rule 10: the drop must be symmetric,
|
||||
* not just cstage-side — 997's byteid above only covered -T mode). */
|
||||
static int
|
||||
nondrop(const char *bin)
|
||||
{
|
||||
int pid = getpid();
|
||||
char wp[256], wt[256], cp[256], stem[256], comb[300], cmd[4096];
|
||||
snprintf(wp, sizeof wp, "/tmp/at997nd_wp_%d.s", pid);
|
||||
snprintf(wt, sizeof wt, "/tmp/at997nd_wt_%d.s", pid);
|
||||
snprintf(cp, sizeof cp, "/tmp/at997nd_cp_%d.s", pid);
|
||||
snprintf(stem, sizeof stem, "/tmp/at997nd_c_%d", pid);
|
||||
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6c_ww test/wcc/data/attest_nondrop.ww -o %s 2>/dev/null", bin, wp);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww non-T nondrop compile\n");
|
||||
return 1;
|
||||
}
|
||||
/* the -T compile synthesizes a main calling lib/test's run(), so it
|
||||
* needs the lib/test-inclusive combined `ww test -c` writes. */
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/ww test -c -o %s test/wcc/data/attest_nondrop.ww > /dev/null 2>&1",
|
||||
bin, stem);
|
||||
runwait(cmd);
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, wt);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww -T nondrop compile\n");
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6c test/wcc/data/attest_nondrop.ww -o %s 2>/dev/null", bin, cp);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c non-T nondrop compile\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
for (size_t i = 0; i < sizeof nondrop_rows / sizeof nondrop_rows[0]; i++) {
|
||||
const char *f = nondrop_rows[i].testmode ? wt : wp;
|
||||
snprintf(cmd, sizeof cmd, "grep -q '^TEXT %s,' %s",
|
||||
nondrop_rows[i].sym, f);
|
||||
int found = runwait(cmd) == 0;
|
||||
if (found != nondrop_rows[i].present) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww — %s: %s %s (expected %s)\n",
|
||||
nondrop_rows[i].what, nondrop_rows[i].sym,
|
||||
found ? "present" : "absent",
|
||||
nondrop_rows[i].present ? "present" : "absent");
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
char *bc = NULL, *bw = NULL;
|
||||
size_t nc = 0, nw = 0;
|
||||
if (slurp(cp, &bc, &nc) < 0 || slurp(wp, &bw, &nw) < 0) {
|
||||
fprintf(stderr, "997 FAIL: slurp non-T nondrop asm\n");
|
||||
rc = 1;
|
||||
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
||||
fprintf(stderr, "997 FAIL: non-T @test-drop asm differs "
|
||||
"(cs %zu, ww %zu)\n", nc, nw);
|
||||
rc = 1;
|
||||
}
|
||||
free(bc); free(bw);
|
||||
}
|
||||
unlink(wp); unlink(wt); unlink(cp); unlink(comb);
|
||||
char tmp[300];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
||||
unlink(stem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* reject_plain — `w6c_ww <fixture>` (NON-T) must exit nonzero. Pins (as
|
||||
* 910 does for cstage) that wwstage type-checks a @test body before the
|
||||
* #6 splice drops it: an undefined symbol is caught loud even though the
|
||||
* fn never reaches codegen (checked at check.ww pass 2/3, dropped after). */
|
||||
static int
|
||||
reject_plain(const char *bin, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c_ww %s -o /dev/null 2>/dev/null",
|
||||
bin, fixture);
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww (non-T) accepted %s "
|
||||
"(expected reject)\n", what);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* accept_byteid — a #23 legal-accept control: `<fixture>` must COMPILE on
|
||||
* BOTH stages (no false dup reject) AND be cs/ww byte-identical (rule 10).
|
||||
* Used for the cross-package same-leaf control (keying is (name, mod), so
|
||||
* distinct-package leaves coexist) and the builtin-redecl carve-out (the
|
||||
* one structural point where wwstage seeds builtins and cstage does not —
|
||||
* byte-id proves the drop-the-redecl mirror is exact). */
|
||||
static int
|
||||
accept_byteid(const char *bin, const char *fixture, const char *what)
|
||||
{
|
||||
int pid = getpid();
|
||||
char cs[256], ws[256], cmd[4096];
|
||||
snprintf(cs, sizeof cs, "/tmp/at997ab_c_%d.s", pid);
|
||||
snprintf(ws, sizeof ws, "/tmp/at997ab_w_%d.s", pid);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6c %s -o %s 2>/dev/null", bin, fixture, cs);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c rejected %s\n", what);
|
||||
return 1;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6c_ww %s -o %s 2>/dev/null", bin, fixture, ws);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww rejected %s\n", what);
|
||||
return 1;
|
||||
}
|
||||
char *bc = NULL, *bw = NULL;
|
||||
size_t nc = 0, nw = 0;
|
||||
int rc = 0;
|
||||
if (slurp(cs, &bc, &nc) < 0 || slurp(ws, &bw, &nw) < 0) {
|
||||
fprintf(stderr, "997 FAIL: slurp %s asm\n", what);
|
||||
rc = 1;
|
||||
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
||||
fprintf(stderr, "997 FAIL: %s asm differs (cs %zu, ww %zu)\n",
|
||||
what, nc, nw);
|
||||
rc = 1;
|
||||
}
|
||||
free(bc); free(bw);
|
||||
unlink(cs); unlink(ws);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* count_text — number of `TEXT <sym>,` directive lines in an asm file
|
||||
* (Plan-9 `TEXT name,$frame`), -1 on open failure. A COUNT (not presence)
|
||||
* is what distinguishes the #84 dead-dup: the bug yields 0x `TEXT run` +
|
||||
* 2x `TEXT test.run`, which a mere presence check would miss. */
|
||||
static int
|
||||
count_text(const char *path, const char *sym)
|
||||
{
|
||||
char want[128];
|
||||
snprintf(want, sizeof want, "TEXT %s,", sym);
|
||||
size_t wlen = strlen(want);
|
||||
FILE *f = fopen(path, "r");
|
||||
if (f == NULL) return -1;
|
||||
char line[8192];
|
||||
int n = 0;
|
||||
while (fgets(line, sizeof line, f) != NULL)
|
||||
if (strncmp(line, want, wlen) == 0) n++;
|
||||
fclose(f);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* coexist_run — a @test unit that ALSO defines a user `fn run` must
|
||||
* COEXIST with lib/test's bound runner, not collide. Post-#80 the synth
|
||||
* `use test;` is prepended before binding, so lib/test's `run` keys under
|
||||
* "test" (not "") and no longer duplicate-collides with the user's bare
|
||||
* `run` (which mangles bare via #84). `w6c_ww -T` of the `ww_ww test -c`
|
||||
* combined now ACCEPTS; the -T asm carries EXACTLY 1 `TEXT run` (user,
|
||||
* bare) + 1 `TEXT test.run` (lib runner) and is byte-identical to w6c's
|
||||
* (cs==ww) — the static-label proof that the user run is distinct in the
|
||||
* real @test/-T path where #84 lives; then, assembled, linked and run, the
|
||||
* synth entry exits 0 (the user `run` did not hijack the runner and the
|
||||
* @test passes). Pre-#80 this loud-rejected "duplicate fn run". */
|
||||
static int
|
||||
coexist_run(const char *bin)
|
||||
{
|
||||
int pid = getpid();
|
||||
char stem[256], comb[300], asmf[320], csasm[320], obj[320], exe[320];
|
||||
char rt[1024], cmd[4096];
|
||||
snprintf(stem, sizeof stem, "/tmp/at997cr_%d", pid);
|
||||
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
||||
snprintf(asmf, sizeof asmf, "%s.run.s", stem);
|
||||
snprintf(csasm, sizeof csasm, "%s.cs.s", stem);
|
||||
snprintf(obj, sizeof obj, "%s.run.o", stem);
|
||||
snprintf(exe, sizeof exe, "%s.exe", stem);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/ww_ww test -c -o %s test/wcc/data/attest_userrun.ww > /dev/null 2>&1",
|
||||
bin, stem);
|
||||
runwait(cmd);
|
||||
if (access(comb, 0) != 0) {
|
||||
fprintf(stderr, "997 FAIL: ww_ww build produced no %s\n", comb);
|
||||
return 1;
|
||||
}
|
||||
int rc = 0;
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o %s 2>/dev/null",
|
||||
bin, comb, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww -T rejected user `fn run` coexist "
|
||||
"(expected accept post-#80)\n");
|
||||
rc = 1;
|
||||
}
|
||||
if (rc == 0) {
|
||||
int nr = count_text(asmf, "run");
|
||||
int nt = count_text(asmf, "test.run");
|
||||
if (nr != 1 || nt != 1) {
|
||||
fprintf(stderr, "997 FAIL: w6c_ww -T asm label count run=%d "
|
||||
"test.run=%d (want 1/1) — user `fn run` not distinct from "
|
||||
"lib runner (a #84 dead-dup gives run=0/test.run=2)\n",
|
||||
nr, nt);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c -T %s -o %s 2>/dev/null",
|
||||
bin, comb, csasm);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "997 FAIL: w6c -T (coexist cs==ww)\n");
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
char *bc = NULL, *bw = NULL;
|
||||
size_t nc = 0, nw = 0;
|
||||
if (slurp(csasm, &bc, &nc) < 0 || slurp(asmf, &bw, &nw) < 0) {
|
||||
fprintf(stderr, "997 FAIL: slurp coexist asm\n");
|
||||
rc = 1;
|
||||
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
||||
fprintf(stderr, "997 FAIL: coexist -T asm cs!=ww "
|
||||
"(cs %zu, ww %zu)\n", nc, nw);
|
||||
rc = 1;
|
||||
}
|
||||
free(bc); free(bw);
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a_ww -o %s %s 2>/dev/null", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: coexist w6a_ww\n"); rc = 1; }
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/w6l_ww -o %s %s %s 2>/dev/null",
|
||||
bin, exe, obj, rt);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: coexist w6l_ww\n"); rc = 1; }
|
||||
}
|
||||
if (rc == 0 && runwait(exe) != 0) {
|
||||
fprintf(stderr, "997 FAIL: coexist synth entry nonzero — user "
|
||||
"`fn run` hijacked the runner or the @test failed\n");
|
||||
rc = 1;
|
||||
}
|
||||
unlink(comb); unlink(asmf); unlink(csasm); unlink(obj); unlink(exe);
|
||||
char tmp[320];
|
||||
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
||||
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
||||
unlink(stem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* modfn_run — `ww_ww run <fixture>` and assert exit 6 (#30): the wwstage
|
||||
* runtime twin of 910's modfn_run. The fixture's main returns `aa() +
|
||||
* aa.helper()` = 1 + 5; the bare fn must resolve to 1 and the qualified
|
||||
* module member to 5, so a mis-resolution that still compiled runs to a
|
||||
* different code. Pins the resolved TARGETS on the wwstage driver. */
|
||||
static int
|
||||
modfn_run(const char *bin, const char *fixture, const char *what)
|
||||
{
|
||||
char cmd[4096];
|
||||
snprintf(cmd, sizeof cmd, "%s/ww_ww run %s > /dev/null 2>&1", bin, fixture);
|
||||
int rc = runwait(cmd);
|
||||
if (rc != 6) {
|
||||
fprintf(stderr, "997 FAIL: ww_ww run %s exited %d (expected 6 — bare "
|
||||
"fn + qualified module resolution)\n", what, rc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = absbin();
|
||||
if (!bin) { fprintf(stderr, "997 FAIL: getcwd\n"); return 1; }
|
||||
|
||||
if (run_fixture(bin) != 0) return 1;
|
||||
if (byteid(bin) != 0) return 1;
|
||||
for (size_t i = 0; i < sizeof rejects / sizeof rejects[0]; i++)
|
||||
if (reject(bin, rejects[i].fixture, rejects[i].what) != 0)
|
||||
return 1;
|
||||
if (nondrop(bin) != 0) return 1;
|
||||
if (reject_plain(bin, "test/wcc/data/attest_undefbody.ww",
|
||||
"undefined symbol in @test body") != 0) return 1;
|
||||
|
||||
/* #23 — wwstage top-level duplicate-decl reject (one row per kind:
|
||||
* all four route through installtop) + legal cross-package control
|
||||
* (byte-id) + the builtin-redecl carve-out (byte-id) + the -T
|
||||
* `fn run` collision parity row. */
|
||||
if (reject_plain(bin, "test/wcc/data/dup_fn.ww",
|
||||
"same-module duplicate fn") != 0) return 1;
|
||||
if (reject_plain(bin, "test/wcc/data/dup_type.ww",
|
||||
"same-module duplicate type") != 0) return 1;
|
||||
if (reject_plain(bin, "test/wcc/data/dup_def.ww",
|
||||
"same-module duplicate def") != 0) return 1;
|
||||
if (reject_plain(bin, "test/wcc/data/dup_let.ww",
|
||||
"same-module duplicate let") != 0) return 1;
|
||||
if (accept_byteid(bin, "test/wcc/data/dup_xpkg_ok.ww",
|
||||
"cross-package same-name") != 0) return 1;
|
||||
if (accept_byteid(bin, "test/wcc/data/builtin_redecl_ok.ww",
|
||||
"builtin nomem redecl (carve-out)") != 0) return 1;
|
||||
/* #30 — a top-level fn whose leaf matches an imported module name
|
||||
* coexists with the module bareword. wwstage now PROMOTES the same-leaf
|
||||
* collision in place (use_alias=1), mirroring cstage exactly, so byte-id
|
||||
* proves the resolved call targets match. Both decl orders are pinned:
|
||||
* use-before-value promotes via installtop's value-arm, value-before-use
|
||||
* via installdecl's N_USE arm — both reach the identical single-sym end
|
||||
* state, so cstage and wwstage agree on every source order. The bare
|
||||
* `aa()` and qualified `aa.helper()` both resolve, else the compile
|
||||
* fails. */
|
||||
if (accept_byteid(bin, "test/wcc/data/modfn_coexist_ok.ww",
|
||||
"fn named like imported module (use-before-value)") != 0) return 1;
|
||||
if (accept_byteid(bin, "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
||||
"fn named like imported module (value-before-use)") != 0) return 1;
|
||||
/* runtime-resolve: both orders run to exit 6 on the wwstage driver,
|
||||
* pinning that the promoted sym resolves bare fn=1 + module member=5. */
|
||||
if (modfn_run(bin, "test/wcc/data/modfn_coexist_ok.ww",
|
||||
"use-before-value") != 0) return 1;
|
||||
if (modfn_run(bin, "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
||||
"value-before-use") != 0) return 1;
|
||||
if (coexist_run(bin) != 0) return 1;
|
||||
|
||||
printf("@test -T (ww_ww): run ok + cs/ww byte-id + rejects + "
|
||||
"non-T @test drop cs/ww byte-id + checked-body (#6) + "
|
||||
"dup fn/type/def/let reject + xpkg/builtin-redecl byte-id + "
|
||||
"modfn coexist byte-id (#30) + fn-run coexist (#80)\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user