summaryrefslogtreecommitdiff
path: root/src/cmd/gc/dcl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/dcl.c')
-rw-r--r--src/cmd/gc/dcl.c567
1 files changed, 356 insertions, 211 deletions
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 5bfeeb97a..4121a45ab 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "y.tab.h"
static void funcargs(Node*);
+static void funcargs2(Type*);
static int
dflag(void)
@@ -115,6 +118,8 @@ dumpdcl(char *st)
Sym *s, *d;
int i;
+ USED(st);
+
i = 0;
for(d=dclstack; d!=S; d=d->link) {
i++;
@@ -170,6 +175,11 @@ declare(Node *n, int ctxt)
n->lineno = parserline();
s = n->sym;
+
+ // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+ if(importpkg == nil && !typecheckok && s->pkg != localpkg)
+ yyerror("cannot declare name %S", s);
+
gen = 0;
if(ctxt == PEXTERN) {
externdcl = list(externdcl, n);
@@ -188,7 +198,7 @@ declare(Node *n, int ctxt)
n->curfn = curfn;
}
if(ctxt == PAUTO)
- n->xoffset = BADWIDTH;
+ n->xoffset = 0;
if(s->block == block)
redeclare(s, "in this block");
@@ -411,6 +421,7 @@ oldname(Sym *s)
c->funcdepth = funcdepth;
c->outer = n->closure;
n->closure = c;
+ n->addrtaken = 1;
c->closure = n;
c->xoffset = 0;
curfn->cvars = list(curfn->cvars, c);
@@ -468,7 +479,7 @@ colasdefn(NodeList *left, Node *defn)
if(isblank(n))
continue;
if(!colasname(n)) {
- yyerror("non-name %#N on left side of :=", n);
+ yyerror("non-name %N on left side of :=", n);
nerr++;
continue;
}
@@ -542,13 +553,6 @@ ifacedcl(Node *n)
void
funchdr(Node *n)
{
-
- if(n->nname != N) {
- n->nname->op = ONAME;
- declare(n->nname, PFUNC);
- n->nname->defn = n;
- }
-
// change the declaration context from extern to auto
if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
@@ -559,16 +563,19 @@ funchdr(Node *n)
n->outer = curfn;
curfn = n;
+
if(n->nname)
funcargs(n->nname->ntype);
- else
+ else if (n->ntype)
funcargs(n->ntype);
+ else
+ funcargs2(n->type);
}
static void
funcargs(Node *nt)
{
- Node *n;
+ Node *n, *nn;
NodeList *l;
int gen;
@@ -577,11 +584,11 @@ funcargs(Node *nt)
// declare the receiver and in arguments.
// no n->defn because type checking of func header
- // will fill in the types before we can demand them.
+ // will not fill in the types until later
if(nt->left != N) {
n = nt->left;
if(n->op != ODCLFIELD)
- fatal("funcargs1 %O", n->op);
+ fatal("funcargs receiver %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
@@ -591,7 +598,7 @@ funcargs(Node *nt)
for(l=nt->list; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
- fatal("funcargs2 %O", n->op);
+ fatal("funcargs in %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
@@ -604,12 +611,16 @@ funcargs(Node *nt)
for(l=nt->rlist; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
- fatal("funcargs3 %O", n->op);
+ fatal("funcargs out %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
if(isblank(n->left)) {
// Give it a name so we can assign to it during return.
+ // preserve the original in ->orig
+ nn = nod(OXXX, N, N);
+ *nn = *n->left;
+ n->left = nn;
snprint(namebuf, sizeof(namebuf), ".anon%d", gen++);
n->left->sym = lookup(namebuf);
}
@@ -619,6 +630,48 @@ funcargs(Node *nt)
}
/*
+ * Same as funcargs, except run over an already constructed TFUNC.
+ * This happens during import, where the hidden_fndcl rule has
+ * used functype directly to parse the function's type.
+ */
+static void
+funcargs2(Type *t)
+{
+ Type *ft;
+ Node *n;
+
+ if(t->etype != TFUNC)
+ fatal("funcargs2 %T", t);
+
+ if(t->thistuple)
+ for(ft=getthisx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname; // no need for newname(ft->nname->sym)
+ n->type = ft->type;
+ declare(n, PPARAM);
+ }
+
+ if(t->intuple)
+ for(ft=getinargx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname;
+ n->type = ft->type;
+ declare(n, PPARAM);
+ }
+
+ if(t->outtuple)
+ for(ft=getoutargx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname;
+ n->type = ft->type;
+ declare(n, PPARAMOUT);
+ }
+}
+
+/*
* finish the body.
* called in auto-declaration context.
* returns in extern-declaration context.
@@ -645,7 +698,7 @@ typedcl0(Sym *s)
{
Node *n;
- n = dclname(s);
+ n = newname(s);
n->op = OTYPE;
declare(n, dclcontext);
return n;
@@ -665,217 +718,265 @@ typedcl1(Node *n, Node *t, int local)
}
/*
- * typedcl1 but during imports
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
*/
-void
-typedcl2(Type *pt, Type *t)
+
+static void
+checkembeddedtype(Type *t)
{
- Node *n;
+ if (t == T)
+ return;
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if(incannedimport &&
- strcmp(importpkg->name, "unsafe") == 0 &&
- strcmp(pt->nod->sym->name, "Pointer") == 0) {
- t = types[TUNSAFEPTR];
+ if(t->sym == S && isptr[t->etype]) {
+ t = t->type;
+ if(t->etype == TINTER)
+ yyerror("embedded type cannot be a pointer to interface");
}
+ if(isptr[t->etype])
+ yyerror("embedded type cannot be a pointer");
+ else if(t->etype == TFORW && t->embedlineno == 0)
+ t->embedlineno = lineno;
+}
- if(pt->etype == TFORW)
- goto ok;
- if(!eqtype(pt->orig, t))
- yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
- return;
+static Type*
+structfield(Node *n)
+{
+ Type *f;
+ int lno;
-ok:
- n = pt->nod;
- copytype(pt->nod, t);
- // unzero nod
- pt->nod = n;
+ lno = lineno;
+ lineno = n->lineno;
+
+ if(n->op != ODCLFIELD)
+ fatal("structfield: oops %N\n", n);
+
+ f = typ(TFIELD);
+ f->isddd = n->isddd;
+
+ if(n->right != N) {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ if(n->left != N)
+ n->left->type = n->type;
+ if(n->embedded)
+ checkembeddedtype(n->type);
+ }
+ n->right = N;
+
+ f->type = n->type;
+ if(f->type == T)
+ f->broke = 1;
+
+ switch(n->val.ctype) {
+ case CTSTR:
+ f->note = n->val.u.sval;
+ break;
+ default:
+ yyerror("field annotation must be string");
+ // fallthrough
+ case CTxxx:
+ f->note = nil;
+ break;
+ }
- pt->sym->lastlineno = parserline();
- declare(n, PEXTERN);
+ if(n->left && n->left->op == ONAME) {
+ f->nname = n->left;
+ f->embedded = n->embedded;
+ f->sym = f->nname->sym;
+ }
- checkwidth(pt);
+ lineno = lno;
+ return f;
}
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
+static void
+checkdupfields(Type *t, char* what)
+{
+ Type* t1;
+ int lno;
+ lno = lineno;
+
+ for( ; t; t=t->down)
+ if(t->sym && t->nname && !isblank(t->nname))
+ for(t1=t->down; t1; t1=t1->down)
+ if(t1->sym == t->sym) {
+ lineno = t->nname->lineno;
+ yyerror("duplicate %s %s", what, t->sym->name);
+ break;
+ }
+
+ lineno = lno;
+}
/*
- * turn a parsed struct into a type
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
*/
-static Type**
-stotype(NodeList *l, int et, Type **t, int funarg)
+Type*
+tostruct(NodeList *l)
{
- Type *f, *t1, *t2, **t0;
- Strlit *note;
+ Type *t, *f, **tp;
+ t = typ(TSTRUCT);
+
+ for(tp = &t->type; l; l=l->next) {
+ f = structfield(l->n);
+
+ *tp = f;
+ tp = &f->down;
+ }
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "field");
+
+ if (!t->broke)
+ checkwidth(t);
+
+ return t;
+}
+
+static Type*
+tofunargs(NodeList *l)
+{
+ Type *t, *f, **tp;
+
+ t = typ(TSTRUCT);
+ t->funarg = 1;
+
+ for(tp = &t->type; l; l=l->next) {
+ f = structfield(l->n);
+ f->funarg = 1;
+
+ // esc.c needs to find f given a PPARAM to add the tag.
+ if(l->n->left && l->n->left->class == PPARAM)
+ l->n->left->paramfld = f;
+
+ *tp = f;
+ tp = &f->down;
+ }
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "argument");
+ return t;
+}
+
+static Type*
+interfacefield(Node *n)
+{
+ Type *f;
int lno;
- Node *n, *left;
- char *what;
- t0 = t;
lno = lineno;
- what = "field";
- if(et == TINTER)
- what = "method";
+ lineno = n->lineno;
- for(; l; l=l->next) {
- n = l->n;
- lineno = n->lineno;
- note = nil;
+ if(n->op != ODCLFIELD)
+ fatal("interfacefield: oops %N\n", n);
- if(n->op != ODCLFIELD)
- fatal("stotype: oops %N\n", n);
- left = n->left;
- if(funarg && isblank(left))
- left = N;
- if(n->right != N) {
- if(et == TINTER && left != N) {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n->type = typ(TINTERMETH);
- n->type->nname = n->right;
- n->right = N;
- left->type = n->type;
- queuemethod(n);
- } else {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- if(n->type == T)
- continue;
- if(left != N)
- left->type = n->type;
- n->right = N;
- if(n->embedded && n->type != T) {
- t1 = n->type;
- if(t1->sym == S && isptr[t1->etype]) {
- t1 = t1->type;
- if(t1->etype == TINTER)
- yyerror("embedded type cannot be a pointer to interface");
- }
- if(isptr[t1->etype])
- yyerror("embedded type cannot be a pointer");
- else if(t1->etype == TFORW && t1->embedlineno == 0)
- t1->embedlineno = lineno;
- }
+ if (n->val.ctype != CTxxx)
+ yyerror("interface method cannot have annotation");
+
+ f = typ(TFIELD);
+ f->isddd = n->isddd;
+
+ if(n->right != N) {
+ if(n->left != N) {
+ // queue resolution of method type for later.
+ // right now all we need is the name list.
+ // avoids cycles for recursive interface types.
+ n->type = typ(TINTERMETH);
+ n->type->nname = n->right;
+ n->left->type = n->type;
+ queuemethod(n);
+
+ if(n->left->op == ONAME) {
+ f->nname = n->left;
+ f->embedded = n->embedded;
+ f->sym = f->nname->sym;
+ if(importpkg && !exportname(f->sym->name))
+ f->sym = pkglookup(f->sym->name, structpkg);
}
- }
- if(n->type == T) {
- // assume error already printed
- continue;
- }
+ } else {
- switch(n->val.ctype) {
- case CTSTR:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- note = n->val.u.sval;
- break;
- default:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- else
- yyerror("field annotation must be string");
- case CTxxx:
- note = nil;
- break;
- }
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+
+ if(n->embedded)
+ checkembeddedtype(n->type);
- if(et == TINTER && left == N) {
- // embedded interface - inline the methods
- if(n->type->etype != TINTER) {
- if(n->type->etype == TFORW)
+ if(n->type)
+ switch(n->type->etype) {
+ case TINTER:
+ break;
+ case TFORW:
yyerror("interface type loop involving %T", n->type);
- else
+ f->broke = 1;
+ break;
+ default:
yyerror("interface contains embedded non-interface %T", n->type);
- continue;
- }
- for(t1=n->type->type; t1!=T; t1=t1->down) {
- f = typ(TFIELD);
- f->type = t1->type;
- f->width = BADWIDTH;
- f->nname = newname(t1->sym);
- f->sym = t1->sym;
- for(t2=*t0; t2!=T; t2=t2->down) {
- if(t2->sym == f->sym) {
- yyerror("duplicate method %s", t2->sym->name);
- break;
- }
+ f->broke = 1;
+ break;
}
- *t = f;
- t = &f->down;
- }
- continue;
}
-
- f = typ(TFIELD);
- f->type = n->type;
- f->note = note;
- f->width = BADWIDTH;
- f->isddd = n->isddd;
-
- if(left != N && left->op == ONAME) {
- f->nname = left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
- if(f->sym && !isblank(f->nname)) {
- for(t1=*t0; t1!=T; t1=t1->down) {
- if(t1->sym == f->sym) {
- yyerror("duplicate %s %s", what, t1->sym->name);
- break;
- }
- }
- }
- }
-
- *t = f;
- t = &f->down;
}
- *t = T;
+ n->right = N;
+
+ f->type = n->type;
+ if(f->type == T)
+ f->broke = 1;
+
lineno = lno;
- return t;
+ return f;
}
Type*
-dostruct(NodeList *l, int et)
+tointerface(NodeList *l)
{
- Type *t;
- int funarg;
+ Type *t, *f, **tp, *t1;
- /*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
+ t = typ(TINTER);
- funarg = 0;
- if(et == TFUNC) {
- funarg = 1;
- et = TSTRUCT;
- }
- t = typ(et);
- t->funarg = funarg;
- stotype(l, et, &t->type, funarg);
- if(t->type == T && l != nil) {
- t->broke = 1;
- return t;
+ tp = &t->type;
+ for(; l; l=l->next) {
+ f = interfacefield(l->n);
+
+ if (l->n->left == N && f->type->etype == TINTER) {
+ // embedded interface, inline methods
+ for(t1=f->type->type; t1; t1=t1->down) {
+ f = typ(TFIELD);
+ f->type = t1->type;
+ f->broke = t1->broke;
+ f->sym = t1->sym;
+ if(f->sym)
+ f->nname = newname(f->sym);
+ *tp = f;
+ tp = &f->down;
+ }
+ } else {
+ *tp = f;
+ tp = &f->down;
+ }
}
- if(et == TINTER)
- t = sortinter(t);
- if(!funarg)
- checkwidth(t);
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "method");
+ t = sortinter(t);
+ checkwidth(t);
+
return t;
}
-
Node*
embedded(Sym *s)
{
@@ -892,7 +993,10 @@ embedded(Sym *s)
*utfrune(name, CenterDot) = 0;
}
- n = newname(lookup(name));
+ if(exportname(name) || s->pkg == builtinpkg) // old behaviour, tests pass, but is it correct?
+ n = newname(lookup(name));
+ else
+ n = newname(pkglookup(name, s->pkg));
n = nod(ODCLFIELD, n, oldname(s));
n->embedded = 1;
return n;
@@ -957,6 +1061,17 @@ checkarglist(NodeList *all, int input)
t = n;
n = N;
}
+
+ // during import l->n->op is OKEY, but l->n->left->sym == S
+ // means it was a '?', not that it was
+ // a lone type This doesn't matter for the exported
+ // declarations, which are parsed by rules that don't
+ // use checkargs, but can happen for func literals in
+ // the inline bodies.
+ // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
+ if(importpkg && n->sym == S)
+ n = N;
+
if(n != N && n->sym == S) {
t = n;
n = N;
@@ -1030,9 +1145,12 @@ functype(Node *this, NodeList *in, NodeList *out)
rcvr = nil;
if(this)
rcvr = list1(this);
- t->type = dostruct(rcvr, TFUNC);
- t->type->down = dostruct(out, TFUNC);
- t->type->down->down = dostruct(in, TFUNC);
+ t->type = tofunargs(rcvr);
+ t->type->down = tofunargs(out);
+ t->type->down->down = tofunargs(in);
+
+ if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
+ t->broke = 1;
if(this)
t->thistuple = 1;
@@ -1050,21 +1168,22 @@ methodsym(Sym *nsym, Type *t0, int iface)
char *p;
Type *t;
char *suffix;
+ Pkg *spkg;
+ static Pkg *toppkg;
t = t0;
if(t == T)
goto bad;
s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
+ if(s == S && isptr[t->etype]) {
t = t->type;
if(t == T)
goto bad;
s = t->sym;
- if(s == S)
- goto bad;
}
+ spkg = nil;
+ if(s != S)
+ spkg = s->pkg;
// if t0 == *t and t0 has a sym,
// we want to see *t, not t0, in the method name.
@@ -1077,11 +1196,23 @@ methodsym(Sym *nsym, Type *t0, int iface)
if(t0->width < types[tptr]->width)
suffix = "·i";
}
- if(t0->sym == S && isptr[t0->etype])
- p = smprint("(%#hT).%s%s", t0, nsym->name, suffix);
- else
- p = smprint("%#hT.%s%s", t0, nsym->name, suffix);
- s = pkglookup(p, s->pkg);
+ if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ } else {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
+ }
+ if(spkg == nil) {
+ if(toppkg == nil)
+ toppkg = mkpkg(strlit("go"));
+ spkg = toppkg;
+ }
+ s = pkglookup(p, spkg);
free(p);
return s;
@@ -1114,11 +1245,16 @@ methodname1(Node *n, Node *t)
}
if(t->sym == S || isblank(n))
return newname(n->sym);
+
if(star)
p = smprint("(%s%S).%S", star, t->sym, n->sym);
else
p = smprint("%S.%S", t->sym, n->sym);
- n = newname(pkglookup(p, t->sym->pkg));
+
+ if(exportname(t->sym->name))
+ n = newname(lookup(p));
+ else
+ n = newname(pkglookup(p, t->sym->pkg));
free(p);
return n;
}
@@ -1133,8 +1269,6 @@ addmethod(Sym *sf, Type *t, int local)
Type *f, *d, *pa;
Node *n;
- pa = nil;
-
// get field sym
if(sf == S)
fatal("no method symbol");
@@ -1147,7 +1281,7 @@ addmethod(Sym *sf, Type *t, int local)
}
pa = pa->type;
- f = methtype(pa);
+ f = methtype(pa, 1);
if(f == T) {
t = pa;
if(t != T) {
@@ -1159,6 +1293,8 @@ addmethod(Sym *sf, Type *t, int local)
t = t->type;
}
}
+ if(t->broke) // rely on typecheck having complained before
+ return;
if(t != T) {
if(t->sym == S) {
yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
@@ -1180,8 +1316,14 @@ addmethod(Sym *sf, Type *t, int local)
}
pa = f;
- if(importpkg && !exportname(sf->name))
- sf = pkglookup(sf->name, importpkg);
+ if(pa->etype == TSTRUCT) {
+ for(f=pa->type; f; f=f->down) {
+ if(f->sym == sf) {
+ yyerror("type %T has both field and method named %S", pa, sf);
+ return;
+ }
+ }
+ }
n = nod(ODCLFIELD, newname(sf), N);
n->type = t;
@@ -1204,10 +1346,16 @@ addmethod(Sym *sf, Type *t, int local)
return;
}
+ f = structfield(n);
+
+ // during import unexported method names should be in the type's package
+ if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
+ fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
+
if(d == T)
- stotype(list1(n), 0, &pa->method, 0);
+ pa->method = f;
else
- stotype(list1(n), 0, &d->down, 0);
+ d->down = f;
return;
}
@@ -1249,6 +1397,3 @@ funccompile(Node *n, int isclosure)
funcdepth = 0;
dclcontext = PEXTERN;
}
-
-
-