parse: enforce strict-package — reject package-less files (#24a)

Flip the soft-default to a hard "missing package clause" error symmetrically in
both stages (cmd/wcc/parse.c + lib/ww/syntax/parse.ww): the first real decl of a
primary section with empty pathmod/resetmod and no seen clause is now rejected.
Closes the documented soft-default divergence (the 63-wrapper carve-out).

The gate flip can't be split from the migration it breaks, so this is one atomic
commit: ~80 test/wcc wrappers gain `package main;` via a shared wwtestpkg.h
helper, 6 data fixtures plus 17 asm-grep assertions update for the bare->main.<leaf>
root-helper mangle shift, and rt/ declares `package rt;` with @symbol pinning the
bare rt_ensure/rt_malloc linker names.

Root mangling narrows: the executable entry `main` stays bare (existing
carve-out), but root helper symbols become main.X. The #84 cluster is rewritten
to assert main.run distinct from aa.run/test.run; its cgen fix and bare machinery
are retained — still load-bearing for package-less module-reset deps. New
table-driven test 782_strict_package.c (6 rows, both stages).

Retiring //ww:module-reset is deferred to #24b: it is load-bearing (clears the
.wwi pathmod so the body's package clause asserts), not a vestige; fusing its
removal here would be a silent mismatch.

All byte-id gates green; full make test reports "all 335 tests passed".
This commit is contained in:
2026-06-29 03:55:26 +09:00
parent d34c90d932
commit 7b9488706b
95 changed files with 579 additions and 223 deletions

View File

@@ -411,6 +411,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_star_fn_deref \
$(BIN)/test_star_fn_deref_call \
$(BIN)/test_match_variant_dispatch \
$(BIN)/test_strict_package \
$(BIN)/test_io_types_run \
$(BIN)/test_dot_aliased_ptr \
$(BIN)/test_return_tagged_forward \
@@ -649,6 +650,13 @@ $(BIN)/test_unknowndecl_reject: test/wcc/989_unknowndecl_reject.c \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# 782_strict_package (#24a): every primary section must open with a `package`
# clause; a missing clause on the first decl is a hard error, symmetric on
# cstage w6c + wwstage w6c_ww. Each reject row reddens under a gate revert.
$(BIN)/test_strict_package: test/wcc/782_strict_package.c \
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# 989_nullableglobal_reject (#45 silent->loud bridge, task #15 prereq): a
# module-level nullable `(*T | void)` GLOBAL has no storage path, so a
# match/is/as on it silently miscompiled (0(BP) read / undefined ref) on

View File

@@ -1407,18 +1407,16 @@ parsefile(Parser *p)
Pos pp = { p->l->file, 1, 1 };
Node *file = newnode(p->a, N_FILE, pp);
Node *head = NULL, *tail = NULL;
int sawpackage = 0;
while (p->cur.kind != TK_EOF) {
/* `package foo;` — directory-as-module declaration. Each
* .ww file's section in a concatenated stream begins with
* one; a single-file or fragment input may omit it (curmod
* stays NULL and decls are treated as primary).
*
* Retained divergence from brief: the strict missing-`package`
* error was softened to silent-default to keep 63 inline-source
* test wrappers (200_parse, 100_lex, 300_check, ...) parsing.
* See task #23 for the wrapper migration that unblocks the
* strict check. Rule 7 + rule 8 documentation. */
/* `package foo;` — directory-as-module declaration. Every
* primary section opens with one (`package main;` for an
* executable); a missing clause on the first real decl is a
* hard error (strict-package, #24a). Imported (pathmod) and
* sep primary-reset (resetmod) regions carry identity
* out-of-band and are exempt. */
if (p->cur.kind == TK_MODULE) {
sawpackage = 1;
advance(p);
const char *name = expectident(p);
expect(p, TK_SEMI);
@@ -1457,6 +1455,7 @@ parsefile(Parser *p)
* leaf `package` clause, and are flagged imported (gates the
* root-only bare-`main` rule, #32). */
if (p->cur.kind == TK_MODPATH) {
sawpackage = 0;
p->pathmod = p->cur.text;
p->curmod = p->cur.text;
p->resetmod = NULL;
@@ -1472,6 +1471,7 @@ parsefile(Parser *p)
* directive after a mid-file `package` would strip subsequent
* decls to bare — that usage is deliberate-only. */
if (p->cur.kind == TK_MODRESET) {
sawpackage = 0;
/* #57: a path-carrying reset (sep primary body) mangles
* decls on the dotted path so definer == importer, but
* leaves imported==0 (curmod set, pathmod NULL) so -c
@@ -1498,6 +1498,16 @@ parsefile(Parser *p)
}
continue;
}
/* strict-package: a primary section's first real decl must be
* preceded by a `package` clause. Imported (pathmod) and sep
* primary-reset (resetmod) regions carry identity out-of-band,
* so they are exempt. Wording mirrors Go's missing-`package`
* diagnostic (rule 5; Hare has no clause to port). */
if (p->pathmod == NULL && p->resetmod == NULL && !sawpackage) {
errorf(p->cur.pos, "missing package clause");
p->errs++;
sawpackage = 1;
}
Node *attrs = parseattrs(p);
int exp = accept(p, TK_EXPORT);
Node *d = NULL;

View File

@@ -416,17 +416,16 @@ export fn parsefile(p: *parser) *node = {
let f = newnode(nkind.N_FILE, p.curfile, p.curline, p.curcol);
let head: *node = nil;
let tail: *node = nil;
let sawpackage: i32 = 0;
for (p.curkind != tkind.TK_EOF) {
// `package foo;` — each contributing source's section in a
// concatenated stream begins with one. Single-file inputs
// may omit it (curmod stays empty; decls treated as primary).
//
// Retained divergence from brief: strict missing-`package`
// error softened to silent-default — 63 inline-source test
// wrappers depend on the soft behavior. See task #23 for
// the wrapper migration that unblocks the strict check.
// Rule 7 + rule 8 documentation.
// `package foo;` — directory-as-module declaration. Every
// primary section opens with one (`package main;` for an
// executable); a missing clause on the first real decl is a
// hard error (strict-package, #24a). Imported (pathmod) and
// sep primary-reset (resetmod) regions carry identity
// out-of-band and are exempt.
if (p.curkind == tkind.TK_MODULE) {
sawpackage = 1;
advance(p);
let name: str;
expectident(p, &name);
@@ -462,6 +461,7 @@ export fn parsefile(p: *parser) *node = {
// leaf `package` clause, and are flagged imported (gates the
// root-only bare-`main` rule, #32).
if (p.curkind == tkind.TK_MODPATH) {
sawpackage = 0;
p.pathmod = p.curtext;
p.curmod = p.curtext;
p.resetmod = "";
@@ -477,6 +477,7 @@ export fn parsefile(p: *parser) *node = {
// directive after a mid-file `package` would strip subsequent
// decls to bare — that usage is deliberate-only.
if (p.curkind == tkind.TK_MODRESET) {
sawpackage = 0;
// #57: a path-carrying reset (sep primary body) mangles decls
// on the dotted path so definer == importer, but leaves
// imported==0 (curmod set, pathmod "") so -c primary-ness and
@@ -503,6 +504,15 @@ export fn parsefile(p: *parser) *node = {
};
continue;
};
// strict-package: a primary section's first real decl must be
// preceded by a `package` clause. Imported (pathmod) and sep
// primary-reset (resetmod) regions carry identity out-of-band,
// so they are exempt. Wording mirrors Go's missing-`package`
// diagnostic (rule 5; Hare has no clause to port).
if (p.pathmod.len == 0 && p.resetmod.len == 0 && sawpackage == 0) {
errmsg(p, "missing package clause");
sawpackage = 1;
};
let attrs = parseattrs(p);
let exported: i32 = 0;
if (p.curkind == tkind.TK_EXPORT) { exported = 1; advance(p); };

View File

@@ -14,10 +14,13 @@
// no per-type wrapper functions (appendu8 / appendi64) needed.
//
// User code never `use`s this — the symbol is resolved at link time
// from libwwrt.a, like rt_malloc and rt_streq. No `module` declaration:
// rt/ensure.ww is compiled standalone via `w6c rt/ensure.ww` (not
// through the driver), and its `export fn rt_ensure` must keep its
// bare symbol name so the linker resolves it.
// from libwwrt.a, like rt_malloc and rt_streq. rt/ensure.ww is compiled
// standalone via `w6c rt/ensure.ww` (not through the driver). Under
// strict-package (#24a) it declares `package rt;` (matching its
// directory) like every primary section; the link-resolved name is
// pinned bare via @symbol on the export (the clause would otherwise
// mangle it to rt.rt_ensure).
package rt;
@symbol("rt_malloc") fn malloc(n: u64) *void;
@@ -31,7 +34,7 @@ type slice = struct {
cap: i64,
};
export fn rt_ensure(s: *slice, membsz: u64) void = {
@symbol("rt_ensure") export fn rt_ensure(s: *slice, membsz: u64) void = {
if (s.cap >= s.len) { return; };
let nc: i64 = s.cap * 2i64;
if (nc < 8i64) { nc = 8i64; };

View File

@@ -1,6 +1,8 @@
// rt/malloc.ww — bump allocator over 2MiB chunks. Archived into
// libwwrt.a, compiled standalone (no `module`) with bare symbols, like
// rt/ensure.ww.
// libwwrt.a, compiled standalone with bare symbols, like rt/ensure.ww.
// Under strict-package (#24a) it declares `package rt;` (matching its
// directory); the export's link name stays bare via its own
// @symbol("rt_malloc").
//
// WHY bump, replacing the page-per-call mmap (rt_segmalloc, ex-rt_malloc):
// the old rt_malloc page-rounded every request, so a 32-72B node cost a
@@ -15,6 +17,7 @@
// Zero-init is preserved: every byte handed out is fresh from
// MAP_ANONYMOUS (kernel-zeroed) and never reused, so alloc(T{})'s
// zero-fill still holds. Lazy first chunk falls out of cur=rem=0.
package rt;
def CHUNKSZ: u64 = 2097152u64; // 1<<21, ref/hare/rt/malloc.ha:24
def ALIGN: u64 = 16u64; // ref/hare/rt/malloc.ha:14

View File

@@ -11,6 +11,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wwtestpkg.h"
static int
must_parse(const char *src)
@@ -18,10 +19,12 @@ must_parse(const char *src)
Arena *a = newarena();
Lex l;
Parser p;
lexinit(&l, a, "<test>", src, strlen(src));
char *ws = wwtest_wrap(src);
lexinit(&l, a, "<test>", ws, strlen(ws));
parserinit(&p, a, &l);
Node *n = parsefile(&p);
int ok = (n != NULL && p.errs == 0 && l.errs == 0);
free(ws);
freearena(a);
return ok;
}
@@ -32,7 +35,8 @@ parse_to_str(const char *src, int *errs)
Arena *a = newarena();
Lex l;
Parser p;
lexinit(&l, a, "<test>", src, strlen(src));
char *ws = wwtest_wrap(src);
lexinit(&l, a, "<test>", ws, strlen(ws));
parserinit(&p, a, &l);
Node *n = parsefile(&p);
*errs = p.errs + l.errs;
@@ -41,6 +45,7 @@ parse_to_str(const char *src, int *errs)
size_t len = 0;
FILE *f = open_memstream(&buf, &len);
if (f == NULL) {
free(ws);
freearena(a);
return NULL;
}
@@ -51,6 +56,7 @@ parse_to_str(const char *src, int *errs)
memcpy(out, buf, len);
out[len] = '\0';
free(buf);
free(ws);
freearena(a);
return out;
}

View File

@@ -8,6 +8,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wwtestpkg.h"
static int
runrow(const char *src, const char *expect)
@@ -16,7 +17,8 @@ runrow(const char *src, const char *expect)
Lex l;
Parser p;
Checker c;
lexinit(&l, a, "<test>", src, strlen(src));
char *ws = wwtest_wrap(src);
lexinit(&l, a, "<test>", ws, strlen(ws));
parserinit(&p, a, &l);
Node *file = parsefile(&p);
@@ -44,6 +46,7 @@ runrow(const char *src, const char *expect)
" src: %s\n", expect, errbuf, src);
}
free(errbuf);
free(ws);
freearena(a);
return ok;
}

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "wwtestpkg.h"
static int
run6c(const char *src, char **out)
@@ -16,7 +17,7 @@ run6c(const char *src, char **out)
snprintf(path, sizeof path, "/tmp/wwt_%d.ww", getpid());
FILE *f = fopen(path, "wb");
if (f == NULL) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
char cmd[256];
@@ -60,7 +61,7 @@ static const struct row rows[] = {
{ "fn cond(x: i32) i32 = { if (x > 0) { return 1; }; return 0; };",
"CMPQ\t$0, AX" },
{ "fn lo() void = { for (let i: i32 = 0; i < 10; i += 1) { }; };", "JMP" },
{ "fn callit() i32 = { return 1; };", "TEXT callit,$0" },
{ "fn callit() i32 = { return 1; };", "TEXT main.callit,$0" },
};
int

View File

@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "wwtestpkg.h"
static int
run(const char *cmd)
@@ -35,7 +36,7 @@ main(void)
int n = 0, fail = 0;
for (int i = 0; programs[i]; i++, n++) {
FILE *f = fopen(src, "wb");
fputs(programs[i], f);
wwtest_fputs(programs[i], f);
fclose(f);
char cmd[512];

View File

@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "wwtestpkg.h"
int
main(void)
@@ -20,7 +21,7 @@ main(void)
snprintf(exe, sizeof exe, "/tmp/wwt_%d.x", getpid());
FILE *f = fopen(src, "wb");
fputs("fn main() i32 = { return 42; };", f);
wwtest_fputs("fn main() i32 = { return 42; };", f);
fclose(f);
char cmd[1024];

View File

@@ -13,6 +13,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int run(const char *cmd) { return system(cmd); }
@@ -33,24 +34,26 @@ main(void)
snprintf(dir, sizeof dir, "/tmp/wwarch_%d", getpid());
mkdir(dir, 0755);
/* lib_good.ww — defines f1() */
/* lib_good.ww — defines f1() (→ main.f1 under strict-package #24a) */
char path[256];
snprintf(path, sizeof path, "%s/lib_good.ww", dir);
FILE *f = fopen(path, "wb");
fputs("export fn f1() i32 = { return 7; };", f);
wwtest_fputs("export fn f1() i32 = { return 7; };", f);
fclose(f);
/* lib_bad.ww — defines f2() but also references an undefined extern */
snprintf(path, sizeof path, "%s/lib_bad.ww", dir);
f = fopen(path, "wb");
fputs("@symbol(\"this_symbol_does_not_exist\") fn bogus() i32;\n"
wwtest_fputs("@symbol(\"this_symbol_does_not_exist\") fn bogus() i32;\n"
"export fn f2() i32 = { return bogus(); };", f);
fclose(f);
/* main.ww — calls f1, NOT f2 */
/* main.ww — calls f1, NOT f2. The plain prototype declares f1 in the
* same (main) module, so the call resolves to main.f1 — matching
* lib_good's moduled definition (no @symbol bare-pin needed). */
snprintf(path, sizeof path, "%s/m.ww", dir);
f = fopen(path, "wb");
fputs("@symbol(\"f1\") fn f1() i32;\n"
wwtest_fputs("fn f1() i32;\n"
"fn main() i32 = { return f1(); };", f);
fclose(f);

View File

@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
run_exit(const char *cmd)
@@ -33,7 +34,7 @@ build_and_run(const char *bin, const char *prog)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(prog, f);
wwtest_fputs(prog, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, src);

View File

@@ -42,6 +42,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -142,7 +143,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
@@ -174,7 +175,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -18,6 +18,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static const char *
absbin(void)
@@ -98,10 +99,10 @@ main(void)
/* a standalone main.o (no undefs) + an unrelated archived foo.o. */
FILE *f = fopen(src, "wb");
fputs("fn main() i32 = { return 42; };", f);
wwtest_fputs("fn main() i32 = { return 42; };", f);
fclose(f);
f = fopen(fsrc, "wb");
fputs("export fn foo() i32 = { return 7; };", f);
wwtest_fputs("export fn foo() i32 = { return 7; };", f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s", bin, asmf, src);

View File

@@ -16,6 +16,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -149,7 +150,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -19,6 +19,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -355,7 +356,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -14,6 +14,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -297,7 +298,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -18,6 +18,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -294,7 +295,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -24,6 +24,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -153,7 +154,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -22,6 +22,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -504,7 +505,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -71,6 +71,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -162,7 +163,7 @@ run_driver(const char *driver, const struct row *r, int i)
mkdir(tmpdir, 0755);
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
@@ -194,7 +195,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -48,6 +48,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
/* want == BYTEID_ONLY: the row cannot LINK/run (a slice-of-struct
* module global does not data-emit yet — separate gap), so only the
@@ -138,7 +139,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
@@ -169,7 +170,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -25,6 +25,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -250,7 +251,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -34,6 +34,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -228,7 +229,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -101,7 +102,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -43,6 +43,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -316,7 +317,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -50,6 +50,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -277,7 +278,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -45,6 +45,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -223,7 +224,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -40,6 +40,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -301,7 +302,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -332,7 +333,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -8,6 +8,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -1812,7 +1813,7 @@ main(void)
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
fputs(rows[i].src, f);
wwtest_fputs(rows[i].src, f);
fclose(f);
char cmd[1024];

View File

@@ -50,6 +50,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -291,7 +292,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -322,7 +323,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -33,6 +33,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -156,7 +157,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -185,7 +186,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -36,6 +36,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -149,7 +150,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -178,7 +179,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -41,6 +41,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -201,7 +202,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -230,7 +231,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -53,6 +53,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -221,7 +222,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -250,7 +251,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -65,6 +65,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -310,7 +311,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -341,7 +342,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -80,6 +80,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -273,7 +274,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -110,6 +110,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -347,7 +348,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
@@ -379,7 +380,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -47,6 +47,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -216,7 +217,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -53,6 +53,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -193,7 +194,7 @@ run_row(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s >/dev/null 2>&1",

View File

@@ -52,6 +52,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -148,7 +149,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -73,6 +73,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -222,7 +223,7 @@ run_driver(const char *driver, const struct row *r, int i)
mkdir(tmpdir, 0755);
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -53,6 +53,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -190,7 +191,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -42,6 +42,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -144,7 +145,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -175,7 +176,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -53,6 +53,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -146,7 +147,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -177,7 +178,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -65,6 +65,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -232,7 +233,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",
@@ -308,7 +309,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
int rc = 0;

View File

@@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -52,44 +53,44 @@ static const struct row rows[] = {
/* Scalar i8 = -1 → low byte 0xff, then 7 bytes of sign-extension. */
{ "i8_neg", "let x: i8 = -1i8;\n"
"fn main() i32 = { return 0; };\n",
"x",
"main.x",
"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff" },
/* Scalar i16 = -2 → 0xfe 0xff then 6 byte sign extension. */
{ "i16_neg", "let x: i16 = -2i16;\n"
"fn main() i32 = { return 0; };\n",
"x",
"main.x",
"\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff" },
/* Scalar i32 = -100 → 0x9C 0xFF 0xFF 0xFF then 4 byte sign extension. */
{ "i32_neg", "let x: i32 = -100i32;\n"
"fn main() i32 = { return 0; };\n",
"x",
"main.x",
"\\x9c\\xff\\xff\\xff\\xff\\xff\\xff\\xff" },
/* Scalar i64 = -1000 → 0xfffffffffffffc18 little-endian. */
{ "i64_neg", "let x: i64 = -1000i64;\n"
"fn main() i32 = { return 0; };\n",
"x",
"main.x",
"\\x18\\xfc\\xff\\xff\\xff\\xff\\xff\\xff" },
/* Array [4]i8 = [1, -2, 3, -4] → 0x01 0xfe 0x03 0xfc. */
{ "i8_arr", "let a: [4]i8 = [1i8, -2i8, 3i8, -4i8];\n"
"fn main() i32 = { return 0; };\n",
"a",
"main.a",
"\\x01\\xfe\\x03\\xfc" },
/* Array [4]i16 = [1, -2, 3, -4] → LE16 each. */
{ "i16_arr", "let a: [4]i16 = [1i16, -2i16, 3i16, -4i16];\n"
"fn main() i32 = { return 0; };\n",
"a",
"main.a",
"\\x01\\x00\\xfe\\xff\\x03\\x00\\xfc\\xff" },
/* Array [3]i32 = [10, -20, 30] → LE32 each. */
{ "i32_arr", "let a: [3]i32 = [10i32, -20i32, 30i32];\n"
"fn main() i32 = { return 0; };\n",
"a",
"main.a",
"\\x0a\\x00\\x00\\x00\\xec\\xff\\xff\\xff\\x1e\\x00\\x00\\x00" },
/* Array [2]i64 = [100, -200] → LE64 each. Note 100 == 'd' and
* 56 == '8' are printable ASCII so emit_data_byte writes them
* raw rather than as `\xNN`. */
{ "i64_arr", "let a: [2]i64 = [100i64, -200i64];\n"
"fn main() i32 = { return 0; };\n",
"a",
"main.a",
"d\\x00\\x00\\x00\\x00\\x00\\x00\\x00"
"8\\xff\\xff\\xff\\xff\\xff\\xff\\xff" },
};
@@ -128,7 +129,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -26,6 +26,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -125,7 +126,7 @@ check_pushdx_before_pushax(const char *spath, const struct row *r)
long off = 0;
int saw_site = 0;
for (;;) {
long call = find_after(buf, off, "CALL\tyield_");
long call = find_after(buf, off, "CALL\tmain.yield_");
if (call < 0) break;
saw_site = 1;
long pdx = find_after(buf, call, "PUSHQ\tDX");
@@ -162,7 +163,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -41,6 +41,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -144,7 +145,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -164,8 +165,8 @@ check_leaq_di_before_call(const char *path, const struct row *r)
char line[1024];
int ok = -1;
while (fgets(line, sizeof line, f)) {
if (strstr(line, "CALL\tmk(SB)")
|| strstr(line, "CALL mk(SB)")) {
if (strstr(line, "CALL\tmain.mk(SB)")
|| strstr(line, "CALL main.mk(SB)")) {
if (strstr(prev, "LEAQ\t")
&& strstr(prev, "(BP), DI")) {
ok = 0;
@@ -199,7 +200,7 @@ check_movq_bp_ax_before_ret(const char *path, const struct row *r)
int ok = -1;
while (fgets(line, sizeof line, f)) {
if (!in_mk) {
if (strstr(line, "TEXT mk,") || strstr(line, "TEXT\tmk,"))
if (strstr(line, "TEXT main.mk,") || strstr(line, "TEXT\tmain.mk,"))
in_mk = 1;
continue;
}
@@ -241,15 +242,15 @@ check_movq_bp_di_before_inner_call(const char *path, const struct row *r)
int ok = -1;
while (fgets(line, sizeof line, f)) {
if (!in_mk) {
if (strstr(line, "TEXT mk,")
|| strstr(line, "TEXT\tmk,"))
if (strstr(line, "TEXT main.mk,")
|| strstr(line, "TEXT\tmain.mk,"))
in_mk = 1;
strncpy(prev, line, sizeof prev - 1);
prev[sizeof prev - 1] = '\0';
continue;
}
if (strstr(line, "CALL\tinner(SB)")
|| strstr(line, "CALL inner(SB)")) {
if (strstr(line, "CALL\tmain.inner(SB)")
|| strstr(line, "CALL main.inner(SB)")) {
if (strstr(prev, "MOVQ\t")
&& strstr(prev, "(BP), DI")
&& !strstr(prev, "LEAQ"))
@@ -283,8 +284,8 @@ check_no_movq_ax_bp_after_call(const char *path, const struct row *r)
int ok = 0;
while (fgets(line, sizeof line, f)) {
if (!seen_call) {
if (strstr(line, "CALL\tmk(SB)")
|| strstr(line, "CALL mk(SB)")) {
if (strstr(line, "CALL\tmain.mk(SB)")
|| strstr(line, "CALL main.mk(SB)")) {
seen_call = 1;
}
continue;

View File

@@ -25,6 +25,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -107,7 +108,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -24,6 +24,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -84,7 +85,7 @@ check_three_push_after_call(const char *spath, const struct row *r)
char buf[1 << 16];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
long call = find_after(buf, 0, "CALL\tview");
long call = find_after(buf, 0, "CALL\tmain.view");
if (call < 0) {
fprintf(stderr, "row[%s]: no CALL view site\n", r->label);
return -1;
@@ -135,7 +136,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -29,6 +29,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -79,7 +80,7 @@ check_movq_zero_present(const char *spath, const struct row *r)
char buf[1 << 16];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
const char *body = strstr(buf, "TEXT produce");
const char *body = strstr(buf, "TEXT main.produce");
if (!body) {
fprintf(stderr, "row[%s]: no TEXT produce label\n", r->label);
return -1;
@@ -112,7 +113,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -76,7 +77,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -97,7 +98,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -172,7 +173,7 @@ check_movsxd_kept(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT promote");
const char *fn = strstr(buf, "TEXT main.promote");
if (!fn) {
fprintf(stderr, "row[%s][%s]: no TEXT promote in %s\n",
r->label, stage, spath);

View File

@@ -36,6 +36,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -131,7 +132,7 @@ run_row(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd,
@@ -155,7 +156,7 @@ run_row(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s run %s >/dev/null 2>&1", driver, src);

View File

@@ -28,6 +28,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -112,7 +113,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -144,8 +145,8 @@ check_narrow_mov(const char *path, const struct row *r)
(void)load_needle;
while (fgets(line, sizeof line, f)) {
if (!in_mk) {
if (strstr(line, "TEXT mk,")
|| strstr(line, "TEXT\tmk,"))
if (strstr(line, "TEXT main.mk,")
|| strstr(line, "TEXT\tmain.mk,"))
in_mk = 1;
continue;
}
@@ -188,8 +189,8 @@ check_no_movq_at_off(const char *path, const struct row *r)
int bad = 0;
while (fgets(line, sizeof line, f)) {
if (!in_mk) {
if (strstr(line, "TEXT mk,")
|| strstr(line, "TEXT\tmk,"))
if (strstr(line, "TEXT main.mk,")
|| strstr(line, "TEXT\tmain.mk,"))
in_mk = 1;
continue;
}

View File

@@ -44,6 +44,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -133,7 +134,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* timeout 180 per repo convention (990-997); test/run does not bound
@@ -187,7 +188,7 @@ asm_byte_identical(const char *bin, const char *src, const char *label, int i)
FILE *f = fopen(wwsrc, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
char w6c[640], w6c_ww[640];
@@ -255,7 +256,7 @@ xmod_fold_present(const char *w6c, const char *stage)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(xmod_src, f);
wwtest_fputs(xmod_src, f);
fclose(f);
if (emit_s(w6c, src, s, sizeof s) != 0) {
@@ -316,7 +317,7 @@ compile_fails(const char *w6c, const struct failrow *r, const char *stage, int i
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* A regressed depth guard would HANG the cycle rows rather than fail

View File

@@ -35,6 +35,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -94,7 +95,7 @@ emit_s(const char *w6c, const char *src_text, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(src_text, f);
wwtest_fputs(src_text, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -32,6 +32,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -96,7 +97,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -117,7 +118,7 @@ check_loadmov(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) {
fprintf(stderr,
"row[%s][%s]: no TEXT probe in %s\n",
@@ -149,7 +150,7 @@ check_inner_scale_only(const char *spath, const struct row *r,
{
char buf[1 << 14];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) return -1;
const char *ret = strstr(fn, "\tRET\n");
if (!ret) ret = fn + strlen(fn);

View File

@@ -34,6 +34,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -98,7 +99,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -119,7 +120,7 @@ check_storemov(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) {
fprintf(stderr,
"row[%s][%s]: no TEXT probe in %s\n",
@@ -164,7 +165,7 @@ check_inner_scale_only(const char *spath, const struct row *r,
{
char buf[1 << 14];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) return -1;
const char *ret = strstr(fn, "\tRET\n");
if (!ret) ret = fn + strlen(fn);

View File

@@ -46,6 +46,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -126,7 +127,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -146,7 +147,7 @@ check_probe(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) {
fprintf(stderr,
"row[%s][%s]: no TEXT probe in %s\n",

View File

@@ -25,6 +25,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -67,7 +68,7 @@ check_caller_stores(const char *spath)
char buf[1 << 16];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
const char *body = strstr(buf, "TEXT main");
const char *body = strstr(buf, "TEXT main,");
if (!body) {
fprintf(stderr, "variadic_pack: no TEXT main label\n");
return -1;
@@ -118,7 +119,7 @@ emit_s(const char *w6c, char *out_s, size_t cap, int tag)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(src_text, f);
wwtest_fputs(src_text, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);

View File

@@ -31,6 +31,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -200,7 +201,7 @@ check_copy_loads(const char *spath, const struct row *r)
static char buf[1 << 16];
if (slurp(spath, buf, sizeof buf) < 0) return -1;
const char *body = strstr(buf, "TEXT produce");
const char *body = strstr(buf, "TEXT main.produce");
if (!body) {
fprintf(stderr, "row[%s]: no TEXT produce label in %s\n",
r->label, spath);
@@ -233,7 +234,7 @@ emit_s(const char *w6c, const struct row *r, int i, int stage,
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->asm_src, f);
wwtest_fputs(r->asm_src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -257,7 +258,7 @@ run_driver(const char *driver, const struct row *r, int i, int stage)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->run_src, f);
wwtest_fputs(r->run_src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",

View File

@@ -51,6 +51,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -111,7 +112,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -129,7 +130,7 @@ check_stride(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) {
fprintf(stderr,
"row[%s][%s]: no TEXT probe in %s\n",

View File

@@ -61,6 +61,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -143,7 +144,7 @@ emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src);
@@ -161,7 +162,7 @@ check_stride(const char *spath, const struct row *r, const char *stage)
r->label, stage, spath);
return -1;
}
const char *fn = strstr(buf, "TEXT probe");
const char *fn = strstr(buf, "TEXT main.probe");
if (!fn) {
fprintf(stderr,
"row[%s][%s]: no TEXT probe in %s\n",

View File

@@ -38,6 +38,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -121,7 +122,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);
@@ -152,7 +153,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -158,7 +159,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null",
@@ -191,7 +192,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src);

View File

@@ -42,6 +42,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -107,7 +108,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* timeout 180 per repo convention; test/run does not bound
@@ -151,7 +152,7 @@ asm_byte_identical(const char *bin, const char *src, const char *label, int i)
FILE *f = fopen(wwsrc, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
char w6c[640], w6c_ww[640];
@@ -212,7 +213,7 @@ cstage_narrow_fails(const char *w6c)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(narrow_src, f);
wwtest_fputs(narrow_src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "timeout 180 %s -o %s %s 2>/dev/null",

View File

@@ -62,6 +62,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -208,7 +209,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* timeout 180 per repo convention (cf. 760); test/run does not
@@ -243,7 +244,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c -o %s %s 2>/dev/null",

View File

@@ -46,6 +46,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -141,7 +142,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* timeout 180 per repo convention (cf. 760, 761); test/run does
@@ -176,7 +177,7 @@ asm_byte_identical(const char *bin, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c -o %s %s 2>/dev/null",

View File

@@ -57,6 +57,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -181,7 +182,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
/* timeout 180 per repo convention (cf. 761, 762); test/run does

View File

@@ -60,6 +60,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -99,7 +100,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
NULL, NULL,
"LEAQ\tadd1(SB)",
"LEAQ\tmain.add1(SB)",
STAGE_CS | STAGE_WW },
{ "branched_callee",
"fn aa(x: i32) i32 = { return x; };\n"
@@ -111,7 +112,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
NULL, NULL,
"LEAQ\tbb(SB)",
"LEAQ\tmain.bb(SB)",
STAGE_CS | STAGE_WW },
{ "alias_chain",
"fn add1(x: i32) i32 = { return x + 1; };\n"
@@ -121,7 +122,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
NULL, NULL,
"LEAQ\tadd1(SB)",
"LEAQ\tmain.add1(SB)",
STAGE_CS | STAGE_WW },
{ "fn_with_args",
"fn many(a: i32, b: i64, p: *i32) i64 = { return b; };\n"
@@ -130,7 +131,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
NULL, NULL,
"LEAQ\tmany(SB)",
"LEAQ\tmain.many(SB)",
STAGE_CS | STAGE_WW },
{ "fn_tuple_return",
"fn pair() (i64, str) = { return (7: i64, \"x\"); };\n"
@@ -139,7 +140,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
NULL, NULL,
"LEAQ\tpair(SB)",
"LEAQ\tmain.pair(SB)",
STAGE_CS | STAGE_WW },
/* Cross-mod: cstage emits the LEAQ via N_DOT TK_AMP (already
* working pre-#180). Wwstage bails asserttyped on the same
@@ -156,6 +157,7 @@ static const struct row rows[] = {
" return 0;\n"
"};\n",
"wcamffn764mod",
"package wcamffn764mod;\n"
"export fn somefn(x: i32) i32 = { return x + 1; };\n",
"LEAQ\twcamffn764mod.somefn(SB)",
STAGE_CS },
@@ -181,13 +183,13 @@ write_sources(const struct row *r, char *src, size_t srcsz,
mkdir(moddir, 0755);
FILE *mf = fopen(modfile, "wb");
if (!mf) return -1;
fputs(r->modsrc, mf);
wwtest_fputs(r->modsrc, mf);
fclose(mf);
}
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
return 0;
}

View File

@@ -60,6 +60,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -144,7 +145,7 @@ write_source(const char *src_path, const char *src)
{
FILE *f = fopen(src_path, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
return 0;
}

View File

@@ -52,6 +52,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -132,7 +133,7 @@ write_source(const char *src_path, const char *src)
{
FILE *f = fopen(src_path, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
return 0;
}

View File

@@ -78,6 +78,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -182,7 +183,7 @@ write_source(const char *src_path, const char *src)
{
FILE *f = fopen(src_path, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
return 0;
}

View File

@@ -0,0 +1,163 @@
/*
* 782_strict_package — #24a strict-package gate, BOTH stages (w6c + w6c_ww).
*
* Every primary section must open with a `package` clause; a missing clause
* on the first real decl is a hard error ("missing package clause"). An
* imported (`//ww:module <path>`) or sep primary-reset region carries its
* identity out-of-band and is exempt; an in-section `package` clause then
* ASSERTS — its leaf must equal the path's last component ("package <x>
* does not match import path <p>"). A bare `//ww:module-reset` opens a fresh
* primary section that must itself re-declare a clause.
*
* Rule-10: every row runs on cstage `w6c` AND wwstage `w6c_ww`; both must
* agree (accept/reject identically; diagnostic text differs by stage —
* cstage `errorf` carries a position, wwstage `errmsg` is terser — so the
* check is on a shared substring, not the whole line). Reject rows feed RAW
* source: the `package` clause IS the unit under test, so there is no
* auto-prepend here (unlike the migrated codegen fixtures).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.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 int
file_contains(const char *path, const char *needle)
{
FILE *f = fopen(path, "r");
if (!f) return 0;
char line[4096];
int found = 0;
while (fgets(line, sizeof line, f))
if (strstr(line, needle)) { found = 1; break; }
fclose(f);
return found;
}
struct row {
const char *label;
const char *src;
int accept; /* 1 = must compile clean; 0 = must reject */
const char *diag; /* reject: required stderr substring (NULL on accept) */
};
static const struct row rows[] = {
/* 1: a `package main;` executable section. */
{ "pkg_main_accept",
"package main;\nexport fn main() i32 = { return 0; };\n",
1, NULL },
/* 2: no clause → hard error on the first decl. */
{ "no_clause_reject",
"export fn main() i32 = { return 0; };\n",
0, "missing package clause" },
/* 3: imported region — the clause leaf matches the path leaf. */
{ "module_leaf_match_accept",
"//ww:module foo\npackage foo;\nexport fn x() i32 = { return 0; };\n",
1, NULL },
/* 4: imported region — the clause leaf mismatches the path. */
{ "module_leaf_mismatch_reject",
"//ww:module foo\npackage bar;\nexport fn x() i32 = { return 0; };\n",
0, "does not match import path" },
/* 5: a comment-only file declares nothing, so no clause is required. */
{ "comment_only_accept",
"// just a comment, no decls\n",
1, NULL },
/* 6: a bare `//ww:module-reset` opens a fresh primary section; the
* clause-less second section is rejected (the #84/#24a boundary). */
{ "reset_second_section_reject",
"package main;\nexport fn a() i32 = { return 0; };\n"
"//ww:module-reset\nexport fn b() i32 = { return 0; };\n",
0, "missing package clause" },
{ NULL, NULL, 0, NULL },
};
/* Compile r->src with `stage` (a w6c-family binary); verify accept/reject
* and, on reject, the diagnostic substring. Returns 0 on success. */
static int
check_stage(const char *stage, const char *tag, const struct row *r,
const char *tmpdir)
{
char src[256], sout[256], errf[256], cmd[2048];
snprintf(src, sizeof src, "%s/sp_%s.ww", tmpdir, r->label);
snprintf(sout, sizeof sout, "%s/sp_%s.s", tmpdir, r->label);
snprintf(errf, sizeof errf, "%s/sp_%s.err", tmpdir, r->label);
FILE *f = fopen(src, "wb");
if (!f) { fprintf(stderr, "782 FAIL: write %s\n", src); return 1; }
fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>%s", stage, sout, src, errf);
int rc = runwait(cmd);
if (r->accept) {
if (rc != 0) {
fprintf(stderr, "782 FAIL: [%s][%s] expected ACCEPT, "
"rejected (rc=%d)\n", r->label, tag, rc);
return 1;
}
return 0;
}
if (rc == 0) {
fprintf(stderr, "782 FAIL: [%s][%s] expected REJECT, "
"accepted\n", r->label, tag);
return 1;
}
if (!file_contains(errf, r->diag)) {
fprintf(stderr, "782 FAIL: [%s][%s] rejected but no `%s` "
"on stderr\n", r->label, tag, r->diag);
return 1;
}
return 0;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
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 cs[1100], ww[1100], tmpdir[64], rmcmd[160];
snprintf(cs, sizeof cs, "%s/w6c", bin);
snprintf(ww, sizeof ww, "%s/w6c_ww", bin);
snprintf(tmpdir, sizeof tmpdir, "/tmp/sp782_%d", getpid());
mkdir(tmpdir, 0755);
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
/* wwstage twin is gated on its presence (rule 14 / 993 pattern). */
int have_ww = (access(ww, X_OK) == 0);
int fail = 0;
for (int i = 0; rows[i].label; i++) {
fail += check_stage(cs, "cs", &rows[i], tmpdir);
if (have_ww)
fail += check_stage(ww, "ww", &rows[i], tmpdir);
}
runwait(rmcmd);
if (fail) {
fprintf(stderr, "782: %d check(s) failed\n", fail);
return 1;
}
printf("strict_package: 6 rows (accept/reject + leaf-assert + bare-reset) "
"agree on cstage w6c%s (#24a)\n", have_ww ? " and wwstage w6c_ww" : "");
return 0;
}

View File

@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "wwtestpkg.h"
static char *
run6c(const char *bin, const char *src)
@@ -18,7 +19,7 @@ run6c(const char *bin, const char *src)
char path[64];
snprintf(path, sizeof path, "/tmp/wwffi_%d.ww", getpid());
FILE *f = fopen(path, "wb");
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
char cmd[512];

View File

@@ -20,6 +20,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -136,7 +137,7 @@ main(void)
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "wb");
fputs(rows[i].src, f);
wwtest_fputs(rows[i].src, f);
fclose(f);
char cmd[1024];

View File

@@ -28,6 +28,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -171,7 +172,7 @@ run_driver(const char *driver, const struct row *r, const char *dir,
FILE *f = fopen(src, "wb");
if (!f) return -1;
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd,

View File

@@ -31,6 +31,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -88,7 +89,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src);

View File

@@ -53,7 +53,8 @@ run_miss(const char *bin)
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "w");
if (!f) { fprintf(stderr, "949 FAIL: stage miss\n"); runwait(rmcmd); return 1; }
fputs("import nosuchpkg;\n"
fputs("package main;\n"
"import nosuchpkg;\n"
"export fn main() i32 = { return 0; };\n", f);
fclose(f);

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runcap(const char *cmd, char **outerr, size_t *outlen)
@@ -42,7 +43,7 @@ writefile(const char *path, const char *src)
{
FILE *f = fopen(path, "wb");
if (!f) return -1;
fputs(src, f);
wwtest_fputs(src, f);
fclose(f);
return 0;
}

View File

@@ -26,6 +26,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -383,7 +384,7 @@ run_driver(const char *driver, const struct row *r, int i)
FILE *f = fopen(src, "wb");
if (!f) { runwait(rmcmd); return -1; }
fputs(r->src, f);
wwtest_fputs(r->src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "%s build -o %s %s",

View File

@@ -12,27 +12,23 @@
* class silent miscompile, gate-blind and symmetric cs==ww. Surfaced by
* #80's `ww test` coexist (lib/test exports `run`).
*
* Fixture (the minimal real repro): a dir-package `aa` exporting `run`,
* imported by a PACKAGE-LESS root that defines its OWN bare `fn run` and
* calls it from `main`. Package-less is REQUIRED: a `package main` root's
* decls mangle `main.<leaf>` (the package clause sets the module), so its
* `run` would be `main.run` — no collision with `aa.run`, vacuous. Only a
* package-less primary yields a truly BARE `run`, the #84 trigger.
* Strict-package (#24a) form: a dir-package `aa` exporting `run`, imported
* by a `package main;` root that defines its OWN `fn run` and calls it from
* `main`. The root's `run` mangles `main.run` — DISTINCT from the imported
* `aa.run` and from the bare entry `main`. The original #84 trigger (a
* truly BARE `run` from a PACKAGE-LESS root) is unreachable now that
* strict-package forbids package-less primaries; the #84 cgen machinery
* (mod_collect / mod_lookup_for_fn) stays dormant-but-load-bearing for
* genuinely package-less `//ww:module-reset` deps until #24b/#26.
*
* Asserts (combined `ww build`, BOTH driver stages; the fix lives in
* mod_collect/mod_lookup_for_fn which run in every mode, so combined is
* the minimal repro — `--sep` reproduces identically):
* 1. Build + run, BOTH stages → exit 9 (the USER's bare `run`, return 9),
* Asserts (combined `ww build`, BOTH driver stages; `--sep` reproduces
* identically):
* 1. Build + run, BOTH stages → exit 9 (the user's `main.run`, return 9),
* never aa.run (return 5).
* 2. cs==ww (rule 10): the combined `.s` is byte-identical between the
* two driver stages.
* 3. NON-VACUITY + SOUNDNESS (the #84-specific signal): the `.s` has
* EXACTLY ONE `TEXT run` (the user's, bare) AND EXACTLY ONE `TEXT
* aa.run` (the import) — i.e. DISTINCT symbols, no dup. Pre-fix this
* row fails: two `TEXT aa.run` (the user's `run` mis-mangled onto the
* import) and zero bare `TEXT run`. (Exit alone is not a reliable
* signal: pre-fix the dup happened to bind the user's copy under this
* link order and still exited 9 — the label count is the proof.)
* 3. DISTINCTNESS: the `.s` has EXACTLY ONE `TEXT main.run` (the user's)
* AND EXACTLY ONE `TEXT aa.run` (the import) — distinct symbols, no dup.
*
* Light wwstage-driver test (CLAUDE.md rule 14): all intermediates are
* `-o`-redirected to /tmp, phase-parallel-safe. Models 989_sepbuild_run.c.
@@ -136,9 +132,13 @@ static const char *aa_src =
"package aa;\n"
"export fn run() i32 = { return 5; };\n";
/* PACKAGE-LESS root (no `package` clause) → its `fn run` is bare (the #84
* trigger); a `package main` root would mangle it `main.run` (vacuous). */
/* Strict-package (#24a) root: declares `package main;`, so its `fn run`
* mangles `main.run` — DISTINCT from the imported `aa.run`, and from the
* bare entry `main`. The bare call `run()` resolves to the local `main.run`
* via the standard exact-hint path (the #84 special-case is bypassed for a
* moduled root). */
static const char *root_src =
"package main;\n"
"import aa;\n"
"fn run() i32 = { return 9; };\n"
"export fn main() i32 = { return run(); };\n";
@@ -191,21 +191,20 @@ main(void)
fail++;
continue;
}
/* (1) the user's bare `run` (9) must win over imported aa.run (5). */
/* (1) the user's `main.run` (9) must win over imported aa.run (5). */
int rc = runwait(stg[s].prog);
if (rc != 9) {
fprintf(stderr, "84 FAIL: %s prog exit=%d expected 9 "
"(bare user run, not aa.run=5)\n", stg[s].drv, rc);
"(user main.run, not aa.run=5)\n", stg[s].drv, rc);
fail++;
}
/* (3) distinct symbols, no dup: exactly one bare `run` + one
* `aa.run`. Pre-fix: two `aa.run` (user run mis-mangled) + zero
* bare `run`. */
int nrun = count_text_label(stg[s].sfile, "run");
/* (3) distinct symbols, no dup: exactly one `main.run` + one
* `aa.run`. */
int nrun = count_text_label(stg[s].sfile, "main.run");
int naa = count_text_label(stg[s].sfile, "aa.run");
if (nrun != 1 || naa != 1) {
fprintf(stderr, "84 FAIL: %s labels TEXT run=%d aa.run=%d "
"(want 1/1 — bare user run distinct from import, no dup)\n",
fprintf(stderr, "84 FAIL: %s labels TEXT main.run=%d aa.run=%d "
"(want 1/1 — user main.run distinct from import, no dup)\n",
stg[s].drv, nrun, naa);
fail++;
}
@@ -224,8 +223,8 @@ out:
fprintf(stderr, "84: %d check(s) failed\n", fail);
return 1;
}
printf("barefn_collide: package-less root `fn run` (bare) coexists with "
"imported aa.run — distinct labels, no dup, user run wins (exit 9), "
"cs==ww, both driver stages (#84)\n");
printf("barefn_collide: `package main;` root `fn run` (main.run) coexists "
"with imported aa.run — distinct labels, no dup, user run wins "
"(exit 9), cs==ww, both driver stages (#84/#24a)\n");
return 0;
}

View File

@@ -41,6 +41,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include <dirent.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -114,7 +115,7 @@ write_file(const char *path, const char *body)
{
FILE *f = fopen(path, "wb");
if (!f) return -1;
fputs(body, f);
wwtest_fputs(body, f);
fclose(f);
return 0;
}
@@ -196,12 +197,13 @@ static struct tcase cases[] = {
/* a non-`fn() void` @test signature must loud-reject, not be coerced. */
{ "badsig", NULL, "test/wcc/data/attest_badsig.ww", 0, 0, 1 },
/* a user `fn run` COEXISTS with lib/test's bound runner (post-#80 synth
* `use test;` keys the runner under "test", #84 mangles the user `run`
* bare) → accept and run to exit 0. Under sep the two land in distinct
* units (`run` in __root.s, `test.run` in test.s), so a regressed #84
* collision re-mangles the user `run` to `test.run` and the force-loaded
* root `.o` + test's `.a` both define `test.run` → w6l duplicate-symbol
* → non-zero; exit 0 is the teeth (empirically confirmed). byteid=1 also
* `use test;` keys the runner under "test"; under strict-package #24a the
* user file's `package main;` mangles its `run` to `main.run`) → accept
* and run to exit 0. Under sep the two land in distinct units (`main.run`
* in __root.s, `test.run` in test.s), so a regressed collision re-mangles
* the user `run` to `test.run` and the force-loaded root `.o` + test's
* `.a` both define `test.run` → w6l duplicate-symbol → non-zero; exit 0
* is the teeth (empirically confirmed). byteid=1 also
* pins this coexist path's cs==ww per-pkg asm + synth presence — the
* rule-10 leg the ported 997 `coexist_run` carried over the #84 mangle. */
{ "collide_run", NULL, "test/wcc/data/attest_userrun.ww", 0, 1, 0 },

View File

@@ -23,6 +23,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -472,7 +473,7 @@ probe_ww_compile(const char *bin)
FILE *f = fopen(src, "wb");
if (!f) { fail++; continue; }
fputs(progs[i].src, f);
wwtest_fputs(progs[i].src, f);
fclose(f);
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -c %s > %s 2>/dev/null",

View File

@@ -17,6 +17,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -129,7 +130,8 @@ run_exit_code(const char *bin, const char *driver, int code)
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);
fprintf(f, "package main;\nexport fn main() i32 = {\n\treturn %d;\n};\n",
code);
fclose(f);
char cmd[256];
@@ -151,7 +153,7 @@ run_build_fail(const char *bin, const char *driver)
snprintf(src, sizeof src, "/tmp/ww_badbuild_%d.ww", getpid());
FILE *f = fopen(src, "w");
if (!f) return -1;
fputs("export fn main() i32 = {\n\treturn 1\n", f); /* no ; no } */
wwtest_fputs("export fn main() i32 = {\n\treturn 1\n", f); /* no ; no } */
fclose(f);
char cmd[256];
@@ -178,7 +180,7 @@ run_missing_pkg(const char *bin, const char *driver)
snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir);
FILE *f = fopen(src, "w");
if (!f) { runwait(rmcmd); return 1; }
fputs("import nosuchpkg;\nexport fn main() i32 = { return 0; };\n", f);
wwtest_fputs("import nosuchpkg;\nexport fn main() i32 = { return 0; };\n", f);
fclose(f);
/* #8: the sep scratch is mkdir'd before the import-resolution failure,
@@ -225,7 +227,7 @@ main(void)
{
FILE *f = fopen(hello_src, "w");
if (!f) return 1;
fputs("import os;\n\n"
wwtest_fputs("import os;\n\n"
"export fn main() i32 = {\n"
"\tos.write(1, \"hi\\n\".ptr, 3u64);\n"
"\treturn 0;\n"

View File

@@ -18,6 +18,7 @@
#include <unistd.h>
#include <sys/wait.h>
#include <dirent.h>
#include "wwtestpkg.h"
static int
runwait(const char *cmd)
@@ -101,7 +102,7 @@ write_file(const char *path, const char *content)
{
FILE *f = fopen(path, "wb");
if (!f) return -1;
fputs(content, f);
wwtest_fputs(content, f);
fclose(f);
return 0;
}

View File

@@ -1,15 +1,16 @@
// #80/#84 -T coexist — a user `fn run` COEXISTS with lib/test's bound
// runner `run` (the synth main's callee). Once `ww test -c` bundles
// lib/test, the synth `use test;` keys lib/test's `run` under module
// "test" (#80: prepended before binding) and the user's package-less
// `run` mangles to a DISTINCT bare `run` (#84) — no duplicate. Both
// "test" (#80: prepended before binding) and the user's `package main;`
// `run` mangles to a DISTINCT `main.run` (#84/#24a) — no duplicate. Both
// stages accept under -T and the synth runner runs the @test to exit 0;
// the user `run` must NOT hijack the entry. Pre-#80 this loud-rejected
// "duplicate fn run". The gate (910/997 coexist_run) static-label-counts
// the -T asm — exactly 1 `TEXT run` (user, bare) + 1 `TEXT test.run` (lib
// the -T asm — exactly 1 `TEXT main.run` (user) + 1 `TEXT test.run` (lib
// runner) — pinning #84 distinctness here in the REAL @test/-T path (a
// dead-dup regression yields 0x run / 2x test.run). General callability of
// the bare run is gated separately by 989_barefn_collide.
// dead-dup regression yields 0x main.run / 2x test.run). General
// callability of the user run is gated separately by 989_barefn_collide.
package main;
fn run() i32 = { return 9; };
@test fn t_one() void = {

View File

@@ -4,6 +4,7 @@
// builtins into c.top, so installtop must DROP this redecl rather than
// erroring. Both stages accept; the builtin `nomem` (= !void) wins, so
// g()'s i32 arm returns 7. Pins the 771/774/926 shape.
package main;
type nomem = !void;
fn g() (i32 | nomem) = { return 7; };
export fn main() i32 = {

View File

@@ -1,5 +1,6 @@
// #23 — two top-level defs of the same name in one (flat) module.
// cstage's install pass rejects "duplicate def D"; wwstage now mirrors.
package main;
def D: i32 = 1;
def D: i32 = 2;
export fn main() i32 = { return 0; };

View File

@@ -1,5 +1,6 @@
// #23 — two top-level fns of the same name in the same (flat) module.
// cstage's install pass rejects "duplicate fn foo"; wwstage now mirrors.
package main;
fn foo() i32 = { return 1; };
fn foo() i32 = { return 2; };
export fn main() i32 = { return foo(); };

View File

@@ -1,5 +1,6 @@
// #23 — two top-level lets of the same name in one (flat) module.
// cstage's install pass rejects "duplicate let g"; wwstage now mirrors.
package main;
let g: i32 = 1;
let g: i32 = 2;
export fn main() i32 = { return 0; };

View File

@@ -1,5 +1,6 @@
// #23 — two top-level types of the same name in one (flat) module.
// cstage's install pass rejects "duplicate type t"; wwstage now mirrors.
package main;
type t = i32;
type t = u32;
export fn main() i32 = { return 0; };

61
test/wcc/wwtestpkg.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* wwtestpkg.h — strict-package (#24a) test support.
*
* Inline ww test fixtures historically omitted the `package main;` clause
* that the parser now requires (a missing clause is a hard error). These
* helpers inject it transparently so the fixtures stay terse, WITHOUT
* disturbing fixtures that already declare their own module identity.
*
* wwtest_fputs is a drop-in for fputs(src, f): it prepends `package main;`
* only when writing at the START of a fresh file (ftell == 0) AND the
* fixture does not already open with its own `package`/`//ww:module`
* directive. The ftell guard keeps multi-part writes and writes to
* non-seekable streams (stderr) behaving exactly like plain fputs.
*/
#ifndef WWTESTPKG_H
#define WWTESTPKG_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static inline int
wwtest_has_module(const char *s)
{
const char *p = s;
while (p != NULL) {
while (*p == ' ' || *p == '\t')
p++;
if (strncmp(p, "package ", 8) == 0
|| strncmp(p, "package\t", 8) == 0
|| strncmp(p, "//ww:module", 11) == 0)
return 1;
p = strchr(p, '\n');
if (p != NULL)
p++;
}
return 0;
}
static inline void
wwtest_fputs(const char *src, FILE *f)
{
if (ftell(f) == 0 && !wwtest_has_module(src))
fputs("package main;\n", f);
fputs(src, f);
}
/* In-process variant: a malloc'd copy of src with the clause prefixed
* (unless src declares its own module). Caller frees. */
static inline char *
wwtest_wrap(const char *src)
{
const char *pfx = wwtest_has_module(src) ? "" : "package main;\n";
size_t np = strlen(pfx), ns = strlen(src);
char *b = malloc(np + ns + 1);
memcpy(b, pfx, np);
memcpy(b + np, src, ns + 1);
return b;
}
#endif