ww imports: reject init bindings before recovery
This commit is contained in:
@@ -2907,6 +2907,25 @@ decl_mod(Node *file, Node *d)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
invalid_init_import(Node *u)
|
||||
{
|
||||
return u != NULL && u->kind == N_USE && !u->useblank
|
||||
&& u->str != NULL && strcmp(u->str, "init") == 0;
|
||||
}
|
||||
|
||||
static Pos
|
||||
import_binding_pos(Node *u)
|
||||
{
|
||||
Pos p = u->pos;
|
||||
if (u->usefile != NULL) {
|
||||
p.file = u->usefile;
|
||||
p.line = u->useline;
|
||||
p.col = u->usecol;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* use_path — map a source-file default qualifier (the imported package's
|
||||
* declared name) to the full canonical import path it binds, for
|
||||
@@ -2932,7 +2951,7 @@ find_use_path(Node *file, const char *curmod, int source, const char *alias,
|
||||
if (strcmp(alias, leaf) == 0) return curmod;
|
||||
}
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->str == NULL
|
||||
if (u->kind != N_USE || u->str == NULL || invalid_init_import(u)
|
||||
|| u->sourceid != source || strcmp(u->str, alias) != 0)
|
||||
continue;
|
||||
const char *p = u->usepath ? u->usepath : u->str;
|
||||
@@ -3960,6 +3979,19 @@ check_import_alt(Node *d, const char *name)
|
||||
d->pos.file ? d->pos.file : "?", d->pos.line, d->pos.col, name);
|
||||
}
|
||||
|
||||
/* Pinned Go 1.26.5 types2 rejects an effective import binding named init and
|
||||
* immediately continues before creating its PkgName. Diagnose every resolved
|
||||
* occurrence at the first import-spec token, then keep it out of all binding
|
||||
* recovery below while retaining the real loader-owned dependency edge. */
|
||||
static void
|
||||
reject_init_imports(Checker *c, Node *file)
|
||||
{
|
||||
for (Node *u = file->list; u; u = u->next)
|
||||
if (invalid_init_import(u))
|
||||
err(c, import_binding_pos(u),
|
||||
"cannot import package as init - init must be a func");
|
||||
}
|
||||
|
||||
/* Go's default import binding lives in the importing file's scope. Reject
|
||||
* only another binding in that same source section; equal names in sibling
|
||||
* files are independent even though their canonical edges are package-wide. */
|
||||
@@ -3968,11 +4000,11 @@ check_import_redeclarations(Checker *c, Node *file)
|
||||
{
|
||||
if (!c->sep_mode) return;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->useblank
|
||||
if (u->kind != N_USE || u->useblank || invalid_init_import(u)
|
||||
|| u->imported || u->str == NULL)
|
||||
continue;
|
||||
for (Node *v = file->list; v != u; v = v->next) {
|
||||
if (v->kind != N_USE || v->useblank
|
||||
if (v->kind != N_USE || v->useblank || invalid_init_import(v)
|
||||
|| v->imported || v->str == NULL
|
||||
|| v->sourceid != u->sourceid)
|
||||
continue;
|
||||
@@ -3994,7 +4026,7 @@ check_import_usage_and_collisions(Checker *c, Node *file)
|
||||
{
|
||||
if (!c->sep_mode) return;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->useblank
|
||||
if (u->kind != N_USE || u->useblank || invalid_init_import(u)
|
||||
|| u->imported || u->used || u->str == NULL)
|
||||
continue;
|
||||
const char *path = u->usesource ? u->usesource
|
||||
@@ -4011,7 +4043,7 @@ check_import_usage_and_collisions(Checker *c, Node *file)
|
||||
if (d->imported || !top_decl_kind(d) || d->str == NULL)
|
||||
continue;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->useblank
|
||||
if (u->kind != N_USE || u->useblank || invalid_init_import(u)
|
||||
|| u->imported || u->str == NULL
|
||||
|| strcmp(d->str, u->str) != 0)
|
||||
continue;
|
||||
@@ -4078,6 +4110,7 @@ check_file(Checker *c, Node *file)
|
||||
file->list = usenode;
|
||||
}
|
||||
}
|
||||
reject_init_imports(c, file);
|
||||
reject_nonfunction_main_decls(c, file);
|
||||
mark_import_uses(c, file);
|
||||
check_import_redeclarations(c, file);
|
||||
@@ -4106,10 +4139,8 @@ check_file(Checker *c, Node *file)
|
||||
"'%s' cannot import itself", owner);
|
||||
if (d->useblank)
|
||||
continue;
|
||||
if (d->str != NULL && strcmp(d->str, "init") == 0) {
|
||||
err(c, d->pos, "cannot import package as init - init must be a func");
|
||||
if (invalid_init_import(d))
|
||||
continue;
|
||||
}
|
||||
Sym *prev = scope_lookup_local(c->cur, d->str);
|
||||
if (prev != NULL) {
|
||||
/* Self-import: the driver concatenates the
|
||||
|
||||
@@ -1323,6 +1323,12 @@ parseuse(Parser *p)
|
||||
Pos pp = p->cur.pos;
|
||||
expect(p, TK_USE);
|
||||
Node *n = newnode(p->a, N_USE, pp);
|
||||
/* Keep n->pos at the import keyword for structural diagnostics. Go's
|
||||
* import declaration position is the first spec token: the explicit alias
|
||||
* when present, otherwise the path. */
|
||||
n->usefile = p->cur.pos.file;
|
||||
n->useline = p->cur.pos.line;
|
||||
n->usecol = p->cur.pos.col;
|
||||
const char *alias = NULL;
|
||||
const char *first;
|
||||
if (p->cur.kind == TK_UNDER) {
|
||||
|
||||
@@ -349,6 +349,10 @@ struct Node {
|
||||
const char *usepath; /* N_USE: canonical, vendor-expanded identity;
|
||||
* initially equal to `usesource`. */
|
||||
const char *usealias; /* N_USE: explicit file-local alias, or NULL. */
|
||||
const char *usefile; /* N_USE: first import-spec token position;
|
||||
* alias when explicit, path otherwise. */
|
||||
int useline;
|
||||
int usecol;
|
||||
const char *usepkgname; /* N_USE: imported declared package name,
|
||||
* independent of the visible binding in `str`. */
|
||||
int useblank; /* N_USE: `_` spelling; no source binding. */
|
||||
|
||||
Reference in New Issue
Block a user