summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/Makefile23
-rw-r--r--src/cmd/gc/align.c76
-rw-r--r--src/cmd/gc/builtin.c.boot18
-rw-r--r--src/cmd/gc/closure.c2
-rw-r--r--src/cmd/gc/const.c22
-rw-r--r--src/cmd/gc/dcl.c20
-rw-r--r--src/cmd/gc/doc.go9
-rw-r--r--src/cmd/gc/export.c3
-rw-r--r--src/cmd/gc/gen.c20
-rw-r--r--src/cmd/gc/go.errors9
-rw-r--r--src/cmd/gc/go.h48
-rw-r--r--src/cmd/gc/go.y174
-rw-r--r--src/cmd/gc/lex.c203
-rwxr-xr-xsrc/cmd/gc/mkbuiltin8
-rw-r--r--src/cmd/gc/mparith1.c42
-rw-r--r--src/cmd/gc/mparith2.c8
-rw-r--r--src/cmd/gc/mparith3.c30
-rw-r--r--src/cmd/gc/obj.c107
-rw-r--r--src/cmd/gc/print.c61
-rw-r--r--src/cmd/gc/range.c17
-rw-r--r--src/cmd/gc/reflect.c116
-rw-r--r--src/cmd/gc/runtime.go22
-rw-r--r--src/cmd/gc/select.c13
-rw-r--r--src/cmd/gc/sinit.c62
-rw-r--r--src/cmd/gc/subr.c177
-rw-r--r--src/cmd/gc/typecheck.c490
-rw-r--r--src/cmd/gc/unsafe.c20
-rw-r--r--src/cmd/gc/walk.c405
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;
+}