diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-01-17 12:40:45 +0100 |
commit | 3e45412327a2654a77944249962b3652e6142299 (patch) | |
tree | bc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/cmd/gc | |
parent | c533680039762cacbc37db8dc7eed074c3e497be (diff) | |
download | golang-upstream/2011.01.12.tar.gz |
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/Makefile | 23 | ||||
-rw-r--r-- | src/cmd/gc/align.c | 76 | ||||
-rw-r--r-- | src/cmd/gc/builtin.c.boot | 18 | ||||
-rw-r--r-- | src/cmd/gc/closure.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 22 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 20 | ||||
-rw-r--r-- | src/cmd/gc/doc.go | 9 | ||||
-rw-r--r-- | src/cmd/gc/export.c | 3 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 20 | ||||
-rw-r--r-- | src/cmd/gc/go.errors | 9 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 48 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 174 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 203 | ||||
-rwxr-xr-x | src/cmd/gc/mkbuiltin | 8 | ||||
-rw-r--r-- | src/cmd/gc/mparith1.c | 42 | ||||
-rw-r--r-- | src/cmd/gc/mparith2.c | 8 | ||||
-rw-r--r-- | src/cmd/gc/mparith3.c | 30 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 107 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 61 | ||||
-rw-r--r-- | src/cmd/gc/range.c | 17 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 116 | ||||
-rw-r--r-- | src/cmd/gc/runtime.go | 22 | ||||
-rw-r--r-- | src/cmd/gc/select.c | 13 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 62 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 177 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 490 | ||||
-rw-r--r-- | src/cmd/gc/unsafe.c | 20 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 405 |
28 files changed, 1629 insertions, 576 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index 46dc6dfbc..dbfd86474 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -2,10 +2,10 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -include ../../Make.conf +include ../../Make.inc +O:=$(HOST_O) -LIB=\ - gc.a$O\ +LIB=gc.a HFILES=\ go.h\ @@ -43,16 +43,10 @@ OFILES=\ walk.$O\ y1.tab.$O\ -$(LIB): $(OFILES) - ar rsc $(LIB) $(OFILES) +NOINSTALL=1 +include ../../Make.clib -$(OFILES): $(HFILES) - -y.tab.h: $(YFILES) - LANG=C LANGUAGE="en_US.UTF8" bison -v -y $(YFLAGS) $(YFILES) - -y.tab.c: y.tab.h - test -f y.tab.c && touch y.tab.c +install: $(LIB) y1.tab.c: y.tab.c # make yystate global, yytname mutable cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c @@ -70,7 +64,4 @@ subr.$O: opnames.h opnames.h: mkopnames go.h ./mkopnames go.h >opnames.h -clean: - rm -f *.[568o] enam.c [568].out a.out y.tab.h y.tab.c y1.tab.c y.output yerr.h $(LIB) mkbuiltin1 builtin.c _builtin.c opnames.h - -install: $(LIB) +CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index 1b9112d69..a3785e871 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -7,8 +7,8 @@ /* * machine size and rounding * alignment is dictated around - * the size of a pointer, set in belexinit - * (see ../6g/align.c). + * the size of a pointer, set in betypeinit + * (see ../6g/galign.c). */ static int defercalc; @@ -16,15 +16,9 @@ static int defercalc; uint32 rnd(uint32 o, uint32 r) { - if(maxround == 0) + if(r < 1 || r > 8 || (r&(r-1)) != 0) fatal("rnd"); - - if(r > maxround) - r = maxround; - if(r != 0) - while(o%r != 0) - o++; - return o; + return (o+r-1)&~(r-1); } static void @@ -43,29 +37,24 @@ offmod(Type *t) } static uint32 -arrayelemwidth(Type *t) -{ - - while(t->etype == TARRAY && t->bound >= 0) - t = t->type; - return t->width; -} - -static uint32 widstruct(Type *t, uint32 o, int flag) { Type *f; - int32 w, m; - + int32 w, maxalign; + + maxalign = flag; + if(maxalign < 1) + maxalign = 1; for(f=t->type; f!=T; f=f->down) { if(f->etype != TFIELD) fatal("widstruct: not TFIELD: %lT", f); dowidth(f->type); + if(f->type->align > maxalign) + maxalign = f->type->align; if(f->type->width < 0) fatal("invalid width %lld", f->type->width); w = f->type->width; - m = arrayelemwidth(f->type); - o = rnd(o, m); + o = rnd(o, f->type->align); f->width = o; // really offset for TFIELD if(f->nname != N) { // this same stackparam logic is in addrescapes @@ -82,7 +71,8 @@ widstruct(Type *t, uint32 o, int flag) } // final width is rounded if(flag) - o = rnd(o, maxround); + o = rnd(o, maxalign); + t->align = maxalign; // type width only includes back to first field's offset if(t->type == T) @@ -100,7 +90,7 @@ dowidth(Type *t) int lno; Type *t1; - if(maxround == 0 || widthptr == 0) + if(widthptr == 0) fatal("dowidth without betypeinit"); if(t == T) @@ -124,6 +114,7 @@ dowidth(Type *t) lno = lineno; lineno = t->lineno; t->width = -2; + t->align = 0; et = t->etype; switch(et) { @@ -166,9 +157,11 @@ dowidth(Type *t) case TFLOAT64: case TCOMPLEX64: w = 8; + t->align = widthptr; break; case TCOMPLEX128: w = 16; + t->align = widthptr; break; case TPTR32: w = 4; @@ -180,6 +173,7 @@ dowidth(Type *t) break; case TINTER: // implemented as 2 pointers w = 2*widthptr; + t->align = widthptr; offmod(t); break; case TCHAN: // implemented as pointer @@ -197,6 +191,7 @@ dowidth(Type *t) dowidth(t->type); // just in case if(t1->type->width >= (1<<16)) yyerror("channel element type too large (>64kB)"); + t->width = 1; break; case TMAP: // implemented as pointer w = widthptr; @@ -217,6 +212,7 @@ dowidth(Type *t) if(sizeof_String == 0) fatal("early dowidth string"); w = sizeof_String; + t->align = widthptr; break; case TARRAY: if(t->type == T) @@ -235,11 +231,13 @@ dowidth(Type *t) yyerror("type %lT larger than address space", t); w = t->bound * t->type->width; if(w == 0) - w = maxround; + w = 1; + t->align = t->type->align; } else if(t->bound == -1) { w = sizeof_Array; checkwidth(t->type); + t->align = widthptr; } else if(t->bound == -100) yyerror("use of [...] array outside of array literal"); @@ -252,7 +250,9 @@ dowidth(Type *t) fatal("dowidth fn struct %T", t); w = widstruct(t, 0, 1); if(w == 0) - w = maxround; + w = 1; + //if(t->align < widthptr) + // warn("align %d: %T\n", t->align, t); break; case TFUNC: @@ -271,16 +271,24 @@ dowidth(Type *t) // compute their widths as side-effect. t1 = t->type; w = widstruct(*getthis(t1), 0, 0); - w = widstruct(*getinarg(t1), w, 1); - w = widstruct(*getoutarg(t1), w, 1); + w = widstruct(*getinarg(t1), w, widthptr); + w = widstruct(*getoutarg(t1), w, widthptr); t1->argwid = w; + if(w%widthptr) + warn("bad type %T %d\n", t1, w); + t->align = 1; break; } // catch all for error cases; avoid divide by zero later if(w == 0) - w = maxround; + w = 1; t->width = w; + if(t->align == 0) { + if(w > 8 || (w&(w-1)) != 0) + fatal("invalid alignment for %T", t); + t->align = w; + } lineno = lno; if(defercalc == 1) @@ -351,8 +359,8 @@ void defercheckwidth(void) { // we get out of sync on syntax errors, so don't be pedantic. - // if(defercalc) - // fatal("defercheckwidth"); + if(defercalc && nerrors == 0) + fatal("defercheckwidth"); defercalc = 1; } @@ -596,10 +604,10 @@ typeinit(void) Array_array = rnd(0, widthptr); Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width); Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width); - sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround); + sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr); // string is same as slice wo the cap - sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround); + sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr); dowidth(types[TSTRING]); dowidth(idealstring); diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index 3e2d98872..380abc642 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -1,6 +1,6 @@ char *runtimeimport = "package runtime\n" - "func \"\".mal (? int32) *any\n" + "func \"\".new (? int32) *any\n" "func \"\".panicindex ()\n" "func \"\".panicslice ()\n" "func \"\".throwreturn ()\n" @@ -19,12 +19,13 @@ char *runtimeimport = "func \"\".printslice (? any)\n" "func \"\".printnl ()\n" "func \"\".printsp ()\n" - "func \"\".printf ()\n" - "func \"\".catstring (? string, ? string) string\n" + "func \"\".goprintf ()\n" + "func \"\".concatstring ()\n" + "func \"\".append ()\n" + "func \"\".appendslice (typ *uint8, x any, y []any) any\n" "func \"\".cmpstring (? string, ? string) int\n" "func \"\".slicestring (? string, ? int, ? int) string\n" "func \"\".slicestring1 (? string, ? int) string\n" - "func \"\".indexstring (? string, ? int) uint8\n" "func \"\".intstring (? int64) string\n" "func \"\".slicebytetostring (? []uint8) string\n" "func \"\".sliceinttostring (? []int) string\n" @@ -33,6 +34,7 @@ char *runtimeimport = "func \"\".stringiter (? string, ? int) int\n" "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func \"\".slicecopy (to any, fr any, wid uint32) int\n" + "func \"\".slicestringcopy (to any, fr any) int\n" "func \"\".convI2E (elem any) any\n" "func \"\".convI2I (typ *uint8, elem any) any\n" "func \"\".convT2E (typ *uint8, elem any) any\n" @@ -75,16 +77,18 @@ char *runtimeimport = "func \"\".selectdefault (sel *uint8) bool\n" "func \"\".selectgo (sel *uint8)\n" "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n" - "func \"\".sliceslice1 (old []any, lb int, width int) []any\n" - "func \"\".sliceslice (old []any, lb int, hb int, width int) []any\n" - "func \"\".slicearray (old *any, nel int, lb int, hb int, width int) []any\n" + "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n" + "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n" + "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n" "func \"\".closure ()\n" "func \"\".int64div (? int64, ? int64) int64\n" "func \"\".uint64div (? uint64, ? uint64) uint64\n" "func \"\".int64mod (? int64, ? int64) int64\n" "func \"\".uint64mod (? uint64, ? uint64) uint64\n" "func \"\".float64toint64 (? float64) int64\n" + "func \"\".float64touint64 (? float64) uint64\n" "func \"\".int64tofloat64 (? int64) float64\n" + "func \"\".uint64tofloat64 (? uint64) float64\n" "func \"\".complex128div (num complex128, den complex128) complex128\n" "\n" "$$\n"; diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index a24a03a49..eb7014366 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -158,7 +158,7 @@ walkclosure(Node *func, NodeList **init) // create the function xfunc = nod(ODCLFUNC, N, N); - snprint(namebuf, sizeof namebuf, "_func_%.3ld", ++closgen); + snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen); xfunc->nname = newname(lookup(namebuf)); xfunc->nname->ntype = xtype; xfunc->nname->defn = xfunc; diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index cec95359a..72e67a634 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -101,7 +101,7 @@ convlit1(Node **np, Type *t, int explicit) break; case OLSH: case ORSH: - convlit1(&n->left, t, explicit); + convlit1(&n->left, t, explicit && isideal(n->left->type)); t = n->left->type; if(t != T && !isint[t->etype]) { yyerror("invalid operation: %#N (shift of type %T)", n, t); @@ -202,8 +202,6 @@ convlit1(Node **np, Type *t, int explicit) goto bad; case CTFLT: case CTINT: - if(explicit) - goto bad; n->val = tocplx(n->val); break; case CTCPLX: @@ -300,7 +298,7 @@ toflt(Val v) f = mal(sizeof(*f)); mpmovefltflt(f, &v.u.cval->real); if(mpcmpfltc(&v.u.cval->imag, 0) != 0) - yyerror("constant %#F truncated to real", v.u.fval); + yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag); v.ctype = CTFLT; v.u.fval = f; break; @@ -324,9 +322,9 @@ toint(Val v) case CTCPLX: i = mal(sizeof(*i)); if(mpmovefltfix(i, &v.u.cval->real) < 0) - yyerror("constant %#F truncated to integer", v.u.fval); + yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag); if(mpcmpfltc(&v.u.cval->imag, 0) != 0) - yyerror("constant %#F truncated to real", v.u.fval); + yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag); v.ctype = CTINT; v.u.xval = i; break; @@ -536,6 +534,12 @@ evconst(Node *n) v = toflt(v); rv = toflt(rv); } + if(v.ctype != rv.ctype) { + // Use of undefined name as constant? + if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0) + return; + fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype); + } // run op switch(TUP(n->op, v.ctype)) { @@ -1086,6 +1090,12 @@ smallintconst(Node *n) case TBOOL: case TPTR32: return 1; + case TINT64: + case TUINT64: + if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0 + || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0) + break; + return 1; } return 0; } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index adb1531c3..a71272aa2 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -729,8 +729,11 @@ stotype(NodeList *l, int et, Type **t) n->right = N; if(n->embedded && n->type != T) { t1 = n->type; - if(t1->sym == S && isptr[t1->etype]) + 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) @@ -841,6 +844,8 @@ dostruct(NodeList *l, int et) t->broke = 1; return t; } + if(et == TINTER) + t = sortinter(t); if(!funarg) checkwidth(t); return t; @@ -1017,11 +1022,12 @@ functype(Node *this, NodeList *in, NodeList *out) } Sym* -methodsym(Sym *nsym, Type *t0) +methodsym(Sym *nsym, Type *t0, int iface) { Sym *s; char *p; Type *t; + char *suffix; t = t0; if(t == T) @@ -1043,7 +1049,13 @@ methodsym(Sym *nsym, Type *t0) if(t != t0 && t0->sym) t0 = ptrto(t); - p = smprint("%#hT·%s", t0, nsym->name); + suffix = ""; + if(iface) { + dowidth(t0); + if(t0->width < types[tptr]->width) + suffix = "·i"; + } + p = smprint("%#hT·%s%s", t0, nsym->name, suffix); s = pkglookup(p, s->pkg); free(p); return s; @@ -1058,7 +1070,7 @@ methodname(Node *n, Type *t) { Sym *s; - s = methodsym(n->sym, t); + s = methodsym(n->sym, t, 0); if(s == S) return n; return newname(s); diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go index 108a091b2..21e1b103b 100644 --- a/src/cmd/gc/doc.go +++ b/src/cmd/gc/doc.go @@ -25,13 +25,18 @@ other packages. It is therefore not necessary when compiling client C of package P to read the files of P's dependencies, only the compiled output of P. -Usage: 6g [flags] *.go (or 8g or 5g) +Usage: + 6g [flags] file... +The specified files must be Go source files and all part of the same package. +Substitute 6g with 8g or 5g where appropriate. Flags: -o file - output file, default 6.out for 6g, etc. + output file, default file.6 for 6g, etc. -e normally the compiler quits after 10 errors; -e prints all errors + -L + show entire file path when printing line numbers in errors -I dir1 -I dir2 add dir1 and dir2 to the list of paths to check for imported packages -N diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index 52853c454..594509915 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -176,7 +176,8 @@ dumpexporttype(Sym *s) yyerror("export of incomplete type %T", t); return; } - Bprint(bout, "type %#T %l#T\n", t, t); + if(Bprint(bout, "type %#T %l#T\n", t, t) < 0) + fatal("Bprint failed for %T", t); } static int diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index fd8a7f39b..04af5a7bb 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -58,7 +58,7 @@ allocparams(void) if(w >= MAXWIDTH) fatal("bad width"); stksize += w; - stksize = rnd(stksize, w); + stksize = rnd(stksize, n->type->align); n->xoffset = -stksize; } lineno = lno; @@ -139,8 +139,10 @@ gen(Node *n) Prog *scontin, *sbreak; Prog *p1, *p2, *p3; Label *lab; + int32 wasregalloc; lno = setlineno(n); + wasregalloc = anyregalloc(); if(n == N) goto ret; @@ -246,9 +248,6 @@ gen(Node *n) gen(n->nincr); // contin: incr patch(p1, pc); // test: - if(n->ntest != N) - if(n->ntest->ninit != nil) - genlist(n->ntest->ninit); bgen(n->ntest, 0, breakpc); // if(!test) goto break genlist(n->nbody); // body gjmp(continpc); @@ -261,9 +260,6 @@ gen(Node *n) p1 = gjmp(P); // goto test p2 = gjmp(P); // p2: goto else patch(p1, pc); // test: - if(n->ntest != N) - if(n->ntest->ninit != nil) - genlist(n->ntest->ninit); bgen(n->ntest, 0, p2); // if(!test) goto p2 genlist(n->nbody); // then p3 = gjmp(P); // goto done @@ -342,6 +338,11 @@ gen(Node *n) } ret: + if(anyregalloc() != wasregalloc) { + dump("node", n); + fatal("registers left allocated"); + } + lineno = lno; } @@ -432,7 +433,7 @@ cgen_discard(Node *nr) switch(nr->op) { case ONAME: - if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC) + if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF) gused(nr); break; @@ -651,7 +652,6 @@ tempname(Node *n, Type *t) snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); statuniqgen++; s = lookup(namebuf); - memset(n, 0, sizeof(*n)); n->op = ONAME; n->sym = s; @@ -664,7 +664,7 @@ tempname(Node *n, Type *t) dowidth(t); w = t->width; stksize += w; - stksize = rnd(stksize, w); + stksize = rnd(stksize, t->align); n->xoffset = -stksize; n->pun = anyregalloc(); } diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors index cdd7578d4..b5af4678c 100644 --- a/src/cmd/gc/go.errors +++ b/src/cmd/gc/go.errors @@ -35,6 +35,15 @@ static struct { % loadsys package imports LTYPE LNAME ';' "unexpected semicolon or newline in type declaration", + % loadsys package imports LCHAN '}' + "unexpected } in channel type", + + % loadsys package imports LCHAN ')' + "unexpected ) in channel type", + + % loadsys package imports LCHAN ',' + "unexpected comma in channel type", + % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE "unexpected semicolon or newline before else", diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 99e369eca..73ea5b976 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -6,6 +6,8 @@ #include <libc.h> #include <bio.h> +#undef OAPPEND + // avoid <ctype.h> #undef isblank #define isblank goisblank @@ -38,9 +40,10 @@ enum ASTRING, AINTER, ANILINTER, + AMEMWORD, BADWIDTH = -1000000000, - MAXWIDTH = 1<<30 + MAXWIDTH = 1<<30 }; /* @@ -151,6 +154,7 @@ struct Type uchar deferwidth; uchar broke; uchar isddd; // TFIELD is ... argument + uchar align; Node* nod; // canonical OTYPE node Type* orig; // original type (type literal or predefined type) @@ -209,12 +213,15 @@ struct Node uchar dodata; // compile literal assignment as data statement uchar used; uchar isddd; - uchar pun; // dont registerize variable ONAME + uchar pun; // don't registerize variable ONAME + uchar readonly; + uchar implicit; // don't show in printout // most nodes Node* left; Node* right; Type* type; + Type* realtype; // as determined by typecheck NodeList* list; NodeList* rlist; @@ -261,6 +268,7 @@ struct Node Sym* sym; // various int32 vargen; // unique name for OTYPE/ONAME int32 lineno; + int32 endlineno; vlong xoffset; int32 ostk; int32 iota; @@ -344,6 +352,7 @@ enum OADD, OSUB, OOR, OXOR, OADDSTR, OADDR, OANDAND, + OAPPEND, OARRAY, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, @@ -356,7 +365,7 @@ enum OCLOSURE, OCMPIFACE, OCMPSTR, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, - OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE, + OCONV, OCONVIFACE, OCONVNOP, OCOPY, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, @@ -364,7 +373,7 @@ enum ODOTTYPE2, OEQ, ONE, OLT, OLE, OGE, OGT, OIND, - OINDEX, OINDEXSTR, OINDEXMAP, + OINDEX, OINDEXMAP, OKEY, OPARAM, OLEN, OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE, @@ -400,7 +409,6 @@ enum ORETURN, OSELECT, OSWITCH, - OTYPECASE, OTYPESW, // l = r.(type) // types @@ -410,6 +418,7 @@ enum OTINTER, OTFUNC, OTARRAY, + OTPAREN, // misc ODDD, @@ -632,9 +641,9 @@ EXTERN Label* labellist; * * typedef struct * { // must not move anything - * uchar array[8]; // pointer to data - * uchar nel[4]; // number of elements - * uchar cap[4]; // allocated number of elements + * uchar array[8]; // pointer to data + * uchar nel[4]; // number of elements + * uchar cap[4]; // allocated number of elements * } Array; */ EXTERN int Array_array; // runtime offsetof(Array,array) - same for String @@ -649,8 +658,8 @@ EXTERN int sizeof_Array; // runtime sizeof(Array) * * typedef struct * { // must not move anything - * uchar array[8]; // pointer to data - * uchar nel[4]; // number of elements + * uchar array[8]; // pointer to data + * uchar nel[4]; // number of elements * } String; */ EXTERN int sizeof_String; // runtime sizeof(String) @@ -743,7 +752,6 @@ EXTERN int hasdefer; // flag that curfn has defer statetment EXTERN Node* curfn; -EXTERN int maxround; EXTERN int widthptr; EXTERN Node* typesw; @@ -858,7 +866,7 @@ int isifacemethod(Type *f); void markdcl(void); Node* methodname(Node *n, Type *t); Node* methodname1(Node *n, Node *t); -Sym* methodsym(Sym *nsym, Type *t0); +Sym* methodsym(Sym *nsym, Type *t0, int iface); Node* newname(Sym *s); Type* newtype(Sym *s); Node* oldname(Sym *s); @@ -914,6 +922,9 @@ char* lexname(int lex); void mkpackage(char* pkgname); void unimportfile(void); int32 yylex(void); +extern int windows; +extern int yylast; +extern int yyprev; /* * mparith1.c @@ -1003,7 +1014,7 @@ void walkrange(Node *n); * reflect.c */ void dumptypestructs(void); -Type* methodfunc(Type *f, int use_receiver); +Type* methodfunc(Type *f, Type*); Node* typename(Type *t); Sym* typesym(Type *t); @@ -1016,7 +1027,7 @@ void walkselect(Node *sel); /* * sinit.c */ -void anylit(int ctxt, Node *n, Node *var, NodeList **init); +void anylit(int, Node *n, Node *var, NodeList **init); int gen_as_init(Node *n); NodeList* initfix(NodeList *l); int oaslit(Node *n, NodeList **init); @@ -1059,7 +1070,7 @@ void flusherrors(void); void frame(int context); Type* funcfirst(Iter *s, Type *t); Type* funcnext(Iter *s); -void genwrapper(Type *rcvr, Type *method, Sym *newnam); +void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface); Type** getinarg(Type *t); Type* getinargx(Type *t); Type** getoutarg(Type *t); @@ -1095,6 +1106,7 @@ Node* nod(int op, Node *nleft, Node *nright); Node* nodbool(int b); void nodconst(Node *n, Type *t, int64 v); Node* nodintconst(int64 v); +Node* nodfltconst(Mpflt *v); Node* nodnil(void); int parserline(void); Sym* pkglookup(char *name, Pkg *pkg); @@ -1103,13 +1115,13 @@ Type* ptrto(Type *t); void* remal(void *p, int32 on, int32 n); Sym* restrictlookup(char *name, Pkg *pkg); Node* safeexpr(Node *n, NodeList **init); +Node* cheapexpr(Node *n, NodeList **init); int32 setlineno(Node *n); void setmaxarg(Type *t); Type* shallow(Type *t); int simsimtype(Type *t); void smagic(Magic *m); Type* sortinter(Type *t); -Node* staticname(Type *t); uint32 stringhash(char *p); Strlit* strlit(char *s); int structcount(Type *t); @@ -1143,7 +1155,7 @@ void typechecklist(NodeList *l, int top); /* * unsafe.c */ -Node* unsafenmagic(Node *fn, NodeList *args); +Node* unsafenmagic(Node *n); /* * walk.c @@ -1206,7 +1218,7 @@ void dumpfuncs(void); void gdata(Node*, Node*, int); void gdatacomplex(Node*, Mpcplx*); void gdatastring(Node*, Strlit*); -void genembedtramp(Type*, Type*, Sym*); +void genembedtramp(Type*, Type*, Sym*, int iface); void ggloblnod(Node *nam, int32 width); void ggloblsym(Sym *s, int32 width, int dupok); Prog* gjmp(Prog*); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index c46abaa56..917265758 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -20,6 +20,8 @@ %{ #include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */ #include "go.h" + +static void fixlbrace(int); %} %union { Node* node; @@ -50,7 +52,7 @@ %type <node> stmt ntype %type <node> arg_type %type <node> case caseblock -%type <node> compound_stmt dotname embed expr +%type <node> compound_stmt dotname embed expr complitexpr %type <node> expr_or_type %type <node> fndcl fnliteral %type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt @@ -58,7 +60,7 @@ %type <node> name_or_type non_expr_type %type <node> new_name dcl_name oexpr typedclname %type <node> onew_name -%type <node> osimple_stmt pexpr +%type <node> osimple_stmt pexpr pexpr_no_paren %type <node> pseudocall range_stmt select_stmt %type <node> simple_stmt %type <node> switch_stmt uexpr @@ -66,7 +68,7 @@ %type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list %type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list -%type <list> oexpr_list oexpr_or_type_list_ocomma caseblock_list stmt_list oarg_type_list_ocomma arg_type_list +%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list %type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list %type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list @@ -459,7 +461,7 @@ case: } break; } -| LCASE name '=' expr ':' +| LCASE expr '=' expr ':' { // will be converted to OCASE // right will point to next case @@ -515,10 +517,33 @@ switch_body: } caseblock: - case stmt_list + case + { + // If the last token read by the lexer was consumed + // as part of the case, clear it (parser has cleared yychar). + // If the last token read by the lexer was the lookahead + // leave it alone (parser has it cached in yychar). + // This is so that the stmt_list action doesn't look at + // the case tokens if the stmt_list is empty. + yylast = yychar; + } + stmt_list { + int last; + + // This is the only place in the language where a statement + // list is not allowed to drop the final semicolon, because + // it's the only place where a statement list is not followed + // by a closing brace. Handle the error for pedantry. + + // Find the final token of the statement list. + // yylast is lookahead; yyprev is last of stmt_list + last = yyprev; + + if(last > 0 && last != ';' && yychar != '}') + yyerror("missing statement after label"); $$ = $1; - $$->nbody = $2; + $$->nbody = $3; } caseblock_list: @@ -648,11 +673,13 @@ select_stmt: LSELECT { markdcl(); + typesw = nod(OXXX, typesw, N); } switch_body { $$ = nod(OSELECT, N, N); $$->list = $3; + typesw = typesw->left; popdcl(); } @@ -783,13 +810,23 @@ uexpr: * can be preceded by 'defer' and 'go' */ pseudocall: - pexpr '(' oexpr_or_type_list_ocomma ')' + pexpr '(' ')' + { + $$ = nod(OCALL, $1, N); + } +| pexpr '(' expr_or_type_list ocomma ')' { $$ = nod(OCALL, $1, N); $$->list = $3; } +| pexpr '(' expr_or_type_list LDDD ocomma ')' + { + $$ = nod(OCALL, $1, N); + $$->list = $3; + $$->isddd = 1; + } -pexpr: +pexpr_no_paren: LLITERAL { $$ = nodlit($1); @@ -806,10 +843,6 @@ pexpr: } $$ = nod(OXDOT, $1, newname($3)); } -| '(' expr_or_type ')' - { - $$ = $2; - } | pexpr '.' '(' expr_or_type ')' { $$ = nod(ODOTTYPE, $1, $4); @@ -824,10 +857,6 @@ pexpr: } | pexpr '[' oexpr ':' oexpr ']' { - if($3 == N) { - yyerror("missing lower bound in slice expression"); - $3 = nodintconst(0); - } $$ = nod(OSLICE, $1, nod(OKEY, $3, $5)); } | pseudocall @@ -842,21 +871,45 @@ pexpr: // composite expression $$ = nod(OCOMPLIT, N, $1); $$->list = $3; - - // If the opening brace was an LBODY, - // set up for another one now that we're done. - // See comment in lex.c about loophack. - if($2 == LBODY) - loophack = 1; + + fixlbrace($2); } -| pexpr '{' braced_keyval_list '}' +| pexpr_no_paren '{' braced_keyval_list '}' { // composite expression $$ = nod(OCOMPLIT, N, $1); $$->list = $3; } +| '(' expr_or_type ')' '{' braced_keyval_list '}' + { + yyerror("cannot parenthesize type in composite literal"); + // composite expression + $$ = nod(OCOMPLIT, N, $2); + $$->list = $5; + } | fnliteral +keyval: + expr ':' complitexpr + { + $$ = nod(OKEY, $1, $3); + } + +complitexpr: + expr +| '{' braced_keyval_list '}' + { + $$ = nod(OCOMPLIT, N, N); + $$->list = $2; + } + +pexpr: + pexpr_no_paren +| '(' expr_or_type ')' + { + $$ = $2; + } + expr_or_type: expr | non_expr_type %prec PreferToRightParen @@ -939,7 +992,7 @@ ntype: | dotname | '(' ntype ')' { - $$ = $2; + $$ = nod(OTPAREN, $2, N); } non_expr_type: @@ -958,7 +1011,7 @@ non_recvchantype: | dotname | '(' ntype ')' { - $$ = $2; + $$ = nod(OTPAREN, $2, N); } convtype: @@ -1030,34 +1083,31 @@ recvchantype: } structtype: - LSTRUCT '{' structdcl_list osemi '}' + LSTRUCT lbrace structdcl_list osemi '}' { $$ = nod(OTSTRUCT, N, N); $$->list = $3; + fixlbrace($2); } -| LSTRUCT '{' '}' +| LSTRUCT lbrace '}' { $$ = nod(OTSTRUCT, N, N); + fixlbrace($2); } interfacetype: - LINTERFACE '{' interfacedcl_list osemi '}' + LINTERFACE lbrace interfacedcl_list osemi '}' { $$ = nod(OTINTER, N, N); $$->list = $3; + fixlbrace($2); } -| LINTERFACE '{' '}' +| LINTERFACE lbrace '}' { $$ = nod(OTINTER, N, N); + fixlbrace($2); } -keyval: - expr ':' expr - { - $$ = nod(OKEY, $1, $3); - } - - /* * function stuff * all in one place to show how crappy it all is @@ -1069,6 +1119,7 @@ xfndcl: if($$ == N) break; $$->nbody = $3; + $$->endlineno = lineno; funcbody($$); } @@ -1118,6 +1169,8 @@ fndcl: yyerror("bad receiver in method"); break; } + if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) + yyerror("cannot parenthesize receiver type"); $$ = nod(ODCLFUNC, N, N); $$->nname = methodname1(name, rcvr->right); @@ -1250,12 +1303,32 @@ structdcl: $1->val = $2; $$ = list1($1); } +| '(' embed ')' oliteral + { + $2->val = $4; + $$ = list1($2); + yyerror("cannot parenthesize embedded type"); + } | '*' embed oliteral { $2->right = nod(OIND, $2->right, N); $2->val = $3; $$ = list1($2); } +| '(' '*' embed ')' oliteral + { + $3->right = nod(OIND, $3->right, N); + $3->val = $5; + $$ = list1($3); + yyerror("cannot parenthesize embedded type"); + } +| '*' '(' embed ')' oliteral + { + $3->right = nod(OIND, $3->right, N); + $3->val = $5; + $$ = list1($3); + yyerror("cannot parenthesize embedded type"); + } packname: LNAME @@ -1296,6 +1369,11 @@ interfacedcl: { $$ = nod(ODCLFIELD, N, oldname($1)); } +| '(' packname ')' + { + $$ = nod(ODCLFIELD, N, oldname($2)); + yyerror("cannot parenthesize embedded type"); + } indcl: '(' oarg_type_list_ocomma ')' fnres @@ -1481,7 +1559,7 @@ keyval_list: { $$ = list1($1); } -| expr +| complitexpr { $$ = list1($1); } @@ -1489,7 +1567,7 @@ keyval_list: { $$ = list($1, $3); } -| keyval_list ',' expr +| keyval_list ',' complitexpr { $$ = list($1, $3); } @@ -1524,12 +1602,6 @@ oexpr_list: } | expr_list -oexpr_or_type_list_ocomma: - { - $$ = nil; - } -| expr_or_type_list ocomma - osimple_stmt: { $$ = N; @@ -1654,7 +1726,6 @@ hidden_type_misc: | LINTERFACE '{' ohidden_interfacedcl_list '}' { $$ = dostruct($3, TINTER); - $$ = sortinter($$); } | '*' hidden_type { @@ -1867,3 +1938,16 @@ hidden_interfacedcl_list: { $$ = list($1, $3); } + +%% + +static void +fixlbrace(int lbr) +{ + // If the opening brace was an LBODY, + // set up for another one now that we're done. + // See comment in lex.c about loophack. + if(lbr == LBODY) + loophack = 1; +} + diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 452acfc76..0f1acd2fc 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -14,6 +14,8 @@ extern int yychar; int windows; +int yyprev; +int yylast; static void lexinit(void); static void lexfini(void); @@ -23,9 +25,45 @@ static void ungetc(int); static int32 getr(void); static int escchar(int, int*, vlong*); static void addidir(char*); - +static int getlinepragma(void); static char *goos, *goarch, *goroot; +// Our own isdigit, isspace, isalpha, isalnum that take care +// of EOF and other out of range arguments. +static int +yy_isdigit(int c) +{ + return c >= 0 && c <= 0xFF && isdigit(c); +} + +static int +yy_isspace(int c) +{ + return c >= 0 && c <= 0xFF && isspace(c); +} + +static int +yy_isalpha(int c) +{ + return c >= 0 && c <= 0xFF && isalpha(c); +} + +static int +yy_isalnum(int c) +{ + return c >= 0 && c <= 0xFF && isalnum(c); +} + +// Disallow use of isdigit etc. +#undef isdigit +#undef isspace +#undef isalpha +#undef isalnum +#define isdigit use_yy_isdigit_instead_of_isdigit +#define isspace use_yy_isspace_instead_of_isspace +#define isalpha use_yy_isalpha_instead_of_isalpha +#define isalnum use_yy_isalnum_instead_of_isalnum + #define DBG if(!debug['x']);else print enum { @@ -35,7 +73,7 @@ enum void usage(void) { - print("usage: %cg [flags] file.go...\n"); + print("gc: usage: %cg [flags] file.go...\n", thechar); print("flags:\n"); // -A is allow use of "any" type, for bootstrapping print(" -I DIR search for packages in DIR\n"); @@ -52,12 +90,27 @@ usage(void) exit(0); } +void +fault(int s) +{ + // If we've already complained about things + // in the program, don't bother complaining + // about the seg fault too; let the user clean up + // the code and try again. + if(nerrors > 0) + errorexit(); + fatal("fault"); +} + int main(int argc, char *argv[]) { int i, c; NodeList *l; char *p; + + signal(SIGBUS, fault); + signal(SIGSEGV, fault); localpkg = mkpkg(strlit("")); localpkg->prefix = "\"\""; @@ -119,7 +172,7 @@ main(int argc, char *argv[]) if(getwd(pathname, 999) == 0) strcpy(pathname, "/???"); - if(isalpha(pathname[0]) && pathname[1] == ':') { + if(yy_isalpha(pathname[0]) && pathname[1] == ':') { // On Windows. windows = 1; @@ -141,7 +194,7 @@ main(int argc, char *argv[]) fmtinstall('F', Fconv); // big float numbers betypeinit(); - if(maxround == 0 || widthptr == 0) + if(widthptr == 0) fatal("betypeinit failed"); lexinit(); @@ -287,7 +340,7 @@ islocalname(Strlit *name) if(!windows && name->len >= 1 && name->s[0] == '/') return 1; if(windows && name->len >= 3 && - isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/') + yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/') return 1; if(name->len >= 2 && strncmp(name->s, "./", 2) == 0) return 1; @@ -300,8 +353,11 @@ static int findpkg(Strlit *name) { Idir *p; + char *q; if(islocalname(name)) { + if(safemode) + return 0; // try .a before .6. important for building libraries: // if there is an array.6 in the array.a library, // want to find all of array.a, not just array.6. @@ -314,6 +370,18 @@ findpkg(Strlit *name) return 0; } + // local imports should be canonicalized already. + // don't want to see "container/../container/vector" + // as different from "container/vector". + q = mal(name->len+1); + memmove(q, name->s, name->len); + q[name->len] = '\0'; + cleanname(q); + if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) { + yyerror("non-canonical import path %Z (should be %s)", name, q); + return 0; + } + for(p = idirs; p != nil; p = p->link) { snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name); if(access(namebuf, 0) >= 0) @@ -368,7 +436,9 @@ importfile(Val *f, int line) path = f->u.sval; if(islocalname(path)) { cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2); - sprint(cleanbuf, "%s/%s", pathname, path->s); + strcpy(cleanbuf, pathname); + strcat(cleanbuf, "/"); + strcat(cleanbuf, path->s); cleanname(cleanbuf); path = strlit(cleanbuf); } @@ -381,7 +451,7 @@ importfile(Val *f, int line) imp = Bopen(namebuf, OREAD); if(imp == nil) { - yyerror("can't open import: %Z", f->u.sval); + yyerror("can't open import: %Z: %r", f->u.sval); errorexit(); } file = strdup(namebuf); @@ -470,7 +540,7 @@ isfrog(int c) return 0; return 1; } - if(0x80 <= c && c <= 0xa0) // unicode block including unbreakable space. + if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space. return 1; return 0; } @@ -496,7 +566,7 @@ _yylex(void) l0: c = getc(); - if(isspace(c)) { + if(yy_isspace(c)) { if(c == '\n' && curio.nlsemi) { ungetc(c); DBG("lex: implicit semi\n"); @@ -514,13 +584,13 @@ l0: goto talph; } - if(isalpha(c)) { + if(yy_isalpha(c)) { cp = lexbuf; ep = lexbuf+sizeof lexbuf; goto talph; } - if(isdigit(c)) + if(yy_isdigit(c)) goto tnum; switch(c) { @@ -536,7 +606,7 @@ l0: case '.': c1 = getc(); - if(isdigit(c1)) { + if(yy_isdigit(c1)) { cp = lexbuf; ep = lexbuf+sizeof lexbuf; *cp++ = c; @@ -656,16 +726,13 @@ l0: } } if(c1 == '/') { + c = getlinepragma(); for(;;) { - c = getr(); - if(c == '\n') { + if(c == '\n' || c == EOF) { ungetc(c); goto l0; } - if(c == EOF) { - yyerror("eof in comment"); - errorexit(); - } + c = getr(); } } if(c1 == '=') { @@ -878,6 +945,10 @@ lx: yyerror("illegal character 0x%ux", c); goto l0; } + if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) { + yyerror("%s: unexpected %c", "syntax error", c); + goto l0; + } return c; asop: @@ -902,7 +973,7 @@ talph: if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7)) yyerror("invalid identifier character 0x%ux", rune); cp += runetochar(cp, &rune); - } else if(!isalnum(c) && c != '_') + } else if(!yy_isalnum(c) && c != '_') break; else *cp++ = c; @@ -940,7 +1011,7 @@ tnum: } *cp++ = c; c = getc(); - if(isdigit(c)) + if(yy_isdigit(c)) continue; goto dc; } @@ -955,7 +1026,7 @@ tnum: } *cp++ = c; c = getc(); - if(isdigit(c)) + if(yy_isdigit(c)) continue; if(c >= 'a' && c <= 'f') continue; @@ -976,7 +1047,7 @@ tnum: yyerror("identifier too long"); errorexit(); } - if(!isdigit(c)) + if(!yy_isdigit(c)) break; if(c < '0' || c > '7') c1 = 1; // not octal @@ -1025,7 +1096,7 @@ casedot: } *cp++ = c; c = getc(); - if(!isdigit(c)) + if(!yy_isdigit(c)) break; } if(c == 'i') @@ -1040,9 +1111,9 @@ casee: *cp++ = c; c = getc(); } - if(!isdigit(c)) + if(!yy_isdigit(c)) yyerror("malformed fp constant exponent"); - while(isdigit(c)) { + while(yy_isdigit(c)) { if(cp+10 >= ep) { yyerror("identifier too long"); errorexit(); @@ -1061,9 +1132,9 @@ casep: *cp++ = c; c = getc(); } - if(!isdigit(c)) + if(!yy_isdigit(c)) yyerror("malformed fp constant exponent"); - while(isdigit(c)) { + while(yy_isdigit(c)) { if(cp+10 >= ep) { yyerror("identifier too long"); errorexit(); @@ -1104,6 +1175,68 @@ caseout: return LLITERAL; } +/* + * read and interpret syntax that looks like + * //line parse.y:15 + * as a discontinuity in sequential line numbers. + * the next line of input comes from parse.y:15 + */ +static int +getlinepragma(void) +{ + int i, c, n; + char *cp, *ep; + Hist *h; + + for(i=0; i<5; i++) { + c = getr(); + if(c != "line "[i]) + goto out; + } + + cp = lexbuf; + ep = lexbuf+sizeof(lexbuf)-5; + for(;;) { + c = getr(); + if(c == '\n' || c == EOF) + goto out; + if(c == ' ') + continue; + if(c == ':') + break; + if(cp < ep) + *cp++ = c; + } + *cp = 0; + + n = 0; + for(;;) { + c = getr(); + if(!yy_isdigit(c)) + break; + n = n*10 + (c-'0'); + if(n > 1e8) { + yyerror("line number out of range"); + errorexit(); + } + } + + if(c != '\n' || n <= 0) + goto out; + + // try to avoid allocating file name over and over + for(h=hist; h!=H; h=h->link) { + if(h->name != nil && strcmp(h->name, lexbuf) == 0) { + linehist(h->name, n, 0); + goto out; + } + } + linehist(strdup(lexbuf), n, 0); + +out: + return c; +} + int32 yylex(void) { @@ -1112,13 +1245,8 @@ yylex(void) lx = _yylex(); if(curio.nlsemi && lx == EOF) { - // if the nlsemi bit is set, we'd be willing to - // insert a ; if we saw a \n, but we didn't. - // that means the final \n is missing. - // complain here, because we can give a - // good message. the syntax error we'd get - // otherwise is inscrutable. - yyerror("missing newline at end of file"); + // Treat EOF as "end of line" for the purposes + // of inserting a semicolon. lx = ';'; } @@ -1140,7 +1268,11 @@ yylex(void) curio.nlsemi = 0; break; } - return lx; + + // Track last two tokens returned by yylex. + yyprev = yylast; + yylast = lx; + return lx; } static int @@ -1395,6 +1527,7 @@ static struct "type", LTYPE, Txxx, OXXX, "var", LVAR, Txxx, OXXX, + "append", LNAME, Txxx, OAPPEND, "cap", LNAME, Txxx, OCAP, "close", LNAME, Txxx, OCLOSE, "closed", LNAME, Txxx, OCLOSED, diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin index 13309ec32..4dfff1caa 100755 --- a/src/cmd/gc/mkbuiltin +++ b/src/cmd/gc/mkbuiltin @@ -10,11 +10,9 @@ set -e -GOBIN="${GOBIN:-$HOME/bin}" - -. "$GOROOT"/src/Make.$GOARCH +eval $(gomake --no-print-directory -f ../../Make.inc go-env) if [ -z "$GC" ]; then - echo 'missing $GC - maybe no Make.$GOARCH?' 1>&2 + echo 'missing $GC - gomake failed?' 1>&2 exit 1 fi @@ -22,7 +20,7 @@ gcc -o mkbuiltin1 mkbuiltin1.c rm -f _builtin.c for i in runtime unsafe do - "$GOBIN"/$GC -A $i.go + $GC -A $i.go O=$O ./mkbuiltin1 $i >>_builtin.c done diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index 8110e77b9..6cd4e2500 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -156,10 +156,11 @@ mpmovefixflt(Mpflt *a, Mpint *b) // convert (truncate) b to a. // return -1 (but still convert) if b was non-integer. -int -mpmovefltfix(Mpint *a, Mpflt *b) +static int +mpexactfltfix(Mpint *a, Mpflt *b) { Mpflt f; + *a = b->val; mpshiftfix(a, b->exp); if(b->exp < 0) { @@ -172,6 +173,35 @@ mpmovefltfix(Mpint *a, Mpflt *b) return 0; } +int +mpmovefltfix(Mpint *a, Mpflt *b) +{ + Mpflt f; + int i; + + if(mpexactfltfix(a, b) == 0) + return 0; + + // try rounding down a little + f = *b; + f.val.a[0] = 0; + if(mpexactfltfix(a, &f) == 0) + return 0; + + // try rounding up a little + for(i=1; i<Mpprec; i++) { + f.val.a[i]++; + if(f.val.a[i] != Mpbase) + break; + f.val.a[i] = 0; + } + mpnorm(&f); + if(mpexactfltfix(a, &f) == 0) + return 0; + + return -1; +} + void mpmovefixfix(Mpint *a, Mpint *b) { @@ -188,6 +218,8 @@ static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 }; static void mppow10flt(Mpflt *a, int p) { + if(p < 0) + abort(); if(p < nelem(tab)) { mpmovecflt(a, tab[p]); return; @@ -267,6 +299,10 @@ mpatoflt(Mpflt *a, char *as) } if(c >= '0' && c <= '9') { ex = ex*10 + (c-'0'); + if(ex > 1e8) { + yyerror("exponent out of range"); + errorexit(); + } continue; } break; @@ -439,6 +475,8 @@ Fconv(Fmt *fp) // for well in range, convert to double and use print's %g if(-900 < fvp->exp && fvp->exp < 900) { d = mpgetflt(fvp); + if(d >= 0 && (fp->flags & FmtSign)) + fmtprint(fp, "+"); return fmtprint(fp, "%g", d); } // TODO(rsc): for well out of range, print diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index b025917fa..403255005 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -319,7 +319,11 @@ mpmulfract(Mpint *a, Mpint *b) s.neg = 0; mpmovecfix(&q, 0); - for(i=0; i<Mpprec; i++) { + x = *--a1; + if(x != 0) + yyerror("mpmulfract not normal"); + + for(i=0; i<Mpprec-1; i++) { x = *--a1; if(x == 0) { mprshw(&s); @@ -532,7 +536,7 @@ mpgetfix(Mpint *a) vlong v; if(a->ovf) { - yyerror("ovf in mpgetfix"); + yyerror("constant overflow"); return 0; } diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c index b9cd4ea84..7b7e66668 100644 --- a/src/cmd/gc/mparith3.c +++ b/src/cmd/gc/mparith3.c @@ -27,16 +27,36 @@ sigfig(Mpflt *a) void mpnorm(Mpflt *a) { - int s; + int s, os; + long x; - s = sigfig(a); - if(s == 0) { + os = sigfig(a); + if(os == 0) { // zero a->exp = 0; a->val.neg = 0; return; } - s = (Mpnorm-s) * Mpscale; + + // this will normalize to the nearest word + x = a->val.a[os-1]; + s = (Mpnorm-os) * Mpscale; + + // further normalize to the nearest bit + for(;;) { + x <<= 1; + if(x & Mpbase) + break; + s++; + if(x == 0) { + // this error comes from trying to + // convert an Inf or something + // where the initial x=0x80000000 + s = (Mpnorm-os) * Mpscale; + break; + } + } + mpshiftfix(&a->val, s); a->exp -= s; } @@ -109,7 +129,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b) } mpmulfract(&a->val, &b->val); - a->exp = (a->exp + b->exp) + Mpscale*Mpprec - 1; + a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1; mpnorm(a); if(Mpdebug) diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index ae16f2725..0d0d70ac9 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -74,41 +74,96 @@ Bputname(Biobuf *b, Sym *s) } static void +outzfile(Biobuf *b, char *p) +{ + char *q, *q2; + + while(p) { + q = utfrune(p, '/'); + if(windows) { + q2 = utfrune(p, '\\'); + if(q2 && (!q || q2 < q)) + q = q2; + } + if(!q) { + zfile(b, p, strlen(p)); + return; + } + if(q > p) + zfile(b, p, q-p); + p = q + 1; + } +} + +#define isdelim(c) (c == '/' || c == '\\') + +static void +outwinname(Biobuf *b, Hist *h, char *ds, char *p) +{ + if(isdelim(p[0])) { + // full rooted name + zfile(b, ds, 3); // leading "c:/" + outzfile(b, p+1); + } else { + // relative name + if(h->offset == 0 && pathname && pathname[1] == ':') { + if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) { + // using current drive + zfile(b, pathname, 3); // leading "c:/" + outzfile(b, pathname+3); + } else { + // using drive other then current, + // we don't have any simple way to + // determine current working directory + // there, therefore will output name as is + zfile(b, ds, 2); // leading "c:" + } + } + outzfile(b, p); + } +} + +static void outhist(Biobuf *b) { Hist *h; - char *p, *q, *op; - int n; + char *p, ds[] = {'c', ':', '/', 0}; for(h = hist; h != H; h = h->link) { p = h->name; - op = 0; - - if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') { - op = p; - p = pathname; - } - - while(p) { - q = utfrune(p, '/'); - if(q) { - n = q-p; - if(n == 0) - n = 1; // leading "/" - q++; + if(p) { + if(windows) { + // if windows variable is set, then, we know already, + // pathname is started with windows drive specifier + // and all '\' were replaced with '/' (see lex.c) + if(isdelim(p[0]) && isdelim(p[1])) { + // file name has network name in it, + // like \\server\share\dir\file.go + zfile(b, "//", 2); // leading "//" + outzfile(b, p+2); + } else if(p[1] == ':') { + // file name has drive letter in it + ds[0] = p[0]; + outwinname(b, h, ds, p+2); + } else { + // no drive letter in file name + outwinname(b, h, pathname, p); + } } else { - n = strlen(p); - q = 0; - } - if(n) - zfile(b, p, n); - p = q; - if(p == 0 && op) { - p = op; - op = 0; + if(p[0] == '/') { + // full rooted name, like /home/rsc/dir/file.go + zfile(b, "/", 1); // leading "/" + outzfile(b, p+1); + } else { + // relative name, like dir/file.go + if(h->offset == 0 && pathname && pathname[0] == '/') { + zfile(b, "/", 1); // leading "/" + outzfile(b, pathname+1); + } + outzfile(b, p); + } } } - zhist(b, h->line, h->offset); } } diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index 8738eb41b..6bb1f026b 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -23,14 +23,21 @@ void exprfmt(Fmt *f, Node *n, int prec) { int nprec; + char *p; nprec = 0; if(n == nil) { fmtprint(f, "<nil>"); return; } + + if(n->implicit) { + exprfmt(f, n->left, prec); + return; + } switch(n->op) { + case OAPPEND: case ONAME: case ONONAME: case OPACK: @@ -53,9 +60,11 @@ exprfmt(Fmt *f, Node *n, int prec) case OPRINT: case OPRINTN: case OCALL: + case OCALLMETH: + case OCALLINTER: + case OCALLFUNC: case OCONV: case OCONVNOP: - case OCONVSLICE: case OMAKESLICE: case ORUNESTR: case OADDR: @@ -66,6 +75,9 @@ exprfmt(Fmt *f, Node *n, int prec) case OPLUS: case ORECV: case OCONVIFACE: + case OTPAREN: + case OINDEX: + case OINDEXMAP: nprec = 7; break; @@ -106,6 +118,11 @@ exprfmt(Fmt *f, Node *n, int prec) case OOROR: nprec = 1; break; + + case OTYPE: + if(n->sym != S) + nprec = 7; + break; } if(prec > nprec) @@ -118,6 +135,10 @@ exprfmt(Fmt *f, Node *n, int prec) break; case OLITERAL: + if(n->sym != S) { + fmtprint(f, "%S", n->sym); + break; + } switch(n->val.ctype) { default: goto bad; @@ -154,6 +175,10 @@ exprfmt(Fmt *f, Node *n, int prec) break; case OTYPE: + if(n->type == T && n->sym != S) { + fmtprint(f, "%S", n->sym); + break; + } fmtprint(f, "%T", n->type); break; @@ -161,6 +186,12 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, "[]"); exprfmt(f, n->left, PFIXME); break; + + case OTPAREN: + fmtprint(f, "("); + exprfmt(f, n->left, 0); + fmtprint(f, ")"); + break; case OTMAP: fmtprint(f, "map["); @@ -178,7 +209,7 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->left, 0); } else { fmtprint(f, " "); - if(n->left->op == OTCHAN && n->left->etype == Crecv) { + if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) { fmtprint(f, "("); exprfmt(f, n->left, 0); fmtprint(f, ")"); @@ -248,6 +279,10 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->left, 0); break; + case OCLOSURE: + fmtprint(f, "func literal"); + break; + case OCOMPLIT: fmtprint(f, "composite literal"); break; @@ -267,6 +302,7 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, "struct literal"); break; + case OXDOT: case ODOT: case ODOTPTR: case ODOTINTER: @@ -274,8 +310,15 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->left, 7); if(n->right == N || n->right->sym == S) fmtprint(f, ".<nil>"); - else - fmtprint(f, ".%s", n->right->sym->name); + else { + // skip leading type· in method name + p = utfrrune(n->right->sym->name, 0xb7); + if(p) + p+=2; + else + p = n->right->sym->name; + fmtprint(f, ".%s", p); + } break; case ODOTTYPE: @@ -291,7 +334,6 @@ exprfmt(Fmt *f, Node *n, int prec) case OINDEX: case OINDEXMAP: - case OINDEXSTR: exprfmt(f, n->left, 7); fmtprint(f, "["); exprfmt(f, n->right, 0); @@ -299,9 +341,12 @@ exprfmt(Fmt *f, Node *n, int prec) break; case OSLICE: + case OSLICESTR: + case OSLICEARR: exprfmt(f, n->left, 7); fmtprint(f, "["); - exprfmt(f, n->right->left, 0); + if(n->right->left != N) + exprfmt(f, n->right->left, 0); fmtprint(f, ":"); if(n->right->right != N) exprfmt(f, n->right->right, 0); @@ -315,6 +360,8 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->left, 7); fmtprint(f, "("); exprlistfmt(f, n->list); + if(n->isddd) + fmtprint(f, "..."); fmtprint(f, ")"); break; @@ -341,7 +388,6 @@ exprfmt(Fmt *f, Node *n, int prec) case OCONV: case OCONVIFACE: case OCONVNOP: - case OCONVSLICE: case OARRAYBYTESTR: case ORUNESTR: if(n->type == T || n->type->sym == S) @@ -355,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, ")"); break; + case OAPPEND: case OCAP: case OCLOSE: case OCLOSED: diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index 09d54b3ee..dca3a5454 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -24,6 +24,8 @@ typecheckrange(Node *n) typecheck(&n->right, Erv); if((t = n->right->type) == T) goto out; + if(isptr[t->etype] && isfixedarray(t->type)) + t = t->type; n->type = t; switch(t->etype) { @@ -104,9 +106,6 @@ walkrange(Node *n) a = nod(OCONV, n->right, N); a->type = types[TSTRING]; } - ha = nod(OXXX, N, N); - tempname(ha, a->type); - init = list(init, nod(OAS, ha, a)); v1 = n->list->n; hv1 = N; @@ -116,6 +115,16 @@ walkrange(Node *n) v2 = n->list->next->n; hv2 = N; + if(v2 == N && t->etype == TARRAY) { + // will have just one reference to argument. + // no need to make a potentially expensive copy. + ha = a; + } else { + ha = nod(OXXX, N, N); + tempname(ha, a->type); + init = list(init, nod(OAS, ha, a)); + } + switch(t->etype) { default: fatal("walkrange"); @@ -131,7 +140,7 @@ walkrange(Node *n) init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); if(v2) { hp = nod(OXXX, N, N); - tempname(hp, ptrto(a->type->type)); + tempname(hp, ptrto(n->type->type)); tmp = nod(OINDEX, ha, nodintconst(0)); tmp->etype = 1; // no bounds check init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 467f3615b..b31eb5154 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -100,16 +100,16 @@ lsort(Sig *l, int(*f)(Sig*, Sig*)) * return function type, receiver as first argument (or not). */ Type* -methodfunc(Type *f, int use_receiver) +methodfunc(Type *f, Type *receiver) { NodeList *in, *out; Node *d; Type *t; in = nil; - if(use_receiver) { + if(receiver) { d = nod(ODCLFIELD, N, N); - d->type = getthisx(f)->type->type; + d->type = receiver; in = list(in, d); } for(t=getinargx(f)->type; t; t=t->down) { @@ -183,14 +183,14 @@ methods(Type *t) a = b; a->name = method->name; - a->isym = methodsym(method, it); - a->tsym = methodsym(method, t); - a->type = methodfunc(f->type, 1); - a->mtype = methodfunc(f->type, 0); + a->isym = methodsym(method, it, 1); + a->tsym = methodsym(method, t, 0); + a->type = methodfunc(f->type, t); + a->mtype = methodfunc(f->type, nil); if(!(a->isym->flags & SymSiggen)) { a->isym->flags |= SymSiggen; - if(!eqtype(this, it)) { + if(!eqtype(this, it) || this->width < types[tptr]->width) { if(oldlist == nil) oldlist = pc; // Is okay to call genwrapper here always, @@ -199,9 +199,9 @@ methods(Type *t) // is a pointer adjustment and a JMP. if(isptr[it->etype] && isptr[this->etype] && f->embedded && !isifacemethod(f->type)) - genembedtramp(it, f, a->isym); + genembedtramp(it, f, a->isym, 1); else - genwrapper(it, f, a->isym); + genwrapper(it, f, a->isym, 1); } } @@ -212,9 +212,9 @@ methods(Type *t) oldlist = pc; if(isptr[t->etype] && isptr[this->etype] && f->embedded && !isifacemethod(f->type)) - genembedtramp(t, f, a->tsym); + genembedtramp(t, f, a->tsym, 0); else - genwrapper(t, f, a->tsym); + genwrapper(t, f, a->tsym, 0); } } } @@ -241,22 +241,27 @@ 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) fatal("imethods: not field"); if(f->type->etype != TFUNC || f->sym == nil) continue; + method = f->sym; a = mal(sizeof(*a)); - a->name = f->sym->name; - if(!exportname(f->sym->name)) - a->pkg = f->sym->pkg; + a->name = method->name; + if(!exportname(method->name)) + a->pkg = method->pkg; a->mtype = f->type; a->offset = 0; - a->type = methodfunc(f->type, 0); + a->type = methodfunc(f->type, nil); + if(last && sigcmp(last, a) >= 0) fatal("sigcmp vs sortinter %s %s", last->name, a->name); if(last == nil) @@ -264,7 +269,34 @@ imethods(Type *t) else last->link = a; last = a; + + // Compiler can only refer to wrappers for + // named interface types. + if(t->sym == S) + continue; + + // NOTE(rsc): Perhaps an oversight that + // IfaceType.Method is not in the reflect data. + // Generate the method body, so that compiled + // code can refer to it. + isym = methodsym(method, t, 0); + if(!(isym->flags & SymSiggen)) { + isym->flags |= SymSiggen; + if(oldlist == nil) + oldlist = pc; + genwrapper(t, f, isym, 0); + } } + + if(oldlist) { + // old list ended with AEND; change to ANOP + // so that the trampolines that follow can be found. + nopout(oldlist); + + // start new data list + newplist(); + } + return all; } @@ -545,7 +577,6 @@ dcommontype(Sym *s, int ot, Type *t) { int i; Sym *s1; - Type *elem; char *p; dowidth(t); @@ -566,26 +597,23 @@ dcommontype(Sym *s, int ot, Type *t) // alg uint8; // align uint8; // fieldAlign uint8; + // kind uint8; // string *string; // *nameInfo; // } ot = duintptr(s, ot, t->width); ot = duint32(s, ot, typehash(t)); ot = duint8(s, ot, algtype(t)); - elem = t; - while(elem->etype == TARRAY && elem->bound >= 0) - elem = elem->type; - i = elem->width; - if(i > maxround) - i = maxround; - ot = duint8(s, ot, i); // align - ot = duint8(s, ot, i); // fieldAlign + ot = duint8(s, ot, t->align); // align + ot = duint8(s, ot, t->align); // fieldAlign i = kinds[t->etype]; if(t->etype == TARRAY && t->bound < 0) i = KindSlice; + if(isptr[t->etype] && t->type->etype == TANY) + i = KindUnsafePointer; if(!haspointers(t)) i |= KindNoPointers; - ot = duint8(s, ot, i); + ot = duint8(s, ot, i); // kind longsymnames = 1; p = smprint("%-T", t); longsymnames = 0; @@ -643,11 +671,10 @@ typename(Type *t) static Sym* dtypesym(Type *t) { - int ot, n, isddd; + int ot, n, isddd, dupok; Sym *s, *s1, *s2; Sig *a, *m; - Type *t1; - Sym *tsym; + Type *t1, *tbase; if(isideal(t)) fatal("dtypesym %T", t); @@ -660,30 +687,22 @@ dtypesym(Type *t) // special case (look for runtime below): // when compiling package runtime, // emit the type structures for int, float, etc. - t1 = T; - if(isptr[t->etype]) - t1 = t->type; - tsym = S; - if(t1) - tsym = t1->sym; - else - tsym = t->sym; + tbase = t; + if(isptr[t->etype] && t->sym == S && t->type->sym != S) + tbase = t->type; + dupok = tbase->sym == S; if(compiling_runtime) { - if(t == types[t->etype]) + if(tbase == types[tbase->etype]) // int, float, etc goto ok; - if(t1 && t1 == types[t1->etype]) - goto ok; - if(t1 && t1->etype == tptr && t1->type->etype == TANY) + if(tbase->etype == tptr && tbase->type->etype == TANY) // unsafe.Pointer goto ok; } - // named types from other files are defined in those files - if(t->sym && !t->local) - return s; - if(!t->sym && t1 && t1->sym && !t1->local) + // named types from other files are defined only by those files + if(tbase->sym && !tbase->local) return s; - if(isforw[t->etype] || (t1 && isforw[t1->etype])) + if(isforw[tbase->etype]) return s; ok: @@ -778,6 +797,7 @@ ok: case TPTR32: case TPTR64: if(t->type->etype == TANY) { + // ../../pkg/runtime/type.go:/UnsafePointerType ot = dcommontype(s, ot, t); break; } @@ -818,7 +838,7 @@ ok: break; } - ggloblsym(s, ot, tsym == nil); + ggloblsym(s, ot, dupok); return s; } @@ -846,7 +866,7 @@ dumptypestructs(void) continue; t = n->type; dtypesym(t); - if(t->sym && !isptr[t->etype]) + if(t->sym) dtypesym(ptrto(t)); } diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 5783faafd..174bc050e 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -10,7 +10,7 @@ package PACKAGE // emitted by compiler, not referred to by go programs -func mal(int32) *any +func new(int32) *any func panicindex() func panicslice() func throwreturn() @@ -31,13 +31,18 @@ func printeface(any) func printslice(any) func printnl() func printsp() -func printf() +func goprintf() + +// filled in by compiler: int n, string, string, ... +func concatstring() + +// filled in by compiler: Type*, int n, Slice, ... +func append() +func appendslice(typ *byte, x any, y []any) any -func catstring(string, string) string func cmpstring(string, string) int func slicestring(string, int, int) string func slicestring1(string, int) string -func indexstring(string, int) byte func intstring(int64) string func slicebytetostring([]byte) string func sliceinttostring([]int) string @@ -46,6 +51,7 @@ func stringtosliceint(string) []int func stringiter(string, int) int func stringiter2(string, int) (retk int, retv int) func slicecopy(to any, fr any, wid uint32) int +func slicestringcopy(to any, fr any) int // interface conversions func convI2E(elem any) (ret any) @@ -99,9 +105,9 @@ func selectdefault(sel *byte) (selected bool) func selectgo(sel *byte) func makeslice(typ *byte, nel int64, cap int64) (ary []any) -func sliceslice1(old []any, lb int, width int) (ary []any) -func sliceslice(old []any, lb int, hb int, width int) (ary []any) -func slicearray(old *any, nel int, lb int, hb int, width int) (ary []any) +func sliceslice1(old []any, lb uint64, width uint64) (ary []any) +func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) +func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any) func closure() // has args, but compiler fills in @@ -111,6 +117,8 @@ func uint64div(uint64, uint64) uint64 func int64mod(int64, int64) int64 func uint64mod(uint64, uint64) uint64 func float64toint64(float64) int64 +func float64touint64(float64) uint64 func int64tofloat64(int64) float64 +func uint64tofloat64(uint64) float64 func complex128div(num complex128, den complex128) (quo complex128) diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 9cba01fa5..1a3771311 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -41,11 +41,18 @@ typecheckselect(Node *sel) setlineno(n); switch(n->op) { default: - yyerror("select case must be receive, send or assign recv");; + yyerror("select case must be receive, send or assign recv"); break; case OAS: // convert x = <-c into OSELRECV(x, c) + // assignment might have introduced a + // conversion. throw it away. + // it will come back when the select code + // gets generated, because it always assigns + // through a temporary. + if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit) + n->right = n->right->left; if(n->right->op != ORECV) { yyerror("select assignment must have receive on right hand side"); break; @@ -68,8 +75,6 @@ typecheckselect(Node *sel) typechecklist(ncase->nbody, Etop); } sel->xoffset = count; - if(count == 0) - yyerror("empty select"); lineno = lno; } @@ -91,7 +96,7 @@ walkselect(Node *sel) typecheck(&r, Etop); init = list(init, r); - if(sel->list == nil) + if(sel->list == nil && sel->xoffset != 0) fatal("double walkselect"); // already rewrote // register cases diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 5ac14a537..19ee3327b 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -92,15 +92,9 @@ init1(Node *n, NodeList **out) break; case OAS2FUNC: - if(n->defn->initorder) - break; - n->defn->initorder = 1; - for(l=n->defn->rlist; l; l=l->next) - init1(l->n, out); - *out = list(*out, n->defn); - break; - case OAS2MAPR: + case OAS2DOTTYPE: + case OAS2RECV: if(n->defn->initorder) break; n->defn->initorder = 1; @@ -190,6 +184,20 @@ static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init); static void slicelit(int ctxt, Node *n, Node *var, NodeList **init); static void maplit(int ctxt, Node *n, Node *var, NodeList **init); +static Node* +staticname(Type *t, int ctxt) +{ + Node *n; + + snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen); + statuniqgen++; + n = newname(lookup(namebuf)); + if(!ctxt) + n->readonly = 1; + addvar(n, t, PEXTERN); + return n; +} + static int isliteral(Node *n) { @@ -402,12 +410,12 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) if(ctxt != 0) { // put everything into static array - vstat = staticname(t); + vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); arraylit(ctxt, 2, n, vstat, init); // copy static to slice - a = nod(OADDR, vstat, N); + a = nod(OSLICE, vstat, nod(OKEY, N, N)); a = nod(OAS, var, a); typecheck(&a, Etop); a->dodata = 2; @@ -439,7 +447,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) vstat = N; mode = getdyn(n, 1); if(mode & MODECONST) { - vstat = staticname(t); + vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); } @@ -465,7 +473,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) } // make slice out of heap (5) - a = nod(OAS, var, vauto); + a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); @@ -514,6 +522,8 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init) Node *vstat, *index, *value; Sym *syma, *symb; +ctxt = 0; + // make the map var nerr = nerrors; @@ -566,7 +576,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init) dowidth(t); // make and initialize static array - vstat = staticname(t); + vstat = staticname(t, ctxt); b = 0; for(l=n->list; l; l=l->next) { r = l->n; @@ -675,7 +685,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(ctxt == 0) { // lay out static data - vstat = staticname(t); + vstat = staticname(t, ctxt); structlit(1, 1, n, vstat, init); // copy static to var @@ -715,7 +725,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(ctxt == 0) { // lay out static data - vstat = staticname(t); + vstat = staticname(t, ctxt); arraylit(1, 1, n, vstat, init); // copy static to automatic @@ -769,8 +779,8 @@ oaslit(Node *n, NodeList **init) // implies generated data executed // exactly once and not subject to races. ctxt = 0; - if(n->dodata == 1) - ctxt = 1; +// if(n->dodata == 1) +// ctxt = 1; switch(n->right->op) { default: @@ -870,8 +880,18 @@ gen_as_init(Node *n) default: goto no; - case OCONVSLICE: - goto slice; + case OCONVNOP: + nr = nr->left; + if(nr == N || nr->op != OSLICEARR) + goto no; + // fall through + + case OSLICEARR: + if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) { + nr = nr->left; + goto slice; + } + goto no; case OLITERAL: break; @@ -920,7 +940,7 @@ yes: slice: gused(N); // in case the data is the dest of a goto - nr = n->right->left; + nl = nr; if(nr == N || nr->op != OADDR) goto no; nr = nr->left; @@ -932,7 +952,7 @@ slice: goto no; nam.xoffset += Array_array; - gdata(&nam, n->right->left, types[tptr]->width); + gdata(&nam, nl, types[tptr]->width); nam.xoffset += Array_nel-Array_array; nodconst(&nod1, types[TINT32], nr->type->bound); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 65b56dee6..3c4501096 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -228,11 +228,15 @@ linehist(char *file, int32 off, int relative) if(debug['i']) { if(file != nil) { if(off < 0) - print("pragma %s at line %L\n", file, lineno); + print("pragma %s", file); else - print("import %s at line %L\n", file, lineno); + if(off > 0) + print("line %s", file); + else + print("import %s", file); } else - print("end of import at line %L\n", lineno); + print("end of import"); + print(" at line %L\n", lexlineno); } if(off < 0 && file[0] != '/' && !relative) { @@ -267,7 +271,6 @@ setlineno(Node *n) case OTYPE: case OPACK: case OLITERAL: - case ONONAME: break; default: lineno = n->lineno; @@ -360,6 +363,8 @@ importdot(Pkg *opkg, Node *pack) for(s = hash[h]; s != S; s = s->link) { if(s->pkg != opkg) continue; + if(s->def == N) + continue; if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot continue; s1 = lookup(s->name); @@ -473,9 +478,12 @@ algtype(Type *t) int a; if(issimple[t->etype] || isptr[t->etype] || iscomplex[t->etype] || - t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) - a = AMEM; // just bytes (int, ptr, etc) - else if(t->etype == TSTRING) + t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) { + if(t->width == widthptr) + a = AMEMWORD; + else + a = AMEM; // just bytes (int, ptr, etc) + } else if(t->etype == TSTRING) a = ASTRING; // string else if(isnilinter(t)) a = ANILINTER; // nil interface @@ -584,6 +592,21 @@ nodintconst(int64 v) return c; } +Node* +nodfltconst(Mpflt* v) +{ + Node *c; + + c = nod(OLITERAL, N, N); + c->addable = 1; + c->val.u.fval = mal(sizeof(*c->val.u.fval)); + mpmovefltflt(c->val.u.fval, v); + c->val.ctype = CTFLT; + c->type = types[TIDEAL]; + ullmancalc(c); + return c; +} + void nodconst(Node *n, Type *t, int64 v) { @@ -804,6 +827,7 @@ goopnames[] = [OANDAND] = "&&", [OANDNOT] = "&^", [OAND] = "&", + [OAPPEND] = "append", [OAS] = "=", [OAS2] = "=", [OBREAK] = "break", @@ -894,12 +918,21 @@ Lconv(Fmt *fp) if(lno < h->line) break; if(h->name) { - if(n < HISTSZ) { /* beginning of file */ - a[n].incl = h; - a[n].idel = h->line; - a[n].line = 0; + if(h->offset > 0) { + // #line directive + if(n > 0 && n < HISTSZ) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + // beginning of file + if(n < HISTSZ) { + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; } - n++; continue; } n--; @@ -919,14 +952,16 @@ Lconv(Fmt *fp) break; fmtprint(fp, " "); } + if(debug['L']) + fmtprint(fp, "%s/", pathname); if(a[i].line) - fmtprint(fp, "%s:%ld[%s:%ld]", + fmtprint(fp, "%s:%d[%s:%d]", a[i].line->name, lno-a[i].ldel+1, a[i].incl->name, lno-a[i].idel+1); else - fmtprint(fp, "%s:%ld", + fmtprint(fp, "%s:%d", a[i].incl->name, lno-a[i].idel+1); - lno = a[i].incl->line - 1; /* now print out start of this file */ + lno = a[i].incl->line - 1; // now print out start of this file } if(n == 0) fmtprint(fp, "<epoch>"); @@ -1003,10 +1038,10 @@ Jconv(Fmt *fp) fmtprint(fp, " a(%d)", n->addable); if(n->vargen != 0) - fmtprint(fp, " g(%ld)", n->vargen); + fmtprint(fp, " g(%d)", n->vargen); if(n->lineno != 0) - fmtprint(fp, " l(%ld)", n->lineno); + fmtprint(fp, " l(%d)", n->lineno); if(n->xoffset != 0) fmtprint(fp, " x(%lld)", n->xoffset); @@ -1029,6 +1064,9 @@ Jconv(Fmt *fp) if(n->isddd != 0) fmtprint(fp, " isddd(%d)", n->isddd); + if(n->implicit != 0) + fmtprint(fp, " implicit(%d)", n->implicit); + return 0; } @@ -1146,7 +1184,7 @@ Tpretty(Fmt *fp, Type *t) case Csend: return fmtprint(fp, "chan<- %T", t->type); } - if(t->type != T && t->type->etype == TCHAN && t->type->chan == Crecv) + if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv) return fmtprint(fp, "chan (%T)", t->type); return fmtprint(fp, "chan %T", t->type); @@ -1256,7 +1294,7 @@ Tpretty(Fmt *fp, Type *t) fmtprint(fp, "...%T", t->type->type); else fmtprint(fp, "%T", t->type); - if(t->note) { + if(t->note) { fmtprint(fp, " "); if(exporting) fmtprint(fp, ":"); @@ -1360,7 +1398,7 @@ Tconv(Fmt *fp) case TARRAY: if(t->bound >= 0) - fmtprint(fp, "[%ld]%T", t->bound, t->type); + fmtprint(fp, "[%d]%T", t->bound, t->type); else fmtprint(fp, "[]%T", t->type); break; @@ -1414,7 +1452,7 @@ Nconv(Fmt *fp) fmtprint(fp, "%O%J", n->op, n); break; } - fmtprint(fp, "%O-%S G%ld%J", n->op, + fmtprint(fp, "%O-%S G%d%J", n->op, n->sym, n->vargen, n); goto ptyp; @@ -1460,7 +1498,7 @@ Nconv(Fmt *fp) break; } if(n->sym != S) - fmtprint(fp, " %S G%ld", n->sym, n->vargen); + fmtprint(fp, " %S G%d", n->sym, n->vargen); ptyp: if(n->type != T) @@ -1909,13 +1947,6 @@ assignop(Type *src, Type *dst, char **why) // 7. Any typed value can be assigned to the blank identifier. if(dst->etype == TBLANK) return OCONVNOP; - - // 8. Array to slice. - // TODO(rsc): Not for long. - if(!src->sym || !dst->sym) - if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst)) - if(eqtype(src->type->type, dst->type)) - return OCONVSLICE; return 0; } @@ -2037,6 +2068,7 @@ assignconv(Node *n, Type *t, char *context) r = nod(op, n, N); r->type = t; r->typecheck = 1; + r->implicit = 1; return r; } @@ -2292,7 +2324,8 @@ ptrto(Type *t) fatal("ptrto: nil"); t1 = typ(tptr); t1->type = t; - t1->width = types[tptr]->width; + t1->width = widthptr; + t1->align = widthptr; return t1; } @@ -2320,7 +2353,7 @@ frame(int context) case ONAME: if(flag) print("--- %s frame ---\n", p); - print("%O %S G%ld %T\n", n->op, n->sym, n->vargen, n->type); + print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type); flag = 0; break; @@ -2584,20 +2617,8 @@ brrev(int a) return a; } -Node* -staticname(Type *t) -{ - Node *n; - - snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen); - statuniqgen++; - n = newname(lookup(namebuf)); - addvar(n, t, PEXTERN); - return n; -} - /* - * return side effect-free appending side effects to init. + * return side effect-free n, appending side effects to init. * result is assignable if n is. */ Node* @@ -2654,6 +2675,24 @@ safeexpr(Node *n, NodeList **init) // make a copy; must not be used as an lvalue if(islvalue(n)) fatal("missing lvalue case in safeexpr: %N", n); + return cheapexpr(n, init); +} + +/* + * return side-effect free and cheap n, appending side effects to init. + * result may not be assignable. + */ +Node* +cheapexpr(Node *n, NodeList **init) +{ + Node *a, *l; + + switch(n->op) { + case ONAME: + case OLITERAL: + return n; + } + l = nod(OXXX, N, N); tempname(l, n->type); a = nod(OAS, l, n); @@ -2939,6 +2978,11 @@ expandmeth(Sym *s, Type *t) if(t == T || t->xmethod != nil) return; + // mark top-level method symbols + // so that expand1 doesn't consider them. + for(f=t->method; f != nil; f=f->down) + f->sym->flags |= SymUniq; + // generate all reachable methods slist = nil; expand1(t, nelem(dotlist)-1, 0); @@ -2958,6 +3002,9 @@ expandmeth(Sym *s, Type *t) } } + for(f=t->method; f != nil; f=f->down) + f->sym->flags &= ~SymUniq; + t->xmethod = t->method; for(sl=slist; sl!=nil; sl=sl->link) { if(sl->good) { @@ -2969,7 +3016,6 @@ expandmeth(Sym *s, Type *t) f->embedded = 2; f->down = t->xmethod; t->xmethod = f; - } } } @@ -3031,15 +3077,19 @@ structargs(Type **tl, int mustname) * newnam - the eventual mangled name of this function */ void -genwrapper(Type *rcvr, Type *method, Sym *newnam) +genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) { - Node *this, *fn, *call, *n, *t; + Node *this, *fn, *call, *n, *t, *pad; NodeList *l, *args, *in, *out; + Type *tpad; + int isddd; if(debug['r']) print("genwrapper rcvrtype=%T method=%T newnam=%S\n", rcvr, method, newnam); + lineno = 1; // less confusing than end of input + dclcontext = PEXTERN; markdcl(); @@ -3050,20 +3100,37 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) fn = nod(ODCLFUNC, N, N); fn->nname = newname(newnam); - t = nod(OTFUNC, this, N); - t->list = in; + t = nod(OTFUNC, N, N); + l = list1(this); + if(iface && rcvr->width < types[tptr]->width) { + // Building method for interface table and receiver + // is smaller than the single pointer-sized word + // that the interface call will pass in. + // Add a dummy padding argument after the + // receiver to make up the difference. + tpad = typ(TARRAY); + tpad->type = types[TUINT8]; + tpad->bound = types[tptr]->width - rcvr->width; + pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad)); + l = list(l, pad); + } + t->list = concat(l, in); t->rlist = out; fn->nname->ntype = t; funchdr(fn); // arg list args = nil; - for(l=in; l; l=l->next) + isddd = 0; + for(l=in; l; l=l->next) { args = list(args, l->n->left); + isddd = l->n->left->isddd; + } // generate call call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N); call->list = args; + call->isddd = isddd; fn->nbody = list1(call); if(method->type->outtuple > 0) { n = nod(ORETURN, N, N); @@ -3563,10 +3630,11 @@ umagic(Magic *m) Sym* ngotype(Node *n) { - if(n->sym != S && strncmp(n->sym->name, "autotmp_", 8) != 0) - if(n->type->etype != TFUNC || n->type->thistuple == 0) - if(n->type->etype != TSTRUCT || n->type->funarg == 0) - return typename(n->type)->left->sym; + 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; + return S; } @@ -3640,4 +3708,3 @@ strlit(char *s) t->len = strlen(s); return t; } - diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 457b82b4c..ca114d47c 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -17,7 +17,8 @@ static void implicitstar(Node**); static int onearg(Node*, char*, ...); static int twoarg(Node*); static int lookdot(Node*, Type*, int); -static void typecheckaste(int, Type*, NodeList*, char*); +static int looktypedot(Node*, Type*, int); +static void typecheckaste(int, int, Type*, NodeList*, char*); static Type* lookdot1(Sym *s, Type *t, Type *f, int); static int nokeys(NodeList*); static void typecheckcomplit(Node**); @@ -63,7 +64,7 @@ typechecklist(NodeList *l, int top) Node* typecheck(Node **np, int top) { - int et, op, ptr; + int et, aop, op, ptr; Node *n, *l, *r; NodeList *args; int lno, ok, ntop; @@ -79,7 +80,7 @@ typecheck(Node **np, int top) n = *np; if(n == N) return N; - + // Resolve definition of name and value of iota lazily. n = resolve(n); *np = n; @@ -111,6 +112,7 @@ typecheck(Node **np, int top) goto error; } walkdef(n); + n->realtype = n->type; if(n->op == ONONAME) goto error; } @@ -169,6 +171,16 @@ reswitch: goto error; break; + case OTPAREN: + ok |= Etype; + l = typecheck(&n->left, Etype); + if(l->type == T) + goto error; + n->op = OTYPE; + n->type = l->type; + n->left = N; + break; + case OTARRAY: ok |= Etype; t = typ(TARRAY); @@ -251,7 +263,6 @@ reswitch: n->type = dostruct(n->list, TINTER); if(n->type == T) goto error; - n->type = sortinter(n->type); break; case OTFUNC: @@ -340,6 +351,26 @@ reswitch: et = t->etype; if(et == TIDEAL) et = TINT; + if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) { + // comparison is okay as long as one side is + // assignable to the other. convert so they have + // the same type. (the only conversion that isn't + // a no-op is concrete == interface.) + if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) { + l = nod(aop, l, N); + l->type = r->type; + l->typecheck = 1; + n->left = l; + t = l->type; + } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) { + r = nod(aop, r, N); + r->type = l->type; + r->typecheck = 1; + n->right = r; + t = r->type; + } + et = t->etype; + } if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { badbinary: defaultlit2(&l, &r, 1); @@ -393,7 +424,7 @@ reswitch: n->right = r; t = r->type; if(!isint[t->etype] || issigned[t->etype]) { - yyerror("invalid operation: %#N (shift count type %T)", n, r->type); + yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type); goto error; } t = l->type; @@ -467,41 +498,42 @@ reswitch: yyerror("rhs of . must be a name"); // impossible goto error; } - if(isptr[t->etype]) { - t = t->type; - if(t == T) - goto error; - n->op = ODOTPTR; - checkwidth(t); - } sym = n->right->sym; - if(!lookdot(n, t, 0)) { - if(lookdot(n, t, 1)) - yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym); - else - yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym); - goto error; - } if(l->op == OTYPE) { - if(n->type->etype != TFUNC || n->type->thistuple != 1) { - yyerror("type %T has no method %hS", n->left->type, sym); - n->type = T; + if(!looktypedot(n, t, 0)) { + if(looktypedot(n, t, 1)) + yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym); + else + yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym); goto error; } - if(t->etype == TINTER) { - yyerror("method expression on interface not implemented"); + if(n->type->etype != TFUNC || n->type->thistuple != 1) { + yyerror("type %T has no method %hS", n->left->type, sym); n->type = T; goto error; } n->op = ONAME; - n->sym = methodsym(sym, l->type); - n->type = methodfunc(n->type, 1); + n->sym = methodsym(sym, l->type, 0); + n->type = methodfunc(n->type, l->type); n->xoffset = 0; - getinargx(n->type)->type->type = l->type; // fix up receiver n->class = PFUNC; ok = Erv; goto ret; } + if(isptr[t->etype] && t->type->etype != TINTER) { + t = t->type; + if(t == T) + goto error; + n->op = ODOTPTR; + checkwidth(t); + } + if(!lookdot(n, t, 0)) { + if(lookdot(n, t, 1)) + yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym); + else + yyerror("%#N undefined (type %T has no field or method %S)", n, t, n->right->sym); + goto error; + } switch(n->op) { case ODOTINTER: case ODOTMETH: @@ -561,7 +593,7 @@ reswitch: goto error; case TARRAY: - defaultlit(&n->right, types[TUINT]); + defaultlit(&n->right, T); if(n->right->type != T && !isint[n->right->type->etype]) yyerror("non-integer array index %#N", n->right); n->type = t->type; @@ -581,7 +613,6 @@ reswitch: if(n->right->type != T && !isint[n->right->type->etype]) yyerror("non-integer string index %#N", n->right); n->type = types[TUINT8]; - n->op = OINDEXSTR; break; } goto ret; @@ -612,6 +643,10 @@ reswitch: l = n->left; if((t = l->type) == T) goto error; + if(t->etype != TCHAN) { + yyerror("invalid operation: %#N (send to non-chan type %T)", n, t); + goto error; + } if(!(t->chan & Csend)) { yyerror("invalid operation: %#N (send to receive-only type %T)", n, t); goto error; @@ -620,6 +655,7 @@ reswitch: r = n->right; if((t = r->type) == T) goto error; + r = assignconv(r, l->type->type, "send"); // TODO: more aggressive n->etype = 0; n->type = T; @@ -635,24 +671,19 @@ reswitch: typecheck(&n->right->left, Erv); typecheck(&n->right->right, Erv); defaultlit(&n->left, T); - defaultlit(&n->right->left, types[TUINT]); - defaultlit(&n->right->right, types[TUINT]); + defaultlit(&n->right->left, T); + defaultlit(&n->right->right, T); if(isfixedarray(n->left->type)) { - // Insert explicit & before fixed array - // so that back end knows to move to heap. n->left = nod(OADDR, n->left, N); typecheck(&n->left, top); } - implicitstar(&n->left); - if(n->right->left == N) { - yyerror("missing slice bounds?"); - goto error; - } - if((t = n->right->left->type) == T) - goto error; - if(!isint[t->etype]) { - yyerror("invalid slice index %#N (type %T)", n->right->left, t); - goto error; + if(n->right->left != N) { + if((t = n->right->left->type) == T) + goto error; + if(!isint[t->etype]) { + yyerror("invalid slice index %#N (type %T)", n->right->left, t); + goto error; + } } if(n->right->right != N) { if((t = n->right->right->type) == T) @@ -670,9 +701,9 @@ reswitch: n->op = OSLICESTR; goto ret; } - if(isfixedarray(t)) { + if(isptr[t->etype] && isfixedarray(t->type)) { n->type = typ(TARRAY); - n->type->type = t->type; + n->type->type = t->type->type; n->type->bound = -1; dowidth(n->type); n->op = OSLICEARR; @@ -690,13 +721,17 @@ reswitch: */ case OCALL: l = n->left; - if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) { + if(l->op == ONAME && (r = unsafenmagic(n)) != N) { + if(n->isddd) + yyerror("invalid use of ... with builtin %#N", l); n = r; goto reswitch; } typecheck(&n->left, Erv | Etype | Ecall); l = n->left; if(l->op == ONAME && l->etype != 0) { + if(n->isddd && l->etype != OAPPEND) + yyerror("invalid use of ... with builtin %#N", l); // builtin: OLEN, OCAP, etc. n->op = l->etype; n->left = n->right; @@ -706,6 +741,8 @@ reswitch: defaultlit(&n->left, T); l = n->left; if(l->op == OTYPE) { + if(n->isddd) + yyerror("invalid use of ... in type conversion", l); // pick off before type-checking arguments ok |= Erv; // turn CALL(type, arg) into CONV(arg) w/ type @@ -732,7 +769,7 @@ reswitch: case ODOTMETH: n->op = OCALLMETH; - typecheckaste(OCALL, getthisx(t), list1(l->left), "method receiver"); + typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver"); break; default: @@ -743,7 +780,7 @@ reswitch: } break; } - typecheckaste(OCALL, getinargx(t), n->list, "function argument"); + typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument"); ok |= Etop; if(t->outtuple == 0) goto ret; @@ -792,6 +829,12 @@ reswitch: case OIMAG: if(!iscomplex[t->etype]) goto badcall1; + if(isconst(l, CTCPLX)){ + if(n->op == OREAL) + n = nodfltconst(&l->val.u.cval->real); + else + n = nodfltconst(&l->val.u.cval->imag); + } n->type = types[cplxsubtype(t->etype)]; goto ret; } @@ -802,7 +845,7 @@ reswitch: nodconst(n, types[TINT], l->val.u.sval->len); break; case TARRAY: - if(t->bound >= 0) + if(t->bound >= 0 && l->op == ONAME) nodconst(n, types[TINT], t->bound); break; } @@ -868,6 +911,40 @@ reswitch: ok |= Etop; goto ret; + case OAPPEND: + ok |= Erv; + args = n->list; + if(args == nil) { + yyerror("missing arguments to append"); + goto error; + } + typechecklist(args, Erv); + if((t = args->n->type) == T) + goto error; + n->type = t; + if(!isslice(t)) { + yyerror("first argument to append must be slice; have %lT", t); + goto error; + } + if(n->isddd) { + if(args->next == nil) { + yyerror("cannot use ... on first argument to append"); + goto error; + } + if(args->next->next != nil) { + yyerror("too many arguments to append"); + goto error; + } + args->next->n = assignconv(args->next->n, t->orig, "append"); + goto ret; + } + for(args=args->next; args != nil; args=args->next) { + if(args->n->type == T) + continue; + args->n = assignconv(args->n, t->type, "append"); + } + goto ret; + case OCOPY: ok |= Etop|Erv; args = n->list; @@ -888,13 +965,18 @@ reswitch: goto error; defaultlit(&n->left, T); 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) || !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); else if(!isslice(n->left->type)) yyerror("first argument to copy should be slice; have %lT", n->left->type); else - yyerror("second argument to copy should be slice; have %lT", n->right->type); + yyerror("second argument to copy should be slice or string; have %lT", n->right->type); goto error; } if(!eqtype(n->left->type->type, n->right->type->type)) { @@ -1048,7 +1130,7 @@ reswitch: case OPRINT: case OPRINTN: ok |= Etop; - typechecklist(n->list, Erv); + typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape goto ret; case OPANIC: @@ -1056,7 +1138,7 @@ reswitch: if(onearg(n, "panic") < 0) goto error; typecheck(&n->left, Erv); - defaultlit(&n->left, T); + defaultlit(&n->left, types[TINTER]); if(n->left->type == T) goto error; goto ret; @@ -1129,9 +1211,13 @@ reswitch: case ORETURN: ok |= Etop; typechecklist(n->list, Erv | Efnstruct); + if(curfn == N) { + yyerror("return outside function"); + goto error; + } if(curfn->type->outnamed && n->list == nil) goto ret; - typecheckaste(ORETURN, getoutargx(curfn->type), n->list, "return argument"); + typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument"); goto ret; case OSELECT: @@ -1149,11 +1235,6 @@ reswitch: typecheckrange(n); goto ret; - case OTYPECASE: - ok |= Etop | Erv; - typecheck(&n->left, Erv); - goto ret; - case OTYPESW: yyerror("use of .(type) outside type switch"); goto error; @@ -1218,7 +1299,7 @@ ret: goto error; } if((ok & Ecall) && !(top & Ecall)) { - yyerror("must call %#N", n); + yyerror("method %#N is not an expression, must be called", n); goto error; } // TODO(rsc): simplify @@ -1257,7 +1338,7 @@ implicitstar(Node **nn) Type *t; Node *n; - // insert implicit * if needed + // insert implicit * if needed for fixed array n = *nn; t = n->type; if(t == T || !isptr[t->etype]) @@ -1347,6 +1428,57 @@ lookdot1(Sym *s, Type *t, Type *f, int dostrcmp) } static int +looktypedot(Node *n, Type *t, int dostrcmp) +{ + Type *f1, *f2, *tt; + Sym *s; + + s = n->right->sym; + + if(t->etype == TINTER) { + f1 = lookdot1(s, t, t->type, dostrcmp); + if(f1 == T) + return 0; + + if(f1->width == BADWIDTH) + fatal("lookdot badwidth %T %p", f1, f1); + n->right = methodname(n->right, t); + n->xoffset = f1->width; + n->type = f1->type; + n->op = ODOTINTER; + return 1; + } + + tt = t; + if(t->sym == S && isptr[t->etype]) + tt = t->type; + + f2 = methtype(tt); + if(f2 == T) + return 0; + + expandmeth(f2->sym, f2); + f2 = lookdot1(s, f2, f2->xmethod, dostrcmp); + if(f2 == T) + return 0; + + // disallow T.m if m requires *T receiver + if(isptr[getthisx(f2->type)->type->type->etype] + && !isptr[t->etype] + && f2->embedded != 2 + && !isifacemethod(f2->type)) { + yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name); + return 0; + } + + n->right = methodname(n->right, t); + n->xoffset = f2->width; + n->type = f2->type; + n->op = ODOTMETH; + return 1; +} + +static int lookdot(Node *n, Type *t, int dostrcmp) { Type *f1, *f2, *tt, *rcvr; @@ -1359,9 +1491,15 @@ lookdot(Node *n, Type *t, int dostrcmp) if(t->etype == TSTRUCT || t->etype == TINTER) f1 = lookdot1(s, t, t->type, dostrcmp); - f2 = methtype(n->left->type); - if(f2 != T) - f2 = lookdot1(s, f2, f2->method, dostrcmp); + f2 = T; + if(n->left->type == t || n->left->type->sym == S) { + f2 = methtype(t); + if(f2 != T) { + // Use f2->method, not f2->xmethod: adddot has + // already inserted all the necessary embedded dots. + f2 = lookdot1(s, f2, f2->method, dostrcmp); + } + } if(f1 != T) { if(f2 != T) @@ -1385,14 +1523,16 @@ lookdot(Node *n, Type *t, int dostrcmp) tt = n->left->type; dowidth(tt); rcvr = getthisx(f2->type)->type->type; - if(n->left->op != OTYPE && !eqtype(rcvr, tt)) { + if(!eqtype(rcvr, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { checklvalue(n->left, "call pointer method on"); addrescapes(n->left); n->left = nod(OADDR, n->left, N); + n->left->implicit = 1; typecheck(&n->left, Etype|Erv); } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) { n->left = nod(OIND, n->left, N); + n->left->implicit = 1; typecheck(&n->left, Etype|Erv); } else { // method is attached to wrong type? @@ -1422,7 +1562,7 @@ nokeys(NodeList *l) * typecheck assignment: type list = expression list */ static void -typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) +typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc) { Type *t, *tl, *tn; Node *n; @@ -1436,63 +1576,79 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) if(nl != nil && nl->next == nil && (n = nl->n)->type != T) if(n->type->etype == TSTRUCT && n->type->funarg) { - setlineno(n); tn = n->type->type; for(tl=tstruct->type; tl; tl=tl->down) { if(tl->isddd) { - for(; tn; tn=tn->down) + for(; tn; tn=tn->down) { + exportassignok(tn->type, desc); if(assignop(tn->type, tl->type->type, &why) == 0) yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); + } goto out; } - if(tn == T) { - yyerror("not enough arguments to %#O", op); - goto out; - } + if(tn == T) + goto notenough; + exportassignok(tn->type, desc); if(assignop(tn->type, tl->type, &why) == 0) yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); tn = tn->down; } if(tn != T) - yyerror("too many arguments to %#O", op); + goto toomany; goto out; } for(tl=tstruct->type; tl; tl=tl->down) { t = tl->type; if(tl->isddd) { - if(nl != nil && nl->n->isddd && !eqtype(nl->n->type, t)) { - // TODO(rsc): This is not actually illegal but will - // help catch bugs. - yyerror("cannot pass %+N as %T (... mismatch)", nl->n, tl); + if(nl != nil && nl->n->op == ONAME && nl->n->isddd && !isddd) { + // TODO(rsc): This is not actually illegal, but it will help catch bugs. + yyerror("to pass '%#N' as ...%T, use '%#N...'", nl->n, t->type, nl->n); + isddd = 1; } - if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t)) + if(isddd) { + if(nl == nil) + goto notenough; + if(nl->next != nil) + goto toomany; + n = nl->n; + setlineno(n); + if(n->type != T) + nl->n = assignconv(n, t, desc); goto out; + } for(; nl; nl=nl->next) { + n = nl->n; setlineno(nl->n); - defaultlit(&nl->n, t->type); - if(assignop(nl->n->type, t->type, &why) == 0) - yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why); + if(n->type != T) + nl->n = assignconv(n, t->type, desc); } goto out; } - if(nl == nil) { - yyerror("not enough arguments to %#O", op); - goto out; - } + if(nl == nil) + goto notenough; n = nl->n; - setlineno(nl->n); + setlineno(n); if(n->type != T) nl->n = assignconv(n, t, desc); nl = nl->next; } - if(nl != nil) { - yyerror("too many arguments to %#O", op); - goto out; - } + if(nl != nil) + goto toomany; + if(isddd) + yyerror("invalid use of ... in %#O", op); out: lineno = lno; + return; + +notenough: + yyerror("not enough arguments to %#O", op); + goto out; + +toomany: + yyerror("too many arguments to %#O", op); + goto out; } /* @@ -1658,23 +1814,103 @@ indexdup(Node *n, Node *hash[], ulong nhash) hash[h] = n; } +static int +prime(ulong h, ulong sr) +{ + ulong n; + + for(n=3; n<=sr; n+=2) + if(h%n == 0) + return 0; + return 1; +} + +static ulong +inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash) +{ + ulong h, sr; + NodeList *ll; + int i; + + // count the number of entries + h = 0; + for(ll=n->list; ll; ll=ll->next) + h++; + + // if the auto hash table is + // large enough use it. + if(h <= nautohash) { + *hash = autohash; + memset(*hash, 0, nautohash * sizeof(**hash)); + return nautohash; + } + + // make hash size odd and 12% larger than entries + h += h/8; + h |= 1; + + // calculate sqrt of h + sr = h/2; + for(i=0; i<5; i++) + sr = (sr + h/sr)/2; + + // check for primeality + while(!prime(h, sr)) + h += 2; + + // build and return a throw-away hash table + *hash = mal(h * sizeof(**hash)); + memset(*hash, 0, h * sizeof(**hash)); + return h; +} + static void typecheckcomplit(Node **np) { int bad, i, len, nerr; - Node *l, *n, *hash[101]; + Node *l, *n, **hash; NodeList *ll; - Type *t, *f; + Type *t, *f, *pushtype; Sym *s; + int32 lno; + ulong nhash; + Node *autohash[101]; n = *np; + lno = lineno; - memset(hash, 0, sizeof hash); + if(n->right == N) { + if(n->list != nil) + setlineno(n->list->n); + yyerror("missing type in composite literal"); + goto error; + } + setlineno(n->right); l = typecheck(&n->right /* sic */, Etype); if((t = l->type) == T) goto error; nerr = nerrors; + + // can omit type on composite literal values if the outer + // composite literal is array, slice, or map, and the + // element type is itself a struct, array, slice, or map. + pushtype = T; + if(t->etype == TARRAY || t->etype == TMAP) { + pushtype = t->type; + if(pushtype != T) { + switch(pushtype->etype) { + case TSTRUCT: + case TARRAY: + case TMAP: + break; + default: + pushtype = T; + break; + } + } + } + switch(t->etype) { default: yyerror("invalid type for composite literal: %T", t); @@ -1682,31 +1918,29 @@ typecheckcomplit(Node **np) break; case TARRAY: + nhash = inithash(n, &hash, autohash, nelem(autohash)); + len = 0; i = 0; for(ll=n->list; ll; ll=ll->next) { l = ll->n; - if(l->op == OKEY) { - typecheck(&l->left, Erv); - evconst(l->left); - i = nonnegconst(l->left); - if(i < 0) { - yyerror("array index must be non-negative integer constant"); - i = -(1<<30); // stay negative for a while - } - typecheck(&l->right, Erv); - defaultlit(&l->right, t->type); - l->right = assignconv(l->right, t->type, "array index"); - } else { - typecheck(&ll->n, Erv); - defaultlit(&ll->n, t->type); - ll->n = assignconv(ll->n, t->type, "array index"); - ll->n = nod(OKEY, nodintconst(i), ll->n); - ll->n->left->type = types[TINT]; - ll->n->left->typecheck = 1; + setlineno(l); + if(l->op != OKEY) { + l = nod(OKEY, nodintconst(i), l); + l->left->type = types[TINT]; + l->left->typecheck = 1; + ll->n = l; + } + + typecheck(&l->left, Erv); + evconst(l->left); + i = nonnegconst(l->left); + if(i < 0) { + yyerror("array index must be non-negative integer constant"); + i = -(1<<30); // stay negative for a while } if(i >= 0) - indexdup(ll->n->left, hash, nelem(hash)); + indexdup(l->left, hash, nhash); i++; if(i > len) { len = i; @@ -1716,6 +1950,12 @@ typecheckcomplit(Node **np) t->bound = -1; // no more errors } } + + if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) + l->right->right = typenod(pushtype); + typecheck(&l->right, Erv); + defaultlit(&l->right, t->type); + l->right = assignconv(l->right, t->type, "array index"); } if(t->bound == -100) t->bound = len; @@ -1725,20 +1965,27 @@ typecheckcomplit(Node **np) break; case TMAP: + nhash = inithash(n, &hash, autohash, nelem(autohash)); + for(ll=n->list; ll; ll=ll->next) { l = ll->n; + setlineno(l); if(l->op != OKEY) { typecheck(&ll->n, Erv); yyerror("missing key in map literal"); continue; } + typecheck(&l->left, Erv); - typecheck(&l->right, Erv); defaultlit(&l->left, t->down); - defaultlit(&l->right, t->type); l->left = assignconv(l->left, t->down, "map key"); + keydup(l->left, hash, nhash); + + if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) + l->right->right = typenod(pushtype); + typecheck(&l->right, Erv); + defaultlit(&l->right, t->type); l->right = assignconv(l->right, t->type, "map value"); - keydup(l->left, hash, nelem(hash)); } n->op = OMAPLIT; break; @@ -1749,6 +1996,7 @@ typecheckcomplit(Node **np) // simple list of variables f = t->type; for(ll=n->list; ll; ll=ll->next) { + setlineno(ll->n); typecheck(&ll->n, Erv); if(f == nil) { if(!bad++) @@ -1766,9 +2014,12 @@ typecheckcomplit(Node **np) if(f != nil) yyerror("too few values in struct initializer"); } else { + nhash = inithash(n, &hash, autohash, nelem(autohash)); + // keyed list for(ll=n->list; ll; ll=ll->next) { l = ll->n; + setlineno(l); if(l->op != OKEY) { if(!bad++) yyerror("mixture of field:value and value initializers"); @@ -1781,6 +2032,11 @@ typecheckcomplit(Node **np) typecheck(&l->right, Erv); continue; } + // Sym might have resolved to name in other top-level + // package, because of import dot. Redirect to correct sym + // before we do the lookup. + if(s->pkg != localpkg) + s = lookup(s->name); l->left = newname(s); l->left->typecheck = 1; f = lookdot1(s, t, t->type, 0); @@ -1790,7 +2046,7 @@ typecheckcomplit(Node **np) continue; } s = f->sym; - fielddup(newname(s), hash, nelem(hash)); + fielddup(newname(s), hash, nhash); l->right = assignconv(l->right, f->type, "field value"); } } @@ -1802,11 +2058,13 @@ typecheckcomplit(Node **np) n->type = t; *np = n; + lineno = lno; return; error: n->type = T; *np = n; + lineno = lno; } /* @@ -1890,6 +2148,8 @@ islvalue(Node *n) case OINDEX: if(isfixedarray(n->left->type)) return islvalue(n->left); + if(n->left->type != T && n->left->type->etype == TSTRING) + return 0; // fall through case OIND: case ODOTPTR: diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c index dbf6f708a..33f375631 100644 --- a/src/cmd/gc/unsafe.c +++ b/src/cmd/gc/unsafe.c @@ -11,13 +11,18 @@ * rewrite with a constant */ Node* -unsafenmagic(Node *fn, NodeList *args) +unsafenmagic(Node *nn) { Node *r, *n; Sym *s; Type *t, *tr; long v; Val val; + Node *fn; + NodeList *args; + + fn = nn->left; + args = nn->list; if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S) goto no; @@ -35,13 +40,14 @@ unsafenmagic(Node *fn, NodeList *args) defaultlit(&r, T); tr = r->type; if(tr == T) - goto no; + goto bad; v = tr->width; goto yes; } if(strcmp(s->name, "Offsetof") == 0) { + typecheck(&r, Erv); if(r->op != ODOT && r->op != ODOTPTR) - goto no; + goto bad; typecheck(&r, Erv); v = r->xoffset; goto yes; @@ -51,7 +57,7 @@ unsafenmagic(Node *fn, NodeList *args) defaultlit(&r, T); tr = r->type; if(tr == T) - goto no; + goto bad; // make struct { byte; T; } t = typ(TSTRUCT); @@ -70,9 +76,15 @@ unsafenmagic(Node *fn, NodeList *args) no: return N; +bad: + yyerror("invalid expression %#N", nn); + v = 0; + goto ret; + yes: if(args->next != nil) yyerror("extra arguments for %S", s); +ret: // any side effects disappear; ignore init val.ctype = CTINT; val.u.xval = mal(sizeof(*n->val.u.xval)); diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 4f59d5598..fa3e5d5e4 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -11,12 +11,14 @@ static Node* makenewvar(Type*, NodeList**, Node**); static Node* ascompatee1(int, Node*, Node*, NodeList**); static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); -static NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**); +static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**); static Node* convas(Node*, NodeList**); static void heapmoves(void); static NodeList* paramstoheap(Type **argin, int out); static NodeList* reorder1(NodeList*); static NodeList* reorder3(NodeList*); +static Node* addstr(Node*, NodeList**); +static Node* append(Node*, NodeList**); static NodeList* walkdefstack; @@ -134,6 +136,10 @@ walkdeftype(Node *n) n->diag = 1; goto ret; } + if(n->type == T) { + n->diag = 1; + goto ret; + } // copy new type and clear fields // that don't come along @@ -257,6 +263,10 @@ walkdef(Node *n) yyerror("const initializer must be constant"); goto ret; } + if(isconst(e, CTNIL)) { + yyerror("const initializer cannot be nil"); + goto ret; + } t = n->type; if(t != T) { convlit(&e, t); @@ -281,6 +291,13 @@ walkdef(Node *n) if(n->defn == N) { if(n->etype != 0) // like OPRINTN break; + if(nerrors > 0) { + // Can have undefined variables in x := foo + // that make x have an n->ndefn == nil. + // If there are other errors anyway, don't + // bother adding to the noise. + break; + } fatal("var without type, init: %S", n->sym); } if(n->defn->op == ONAME) { @@ -292,10 +309,14 @@ walkdef(Node *n) break; case OTYPE: + if(curfn) + defercheckwidth(); n->walkdef = 1; n->type = typ(TFORW); n->type->sym = n->sym; walkdeftype(n); + if(curfn) + resumecheckwidth(); break; case OPACK: @@ -354,7 +375,7 @@ walkstmt(Node **np) NodeList *init; NodeList *ll, *rl; int cl, lno; - Node *n; + Node *n, *f; n = *np; if(n == N) @@ -481,11 +502,19 @@ walkstmt(Node **np) n->list = nil; break; } + if(count(n->list) == 1 && count(rl) > 1) { + // OAS2FUNC in disguise + f = n->list->n; + if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER) + fatal("expected return of call, have %#N", f); + n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit)); + break; + } ll = ascompatee(n->op, rl, n->list, &n->ninit); n->list = reorder3(ll); break; } - ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit); + ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit); n->list = ll; break; @@ -542,6 +571,7 @@ walkexpr(Node **np, NodeList **init) NodeList *ll, *lr, *lpost; Type *t; int et; + int64 v, v1, v2, len; int32 lno; Node *n, *fn; char buf[100], *p; @@ -594,8 +624,6 @@ walkexpr(Node **np, NodeList **init) case OMINUS: case OPLUS: case OCOM: - case OLEN: - case OCAP: case OREAL: case OIMAG: case ODOT: @@ -606,13 +634,27 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); goto ret; + case OLEN: + case OCAP: + walkexpr(&n->left, init); + + // replace len(*[10]int) with 10. + // delayed until now to preserve side effects. + t = n->left->type; + if(isptr[t->etype]) + t = t->type; + if(isfixedarray(t)) { + safeexpr(n->left, init); + nodconst(n, n->type, t->bound); + n->typecheck = 1; + } + goto ret; + case OLSH: case ORSH: case OAND: case OOR: case OXOR: - case OANDAND: - case OOROR: case OSUB: case OMUL: case OEQ: @@ -626,6 +668,17 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); walkexpr(&n->right, init); goto ret; + + case OANDAND: + case OOROR: + walkexpr(&n->left, init); + // cannot put side effects from n->right on init, + // because they cannot run before n->left is checked. + // save elsewhere and store on the eventual n->right. + ll = nil; + walkexpr(&n->right, &ll); + n->right->ninit = concat(n->right->ninit, ll); + goto ret; case OPRINT: case OPRINTN: @@ -656,7 +709,7 @@ walkexpr(Node **np, NodeList **init) goto ret; walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, getinarg(t), n->list, 0, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); goto ret; @@ -666,7 +719,7 @@ walkexpr(Node **np, NodeList **init) goto ret; walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, getinarg(t), n->list, 0, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); if(isselect(n)) { // special prob with selectsend and selectrecv: @@ -676,7 +729,7 @@ walkexpr(Node **np, NodeList **init) Node *b; b = nodbool(0); typecheck(&b, Erv); - lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init); + lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init); n->list = concat(n->list, lr); } goto ret; @@ -687,8 +740,8 @@ walkexpr(Node **np, NodeList **init) goto ret; walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, getinarg(t), n->list, 0, init); - lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init); + ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init); + lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); ll = concat(ll, lr); n->left->left = N; ullmancalc(n->left); @@ -882,43 +935,55 @@ walkexpr(Node **np, NodeList **init) case OCONV: case OCONVNOP: if(thechar == '5') { - if(isfloat[n->left->type->etype] && - (n->type->etype == TINT64 || n->type->etype == TUINT64)) { - n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64])); - goto ret; + if(isfloat[n->left->type->etype]) { + if(n->type->etype == TINT64) { + n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64])); + goto ret; + } + if(n->type->etype == TUINT64) { + n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64])); + goto ret; + } } - if((n->left->type->etype == TINT64 || n->left->type->etype == TUINT64) && - isfloat[n->type->etype]) { - n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64])); - goto ret; + if(isfloat[n->type->etype]) { + if(n->left->type->etype == TINT64) { + n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64])); + goto ret; + } + if(n->left->type->etype == TUINT64) { + n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64])); + goto ret; + } } } walkexpr(&n->left, init); goto ret; case OASOP: - n->left = safeexpr(n->left, init); - walkexpr(&n->left, init); - l = n->left; - walkexpr(&n->right, init); if(n->etype == OANDNOT) { n->etype = OAND; n->right = nod(OCOM, n->right, N); typecheck(&n->right, Erv); } + n->left = safeexpr(n->left, init); + walkexpr(&n->left, init); + l = n->left; + walkexpr(&n->right, init); /* * on 32-bit arch, rewrite 64-bit ops into l = l op r. * on 386, rewrite float ops into l = l op r. * everywhere, rewrite map ops into l = l op r. * everywhere, rewrite string += into l = l op r. + * everywhere, rewrite complex /= into l = l op r. * TODO(rsc): Maybe this rewrite should be done always? */ et = n->left->type->etype; if((widthptr == 4 && (et == TUINT64 || et == TINT64)) || (thechar == '8' && isfloat[et]) || l->op == OINDEXMAP || - et == TSTRING) { + et == TSTRING || + (iscomplex[et] && n->etype == ODIV)) { l = safeexpr(n->left, init); a = l; if(a->op == OINDEXMAP) { @@ -952,9 +1017,11 @@ walkexpr(Node **np, NodeList **init) */ et = n->left->type->etype; if(iscomplex[et] && n->op == ODIV) { - n = mkcall("complex128div", n->type, init, + t = n->type; + n = mkcall("complex128div", types[TCOMPLEX128], init, conv(n->left, types[TCOMPLEX128]), conv(n->right, types[TCOMPLEX128])); + n = conv(n, t); goto ret; } /* @@ -981,11 +1048,36 @@ walkexpr(Node **np, NodeList **init) // if range of type cannot exceed static array bound, // disable bounds check - if(!isslice(n->left->type)) + if(isfixedarray(n->left->type)) if(n->right->type->width < 4) if((1<<(8*n->right->type->width)) <= n->left->type->bound) n->etype = 1; + if(isconst(n->left, CTSTR)) + if(n->right->type->width < 4) + if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len) + n->etype = 1; + + // check for static out of bounds + if(isconst(n->right, CTINT) && !n->etype) { + v = mpgetfix(n->right->val.u.xval); + len = 1LL<<60; + t = n->left->type; + if(isconst(n->left, CTSTR)) + len = n->left->val.u.sval->len; + if(t != T && isptr[t->etype]) + t = t->type; + if(isfixedarray(t)) + len = t->bound; + if(v < 0 || v >= (1LL<<31) || v >= len) + yyerror("index out of bounds"); + else if(isconst(n->left, CTSTR)) { + // replace "abc"[2] with 'b'. + // delayed until now because "abc"[2] is not + // an ideal constant. + nodconst(n, n->type, n->left->val.u.sval->s[v]); + } + } goto ret; case OINDEXMAP: @@ -1002,24 +1094,61 @@ walkexpr(Node **np, NodeList **init) goto ret; case OSLICE: + case OSLICEARR: walkexpr(&n->left, init); n->left = safeexpr(n->left, init); walkexpr(&n->right->left, init); n->right->left = safeexpr(n->right->left, init); walkexpr(&n->right->right, init); n->right->right = safeexpr(n->right->right, init); + + len = 1LL<<60; + t = n->left->type; + if(t != T && isptr[t->etype]) + t = t->type; + if(isfixedarray(t)) + len = t->bound; + + // check for static out of bounds + // NOTE: v > len not v >= len. + v1 = -1; + v2 = -1; + if(isconst(n->right->left, CTINT)) { + v1 = mpgetfix(n->right->left->val.u.xval); + if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) { + yyerror("slice index out of bounds"); + v1 = -1; + } + } + if(isconst(n->right->right, CTINT)) { + v2 = mpgetfix(n->right->right->val.u.xval); + if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) { + yyerror("slice index out of bounds"); + v2 = -1; + } + } + if(v1 >= 0 && v2 >= 0 && v1 > v2) + yyerror("inverted slice range"); + + if(n->op == OSLICEARR) + goto slicearray; + // dynamic slice - // sliceslice(old []any, lb int, hb int, width int) (ary []any) - // sliceslice1(old []any, lb int, width int) (ary []any) + // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) + // sliceslice1(old []any, lb uint64, width uint64) (ary []any) t = n->type; + if(n->right->left == N) + l = nodintconst(0); + else + l = conv(n->right->left, types[TUINT64]); if(n->right->right != N) { fn = syslook("sliceslice", 1); argtype(fn, t->type); // any-1 argtype(fn, t->type); // any-2 n = mkcall1(fn, t, init, n->left, - conv(n->right->left, types[TINT]), - conv(n->right->right, types[TINT]), + l, + conv(n->right->right, types[TUINT64]), nodintconst(t->type->width)); } else { fn = syslook("sliceslice1", 1); @@ -1027,47 +1156,33 @@ walkexpr(Node **np, NodeList **init) argtype(fn, t->type); // any-2 n = mkcall1(fn, t, init, n->left, - conv(n->right->left, types[TINT]), + l, nodintconst(t->type->width)); } goto ret; - case OSLICEARR: - walkexpr(&n->left, init); - n->left = safeexpr(n->left, init); - walkexpr(&n->right->left, init); - n->right->left = safeexpr(n->right->left, init); - walkexpr(&n->right->right, init); - n->right->right = safeexpr(n->right->right, init); + slicearray: // static slice - // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any) + // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any) t = n->type; fn = syslook("slicearray", 1); - argtype(fn, n->left->type); // any-1 + argtype(fn, n->left->type->type); // any-1 argtype(fn, t->type); // any-2 + if(n->right->left == N) + l = nodintconst(0); + else + l = conv(n->right->left, types[TUINT64]); if(n->right->right == N) - r = nodintconst(n->left->type->bound); + r = nodintconst(n->left->type->type->bound); else - r = conv(n->right->right, types[TINT]); + r = conv(n->right->right, types[TUINT64]); n = mkcall1(fn, t, init, - nod(OADDR, n->left, N), nodintconst(n->left->type->bound), - conv(n->right->left, types[TINT]), + n->left, nodintconst(n->left->type->type->bound), + l, r, nodintconst(t->type->width)); goto ret; - case OCONVSLICE: - // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any) - fn = syslook("slicearray", 1); - argtype(fn, n->left->type->type); // any-1 - argtype(fn, n->type->type); // any-2 - n = mkcall1(fn, n->type, init, n->left, - nodintconst(n->left->type->type->bound), - nodintconst(0), - nodintconst(n->left->type->type->bound), - nodintconst(n->type->type->width)); - goto ret; - case OADDR:; Node *nvar, *nstar; @@ -1118,46 +1233,62 @@ walkexpr(Node **np, NodeList **init) goto ret; } + // prepare for rewrite below + if(n->etype == OEQ || n->etype == ONE) { + n->left = cheapexpr(n->left, init); + n->right = cheapexpr(n->right, init); + } + // sys_cmpstring(s1, s2) :: 0 r = mkcall("cmpstring", types[TINT], init, conv(n->left, types[TSTRING]), conv(n->right, types[TSTRING])); r = nod(n->etype, r, nodintconst(0)); + + // quick check of len before full compare for == or != + if(n->etype == OEQ || n->etype == ONE) { + if(n->etype == OEQ) + r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); + else + r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); + typecheck(&r, Erv); + walkexpr(&r, nil); + } typecheck(&r, Erv); n = r; goto ret; case OADDSTR: - // sys_catstring(s1, s2) - n = mkcall("catstring", n->type, init, - conv(n->left, types[TSTRING]), - conv(n->right, types[TSTRING])); + n = addstr(n, init); goto ret; case OSLICESTR: // sys_slicestring(s, lb, hb) + if(n->right->left == N) + l = nodintconst(0); + else + l = conv(n->right->left, types[TINT]); if(n->right->right) { n = mkcall("slicestring", n->type, init, conv(n->left, types[TSTRING]), - conv(n->right->left, types[TINT]), + l, conv(n->right->right, types[TINT])); } else { n = mkcall("slicestring1", n->type, init, conv(n->left, types[TSTRING]), - conv(n->right->left, types[TINT])); + l); } goto ret; - - case OINDEXSTR: - // TODO(rsc): should be done in back end - // sys_indexstring(s, i) - n = mkcall("indexstring", n->type, init, - conv(n->left, types[TSTRING]), - conv(n->right, types[TINT])); + + case OAPPEND: + n = append(n, init); goto ret; case OCOPY: - fn = syslook("slicecopy", 1); + if(n->right->type->etype == TSTRING) + fn = syslook("slicestringcopy", 1); + else + fn = syslook("slicecopy", 1); argtype(fn, n->left->type); argtype(fn, n->right->type); n = mkcall1(fn, n->type, init, @@ -1441,47 +1572,51 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init) /* * helpers for shape errors */ -static void +static char* dumptypes(Type **nl, char *what) { int first; Type *l; Iter savel; + Fmt fmt; + fmtstrinit(&fmt); + fmtprint(&fmt, "\t"); l = structfirst(&savel, nl); - print("\t"); first = 1; for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) { if(first) first = 0; else - print(", "); - print("%T", l); + fmtprint(&fmt, ", "); + fmtprint(&fmt, "%T", l); } if(first) - print("[no arguments %s]", what); - print("\n"); + fmtprint(&fmt, "[no arguments %s]", what); + return fmtstrflush(&fmt); } -static void +static char* dumpnodetypes(NodeList *l, char *what) { int first; Node *r; + Fmt fmt; - print("\t"); + fmtstrinit(&fmt); + fmtprint(&fmt, "\t"); first = 1; for(; l; l=l->next) { r = l->n; if(first) first = 0; else - print(", "); - print("%T", r->type); + fmtprint(&fmt, ", "); + fmtprint(&fmt, "%T", r->type); } if(first) - print("[no arguments %s]", what); - print("\n"); + fmtprint(&fmt, "[no arguments %s]", what); + return fmtstrflush(&fmt); } /* @@ -1491,12 +1626,13 @@ dumpnodetypes(NodeList *l, char *what) * func(expr-list) */ static NodeList* -ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init) +ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) { Type *l, *ll; Node *r, *a; NodeList *nn, *lr0, *alist; Iter savel; + char *l1, *l2; lr0 = lr; l = structfirst(&savel, nl); @@ -1545,7 +1681,7 @@ loop: // only if we are assigning a single ddd // argument to a ddd parameter then it is // passed thru unencapsulated - if(r != N && lr->next == nil && r->isddd && eqtype(l->type, r->type)) { + if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) { a = nod(OAS, nodarg(l, fp), r); a = convas(a, init); nn = list(nn, a); @@ -1561,12 +1697,12 @@ loop: if(l == T || r == N) { if(l != T || r != N) { + l1 = dumptypes(nl, "expected"); + l2 = dumpnodetypes(lr0, "given"); if(l != T) - yyerror("not enough arguments to %O", op); + yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2); else - yyerror("too many arguments to %O", op); - dumptypes(nl, "expected"); - dumpnodetypes(lr0, "given"); + yyerror("too many arguments to %O\n%s\n%s", op, l1, l2); } goto ret; } @@ -1740,7 +1876,7 @@ walkprint(Node *nn, NodeList **init, int defer) if(defer) { if(op == OPRINTN) fmtprint(&fmt, "\n"); - on = syslook("printf", 1); + on = syslook("goprintf", 1); on->type = functype(nil, intypes, nil); args->n = nod(OLITERAL, N, N); args->n->val.ctype = CTSTR; @@ -1769,7 +1905,7 @@ callnew(Type *t) Node *fn; dowidth(t); - fn = syslook("mal", 1); + fn = syslook("new", 1); argtype(fn, t); return mkcall1(fn, ptrto(t), nil, nodintconst(t->width)); } @@ -2046,12 +2182,17 @@ static void heapmoves(void) { NodeList *nn; - + int32 lno; + + lno = lineno; + lineno = curfn->lineno; nn = paramstoheap(getthis(curfn->type), 0); nn = concat(nn, paramstoheap(getinarg(curfn->type), 0)); nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1)); curfn->enter = concat(curfn->enter, nn); + lineno = curfn->endlineno; curfn->exit = returnsfromheap(getoutarg(curfn->type)); + lineno = lno; } static Node* @@ -2143,3 +2284,83 @@ mapfn(char *name, Type *t) argtype(fn, t->type); return fn; } + +static Node* +addstr(Node *n, NodeList **init) +{ + Node *r, *cat, *typstr; + NodeList *in, *args; + int i, count; + + count = 0; + for(r=n; r->op == OADDSTR; r=r->left) + count++; // r->right + count++; // r + + // prepare call of runtime.catstring of type int, string, string, string + // with as many strings as we have. + cat = syslook("concatstring", 1); + cat->type = T; + cat->ntype = nod(OTFUNC, N, N); + in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count + typstr = typenod(types[TSTRING]); + for(i=0; i<count; i++) + in = list(in, nod(ODCLFIELD, N, typstr)); + cat->ntype->list = in; + cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr)); + + args = nil; + for(r=n; r->op == OADDSTR; r=r->left) + args = concat(list1(conv(r->right, types[TSTRING])), args); + args = concat(list1(conv(r, types[TSTRING])), args); + args = concat(list1(nodintconst(count)), args); + + r = nod(OCALL, cat, N); + r->list = args; + typecheck(&r, Erv); + walkexpr(&r, init); + r->type = n->type; + + return r; +} + +static Node* +append(Node *n, NodeList **init) +{ + int i, j; + Node *f, *r; + NodeList *in, *args; + + if(n->isddd) { + f = syslook("appendslice", 1); + argtype(f, n->type); + argtype(f, n->type->type); + argtype(f, n->type); + r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n); + return r; + } + + j = count(n->list) - 1; + f = syslook("append", 1); + f->type = T; + f->ntype = nod(OTFUNC, N, N); + in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type + in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count + in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice + for(i=0; i<j; i++) + in = list(in, nod(ODCLFIELD, N, typenod(n->type->type))); + f->ntype->list = in; + f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type))); + + args = list1(typename(n->type)); + args = list(args, nodintconst(j)); + args = concat(args, n->list); + + r = nod(OCALL, f, N); + r->list = args; + typecheck(&r, Erv); + walkexpr(&r, init); + r->type = n->type; + + return r; +} |