diff options
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/align.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/cplx.c | 20 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 41 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 5 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 4 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 10 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 11 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 87 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 28 | ||||
-rw-r--r-- | src/cmd/gc/swt.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 57 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 83 |
12 files changed, 266 insertions, 88 deletions
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index a01e2ea46..a8454bf13 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -468,7 +468,7 @@ typeinit(void) okforadd[i] = 1; okforarith[i] = 1; okforconst[i] = 1; -// issimple[i] = 1; + issimple[i] = 1; } } @@ -530,7 +530,7 @@ typeinit(void) okfor[OCOM] = okforand; okfor[OMINUS] = okforarith; okfor[ONOT] = okforbool; - okfor[OPLUS] = okforadd; + okfor[OPLUS] = okforarith; // special okfor[OCAP] = okforcap; diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c index 3ec9fe5a2..890cf7f10 100644 --- a/src/cmd/gc/cplx.c +++ b/src/cmd/gc/cplx.c @@ -12,6 +12,19 @@ static void minus(Node *nl, Node *res); #define CASE(a,b) (((a)<<16)|((b)<<0)) +static int +overlap(Node *f, Node *t) +{ + // check whether f and t could be overlapping stack references. + // not exact, because it's hard to check for the stack register + // in portable code. close enough: worst case we will allocate + // an extra temporary and the registerizer will clean it up. + return f->op == OINDREG && + t->op == OINDREG && + f->xoffset+f->type->width >= t->xoffset && + t->xoffset+t->type->width >= f->xoffset; +} + /* * generate: * res = n; @@ -43,9 +56,10 @@ complexmove(Node *f, Node *t) case CASE(TCOMPLEX64,TCOMPLEX128): case CASE(TCOMPLEX128,TCOMPLEX64): case CASE(TCOMPLEX128,TCOMPLEX128): - // complex to complex move/convert - // make from addable - if(!f->addable) { + // complex to complex move/convert. + // make f addable. + // also use temporary if possible stack overlap. + if(!f->addable || overlap(f, t)) { tempname(&n1, f->type); complexmove(f, &n1); f = &n1; diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 3089a23b0..99af18d9f 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -560,6 +560,7 @@ funcargs(Node *nt) { Node *n; NodeList *l; + int gen; if(nt->op != OTFUNC) fatal("funcargs %O", nt->op); @@ -589,6 +590,7 @@ funcargs(Node *nt) } // declare the out arguments. + gen = 0; for(l=nt->rlist; l; l=l->next) { n = l->n; if(n->op != ODCLFIELD) @@ -596,6 +598,11 @@ funcargs(Node *nt) 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. + snprint(namebuf, sizeof(namebuf), ".anon%d", gen++); + n->left->sym = lookup(namebuf); + } declare(n->left, PPARAMOUT); } } @@ -672,10 +679,10 @@ typedcl2(Type *pt, Type *t) ok: n = pt->nod; - *pt = *t; - pt->method = nil; + copytype(pt->nod, t); + // unzero nod pt->nod = n; - pt->sym = n->sym; + pt->sym->lastlineno = parserline(); declare(n, PEXTERN); @@ -697,12 +704,10 @@ stotype(NodeList *l, int et, Type **t, int funarg) Type *f, *t1, *t2, **t0; Strlit *note; int lno; - NodeList *init; Node *n, *left; char *what; t0 = t; - init = nil; lno = lineno; what = "field"; if(et == TINTER) @@ -1130,6 +1135,32 @@ addmethod(Sym *sf, Type *t, int local) pa = pa->type; f = methtype(pa); if(f == T) { + t = pa; + if(t != T) { + if(isptr[t->etype]) { + if(t->sym != S) { + yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); + return; + } + t = t->type; + } + } + if(t != T) { + if(t->sym == S) { + yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t); + return; + } + if(isptr[t->etype]) { + yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); + return; + } + if(t->etype == TINTER) { + yyerror("invalid receiver type %T (%T is an interface type)", pa, t); + return; + } + } + // Should have picked off all the reasons above, + // but just in case, fall back to generic error. yyerror("invalid receiver type %T", pa); return; } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index bb258a193..f58b76789 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -315,6 +315,7 @@ struct Pkg { char* name; Strlit* path; + Sym* pathsym; char* prefix; Pkg* link; char exported; // import line written in export data @@ -581,6 +582,7 @@ struct Io Biobuf* bin; int32 ilineno; int nlsemi; + int eofnl; int peekc; int peekc1; // second peekc for ... char* cp; // used for content when bin==nil @@ -1170,9 +1172,12 @@ Node* unsafenmagic(Node *n); */ Node* callnew(Type *t); Node* chanfn(char *name, int n, Type *t); +void copytype(Node *n, Type *t); +void defertypecopy(Node *n, Type *t); Node* mkcall(char *name, Type *t, NodeList **init, ...); Node* mkcall1(Node *fn, Type *t, NodeList **init, ...); void queuemethod(Node *n); +void resumetypecopy(void); int vmatch1(Node *l, Node *r); void walk(Node *fn); Node* walkdef(Node *n); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 89899ae1e..7adfd002a 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1853,6 +1853,10 @@ hidden_interfacedcl: { $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); } +| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres + { + $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); + } ohidden_funres: { diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index bfd96274e..04dd0d5b9 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -249,6 +249,7 @@ main(int argc, char *argv[]) for(l=xtop; l; l=l->next) if(l->n->op == ODCL || l->n->op == OAS) typecheck(&l->n, Etop); + resumetypecopy(); resumecheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) @@ -1310,7 +1311,7 @@ getc(void) lexlineno++; return c; } - + if(curio.bin == nil) { c = *curio.cp & 0xff; if(c != 0) @@ -1325,8 +1326,11 @@ getc(void) break; } case EOF: - return EOF; - + // insert \n at EOF + if(curio.eofnl) + return EOF; + curio.eofnl = 1; + c = '\n'; case '\n': if(pushedio.bin == nil) lexlineno++; diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index fee37f6d0..e03a14080 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -242,6 +242,17 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->right, 0); break; + case OAS2: + case OAS2DOTTYPE: + case OAS2FUNC: + case OAS2MAPR: + case OAS2MAPW: + case OAS2RECV: + exprlistfmt(f, n->list); + fmtprint(f, " = "); + exprlistfmt(f, n->rlist); + break; + case OADD: case OANDAND: case OANDNOT: diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index b98e820c6..810787d30 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -137,7 +137,6 @@ methodfunc(Type *f, Type *receiver) static Sig* methods(Type *t) { - int o; Type *f, *mt, *it, *this; Sig *a, *b; Sym *method; @@ -157,7 +156,6 @@ methods(Type *t) // make list of methods for t, // generating code if necessary. a = nil; - o = 0; oldlist = nil; for(f=mt->xmethod; f; f=f->down) { if(f->type->etype != TFUNC) @@ -184,6 +182,11 @@ methods(Type *t) a = b; a->name = method->name; + if(!exportname(method->name)) { + if(method->pkg == nil) + fatal("methods: missing package"); + a->pkg = method->pkg; + } a->isym = methodsym(method, it, 1); a->tsym = methodsym(method, t, 0); a->type = methodfunc(f->type, t); @@ -240,14 +243,12 @@ static Sig* imethods(Type *t) { Sig *a, *all, *last; - int o; Type *f; Sym *method, *isym; Prog *oldlist; all = nil; last = nil; - o = 0; oldlist = nil; for(f=t->type; f; f=f->down) { if(f->etype != TFIELD) @@ -257,8 +258,11 @@ imethods(Type *t) method = f->sym; a = mal(sizeof(*a)); a->name = method->name; - if(!exportname(method->name)) + if(!exportname(method->name)) { + if(method->pkg == nil) + fatal("imethods: missing package"); a->pkg = method->pkg; + } a->mtype = f->type; a->offset = 0; a->type = methodfunc(f->type, nil); @@ -301,26 +305,6 @@ imethods(Type *t) return all; } -static int -dgopkgpath(Sym *s, int ot, Pkg *pkg) -{ - if(pkg == nil) - return dgostringptr(s, ot, nil); - - // Emit reference to go.importpath.""., which 6l will - // rewrite using the correct import path. Every package - // that imports this one directly defines the symbol. - if(pkg == localpkg) { - static Sym *ns; - - if(ns == nil) - ns = pkglookup("importpath.\"\".", mkpkg(strlit("go"))); - return dsymptr(s, ot, ns, 0); - } - - return dgostringptr(s, ot, pkg->name); -} - static void dimportpath(Pkg *p) { @@ -328,6 +312,9 @@ dimportpath(Pkg *p) char *nam; Node *n; + if(p->pathsym != S) + return; + if(gopkg == nil) { gopkg = mkpkg(strlit("go")); gopkg->name = "go"; @@ -339,11 +326,33 @@ dimportpath(Pkg *p) free(nam); n->class = PEXTERN; n->xoffset = 0; + p->pathsym = n->sym; gdatastring(n, p->path); ggloblsym(n->sym, types[TSTRING]->width, 1); } +static int +dgopkgpath(Sym *s, int ot, Pkg *pkg) +{ + if(pkg == nil) + return dgostringptr(s, ot, nil); + + // Emit reference to go.importpath.""., which 6l will + // rewrite using the correct import path. Every package + // that imports this one directly defines the symbol. + if(pkg == localpkg) { + static Sym *ns; + + if(ns == nil) + ns = pkglookup("importpath.\"\".", mkpkg(strlit("go"))); + return dsymptr(s, ot, ns, 0); + } + + dimportpath(pkg); + return dsymptr(s, ot, pkg->pathsym, 0); +} + /* * uncommonType * ../../pkg/runtime/type.go:/uncommonType @@ -694,7 +703,7 @@ dtypesym(Type *t) int ot, xt, n, isddd, dupok; Sym *s, *s1, *s2; Sig *a, *m; - Type *t1, *tbase; + Type *t1, *tbase, *t2; if(isideal(t)) fatal("dtypesym %T", t); @@ -731,15 +740,25 @@ ok: break; case TARRAY: - // ../../pkg/runtime/type.go:/ArrayType - s1 = dtypesym(t->type); - ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; - ot = dsymptr(s, ot, s1, 0); - if(t->bound < 0) - ot = duintptr(s, ot, -1); - else + if(t->bound >= 0) { + // ../../pkg/runtime/type.go:/ArrayType + s1 = dtypesym(t->type); + t2 = typ(TARRAY); + t2->type = t->type; + t2->bound = -1; // slice + s2 = dtypesym(t2); + ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; + ot = dsymptr(s, ot, s1, 0); + ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); + } else { + // ../../pkg/runtime/type.go:/SliceType + s1 = dtypesym(t->type); + ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; + ot = dsymptr(s, ot, s1, 0); + } break; case TCHAN: diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 2098794a7..bb2505694 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -488,7 +488,7 @@ algtype(Type *t) { int a; - if(issimple[t->etype] || isptr[t->etype] || iscomplex[t->etype] || + if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) { if(t->width == widthptr) a = AMEMWORD; @@ -660,12 +660,10 @@ nodbool(int b) Type* aindex(Node *b, Type *t) { - NodeList *init; Type *r; int bound; bound = -1; // open bound - init = nil; typecheck(&b, Erv); if(b != nil) { switch(consttype(b)) { @@ -1266,7 +1264,12 @@ Tpretty(Fmt *fp, Type *t) case TINTER: fmtprint(fp, "interface {"); for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, " %hS%hhT", t1->sym, t1->type); + fmtprint(fp, " "); + if(exportname(t1->sym->name)) + fmtprint(fp, "%hS", t1->sym); + else + fmtprint(fp, "%S", t1->sym); + fmtprint(fp, "%hhT", t1->type); if(t1->down) fmtprint(fp, ";"); } @@ -1728,17 +1731,13 @@ isideal(Type *t) Type* methtype(Type *t) { - int ptr; - if(t == T) return T; // strip away pointer if it's there - ptr = 0; if(isptr[t->etype]) { if(t->sym != S) return T; - ptr = 1; t = t->type; if(t == T) return T; @@ -1929,13 +1928,14 @@ assignop(Type *src, Type *dst, char **why) } return 0; } + if(isptrto(dst, TINTER)) { + if(why != nil) + *why = smprint(":\n\t%T is pointer to interface, not interface", dst); + return 0; + } if(src->etype == TINTER && dst->etype != TBLANK) { - if(why != nil) { - if(isptrto(dst, TINTER)) - *why = smprint(":\n\t%T is interface, not pointer to interface", src); - else - *why = ": need type assertion"; - } + if(why != nil) + *why = ": need type assertion"; return 0; } diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index fbc9c4903..6e8436c3c 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -250,7 +250,7 @@ newlabel(void) static void casebody(Node *sw, Node *typeswvar) { - Node *os, *oc, *n, *c, *last; + Node *n, *c, *last; Node *def; NodeList *cas, *stat, *l, *lc; Node *go, *br; @@ -263,8 +263,6 @@ casebody(Node *sw, Node *typeswvar) cas = nil; // cases stat = nil; // statements def = N; // defaults - os = N; // last statement - oc = N; // last case br = nod(OBREAK, N, N); for(l=sw->list; l; l=l->next) { diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 1cc5abd5c..c48bf7a29 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -31,6 +31,7 @@ static void checkassign(Node*); static void checkassignlist(NodeList*); static void stringtoarraylit(Node**); static Node* resolve(Node*); +static Type* getforwtype(Node*); /* * resolve ONONAME to definition, if any. @@ -56,7 +57,7 @@ typechecklist(NodeList *l, int top) typecheck(&l->n, top); } -static char* typekind[] = { +static char* _typekind[] = { [TINT] = "int", [TUINT] = "uint", [TINT8] = "int8", @@ -82,8 +83,22 @@ static char* typekind[] = { [TMAP] = "map", [TARRAY] = "array", [TFUNC] = "func", + [TNIL] = "nil", + [TIDEAL] = "ideal number", }; +static char* +typekind(int et) +{ + static char buf[50]; + char *s; + + if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil) + return s; + snprint(buf, sizeof buf, "etype=%d", et); + return buf; +} + /* * type check node *np. * replaces *np with a new pointer in some cases. @@ -96,7 +111,7 @@ typecheck(Node **np, int top) Node *n, *l, *r; NodeList *args; int lno, ok, ntop; - Type *t, *tp, *missing, *have; + Type *t, *tp, *ft, *missing, *have; Sym *sym; Val v; char *why; @@ -139,6 +154,11 @@ typecheck(Node **np, int top) yyerror("use of builtin %S not in function call", n->sym); goto error; } + + // a dance to handle forward-declared recursive pointer types. + if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T) + defertypecopy(n, ft); + walkdef(n); n->realtype = n->type; if(n->op == ONONAME) @@ -406,7 +426,7 @@ reswitch: } if(!okfor[op][et]) { notokfor: - yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind[et]); + yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et)); goto error; } // okfor allows any array == array; @@ -992,9 +1012,13 @@ reswitch: defaultlit(&n->right, T); // copy([]byte, string) - if(isslice(n->left->type) && n->left->type->type == types[TUINT8] && n->right->type->etype == TSTRING) - goto ret; - + if(isslice(n->left->type) && n->right->type->etype == TSTRING) { + if (n->left->type->type ==types[TUINT8]) + goto ret; + yyerror("arguments to copy have different element types: %lT and string", n->left->type); + goto error; + } + if(!isslice(n->left->type) || !isslice(n->right->type)) { if(!isslice(n->left->type) && !isslice(n->right->type)) yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type); @@ -2452,3 +2476,24 @@ stringtoarraylit(Node **np) typecheck(&nn, Erv); *np = nn; } + +static Type* +getforwtype(Node *n) +{ + Node *f1, *f2; + + for(f1=f2=n; ; n=n->ntype) { + if((n = resolve(n)) == N || n->op != OTYPE) + return T; + + if(n->type != T && n->type->etype == TFORW) + return n->type; + + // Check for ntype cycle. + if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) { + f2 = resolve(f1->ntype); + if(f1 == n || f2 == n) + return T; + } + } +} diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index b8c6842e0..278eef414 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -119,6 +119,62 @@ domethod(Node *n) checkwidth(n->type); } +typedef struct NodeTypeList NodeTypeList; +struct NodeTypeList { + Node *n; + Type *t; + NodeTypeList *next; +}; + +static NodeTypeList *dntq; +static NodeTypeList *dntend; + +void +defertypecopy(Node *n, Type *t) +{ + NodeTypeList *ntl; + + if(n == N || t == T) + return; + + ntl = mal(sizeof *ntl); + ntl->n = n; + ntl->t = t; + ntl->next = nil; + + if(dntq == nil) + dntq = ntl; + else + dntend->next = ntl; + + dntend = ntl; +} + +void +resumetypecopy(void) +{ + NodeTypeList *l; + + for(l=dntq; l; l=l->next) + copytype(l->n, l->t); +} + +void +copytype(Node *n, Type *t) +{ + *n->type = *t; + + t = n->type; + t->sym = n->sym; + t->local = n->local; + t->vargen = n->vargen; + t->siggen = 0; + t->method = nil; + t->nod = N; + t->printed = 0; + t->deferwidth = 0; +} + static void walkdeftype(Node *n) { @@ -141,20 +197,14 @@ walkdeftype(Node *n) goto ret; } - // copy new type and clear fields - // that don't come along maplineno = n->type->maplineno; embedlineno = n->type->embedlineno; - *n->type = *t; - t = n->type; - t->sym = n->sym; - t->local = n->local; - t->vargen = n->vargen; - t->siggen = 0; - t->method = nil; - t->nod = N; - t->printed = 0; - t->deferwidth = 0; + + // copy new type and clear fields + // that don't come along. + // anything zeroed here must be zeroed in + // typedcl2 too. + copytype(n, t); // double-check use of type as map key. if(maplineno) { @@ -197,7 +247,6 @@ Node* walkdef(Node *n) { int lno; - NodeList *init; Node *e; Type *t; NodeList *l; @@ -236,7 +285,6 @@ walkdef(Node *n) if(n->type != T || n->sym == S) // builtin or no name goto ret; - init = nil; switch(n->op) { default: fatal("walkdef %O", n->op); @@ -380,14 +428,13 @@ walkstmt(Node **np) { NodeList *init; NodeList *ll, *rl; - int cl, lno; + int cl; Node *n, *f; n = *np; if(n == N) return; - lno = lineno; setlineno(n); switch(n->op) { @@ -1359,7 +1406,7 @@ walkexpr(Node **np, NodeList **init) case OSTRARRAYBYTE: // stringtoslicebyte(string) []byte; - n = mkcall("stringtoslicebyte", n->type, init, n->left); + n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING])); goto ret; case OSTRARRAYRUNE: @@ -1788,7 +1835,7 @@ walkprint(Node *nn, NodeList **init, int defer) on = syslook("printiface", 1); argtype(on, n->type); // any-1 } - } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC) { + } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) { if(defer) { fmtprint(&fmt, "%%p"); } else { |