test: port the @test drop/keep/link observer to ww; retire 911_attest_drop
This commit is contained in:
3
Makefile
3
Makefile
@@ -420,7 +420,8 @@ MISC_WW_TARGETS = $(MISC_WW_TESTS:%=wwtest/%)
|
||||
# wide-rune round-trips, the c6 sep soak). Compiler/driver gates like
|
||||
# test/sep: they run under test-compiler.
|
||||
TOOL_WW_TESTS = test/tool/rejects_test.ww test/tool/driver_test.ww \
|
||||
test/tool/wwdump_test.ww test/tool/ffi_test.ww
|
||||
test/tool/wwdump_test.ww test/tool/ffi_test.ww \
|
||||
test/tool/attest_test.ww
|
||||
TOOL_WW_TARGETS = $(TOOL_WW_TESTS:%=wwtest/%)
|
||||
BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \
|
||||
test/wcc/991_w6a_ww.c \
|
||||
|
||||
177
test/tool/attest_test.ww
Normal file
177
test/tool/attest_test.ww
Normal file
@@ -0,0 +1,177 @@
|
||||
package attest_test;
|
||||
|
||||
// The #6 @test DROP/KEEP/LINK emission property, driven by w6c /
|
||||
// w6c_ww DIRECTLY on the import-free test/wcc/data/attest_* fixtures.
|
||||
// Port of the retired native carrier test/wcc/911_attest_drop.c;
|
||||
// every assertion preserved.
|
||||
//
|
||||
// Direct-frontend is the only host that can compare -T and non-T on
|
||||
// the SAME input: `ww test` is always -T, `ww build` always non-T.
|
||||
// A @test fn is spliced out of a non-test build (harec-faithful,
|
||||
// ref/harec/src/check.c:3941 — checked but never emitted) and kept
|
||||
// under -T (the synth entry references it); the -T synth's `test.run`
|
||||
// callee stays an external CALL, so no driver resolution is needed.
|
||||
//
|
||||
// nondrop — attest_nondrop.ww compiled four ways (cs/ww x non-T/-T):
|
||||
// the plain fn's TEXT def is present in both modes; the three @test
|
||||
// TEXT defs are absent non-T and present under -T. The fixture layout
|
||||
// exercises the splice loop's unlink edges (head @test, surviving
|
||||
// plain fn, two consecutive @test). The presence rows run against the
|
||||
// cstage .s; the cs==ww byte-id in BOTH modes (rule 10) carries them
|
||||
// onto the wwstage .s by construction.
|
||||
//
|
||||
// undefbody — a @test body referencing an undefined symbol rejects in
|
||||
// non-T on both frontends: the body is type-checked BEFORE the splice
|
||||
// drops it (harec checks at :3913, drops at :3941).
|
||||
//
|
||||
// linkfail — non-test code CALLs a @test fn: non-T compile+assemble
|
||||
// succeed per stage triple, but the link MUST fail, and the link
|
||||
// stderr must name calldropped_test (non-vacuity: the failure is ON
|
||||
// the dropped @test symbol — a libwwrt path drift failing every link
|
||||
// would otherwise mask the property).
|
||||
|
||||
import os;
|
||||
import os.exec;
|
||||
import strings;
|
||||
import testenv;
|
||||
import time;
|
||||
|
||||
fn fail(label: str, why: str) void = {
|
||||
let m: str = strings.concat("attest FAIL: ", label, " -- ", why,
|
||||
"\n");
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
assert(false);
|
||||
};
|
||||
|
||||
fn tmo() time.duration = {
|
||||
return (60i64 * (time.second: i64)): time.duration;
|
||||
};
|
||||
|
||||
fn runcode(dir: str, name: str, argv: []str) i32 = {
|
||||
let co: testenv.commandout;
|
||||
testenv.runcommand(dir, dir, name, argv, tmo(), &co);
|
||||
if (co.termination != exec.termination.EXIT) { return -1; };
|
||||
return co.code;
|
||||
};
|
||||
|
||||
// column-0 anchored TEXT label; the '\n' prepend counts a
|
||||
// file-leading label too.
|
||||
fn hastext(s: str, sym: str) bool = {
|
||||
return testenv.occurrences(strings.concat("\n", s),
|
||||
strings.concat("\nTEXT ", sym, ",")) > 0;
|
||||
};
|
||||
|
||||
@test fn nondrop() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let fixture: str = strings.concat(testenv.repo(),
|
||||
"/test/wcc/data/attest_nondrop.ww");
|
||||
let comps: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"];
|
||||
let testmode: []bool = [false, true, false, true];
|
||||
let names: []str = ["cp", "ct", "wp", "wt"];
|
||||
let asms: []str = ["", "", "", ""];
|
||||
let j: i32 = 0;
|
||||
for (j < 4) {
|
||||
let outf: str = strings.concat(td, "/", names[j], ".s");
|
||||
let av: []str = alloc([], 5u64)!;
|
||||
append(av, testenv.driver(comps[j]));
|
||||
if (testmode[j]) { append(av, "-T"); };
|
||||
append(av, fixture);
|
||||
append(av, "-o");
|
||||
append(av, outf);
|
||||
if (runcode(td, names[j], av) != 0) {
|
||||
fail("nondrop", strings.concat(comps[j],
|
||||
" nondrop compile failed"));
|
||||
};
|
||||
asms[j] = testenv.readfile(outf);
|
||||
j += 1;
|
||||
};
|
||||
|
||||
let syms: []str = ["data.nondrop_keep", "data.nondrop_test_a",
|
||||
"data.nondrop_test_b", "data.nondrop_test_c",
|
||||
"data.nondrop_keep", "data.nondrop_test_a",
|
||||
"data.nondrop_test_b", "data.nondrop_test_c"];
|
||||
let rowmode: []bool = [false, false, false, false,
|
||||
true, true, true, true];
|
||||
let present: []bool = [true, false, false, false,
|
||||
true, true, true, true];
|
||||
let whats: []str = ["plain fn kept non-T", "head @test dropped non-T",
|
||||
"mid @test dropped non-T", "consecutive @test dropped non-T",
|
||||
"plain fn kept under -T", "head @test kept under -T",
|
||||
"mid @test kept under -T", "consecutive @test kept under -T"];
|
||||
let i: i32 = 0;
|
||||
for (i < syms.len) {
|
||||
let s: str = asms[0];
|
||||
if (rowmode[i]) { s = asms[1]; };
|
||||
if (hastext(s, syms[i]) != present[i]) {
|
||||
fail("nondrop", whats[i]);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (!testenv.same(asms[0], asms[2])) {
|
||||
fail("nondrop", "non-T @test-drop asm cs!=ww (rule 10)");
|
||||
};
|
||||
if (!testenv.same(asms[1], asms[3])) {
|
||||
fail("nondrop", "-T @test-keep asm cs!=ww (rule 10)");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn undefbody() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let fixture: str = strings.concat(testenv.repo(),
|
||||
"/test/wcc/data/attest_undefbody.ww");
|
||||
let comps: []str = ["w6c", "w6c_ww"];
|
||||
let c: i32 = 0;
|
||||
for (c < 2) {
|
||||
let av: []str = [testenv.driver(comps[c]), fixture, "-o",
|
||||
"/dev/null"];
|
||||
if (runcode(td, strings.concat("reject_", comps[c]), av) == 0) {
|
||||
fail("undefbody", strings.concat(comps[c],
|
||||
" (non-T) accepted an undefined symbol in a @test body"));
|
||||
};
|
||||
c += 1;
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn linkfail() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let fixture: str = strings.concat(testenv.repo(),
|
||||
"/test/wcc/data/attest_calldropped.ww");
|
||||
let rt: str = strings.concat(testenv.repo(), "/out/lib/libwwrt.a");
|
||||
let comps: []str = ["w6c", "w6c_ww"];
|
||||
let asmts: []str = ["w6a", "w6a_ww"];
|
||||
let linkts: []str = ["w6l", "w6l_ww"];
|
||||
let s: i32 = 0;
|
||||
for (s < 2) {
|
||||
let asmf: str = strings.concat(td, "/lf.", comps[s], ".s");
|
||||
let obj: str = strings.concat(td, "/lf.", comps[s], ".o");
|
||||
let exe: str = strings.concat(td, "/lf.", comps[s], ".exe");
|
||||
let cav: []str = [testenv.driver(comps[s]), fixture, "-o", asmf];
|
||||
if (runcode(td, strings.concat("cc_", comps[s]), cav) != 0) {
|
||||
fail("linkfail", strings.concat(comps[s],
|
||||
" non-T calldropped compile failed"));
|
||||
};
|
||||
let aav: []str = [testenv.driver(asmts[s]), "-o", obj, asmf];
|
||||
if (runcode(td, strings.concat("as_", asmts[s]), aav) != 0) {
|
||||
fail("linkfail", strings.concat(asmts[s],
|
||||
" calldropped assemble failed"));
|
||||
};
|
||||
let lo: testenv.commandout;
|
||||
let lav: []str = [testenv.driver(linkts[s]), "-o", exe, obj, rt];
|
||||
testenv.runcommand(td, td, strings.concat("ld_", linkts[s]), lav,
|
||||
tmo(), &lo);
|
||||
assert(lo.termination == exec.termination.EXIT);
|
||||
if (lo.code == 0) {
|
||||
fail("linkfail", strings.concat(linkts[s],
|
||||
" linked calldropped (expected undefined-reference to ",
|
||||
"the dropped @test sym)"));
|
||||
};
|
||||
if (!testenv.has(lo.stderr, "calldropped_test")) {
|
||||
fail("linkfail", strings.concat(linkts[s],
|
||||
" link failed but not on the dropped @test sym (masked)"));
|
||||
};
|
||||
s += 1;
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* 911_attest_drop — the #6 @test DROP/KEEP/LINK emission property, driven
|
||||
* by `w6c` / `w6c_ww` DIRECTLY on import-free fixtures (task #83, M4 E2-C2b).
|
||||
*
|
||||
* The drop/keep behavior is a property of w6c's `-T` flag, NOT the build
|
||||
* model: a @test fn is spliced out of a non-test build (harec-faithful,
|
||||
* ref/harec/src/check.c:3941 — checked but never emitted) and kept under
|
||||
* -T (the synth entry references it). Direct-w6c is the only host that can
|
||||
* compare BOTH flags on the same input — `ww test` is always -T, `ww build`
|
||||
* always non-T. The fixtures are import-free so they feed w6c with no driver
|
||||
* resolution; the -T synth's `test.run` callee is left as an external CALL
|
||||
* (resolved at link, never needed for the emission grep), so no combined
|
||||
* unit is required. Re-hosts the 910/997 nondrop+undefbody+linkfail legs,
|
||||
* which die when those gates are deleted at the M4 flip.
|
||||
*
|
||||
* Legs:
|
||||
* nondrop — @test defs ABSENT non-T, PRESENT under -T (8 rows); the .s
|
||||
* is cs==ww in BOTH modes (rule 10 — the drop is symmetric).
|
||||
* undefbody — a @test body referencing an undef sym rejects in non-T:
|
||||
* the body is type-checked BEFORE the splice drops it
|
||||
* (harec checks at :3913, drops at :3941). Both stages.
|
||||
* linkfail — non-test code CALLs a @test fn: non-T drops the def but the
|
||||
* CALL survives, so the link fails on the dangling symbol —
|
||||
* harec-faithful loud failure, never a silent mis-link. Both
|
||||
* stages.
|
||||
*/
|
||||
#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;
|
||||
}
|
||||
|
||||
/* cmp_asm — w6c and w6c_ww asm for the same input must be byte-identical
|
||||
* (rule 10). Returns 0 on match. */
|
||||
static int
|
||||
cmp_asm(const char *csa, const char *wsa, const char *what)
|
||||
{
|
||||
char *bc = NULL, *bw = NULL;
|
||||
size_t nc = 0, nw = 0;
|
||||
int rc = 0;
|
||||
if (slurp(csa, &bc, &nc) < 0 || slurp(wsa, &bw, &nw) < 0) {
|
||||
fprintf(stderr, "911 FAIL: slurp %s asm\n", what);
|
||||
rc = 1;
|
||||
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
||||
fprintf(stderr, "911 FAIL: %s asm cs!=ww (cs %zu, ww %zu)\n",
|
||||
what, nc, nw);
|
||||
rc = 1;
|
||||
}
|
||||
free(bc); free(bw);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* #6: each row asserts whether a symbol's TEXT def appears in the asm emitted
|
||||
* for attest_nondrop.ww in a given mode. A @test fn is spliced out of a
|
||||
* non-test build (ref/harec/src/check.c:3941) and kept under -T (the synth
|
||||
* entry references it); a plain fn is always emitted. The fixture layout
|
||||
* exercises the splice loop's unlink edges: @test head (prev==nil), a
|
||||
* surviving plain fn, then two consecutive @test fns (unlink-after-unlink).
|
||||
*/
|
||||
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 four ways (cs/ww × non-T/-T) straight
|
||||
* to asm (no driver resolution), assert each row's TEXT def is present/absent
|
||||
* on the cstage output, then byte-compare cs vs ww in BOTH modes. The
|
||||
* present/absent rows run against the cstage .s alone; the cs==ww byte-id
|
||||
* carries the assertion onto the wwstage .s by construction. */
|
||||
static int
|
||||
nondrop(const char *bin)
|
||||
{
|
||||
int pid = getpid();
|
||||
char cp[256], ct[256], wp[256], wt[256], cmd[4096];
|
||||
snprintf(cp, sizeof cp, "/tmp/at911nd_cp_%d.s", pid);
|
||||
snprintf(ct, sizeof ct, "/tmp/at911nd_ct_%d.s", pid);
|
||||
snprintf(wp, sizeof wp, "/tmp/at911nd_wp_%d.s", pid);
|
||||
snprintf(wt, sizeof wt, "/tmp/at911nd_wt_%d.s", pid);
|
||||
|
||||
int rc = 0;
|
||||
struct { const char *comp; const char *flag; const char *out; } jobs[] = {
|
||||
{ "w6c", "", cp },
|
||||
{ "w6c", "-T ", ct },
|
||||
{ "w6c_ww", "", wp },
|
||||
{ "w6c_ww", "-T ", wt },
|
||||
};
|
||||
for (size_t i = 0; i < sizeof jobs / sizeof jobs[0]; i++) {
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/%s %stest/wcc/data/attest_nondrop.ww -o %s 2>/dev/null",
|
||||
bin, jobs[i].comp, jobs[i].flag, jobs[i].out);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "911 FAIL: %s %snondrop compile\n",
|
||||
jobs[i].comp, jobs[i].flag);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; rc == 0 && i < sizeof nondrop_rows / sizeof nondrop_rows[0]; i++) {
|
||||
const char *f = nondrop_rows[i].testmode ? ct : cp;
|
||||
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, "911 FAIL: %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;
|
||||
}
|
||||
}
|
||||
if (rc == 0 && cmp_asm(cp, wp, "non-T @test-drop") != 0) rc = 1;
|
||||
if (rc == 0 && cmp_asm(ct, wt, "-T @test-keep") != 0) rc = 1;
|
||||
|
||||
unlink(cp); unlink(ct); unlink(wp); unlink(wt);
|
||||
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, "911 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). */
|
||||
static int
|
||||
linkfail(const char *bin, const char *comp, const char *asmt, const char *linkt)
|
||||
{
|
||||
int pid = getpid();
|
||||
char asmf[256], obj[256], exe[256], lerr[256], rt[1024], cmd[4096];
|
||||
snprintf(asmf, sizeof asmf, "/tmp/at911lf_%s_%d.s", comp, pid);
|
||||
snprintf(obj, sizeof obj, "/tmp/at911lf_%s_%d.o", comp, pid);
|
||||
snprintf(exe, sizeof exe, "/tmp/at911lf_%s_%d.exe", comp, pid);
|
||||
snprintf(lerr, sizeof lerr, "/tmp/at911lf_%s_%d.err", comp, pid);
|
||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
||||
|
||||
int rc = 0;
|
||||
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, "911 FAIL: %s non-T calldropped compile\n", comp);
|
||||
rc = 1;
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/%s -o %s %s 2>/dev/null",
|
||||
bin, asmt, obj, asmf);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "911 FAIL: %s calldropped\n", asmt);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s/%s -o %s %s %s 2>%s",
|
||||
bin, linkt, exe, obj, rt, lerr);
|
||||
if (runwait(cmd) == 0) {
|
||||
fprintf(stderr, "911 FAIL: %s linked calldropped (expected "
|
||||
"undefined-reference to the dropped @test sym)\n", linkt);
|
||||
rc = 1;
|
||||
} else {
|
||||
/* Non-vacuity: the link must fail ON the dropped @test
|
||||
* symbol, not for an unrelated reason — a libwwrt path drift
|
||||
* would otherwise mask the property by failing every link. */
|
||||
snprintf(cmd, sizeof cmd, "grep -q calldropped_test %s", lerr);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "911 FAIL: %s link failed but not on the "
|
||||
"dropped @test sym (masked)\n", linkt);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
unlink(asmf); unlink(obj); unlink(exe); unlink(lerr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Both stages: each tool triple compiles + assembles + links the same
|
||||
* import-free fixtures, so the drop/keep/link property is pinned on cstage
|
||||
* AND wwstage (the nondrop leg's cs==ww byte-id proves the .s identical;
|
||||
* the reject + link legs re-run the whole pipeline per stage). */
|
||||
static const struct {
|
||||
const char *comp;
|
||||
const char *asmt;
|
||||
const char *linkt;
|
||||
} stages[] = {
|
||||
{ "w6c", "w6a", "w6l" },
|
||||
{ "w6c_ww", "w6a_ww", "w6l_ww" },
|
||||
};
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = absbin();
|
||||
if (!bin) { fprintf(stderr, "911 FAIL: getcwd\n"); return 1; }
|
||||
|
||||
if (nondrop(bin) != 0) return 1;
|
||||
for (size_t i = 0; i < sizeof stages / sizeof stages[0]; i++) {
|
||||
if (reject_plain(bin, stages[i].comp,
|
||||
"test/wcc/data/attest_undefbody.ww",
|
||||
"undefined symbol in @test body") != 0) return 1;
|
||||
if (linkfail(bin, stages[i].comp, stages[i].asmt,
|
||||
stages[i].linkt) != 0) return 1;
|
||||
}
|
||||
|
||||
printf("@test -T direct-w6c: non-T drop + -T keep (8 rows, cs==ww both "
|
||||
"modes) + checked-body reject + dangling-call link-fail, both "
|
||||
"stages (#6)\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user