summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-02-14 13:23:51 +0100
committerOndřej Surý <ondrej@sury.org>2011-02-14 13:23:51 +0100
commit758ff64c69e34965f8af5b2d6ffd65e8d7ab2150 (patch)
tree6d6b34f8c678862fe9b56c945a7b63f68502c245 /src/cmd/gc
parent3e45412327a2654a77944249962b3652e6142299 (diff)
downloadgolang-758ff64c69e34965f8af5b2d6ffd65e8d7ab2150.tar.gz
Imported Upstream version 2011-02-01.1upstream/2011-02-01.1
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/align.c2
-rw-r--r--src/cmd/gc/builtin.c.boot6
-rw-r--r--src/cmd/gc/const.c12
-rw-r--r--src/cmd/gc/cplx.c6
-rw-r--r--src/cmd/gc/go.h8
-rw-r--r--src/cmd/gc/go.y15
-rw-r--r--src/cmd/gc/lex.c2
-rw-r--r--src/cmd/gc/print.c5
-rw-r--r--src/cmd/gc/range.c13
-rw-r--r--src/cmd/gc/reflect.c7
-rw-r--r--src/cmd/gc/runtime.go7
-rw-r--r--src/cmd/gc/select.c217
-rw-r--r--src/cmd/gc/sinit.c4
-rw-r--r--src/cmd/gc/subr.c8
-rw-r--r--src/cmd/gc/typecheck.c113
-rw-r--r--src/cmd/gc/walk.c24
16 files changed, 314 insertions, 135 deletions
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index a3785e871..ed20e7e8b 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -412,11 +412,9 @@ typeinit(void)
isfloat[TFLOAT32] = 1;
isfloat[TFLOAT64] = 1;
- isfloat[TFLOAT] = 1;
iscomplex[TCOMPLEX64] = 1;
iscomplex[TCOMPLEX128] = 1;
- iscomplex[TCOMPLEX] = 1;
isptr[TPTR32] = 1;
isptr[TPTR64] = 1;
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 380abc642..48f45293f 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -66,16 +66,18 @@ char *runtimeimport =
"func \"\".mapiter2 (hiter *any) (key any, val any)\n"
"func \"\".makechan (elem *uint8, hint int64) chan any\n"
"func \"\".chanrecv1 (hchan <-chan any) any\n"
- "func \"\".chanrecv2 (hchan <-chan any) (elem any, pres bool)\n"
+ "func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n"
"func \"\".chansend1 (hchan chan<- any, elem any)\n"
- "func \"\".chansend2 (hchan chan<- any, elem any) bool\n"
"func \"\".closechan (hchan any)\n"
"func \"\".closedchan (hchan any) bool\n"
+ "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
+ "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
"func \"\".newselect (size int) *uint8\n"
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
"func \"\".selectdefault (sel *uint8) bool\n"
"func \"\".selectgo (sel *uint8)\n"
+ "func \"\".block ()\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
"func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
"func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 72e67a634..0ee693c02 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -980,10 +980,10 @@ defaultlit(Node **np, Type *t)
n->type = types[TINT];
goto num;
case CTFLT:
- n->type = types[TFLOAT];
+ n->type = types[TFLOAT64];
goto num;
case CTCPLX:
- n->type = types[TCOMPLEX];
+ n->type = types[TCOMPLEX128];
goto num;
num:
if(t != T) {
@@ -1034,13 +1034,13 @@ defaultlit2(Node **lp, Node **rp, int force)
if(!force)
return;
if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
- convlit(lp, types[TCOMPLEX]);
- convlit(rp, types[TCOMPLEX]);
+ convlit(lp, types[TCOMPLEX128]);
+ convlit(rp, types[TCOMPLEX128]);
return;
}
if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
- convlit(lp, types[TFLOAT]);
- convlit(rp, types[TFLOAT]);
+ convlit(lp, types[TFLOAT64]);
+ convlit(rp, types[TFLOAT64]);
return;
}
convlit(lp, types[TINT]);
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
index e25f3cabb..3ec9fe5a2 100644
--- a/src/cmd/gc/cplx.c
+++ b/src/cmd/gc/cplx.c
@@ -84,7 +84,7 @@ maybe:
case OSUB:
case OMUL:
case OMINUS:
- case OCMPLX:
+ case OCOMPLEX:
case OREAL:
case OIMAG:
goto yes;
@@ -120,7 +120,7 @@ complexgen(Node *n, Node *res)
// pick off float/complex opcodes
switch(n->op) {
- case OCMPLX:
+ case OCOMPLEX:
if(res->addable) {
subnode(&n1, &n2, res);
tempname(&tmp, n1.type);
@@ -195,7 +195,7 @@ complexgen(Node *n, Node *res)
case OSUB:
case OMUL:
case OMINUS:
- case OCMPLX:
+ case OCOMPLEX:
case OREAL:
case OIMAG:
break;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 73ea5b976..bf84c12a1 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -356,7 +356,7 @@ enum
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
- OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
+ OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,
@@ -383,14 +383,14 @@ enum
ONOT, OCOM, OPLUS, OMINUS,
OOROR,
OPANIC, OPRINT, OPRINTN,
- OSEND, OSENDNB,
+ OSEND,
OSLICE, OSLICEARR, OSLICESTR,
ORECOVER,
ORECV,
ORUNESTR,
OSELRECV,
OIOTA,
- OREAL, OIMAG, OCMPLX,
+ OREAL, OIMAG, OCOMPLEX,
// stmts
OBLOCK,
@@ -440,11 +440,9 @@ enum
TCOMPLEX64, // 12
TCOMPLEX128,
- TCOMPLEX,
TFLOAT32, // 15
TFLOAT64,
- TFLOAT,
TBOOL, // 18
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 917265758..994840ee8 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -93,9 +93,10 @@ static void fixlbrace(int);
%type <type> hidden_type_func
%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
+%left LCOMM /* outside the usual hierarchy; here for good error messages */
+
%left LOROR
%left LANDAND
-%left LCOMM
%left LEQ LNE LLE LGE LLT LGT
%left '+' '-' '|' '^'
%left '*' '/' '%' '&' LLSH LRSH LANDNOT
@@ -421,11 +422,18 @@ simple_stmt:
| expr_list LCOLAS expr_list
{
if($3->n->op == OTYPESW) {
+ Node *n;
+
+ n = N;
if($3->next != nil)
yyerror("expr.(type) must be alone in list");
- else if($1->next != nil)
+ if($1->next != nil)
yyerror("argument count mismatch: %d = %d", count($1), 1);
- $$ = nod(OTYPESW, $1->n, $3->n->right);
+ else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
+ yyerror("invalid variable name %#N in type switch", $1->n);
+ else
+ n = $1->n;
+ $$ = nod(OTYPESW, n, $3->n->right);
break;
}
$$ = colas($1, $3);
@@ -764,6 +772,7 @@ expr:
{
$$ = nod(ORSH, $1, $3);
}
+ /* not an expression anymore, but left in so we can give a good error */
| expr LCOMM expr
{
$$ = nod(OSEND, $1, $3);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 0f1acd2fc..45b1257fa 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1531,7 +1531,7 @@ static struct
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
- "cmplx", LNAME, Txxx, OCMPLX,
+ "complex", LNAME, Txxx, OCOMPLEX,
"copy", LNAME, Txxx, OCOPY,
"imag", LNAME, Txxx, OIMAG,
"len", LNAME, Txxx, OLEN,
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index 6bb1f026b..695a5a397 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -48,6 +48,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODOTMETH:
case ODOTTYPE:
case ODOTTYPE2:
+ case OXDOT:
case OARRAYBYTESTR:
case OCAP:
case OCLOSE:
@@ -365,8 +366,8 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, ")");
break;
- case OCMPLX:
- fmtprint(f, "cmplx(");
+ case OCOMPLEX:
+ fmtprint(f, "complex(");
exprfmt(f, n->left, 0);
fmtprint(f, ", ");
exprfmt(f, n->right, 0);
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index dca3a5454..4ee8f39a7 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -93,6 +93,7 @@ walkrange(Node *n)
Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
Node *ha, *hit; // hidden aggregate, iterator
Node *hn, *hp; // hidden len, pointer
+ Node *hb; // hidden bool
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn, *tmp;
NodeList *body, *init;
@@ -199,9 +200,15 @@ walkrange(Node *n)
case TCHAN:
hv1 = nod(OXXX, N, n);
tempname(hv1, t->type);
-
- n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
- n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
+ hb = nod(OXXX, N, N);
+ tempname(hb, types[TBOOL]);
+
+ n->ntest = nod(ONOT, hb, N);
+ a = nod(OAS2RECVCLOSED, N, N);
+ a->typecheck = 1;
+ a->list = list(list1(hv1), hb);
+ a->rlist = list1(nod(ORECV, ha, N));
+ n->ntest->ninit = list1(a);
body = list1(nod(OAS, v1, hv1));
break;
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index b31eb5154..36c245d47 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -419,10 +419,8 @@ enum {
KindUint32,
KindUint64,
KindUintptr,
- KindFloat,
KindFloat32,
KindFloat64,
- KindComplex,
KindComplex64,
KindComplex128,
KindArray,
@@ -453,7 +451,6 @@ kinds[] =
[TINT64] = KindInt64,
[TUINT64] = KindUint64,
[TUINTPTR] = KindUintptr,
- [TFLOAT] = KindFloat,
[TFLOAT32] = KindFloat32,
[TFLOAT64] = KindFloat64,
[TBOOL] = KindBool,
@@ -466,7 +463,6 @@ kinds[] =
[TMAP] = KindMap,
[TARRAY] = KindArray,
[TFUNC] = KindFunc,
- [TCOMPLEX] = KindComplex,
[TCOMPLEX64] = KindComplex64,
[TCOMPLEX128] = KindComplex128,
};
@@ -485,10 +481,8 @@ structnames[] =
[TINT64] = "*runtime.IntType",
[TUINT64] = "*runtime.UintType",
[TUINTPTR] = "*runtime.UintType",
- [TCOMPLEX] = "*runtime.ComplexType",
[TCOMPLEX64] = "*runtime.ComplexType",
[TCOMPLEX128] = "*runtime.ComplexType",
- [TFLOAT] = "*runtime.FloatType",
[TFLOAT32] = "*runtime.FloatType",
[TFLOAT64] = "*runtime.FloatType",
[TBOOL] = "*runtime.BoolType",
@@ -542,7 +536,6 @@ haspointers(Type *t)
case TINT64:
case TUINT64:
case TUINTPTR:
- case TFLOAT:
case TFLOAT32:
case TFLOAT64:
case TBOOL:
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 174bc050e..bf7d045c0 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -92,17 +92,20 @@ func mapiter2(hiter *any) (key any, val any)
// *byte is really *runtime.Type
func makechan(elem *byte, hint int64) (hchan chan any)
func chanrecv1(hchan <-chan any) (elem any)
-func chanrecv2(hchan <-chan any) (elem any, pres bool)
+func chanrecv3(hchan <-chan any) (elem any, closed bool)
func chansend1(hchan chan<- any, elem any)
-func chansend2(hchan chan<- any, elem any) (pres bool)
func closechan(hchan any)
func closedchan(hchan any) bool
+func selectnbsend(hchan chan<- any, elem any) bool
+func selectnbrecv(elem *any, hchan <-chan any) bool
+
func newselect(size int) (sel *byte)
func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
+func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 1a3771311..5686e9599 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -45,27 +45,23 @@ typecheckselect(Node *sel)
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.
+ // convert x = <-c into OSELRECV(x, <-c).
+ // remove implicit conversions; the eventual assignment
+ // will reintroduce them.
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;
}
n->op = OSELRECV;
- n->right = n->right->left;
break;
case ORECV:
- // convert <-c into OSELRECV(N, c)
- n->op = OSELRECV;
- n->right = n->left;
- n->left = N;
+ // convert <-c into OSELRECV(N, <-c)
+ n = nod(OSELRECV, N, n);
+ ncase->left = n;
break;
case OSEND:
@@ -81,11 +77,149 @@ typecheckselect(Node *sel)
void
walkselect(Node *sel)
{
- int lno;
- Node *n, *ncase, *r, *a, *tmp, *var;
+ int lno, i;
+ Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
NodeList *l, *init;
-
+
+ if(sel->list == nil && sel->xoffset != 0)
+ fatal("double walkselect"); // already rewrote
+
lno = setlineno(sel);
+ i = count(sel->list);
+
+ // optimization: zero-case select
+ if(i == 0) {
+ sel->nbody = list1(mkcall("block", nil, nil));
+ goto out;
+ }
+
+ // optimization: one-case select: single op.
+ if(i == 1) {
+ cas = sel->list->n;
+ l = cas->ninit;
+ if(cas->left != N) { // not default:
+ n = cas->left;
+ l = concat(l, n->ninit);
+ n->ninit = nil;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ ch = cheapexpr(n->left, &l);
+ n->left = ch;
+ break;
+
+ case OSELRECV:
+ r = n->right;
+ ch = cheapexpr(r->left, &l);
+ r->left = ch;
+
+ if(n->left == N)
+ n = r;
+ else {
+ n = nod(OAS, n->left, r);
+ typecheck(&n, Etop);
+ }
+ break;
+ }
+
+ // if ch == nil { block() }; n;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, ch, nodnil());
+ a->nbody = list1(mkcall("block", nil, &l));
+ typecheck(&a, Etop);
+ l = list(l, a);
+ l = list(l, n);
+ }
+ l = concat(l, cas->nbody);
+ sel->nbody = l;
+ goto out;
+ }
+
+ // introduce temporary variables for OSELRECV where needed.
+ // this rewrite is used by both the general code and the next optimization.
+ for(l=sel->list; l; l=l->next) {
+ cas = l->n;
+ n = cas->left;
+ if(n == N)
+ continue;
+ switch(n->op) {
+ case OSELRECV:
+ ch = n->right->left;
+
+ // If we can use the address of the target without
+ // violating addressability or order of operations, do so.
+ // Otherwise introduce a temporary.
+ // Also introduce a temporary for := variables that escape,
+ // so that we can delay the heap allocation until the case
+ // is selected.
+ if(n->left == N || isblank(n->left))
+ n->left = nodnil();
+ else if(n->left->op == ONAME &&
+ (!n->colas || (n->class&PHEAP) == 0) &&
+ convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
+ n->left = nod(OADDR, n->left, N);
+ n->left->etype = 1; // pointer does not escape
+ typecheck(&n->left, Erv);
+ } else {
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, ch->type->type);
+ a = nod(OADDR, tmp, N);
+ a->etype = 1; // pointer does not escape
+ typecheck(&a, Erv);
+ r = nod(OAS, n->left, tmp);
+ typecheck(&r, Etop);
+ cas->nbody = concat(n->ninit, cas->nbody);
+ n->ninit = nil;
+ cas->nbody = concat(list1(r), cas->nbody);
+ n->left = a;
+ }
+ }
+ }
+
+ // optimization: two-case select but one is default: single non-blocking op.
+ if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
+ if(sel->list->n->left == nil) {
+ cas = sel->list->next->n;
+ dflt = sel->list->n;
+ } else {
+ dflt = sel->list->next->n;
+ cas = sel->list->n;
+ }
+
+ n = cas->left;
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // if c != nil && selectnbsend(c, v) { body } else { default body }
+ ch = cheapexpr(n->left, &r->ninit);
+ r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
+ mkcall1(chanfn("selectnbsend", 2, ch->type),
+ types[TBOOL], &r->ninit, ch, n->right));
+ break;
+
+ case OSELRECV:
+ // if c != nil && selectnbrecv(&v, c) { body } else { default body }
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ ch = cheapexpr(n->right->left, &r->ninit);
+ r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
+ mkcall1(chanfn("selectnbrecv", 2, ch->type),
+ types[TBOOL], &r->ninit, n->left, ch));
+ break;
+ }
+ typecheck(&r->ntest, Erv);
+ r->nbody = cas->nbody;
+ r->nelse = concat(dflt->ninit, dflt->nbody);
+ sel->nbody = list1(r);
+ goto out;
+ }
+
init = sel->ninit;
sel->ninit = nil;
@@ -96,16 +230,13 @@ walkselect(Node *sel)
typecheck(&r, Etop);
init = list(init, r);
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
// register cases
for(l=sel->list; l; l=l->next) {
- ncase = l->n;
- n = ncase->left;
+ cas = l->n;
+ n = cas->left;
r = nod(OIF, N, N);
- r->nbody = ncase->ninit;
- ncase->ninit = nil;
+ r->nbody = cas->ninit;
+ cas->ninit = nil;
if(n != nil) {
r->nbody = concat(r->nbody, n->ninit);
n->ninit = nil;
@@ -113,29 +244,24 @@ walkselect(Node *sel)
if(n == nil) {
// selectdefault(sel *byte);
r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
- } else if(n->op == OSEND) {
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &init, var, n->left, n->right);
- } else if(n->op == OSELRECV) {
- tmp = N;
- if(n->left == N)
- a = nodnil();
- else {
- // introduce temporary until we're sure this will succeed.
- tmp = nod(OXXX, N, N);
- tempname(tmp, n->right->type->type);
- a = nod(OADDR, tmp, N);
- }
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->type), types[TBOOL], &init, var, n->right, a);
- if(tmp != N) {
- a = nod(OAS, n->left, tmp);
- typecheck(&a, Etop);
- r->nbody = list(r->nbody, a);
+ } else {
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
+ &init, var, n->left, n->right);
+ break;
+ case OSELRECV:
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
+ &init, var, n->right->left, n->left);
+ break;
}
- } else
- fatal("select %O", n->op);
- r->nbody = concat(r->nbody, ncase->nbody);
+ }
+ r->nbody = concat(r->nbody, cas->nbody);
r->nbody = list(r->nbody, nod(OBREAK, N, N));
init = list(init, r);
}
@@ -143,8 +269,9 @@ walkselect(Node *sel)
// run the select
init = list(init, mkcall("selectgo", T, nil, var));
sel->nbody = init;
- sel->list = nil;
- walkstmtlist(init);
+out:
+ sel->list = nil;
+ walkstmtlist(sel->nbody);
lineno = lno;
}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 19ee3327b..31781646d 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -94,7 +94,7 @@ init1(Node *n, NodeList **out)
case OAS2FUNC:
case OAS2MAPR:
case OAS2DOTTYPE:
- case OAS2RECV:
+ case OAS2RECVCLOSED:
if(n->defn->initorder)
break;
n->defn->initorder = 1;
@@ -917,14 +917,12 @@ gen_as_init(Node *n)
case TPTR64:
case TFLOAT32:
case TFLOAT64:
- case TFLOAT:
gused(N); // in case the data is the dest of a goto
gdata(&nam, nr, nr->type->width);
break;
case TCOMPLEX64:
case TCOMPLEX128:
- case TCOMPLEX:
gused(N); // in case the data is the dest of a goto
gdatacomplex(&nam, nr->val.u.cval);
break;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 3c4501096..cb5e2a831 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -836,7 +836,7 @@ goopnames[] =
[OCASE] = "case",
[OCLOSED] = "closed",
[OCLOSE] = "close",
- [OCMPLX] = "cmplx",
+ [OCOMPLEX] = "complex",
[OCOM] = "^",
[OCONTINUE] = "continue",
[OCOPY] = "copy",
@@ -993,10 +993,8 @@ etnames[] =
[TINT64] = "INT64",
[TUINT64] = "UINT64",
[TUINTPTR] = "UINTPTR",
- [TFLOAT] = "FLOAT",
[TFLOAT32] = "FLOAT32",
[TFLOAT64] = "FLOAT64",
- [TCOMPLEX] = "COMPLEX",
[TCOMPLEX64] = "COMPLEX64",
[TCOMPLEX128] = "COMPLEX128",
[TBOOL] = "BOOL",
@@ -1117,10 +1115,8 @@ basicnames[] =
[TINT64] = "int64",
[TUINT64] = "uint64",
[TUINTPTR] = "uintptr",
- [TFLOAT] = "float",
[TFLOAT32] = "float32",
[TFLOAT64] = "float64",
- [TCOMPLEX] = "complex",
[TCOMPLEX64] = "complex64",
[TCOMPLEX128] = "complex128",
[TBOOL] = "bool",
@@ -1752,8 +1748,6 @@ int
cplxsubtype(int et)
{
switch(et) {
- case TCOMPLEX:
- return TFLOAT;
case TCOMPLEX64:
return TFLOAT32;
case TCOMPLEX128:
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index ca114d47c..931d0327a 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -18,7 +18,7 @@ static int onearg(Node*, char*, ...);
static int twoarg(Node*);
static int lookdot(Node*, Type*, int);
static int looktypedot(Node*, Type*, int);
-static void typecheckaste(int, int, Type*, NodeList*, char*);
+static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
@@ -56,6 +56,34 @@ typechecklist(NodeList *l, int top)
typecheck(&l->n, top);
}
+static char* typekind[] = {
+ [TINT] = "int",
+ [TUINT] = "uint",
+ [TINT8] = "int8",
+ [TUINT8] = "uint8",
+ [TINT16] = "int16",
+ [TUINT16] = "uint16",
+ [TINT32] = "int32",
+ [TUINT32] = "uint32",
+ [TINT64] = "int64",
+ [TUINT64] = "uint64",
+ [TUINTPTR] = "uintptr",
+ [TCOMPLEX64] = "complex64",
+ [TCOMPLEX128] = "complex128",
+ [TFLOAT32] = "float32",
+ [TFLOAT64] = "float64",
+ [TBOOL] = "bool",
+ [TSTRING] = "string",
+ [TPTR32] = "pointer",
+ [TPTR64] = "pointer",
+ [TSTRUCT] = "struct",
+ [TINTER] = "interface",
+ [TCHAN] = "chan",
+ [TMAP] = "map",
+ [TARRAY] = "array",
+ [TFUNC] = "func",
+};
+
/*
* type check node *np.
* replaces *np with a new pointer in some cases.
@@ -372,21 +400,25 @@ reswitch:
et = t->etype;
}
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- badbinary:
defaultlit2(&l, &r, 1);
- yyerror("invalid operation: %#N (type %T %#O %T)", n, l->type, op, r->type);
+ yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
+ goto error;
+ }
+ if(!okfor[op][et]) {
+ notokfor:
+ yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind[et]);
goto error;
}
- if(!okfor[op][et])
- goto badbinary;
// okfor allows any array == array;
// restrict to slice == nil and nil == slice.
if(l->type->etype == TARRAY && !isslice(l->type))
- goto badbinary;
+ goto notokfor;
if(r->type->etype == TARRAY && !isslice(r->type))
- goto badbinary;
- if(isslice(l->type) && !isnil(l) && !isnil(r))
- goto badbinary;
+ goto notokfor;
+ if(isslice(l->type) && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
+ goto error;
+ }
t = l->type;
if(iscmp[n->op]) {
evconst(n);
@@ -472,7 +504,7 @@ reswitch:
l = n->left;
if((t = l->type) == T)
goto error;
- if(!(top & Eindir))
+ if(!(top & Eindir) && !n->etype)
addrescapes(n->left);
n->type = ptrto(t);
goto ret;
@@ -636,6 +668,10 @@ reswitch:
goto ret;
case OSEND:
+ if(top & Erv) {
+ yyerror("send statement %#N used as value; use select for non-blocking send", n);
+ goto error;
+ }
ok |= Etop | Erv;
l = typecheck(&n->left, Erv);
typecheck(&n->right, Erv);
@@ -659,10 +695,6 @@ reswitch:
// TODO: more aggressive
n->etype = 0;
n->type = T;
- if(top & Erv) {
- n->op = OSENDNB;
- n->type = types[TBOOL];
- }
goto ret;
case OSLICE:
@@ -769,7 +801,7 @@ reswitch:
case ODOTMETH:
n->op = OCALLMETH;
- typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver");
+ typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver");
break;
default:
@@ -780,7 +812,7 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument");
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -852,7 +884,7 @@ reswitch:
n->type = types[TINT];
goto ret;
- case OCMPLX:
+ case OCOMPLEX:
ok |= Erv;
if(twoarg(n) < 0)
goto error;
@@ -865,7 +897,7 @@ reswitch:
n->right = r;
if(l->type->etype != r->type->etype) {
badcmplx:
- yyerror("invalid operation: %#N (cmplx of types %T, %T)", n, l->type, r->type);
+ yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
goto error;
}
switch(l->type->etype) {
@@ -874,9 +906,6 @@ reswitch:
case TIDEAL:
t = types[TIDEAL];
break;
- case TFLOAT:
- t = types[TCOMPLEX];
- break;
case TFLOAT32:
t = types[TCOMPLEX64];
break;
@@ -1217,7 +1246,7 @@ reswitch:
}
if(curfn->type->outnamed && n->list == nil)
goto ret;
- typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument");
+ typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
goto ret;
case OSELECT:
@@ -1562,7 +1591,7 @@ nokeys(NodeList *l)
* typecheck assignment: type list = expression list
*/
static void
-typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
+typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
{
Type *t, *tl, *tn;
Node *n;
@@ -1581,16 +1610,24 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
if(tl->isddd) {
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);
+ if(assignop(tn->type, tl->type->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, desc, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ }
}
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);
+ if(assignop(tn->type, tl->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, desc, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
+ }
tn = tn->down;
}
if(tn != T)
@@ -1635,19 +1672,29 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
}
if(nl != nil)
goto toomany;
- if(isddd)
- yyerror("invalid use of ... in %#O", op);
+ if(isddd) {
+ if(call != N)
+ yyerror("invalid use of ... in call to %#N", call);
+ else
+ yyerror("invalid use of ... in %#O", op);
+ }
out:
lineno = lno;
return;
notenough:
- yyerror("not enough arguments to %#O", op);
+ if(call != N)
+ yyerror("not enough arguments in call to %#N", call);
+ else
+ yyerror("not enough arguments to %#O", op);
goto out;
toomany:
- yyerror("too many arguments to %#O", op);
+ if(call != N)
+ yyerror("too many arguments in call to %#N", call);
+ else
+ yyerror("too many arguments to %#O", op);
goto out;
}
@@ -2329,8 +2376,8 @@ typecheckas2(Node *n)
n->op = OAS2MAPR;
goto common;
case ORECV:
- n->op = OAS2RECV;
- goto common;
+ yyerror("cannot use multiple-value assignment for non-blocking receive; use select");
+ goto out;
case ODOTTYPE:
n->op = OAS2DOTTYPE;
r->op = ODOTTYPE2;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index fa3e5d5e4..b32b6fff5 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -269,9 +269,15 @@ walkdef(Node *n)
}
t = n->type;
if(t != T) {
- convlit(&e, t);
- if(!okforconst[t->etype])
+ if(!okforconst[t->etype]) {
yyerror("invalid constant type %T", t);
+ goto ret;
+ }
+ if(!isideal(e->type) && !eqtype(t, e->type)) {
+ yyerror("cannot use %+N as type %T in const initializer", e, t);
+ goto ret;
+ }
+ convlit(&e, t);
}
n->val = e->val;
n->type = e->type;
@@ -397,7 +403,7 @@ walkstmt(Node **np)
case OAS:
case OAS2:
case OAS2DOTTYPE:
- case OAS2RECV:
+ case OAS2RECVCLOSED:
case OAS2FUNC:
case OAS2MAPW:
case OAS2MAPR:
@@ -664,7 +670,7 @@ walkexpr(Node **np, NodeList **init)
case OGE:
case OGT:
case OADD:
- case OCMPLX:
+ case OCOMPLEX:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
@@ -816,14 +822,14 @@ walkexpr(Node **np, NodeList **init)
n = liststmt(concat(concat(list1(r), ll), lpost));
goto ret;
- case OAS2RECV:
- // a,b = <-c
+ case OAS2RECVCLOSED:
+ // a = <-c; b = closed(c) but atomic
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
- fn = chanfn("chanrecv2", 2, r->left->type);
+ fn = chanfn("chanrecv3", 2, r->left->type);
r = mkcall1(fn, getoutargx(fn->type), init, r->left);
n->rlist->n = r;
n->op = OAS2FUNC;
@@ -1401,10 +1407,6 @@ walkexpr(Node **np, NodeList **init)
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
goto ret;
- case OSENDNB:
- n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
- goto ret;
-
case OCLOSURE:
n = walkclosure(n, init);
goto ret;