Commit 9435dc2b authored by Russ Cox's avatar Russ Cox

allow forward declaration of struct in another file

(in the same package).

allow forward method declaration to be satisfied
by implementation in another file (in the same package).
all methods must be declared in the same file
as the receiver type.

R=ken
OCL=30864
CL=30869
parent 3119221e
...@@ -1216,7 +1216,7 @@ longt(Armember *bp) ...@@ -1216,7 +1216,7 @@ longt(Armember *bp)
pmode(strtoul(bp->hdr.mode, 0, 8)); pmode(strtoul(bp->hdr.mode, 0, 8));
Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0)); Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
Bprint(&bout, "%7ld", bp->size); Bprint(&bout, "%7ld", bp->size);
cp = ctime(bp->date); cp = ctime(&bp->date);
Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
} }
...@@ -1455,7 +1455,6 @@ typedef struct Import Import; ...@@ -1455,7 +1455,6 @@ typedef struct Import Import;
struct Import struct Import
{ {
Import *hash; // next in hash table Import *hash; // next in hash table
char *export; // marked as export or package?
char *prefix; // "type", "var", "func", "const" char *prefix; // "type", "var", "func", "const"
char *name; char *name;
char *def; char *def;
...@@ -1485,58 +1484,65 @@ ilookup(char *name) ...@@ -1485,58 +1484,65 @@ ilookup(char *name)
return x; return x;
} }
/*
* a and b don't match.
* is one a forward declaration and the other a valid completion?
* if so, return the one to keep.
*/
char*
forwardfix(char *a, char *b)
{
char *t;
if(strlen(a) > strlen(b)) {
t = a;
a = b;
b = t;
}
if(strcmp(a, "struct") == 0 && strncmp(b, "struct ", 7) == 0)
return b;
if(strcmp(a, "interface") == 0 && strncmp(b, "interface ", 10) == 0)
return b;
return nil;
}
int parsemethod(char**, char*, char**); int parsemethod(char**, char*, char**);
int parsepkgdata(char**, char*, char**, char**, char**, char**); int parsepkgdata(char**, char*, char**, char**, char**);
void void
loadpkgdata(char *data, int len) loadpkgdata(char *data, int len)
{ {
char *export; char *p, *ep, *prefix, *name, *def, *ndef;
char *p, *ep, *prefix, *name, *def;
Import *x; Import *x;
p = data; p = data;
ep = data + len; ep = data + len;
while(parsepkgdata(&p, ep, &export, &prefix, &name, &def) > 0) { while(parsepkgdata(&p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name); x = ilookup(name);
if(x->prefix == nil) { if(x->prefix == nil) {
x->prefix = prefix; x->prefix = prefix;
x->def = def; x->def = def;
x->file = file; x->file = file;
x->export = export; } else if(strcmp(x->prefix, prefix) != 0) {
} else {
if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "ar: conflicting definitions for %s\n", name); fprint(2, "ar: conflicting definitions for %s\n", name);
fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
fprint(2, "%s:\t%s %s ...\n", file, prefix, name); fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
errors++; errors++;
} } else if(strcmp(x->def, def) == 0) {
else if(strcmp(x->def, def) != 0) { // fine
} else if((ndef = forwardfix(x->def, def)) != nil) {
x->def = ndef;
} else {
fprint(2, "ar: conflicting definitions for %s\n", name); fprint(2, "ar: conflicting definitions for %s\n", name);
fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
errors++; errors++;
} }
// okay if some .6 say export/package and others don't.
// all it takes is one. not okay if some say export
// and others say package.
if(export) {
if(x->export == nil)
x->export = export;
else if(strcmp(x->export, export) != 0) {
fprint(2, "ar: conflicting scopes for %s\n", name);
fprint(2, "%s:\t%s\n", x->file, x->export);
fprint(2, "%s:\t%s\n", file, export);
errors++;
}
}
}
} }
} }
int int
parsepkgdata(char **pp, char *ep, char **exportp, char **prefixp, char **namep, char **defp) parsepkgdata(char **pp, char *ep, char **prefixp, char **namep, char **defp)
{ {
char *p, *prefix, *name, *def, *edef, *meth; char *p, *prefix, *name, *def, *edef, *meth;
int n; int n;
...@@ -1548,16 +1554,6 @@ parsepkgdata(char **pp, char *ep, char **exportp, char **prefixp, char **namep, ...@@ -1548,16 +1554,6 @@ parsepkgdata(char **pp, char *ep, char **exportp, char **prefixp, char **namep,
if(p == ep) if(p == ep)
return 0; return 0;
// [export|package ]
*exportp = 0;
if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) {
*exportp = "export";
p += 7;
} else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) {
*exportp = "package";
p += 8;
}
// prefix: (var|type|func|const) // prefix: (var|type|func|const)
prefix = p; prefix = p;
...@@ -1710,8 +1706,6 @@ getpkgdef(char **datap, int *lenp) ...@@ -1710,8 +1706,6 @@ getpkgdef(char **datap, int *lenp)
len += strlen(x->prefix) + 1 len += strlen(x->prefix) + 1
+ strlen(x->name) + 1 + strlen(x->name) + 1
+ strlen(x->def) + 1; + strlen(x->def) + 1;
if(x->export)
len += strlen(x->export) + 1;
} }
} }
if(j != nimport) { if(j != nimport) {
...@@ -1735,11 +1729,7 @@ getpkgdef(char **datap, int *lenp) ...@@ -1735,11 +1729,7 @@ getpkgdef(char **datap, int *lenp)
p = strappend(p, "\n"); p = strappend(p, "\n");
for(i=0; i<nimport; i++) { for(i=0; i<nimport; i++) {
x = all[i]; x = all[i];
// [export|package] prefix name def\n // prefix name def\n
if(x->export) {
p = strappend(p, x->export);
p = strappend(p, " ");
}
p = strappend(p, x->prefix); p = strappend(p, x->prefix);
p = strappend(p, " "); p = strappend(p, " ");
p = strappend(p, x->name); p = strappend(p, x->name);
......
...@@ -93,12 +93,13 @@ updatetype(Type *n, Type *t) ...@@ -93,12 +93,13 @@ updatetype(Type *n, Type *t)
{ {
Sym *s; Sym *s;
int local; int local;
int maplineno, lno; int maplineno, lno, etype;
s = n->sym; s = n->sym;
if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n) if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n)
fatal("updatetype %T = %T", n, t); fatal("updatetype %T = %T", n, t);
etype = n->etype;
switch(n->etype) { switch(n->etype) {
case TFORW: case TFORW:
break; break;
...@@ -316,13 +317,7 @@ addmethod(Node *n, Type *t, int local) ...@@ -316,13 +317,7 @@ addmethod(Node *n, Type *t, int local)
if(f == T) if(f == T)
goto bad; goto bad;
if(local && !f->local) {
yyerror("cannot define methods on non-local type %T", f);
return;
}
pa = f; pa = f;
if(pkgimportname != S && !exportname(sf->name)) if(pkgimportname != S && !exportname(sf->name))
sf = pkglookup(sf->name, pkgimportname->name); sf = pkglookup(sf->name, pkgimportname->name);
...@@ -331,13 +326,11 @@ addmethod(Node *n, Type *t, int local) ...@@ -331,13 +326,11 @@ addmethod(Node *n, Type *t, int local)
d = T; // last found d = T; // last found
for(f=pa->method; f!=T; f=f->down) { for(f=pa->method; f!=T; f=f->down) {
d = f;
if(f->etype != TFIELD) if(f->etype != TFIELD)
fatal("addmethod: not TFIELD: %N", f); fatal("addmethod: not TFIELD: %N", f);
if(strcmp(sf->name, f->sym->name) != 0)
if(strcmp(sf->name, f->sym->name) != 0) {
d = f;
continue; continue;
}
if(!eqtype(t, f->type)) { if(!eqtype(t, f->type)) {
yyerror("method redeclared: %T.%S", pa, sf); yyerror("method redeclared: %T.%S", pa, sf);
print("\t%T\n\t%T\n", f->type, t); print("\t%T\n\t%T\n", f->type, t);
...@@ -345,6 +338,14 @@ addmethod(Node *n, Type *t, int local) ...@@ -345,6 +338,14 @@ addmethod(Node *n, Type *t, int local)
return; return;
} }
if(local && !pa->local) {
// defining method on non-local type.
// method must have been forward declared
// elsewhere, i.e. where the type was.
yyerror("cannot define new methods on non-local type %T", pa);
return;
}
if(d == T) if(d == T)
stotype(n, 0, &pa->method); stotype(n, 0, &pa->method);
else else
......
...@@ -168,9 +168,13 @@ dumpexporttype(Sym *s) ...@@ -168,9 +168,13 @@ dumpexporttype(Sym *s)
Bprint(bout, "\t"); Bprint(bout, "\t");
switch (t->etype) { switch (t->etype) {
case TFORW: case TFORW:
yyerror("export of incomplete type %T", t);
return;
case TFORWSTRUCT: case TFORWSTRUCT:
Bprint(bout, "type %#T struct\n", t);
return;
case TFORWINTER: case TFORWINTER:
yyerror("export of incomplete type %T", t); Bprint(bout, "type %#T interface\n", t);
return; return;
} }
Bprint(bout, "type %#T %l#T\n", t, t); Bprint(bout, "type %#T %l#T\n", t, t);
...@@ -276,11 +280,15 @@ importsym(Sym *s, int op) ...@@ -276,11 +280,15 @@ importsym(Sym *s, int op)
else else
yyerror("redeclaration of %lS during import", s, s->def->op, op); yyerror("redeclaration of %lS during import", s, s->def->op, op);
} }
// mark the symbol so it is not reexported
if(s->def == N) {
if(exportname(s->name)) if(exportname(s->name))
s->export = 1; s->export = 1;
else else
s->export = 2; // package scope s->export = 2; // package scope
s->imported = 1; s->imported = 1;
}
return s; return s;
} }
...@@ -359,9 +367,12 @@ importtype(Sym *s, Type *t) ...@@ -359,9 +367,12 @@ importtype(Sym *s, Type *t)
if(n != N && n->op == OTYPE) { if(n != N && n->op == OTYPE) {
if(cvttype(t, n->type)) if(cvttype(t, n->type))
return; return;
if(n->type->etype != TFORW) { if(t->etype == TFORWSTRUCT && n->type->etype == TSTRUCT)
warn("redeclare import type %S from %lT to %lT", return;
s, n->type, t); if(t->etype == TFORWINTER && n->type->etype == TINTER)
return;
if(n->type->etype != TFORW && n->type->etype != TFORWSTRUCT && n->type->etype != TFORWINTER) {
yyerror("redeclare import type %S from %lT to %lT", s, n->type, t);
n = s->def = typenod(typ(0)); n = s->def = typenod(typ(0));
} }
} }
...@@ -376,7 +387,16 @@ importtype(Sym *s, Type *t) ...@@ -376,7 +387,16 @@ importtype(Sym *s, Type *t)
*n->type = *t; *n->type = *t;
n->type->sym = s; n->type->sym = s;
n->type->nod = n; n->type->nod = n;
switch(n->type->etype) {
case TFORWINTER:
case TFORWSTRUCT:
// allow re-export in case it gets defined
s->export = 0;
s->imported = 0;
break;
default:
checkwidth(n->type); checkwidth(n->type);
}
if(debug['E']) if(debug['E'])
print("import type %S %lT\n", s, t); print("import type %S %lT\n", s, t);
......
...@@ -1700,6 +1700,14 @@ hidden_import: ...@@ -1700,6 +1700,14 @@ hidden_import:
{ {
importtype($2, $3); importtype($2, $3);
} }
| LTYPE hidden_pkg_importsym LSTRUCT
{
importtype($2, typ(TFORWSTRUCT));
}
| LTYPE hidden_pkg_importsym LINTERFACE
{
importtype($2, typ(TFORWINTER));
}
| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres | LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
{ {
importvar($2, functype(N, $4, $6), PFUNC); importvar($2, functype(N, $4, $6), PFUNC);
......
...@@ -22,7 +22,6 @@ typedef struct Import Import; ...@@ -22,7 +22,6 @@ typedef struct Import Import;
struct Import struct Import
{ {
Import *hash; // next in hash table Import *hash; // next in hash table
int export; // marked as export?
char *prefix; // "type", "var", "func", "const" char *prefix; // "type", "var", "func", "const"
char *name; char *name;
char *def; char *def;
...@@ -89,7 +88,7 @@ gotypefor(char *name) ...@@ -89,7 +88,7 @@ gotypefor(char *name)
static void loadpkgdata(char*, char*, int); static void loadpkgdata(char*, char*, int);
static int parsemethod(char**, char*, char**); static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char**, char*, int*, char**, char**, char**); static int parsepkgdata(char*, char**, char*, char**, char**, char**);
void void
ldpkg(Biobuf *f, int64 len, char *filename) ldpkg(Biobuf *f, int64 len, char *filename)
...@@ -154,47 +153,63 @@ ldpkg(Biobuf *f, int64 len, char *filename) ...@@ -154,47 +153,63 @@ ldpkg(Biobuf *f, int64 len, char *filename)
loadpkgdata(filename, p0, p1 - p0); loadpkgdata(filename, p0, p1 - p0);
} }
/*
* a and b don't match.
* is one a forward declaration and the other a valid completion?
* if so, return the one to keep.
*/
char*
forwardfix(char *a, char *b)
{
char *t;
if(strlen(a) > strlen(b)) {
t = a;
a = b;
b = t;
}
if(strcmp(a, "struct") == 0 && strncmp(b, "struct ", 7) == 0)
return b;
if(strcmp(a, "interface") == 0 && strncmp(b, "interface ", 10) == 0)
return b;
return nil;
}
static void static void
loadpkgdata(char *file, char *data, int len) loadpkgdata(char *file, char *data, int len)
{ {
int export; char *p, *ep, *prefix, *name, *def, *ndef;
char *p, *ep, *prefix, *name, *def;
Import *x; Import *x;
file = strdup(file); file = strdup(file);
p = data; p = data;
ep = data + len; ep = data + len;
while(parsepkgdata(file, &p, ep, &export, &prefix, &name, &def) > 0) { while(parsepkgdata(file, &p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name); x = ilookup(name);
if(x->prefix == nil) { if(x->prefix == nil) {
x->prefix = prefix; x->prefix = prefix;
x->def = def; x->def = def;
x->file = file; x->file = file;
x->export = export; } else if(strcmp(x->prefix, prefix) != 0) {
} else {
if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name); fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
fprint(2, "%s:\t%s %s ...\n", file, prefix, name); fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
nerrors++; nerrors++;
} } else if(strcmp(x->def, def) == 0) {
else if(strcmp(x->def, def) != 0) { // fine
fprint(2, "%s: conflicting definitions for %s\n", argv0, name); } else if((ndef = forwardfix(x->def, def)) != nil) {
x->def = ndef;
} else {
fprint(2, "%d: conflicting definitions for %s\n", argv0, name);
fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
nerrors++; nerrors++;
} }
// okay if some .6 say export and others don't.
// all it takes is one.
if(export)
x->export = 1;
}
} }
} }
static int static int
parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char **namep, char **defp) parsepkgdata(char *file, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{ {
char *p, *prefix, *name, *def, *edef, *meth; char *p, *prefix, *name, *def, *edef, *meth;
int n; int n;
...@@ -206,17 +221,6 @@ parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char ...@@ -206,17 +221,6 @@ parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char
if(p == ep || strncmp(p, "$$\n", 3) == 0) if(p == ep || strncmp(p, "$$\n", 3) == 0)
return 0; return 0;
// [export|package ]
*exportp = 0;
if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) {
*exportp = 1;
p += 7;
}
else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) {
*exportp = 2;
p += 8;
}
// prefix: (var|type|func|const) // prefix: (var|type|func|const)
prefix = p; prefix = p;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment