/* * 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 `) 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 * does not match import path

"). 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 #include #include #include #include #include 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; }