diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-02-14 13:23:51 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-02-14 13:23:51 +0100 |
commit | 758ff64c69e34965f8af5b2d6ffd65e8d7ab2150 (patch) | |
tree | 6d6b34f8c678862fe9b56c945a7b63f68502c245 /src/cmd/gc | |
parent | 3e45412327a2654a77944249962b3652e6142299 (diff) | |
download | golang-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.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/builtin.c.boot | 6 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/cplx.c | 6 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 8 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 15 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 5 | ||||
-rw-r--r-- | src/cmd/gc/range.c | 13 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 7 | ||||
-rw-r--r-- | src/cmd/gc/runtime.go | 7 | ||||
-rw-r--r-- | src/cmd/gc/select.c | 217 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 8 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 113 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 24 |
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; |