summaryrefslogtreecommitdiff
path: root/src/cmd/gc/subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/subr.c')
-rw-r--r--src/cmd/gc/subr.c148
1 files changed, 109 insertions, 39 deletions
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index bd53520df..c53eaf285 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -142,18 +142,32 @@ yyerror(char *fmt, ...)
if(debug['x'])
print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
+ // An unexpected EOF caused a syntax error. Use the previous
+ // line number since getc generated a fake newline character.
+ if(curio.eofnl)
+ lexlineno = prevlineno;
+
// only one syntax error per line
if(lastsyntax == lexlineno)
return;
lastsyntax = lexlineno;
-
- if(strstr(fmt, "{ or {")) {
+
+ if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) {
// The grammar has { and LBRACE but both show up as {.
// Rewrite syntax error referring to "{ or {" to say just "{".
strecpy(buf, buf+sizeof buf, fmt);
p = strstr(buf, "{ or {");
if(p)
memmove(p+1, p+6, strlen(p+6)+1);
+
+ // The grammar has ? and @ but only for reading imports.
+ // Silence them in ordinary errors.
+ p = strstr(buf, " or ?");
+ if(p)
+ memmove(p, p+5, strlen(p+5)+1);
+ p = strstr(buf, " or @");
+ if(p)
+ memmove(p, p+5, strlen(p+5)+1);
fmt = buf;
}
@@ -214,6 +228,8 @@ warnl(int line, char *fmt, ...)
va_start(arg, fmt);
adderr(line, fmt, arg);
va_end(arg);
+ if(debug['m'])
+ flusherrors();
}
void
@@ -377,6 +393,7 @@ importdot(Pkg *opkg, Node *pack)
Sym *s, *s1;
uint32 h;
int n;
+ char *pkgerror;
n = 0;
for(h=0; h<NHASH; h++) {
@@ -389,12 +406,14 @@ importdot(Pkg *opkg, Node *pack)
continue;
s1 = lookup(s->name);
if(s1->def != N) {
- redeclare(s1, "during import");
+ pkgerror = smprint("during import \"%Z\"", opkg->path);
+ redeclare(s1, pkgerror);
continue;
}
s1->def = s->def;
s1->block = s->block;
s1->def->pack = pack;
+ s1->origpkg = opkg;
n++;
}
}
@@ -494,6 +513,31 @@ nod(int op, Node *nleft, Node *nright)
return n;
}
+void
+saveorignode(Node *n)
+{
+ Node *norig;
+
+ if(n->orig != N)
+ return;
+ norig = nod(n->op, N, N);
+ *norig = *n;
+ n->orig = norig;
+}
+
+// ispaddedfield returns whether the given field
+// is followed by padding. For the case where t is
+// the last field, total gives the size of the enclosing struct.
+static int
+ispaddedfield(Type *t, vlong total)
+{
+ if(t->etype != TFIELD)
+ fatal("ispaddedfield called non-field %T", t);
+ if(t->down == T)
+ return t->width + t->type->width != total;
+ return t->width + t->type->width != t->down->width;
+}
+
int
algtype1(Type *t, Type **bad)
{
@@ -571,8 +615,12 @@ algtype1(Type *t, Type **bad)
}
ret = AMEM;
for(t1=t->type; t1!=T; t1=t1->down) {
- if(isblanksym(t1->sym))
+ // Blank fields and padding must be ignored,
+ // so need special compare.
+ if(isblanksym(t1->sym) || ispaddedfield(t1, t->width)) {
+ ret = -1;
continue;
+ }
a = algtype1(t1->type, bad);
if(a == ANOEQ)
return ANOEQ; // not comparable
@@ -813,6 +861,7 @@ treecopy(Node *n)
default:
m = nod(OXXX, N, N);
*m = *n;
+ m->orig = m;
m->left = treecopy(n->left);
m->right = treecopy(n->right);
m->list = listtreecopy(n->list);
@@ -1214,7 +1263,7 @@ assignop(Type *src, Type *dst, char **why)
return 0;
}
if(src->etype == TINTER && dst->etype != TBLANK) {
- if(why != nil)
+ if(why != nil && implements(dst, src, &missing, &have, &ptr))
*why = ": need type assertion";
return 0;
}
@@ -1379,6 +1428,7 @@ assignconv(Node *n, Type *t, char *context)
r->type = t;
r->typecheck = 1;
r->implicit = 1;
+ r->orig = n->orig;
return r;
}
@@ -2029,11 +2079,13 @@ cheapexpr(Node *n, NodeList **init)
/*
* return n in a local variable of type t if it is not already.
+ * the value is guaranteed not to change except by direct
+ * assignment to it.
*/
Node*
localexpr(Node *n, Type *t, NodeList **init)
{
- if(n->op == ONAME &&
+ if(n->op == ONAME && !n->addrtaken &&
(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
convertop(n->type, t, nil) == OCONVNOP)
return n;
@@ -2508,6 +2560,9 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
funcbody(fn);
curfn = fn;
+ // wrappers where T is anonymous (struct{ NamedType }) can be duplicated.
+ if(rcvr->etype == TSTRUCT || isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
+ fn->dupok = 1;
typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop);
curfn = nil;
@@ -2591,7 +2646,7 @@ genhash(Sym *sym, Type *t)
Node *hashel;
Type *first, *t1;
int old_safemode;
- int64 size, mul;
+ int64 size, mul, offend;
if(debug['r'])
print("genhash %S %T\n", sym, t);
@@ -2664,7 +2719,7 @@ genhash(Sym *sym, Type *t)
call->list = list(call->list, nh);
call->list = list(call->list, nodintconst(t->type->width));
nx = nod(OINDEX, np, ni);
- nx->etype = 1; // no bounds check
+ nx->bounded = 1;
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
@@ -2677,22 +2732,21 @@ genhash(Sym *sym, Type *t)
// Walk the struct using memhash for runs of AMEM
// and calling specific hash functions for the others.
first = T;
+ offend = 0;
for(t1=t->type;; t1=t1->down) {
- if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
- if(first == T && !isblanksym(t1->sym))
+ if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
+ offend = t1->width + t1->type->width;
+ if(first == T)
first = t1;
- continue;
+ // If it's a memory field but it's padded, stop here.
+ if(ispaddedfield(t1, t->width))
+ t1 = t1->down;
+ else
+ continue;
}
// Run memhash for fields up to this one.
- while(first != T && isblanksym(first->sym))
- first = first->down;
if(first != T) {
- if(first->down == t1)
- size = first->type->width;
- else if(t1 == T)
- size = t->width - first->width; // first->width is offset
- else
- size = t1->width - first->width; // both are offsets
+ size = offend - first->width; // first->width is offset
hashel = hashmem(first->type);
// hashel(h, size, &p.first)
call = nod(OCALL, hashel, N);
@@ -2708,6 +2762,8 @@ genhash(Sym *sym, Type *t)
}
if(t1 == T)
break;
+ if(isblanksym(t1->sym))
+ continue;
// Run hash for this field.
hashel = hashfor(t1->type);
@@ -2721,6 +2777,8 @@ genhash(Sym *sym, Type *t)
call->list = list(call->list, na);
fn->nbody = list(fn->nbody, call);
}
+ // make sure body is not empty.
+ fn->nbody = list(fn->nbody, nod(ORETURN, N, N));
break;
}
@@ -2822,6 +2880,7 @@ geneq(Sym *sym, Type *t)
Type *t1, *first;
int old_safemode;
int64 size;
+ int64 offend;
if(debug['r'])
print("geneq %S %T\n", sym, t);
@@ -2875,9 +2934,9 @@ geneq(Sym *sym, Type *t)
// if p[i] != q[i] { *eq = false; return }
nx = nod(OINDEX, np, ni);
- nx->etype = 1; // no bounds check
+ nx->bounded = 1;
ny = nod(OINDEX, nq, ni);
- ny->etype = 1; // no bounds check
+ ny->bounded = 1;
nif = nod(OIF, N, N);
nif->ntest = nod(ONE, nx, ny);
@@ -2893,18 +2952,23 @@ geneq(Sym *sym, Type *t)
case TSTRUCT:
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
+ // Skip blank-named fields.
first = T;
+ offend = 0;
for(t1=t->type;; t1=t1->down) {
- if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
- if(first == T && !isblanksym(t1->sym))
+ if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
+ offend = t1->width + t1->type->width;
+ if(first == T)
first = t1;
- continue;
+ // If it's a memory field but it's padded, stop here.
+ if(ispaddedfield(t1, t->width))
+ t1 = t1->down;
+ else
+ continue;
}
// Run memequal for fields up to this one.
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
- while(first != T && isblanksym(first->sym))
- first = first->down;
if(first != T) {
if(first->down == t1) {
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
@@ -2915,16 +2979,15 @@ geneq(Sym *sym, Type *t)
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
} else {
// More than two fields: use memequal.
- if(t1 == T)
- size = t->width - first->width; // first->width is offset
- else
- size = t1->width - first->width; // both are offsets
+ size = offend - first->width; // first->width is offset
fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq));
}
first = T;
}
if(t1 == T)
break;
+ if(isblanksym(t1->sym))
+ continue;
// Check this field, which is not just memory.
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq));
@@ -3031,7 +3094,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr, 0);
- if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) {
+ if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
if(tm == T)
tm = ifacelookdot(im->sym, t, &followptr, 1);
*m = im;
@@ -3504,11 +3567,8 @@ umagic(Magic *m)
Sym*
ngotype(Node *n)
{
- if(n->sym != S && n->realtype != T)
- if(strncmp(n->sym->name, "autotmp_", 8) != 0)
- if(strncmp(n->sym->name, "statictmp_", 8) != 0)
- return typename(n->realtype)->left->sym;
-
+ if(n->type != T)
+ return typenamesym(n->type);
return S;
}
@@ -3564,9 +3624,6 @@ mkpkg(Strlit *path)
Pkg *p;
int h;
- if(isbadimport(path))
- errorexit();
-
h = stringhash(path->s) & (nelem(phash)-1);
for(p=phash[h]; p; p=p->link)
if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
@@ -3615,9 +3672,15 @@ addinit(Node **np, NodeList *init)
n->ullman = UINF;
}
+static char* reservedimports[] = {
+ "go",
+ "type",
+};
+
int
isbadimport(Strlit *path)
{
+ int i;
char *s;
Rune r;
@@ -3625,6 +3688,13 @@ isbadimport(Strlit *path)
yyerror("import path contains NUL");
return 1;
}
+
+ for(i=0; i<nelem(reservedimports); i++) {
+ if(strcmp(path->s, reservedimports[i]) == 0) {
+ yyerror("import path \"%s\" is reserved and cannot be used", path->s);
+ return 1;
+ }
+ }
s = path->s;
while(*s) {