wcc/check: reject self-import, both stages (#16 ENFORCE-checker)
check-(c): a package importing itself (any spelling) is a hard error, mirroring Go. Predicate is leaf==owner at the N_USE/installdecl seam — sound only after the PREP commits (dotted-test renames, package-less boundary directive). Identical wording both stages; diagnostics-only, byte-id-neutral. 948 pins the reject in both compilers; 708's pos_selfimp (which pinned the abolished self-import skip) converts to neg_selfimp + new pos_crossmod preserving the param-shadow tolerance the case existed for. Checks (a) unused and (b)/(d) name-membership stay deferred to the multi-package arc: imports are filename-keyed pulls, so those need import->file provenance this compiler lacks.
This commit is contained in:
89
test/wcc/948_selfimport.c
Normal file
89
test/wcc/948_selfimport.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 948_selfimport — #16 check-(c): a package may not import itself.
|
||||
*
|
||||
* Both compiler stages (w6c, w6c_ww) must loud-reject `package foo;
|
||||
* import foo;` — nonzero exit AND a "self-import" diagnostic on stderr.
|
||||
* Compile-only (`-o /dev/null`): w6c/w6c_ww do not expand imports (the
|
||||
* driver does), so a lone fixture triggers check-(c) directly. This is
|
||||
* NOT a ww_ww DRIVER test — it never invokes the driver — so it is
|
||||
* Phase-1-safe and does not race the 990-997 byte-id gates (rule 14).
|
||||
*
|
||||
* check-(a) unused + (b)/(d) membership are DEFERRED to task #8 (ww's
|
||||
* filename-keyed file-inclusion imports lack import->file->symbol
|
||||
* provenance); only self-import is package-model-independent.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* reject — `<comp> <fixture> -o /dev/null` must exit nonzero and print
|
||||
* <substr> on stderr. */
|
||||
static int
|
||||
reject(const char *bin, const char *comp, const char *fixture,
|
||||
const char *substr)
|
||||
{
|
||||
int pid = getpid();
|
||||
char errf[256], cmd[4096], line[4096];
|
||||
snprintf(errf, sizeof errf, "/tmp/si948_%s_%d.err", comp, pid);
|
||||
snprintf(cmd, sizeof cmd, "%s/%s %s -o /dev/null 2>%s",
|
||||
bin, comp, fixture, errf);
|
||||
|
||||
int rc = system(cmd);
|
||||
if (rc == 0) {
|
||||
fprintf(stderr, "948 FAIL: %s accepted %s (expected reject)\n",
|
||||
comp, fixture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
FILE *f = fopen(errf, "r");
|
||||
if (f) {
|
||||
while (fgets(line, sizeof line, f))
|
||||
if (strstr(line, substr)) { found = 1; break; }
|
||||
fclose(f);
|
||||
}
|
||||
unlink(errf);
|
||||
if (!found) {
|
||||
fprintf(stderr, "948 FAIL: %s rejected %s but no '%s' on stderr\n",
|
||||
comp, fixture, substr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *comp;
|
||||
const char *fixture;
|
||||
const char *substr;
|
||||
} rows[] = {
|
||||
{ "w6c", "test/wcc/data/selfimport.ww", "self-import" },
|
||||
{ "w6c_ww", "test/wcc/data/selfimport.ww", "self-import" },
|
||||
};
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = absbin();
|
||||
if (!bin) { fprintf(stderr, "948 FAIL: getcwd\n"); return 1; }
|
||||
|
||||
for (size_t i = 0; i < sizeof rows / sizeof rows[0]; i++)
|
||||
if (reject(bin, rows[i].comp, rows[i].fixture, rows[i].substr) != 0)
|
||||
return 1;
|
||||
|
||||
printf("self-import rejected by w6c and w6c_ww\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user