diff options
Diffstat (limited to 'src/cmd/gc/typecheck.c')
-rw-r--r-- | src/cmd/gc/typecheck.c | 255 |
1 files changed, 204 insertions, 51 deletions
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 31a2f2c5c..c50b2285b 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -310,7 +310,7 @@ typecheck1(Node **np, int top) int ok, ntop; Type *t, *tp, *missing, *have, *badtype; Val v; - char *why; + char *why, *desc, descbuf[64]; n = *np; @@ -368,7 +368,7 @@ reswitch: goto ret; case OPACK: - yyerror("use of package %S not in selector", n->sym); + yyerror("use of package %S without selector", n->sym); goto error; case ODDD: @@ -535,6 +535,19 @@ reswitch: op = n->etype; goto arith; + case OADDPTR: + ok |= Erv; + l = typecheck(&n->left, Erv); + r = typecheck(&n->right, Erv); + if(l->type == T || r->type == T) + goto error; + if(l->type->etype != tptr) + fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left); + if(r->type->etype != TUINTPTR) + fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right); + n->type = types[tptr]; + goto ret; + case OADD: case OAND: case OANDAND: @@ -654,8 +667,20 @@ reswitch: if(iscmp[n->op]) { n->etype = n->op; n->op = OCMPSTR; - } else if(n->op == OADD) + } else if(n->op == OADD) { + // create OADDSTR node with list of strings in x + y + z + (w + v) + ... n->op = OADDSTR; + if(l->op == OADDSTR) + n->list = l->list; + else + n->list = list1(l); + if(r->op == OADDSTR) + n->list = concat(n->list, r->list); + else + n->list = list(n->list, r); + n->left = N; + n->right = N; + } } if(et == TINTER) { if(l->op == OLITERAL && l->val.ctype == CTNIL) { @@ -721,8 +746,11 @@ reswitch: if(n->left->type == T) goto error; checklvalue(n->left, "take the address of"); - for(l=n->left; l->op == ODOT; l=l->left) + r = outervalue(n->left); + for(l = n->left; l != r; l = l->left) l->addrtaken = 1; + if(l->orig != l && l->op == ONAME) + fatal("found non-orig name node %N", l); l->addrtaken = 1; defaultlit(&n->left, T); l = n->left; @@ -864,7 +892,7 @@ reswitch: goto error; switch(t->etype) { default: - yyerror("invalid operation: %N (index of type %T)", n, t); + yyerror("invalid operation: %N (type %T does not support indexing)", n, t); goto error; @@ -947,7 +975,7 @@ reswitch: r = n->right; if(r->type == T) goto error; - r = assignconv(r, l->type->type, "send"); + n->right = assignconv(r, l->type->type, "send"); // TODO: more aggressive n->etype = 0; n->type = T; @@ -1062,6 +1090,7 @@ reswitch: goto reswitch; } typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); + n->diag |= n->left->diag; l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) @@ -1123,7 +1152,11 @@ reswitch: } break; } - typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument"); + if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf) + desc = descbuf; + else + desc = "function argument"; + typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc); ok |= Etop; if(t->outtuple == 0) goto ret; @@ -1209,17 +1242,29 @@ reswitch: case OCOMPLEX: ok |= Erv; - if(twoarg(n) < 0) - goto error; - l = typecheck(&n->left, Erv | (top & Eiota)); - r = typecheck(&n->right, Erv | (top & Eiota)); - if(l->type == T || r->type == T) - goto error; - defaultlit2(&l, &r, 0); - if(l->type == T || r->type == T) - goto error; - n->left = l; - n->right = r; + if(count(n->list) == 1) { + typechecklist(n->list, Efnstruct); + t = n->list->n->left->type; + if(t->outtuple != 2) { + yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple); + goto error; + } + t = n->list->n->type->type; + l = t->nname; + r = t->down->nname; + } else { + if(twoarg(n) < 0) + goto error; + l = typecheck(&n->left, Erv | (top & Eiota)); + r = typecheck(&n->right, Erv | (top & Eiota)); + if(l->type == T || r->type == T) + goto error; + defaultlit2(&l, &r, 0); + if(l->type == T || r->type == T) + goto error; + n->left = l; + n->right = r; + } if(!eqtype(l->type, r->type)) { yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); goto error; @@ -1298,9 +1343,22 @@ reswitch: yyerror("missing arguments to append"); goto error; } - typechecklist(args, Erv); + + if(count(args) == 1 && !n->isddd) + typecheck(&args->n, Erv | Efnstruct); + else + typechecklist(args, Erv); + if((t = args->n->type) == T) goto error; + + // Unpack multiple-return result before type-checking. + if(istype(t, TSTRUCT)) { + t = t->type; + if(istype(t, TFIELD)) + t = t->type; + } + n->type = t; if(!isslice(t)) { if(isconst(args->n, CTNIL)) { @@ -1355,6 +1413,8 @@ reswitch: goto error; defaultlit(&n->left, T); defaultlit(&n->right, T); + if(n->left->type == T || n->right->type == T) + goto error; // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { @@ -1406,6 +1466,9 @@ reswitch: } break; case OSTRARRAYBYTE: + // do not use stringtoarraylit. + // generated code and compiler memory footprint is better without it. + break; case OSTRARRAYRUNE: if(n->left->op == OLITERAL) stringtoarraylit(&n); @@ -1621,6 +1684,7 @@ reswitch: case OGOTO: case OLABEL: case OXFALL: + case OVARKILL: ok |= Etop; goto ret; @@ -2116,6 +2180,31 @@ nokeys(NodeList *l) return 1; } +static int +hasddd(Type *t) +{ + Type *tl; + + for(tl=t->type; tl; tl=tl->down) { + if(tl->isddd) + return 1; + } + return 0; +} + +static int +downcount(Type *t) +{ + Type *tl; + int n; + + n = 0; + for(tl=t->type; tl; tl=tl->down) { + n++; + } + return n; +} + /* * typecheck assignment: type list = expression list */ @@ -2126,14 +2215,25 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * Node *n; int lno; char *why; + int n1, n2; lno = lineno; if(tstruct->broke) goto out; + n = N; if(nl != nil && nl->next == nil && (n = nl->n)->type != T) if(n->type->etype == TSTRUCT && n->type->funarg) { + if(!hasddd(tstruct)) { + n1 = downcount(tstruct); + n2 = downcount(n->type); + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + tn = n->type->type; for(tl=tstruct->type; tl; tl=tl->down) { if(tl->isddd) { @@ -2162,6 +2262,26 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * goto out; } + n1 = downcount(tstruct); + n2 = count(nl); + if(!hasddd(tstruct)) { + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + else { + if(!isddd) { + if(n2 < n1-1) + goto notenough; + } else { + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + } + for(tl=tstruct->type; tl; tl=tl->down) { t = tl->type; if(tl->isddd) { @@ -2206,10 +2326,14 @@ out: return; notenough: - if(call != N) - yyerror("not enough arguments in call to %N", call); - else - yyerror("not enough arguments to %O", op); + if(n == N || !n->diag) { + if(call != N) + yyerror("not enough arguments in call to %N", call); + else + yyerror("not enough arguments to %O", op); + if(n != N) + n->diag = 1; + } goto out; toomany: @@ -2252,10 +2376,13 @@ keydup(Node *n, Node *hash[], ulong nhash) ulong b; double d; int i; - Node *a; + Node *a, *orign; Node cmp; char *s; + orign = n; + if(n->op == OCONVIFACE) + n = n->left; evconst(n); if(n->op != OLITERAL) return; // we dont check variables @@ -2288,17 +2415,25 @@ keydup(Node *n, Node *hash[], ulong nhash) for(a=hash[h]; a!=N; a=a->ntest) { cmp.op = OEQ; cmp.left = n; - cmp.right = a; - evconst(&cmp); - b = cmp.val.u.bval; + b = 0; + if(a->op == OCONVIFACE && orign->op == OCONVIFACE) { + if(eqtype(a->left->type, n->type)) { + cmp.right = a->left; + evconst(&cmp); + b = cmp.val.u.bval; + } + } else if(eqtype(a->type, n->type)) { + cmp.right = a; + evconst(&cmp); + b = cmp.val.u.bval; + } if(b) { - // too lazy to print the literal yyerror("duplicate key %N in map literal", n); return; } } - n->ntest = hash[h]; - hash[h] = n; + orign->ntest = hash[h]; + hash[h] = orign; } static void @@ -2486,8 +2621,9 @@ typecheckcomplit(Node **np) typecheck(&l->left, Erv); evconst(l->left); i = nonnegconst(l->left); - if(i < 0) { + if(i < 0 && !l->left->diag) { yyerror("array index must be non-negative integer constant"); + l->left->diag = 1; i = -(1<<30); // stay negative for a while } if(i >= 0) @@ -2497,7 +2633,7 @@ typecheckcomplit(Node **np) len = i; if(t->bound >= 0 && len > t->bound) { setlineno(l); - yyerror("array index %d out of bounds [0:%d]", len, t->bound); + yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound); t->bound = -1; // no more errors } } @@ -2680,6 +2816,11 @@ checkassign(Node *n) n->etype = 1; return; } + + // have already complained about n being undefined + if(n->op == ONONAME) + return; + yyerror("cannot assign to %N", n); } @@ -2804,7 +2945,7 @@ typecheckas2(Node *n) n->op = OAS2FUNC; t = structfirst(&s, &r->type); for(ll=n->list; ll; ll=ll->next) { - if(ll->n->type != T) + if(t->type != T && ll->n->type != T) checkassignto(t->type, ll->n); if(ll->n->defn == n && ll->n->ntype == N) ll->n->type = t->type; @@ -3130,7 +3271,10 @@ typecheckdef(Node *n) goto ret; } if(e->type != T && e->op != OLITERAL || !isgoconst(e)) { - yyerror("const initializer %N is not a constant", e); + if(!e->diag) { + yyerror("const initializer %N is not a constant", e); + e->diag = 1; + } goto ret; } t = n->type; @@ -3220,29 +3364,38 @@ static int checkmake(Type *t, char *arg, Node *n) { if(n->op == OLITERAL) { - n->val = toint(n->val); - if(mpcmpfixc(n->val.u.xval, 0) < 0) { - yyerror("negative %s argument in make(%T)", arg, t); - return -1; - } - if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) { - yyerror("%s argument too large in make(%T)", arg, t); - return -1; + switch(n->val.ctype) { + case CTINT: + case CTRUNE: + case CTFLT: + case CTCPLX: + n->val = toint(n->val); + if(mpcmpfixc(n->val.u.xval, 0) < 0) { + yyerror("negative %s argument in make(%T)", arg, t); + return -1; + } + if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) { + yyerror("%s argument too large in make(%T)", arg, t); + return -1; + } + + // Delay defaultlit until after we've checked range, to avoid + // a redundant "constant NNN overflows int" error. + defaultlit(&n, types[TINT]); + return 0; + default: + break; } - - // Delay defaultlit until after we've checked range, to avoid - // a redundant "constant NNN overflows int" error. - defaultlit(&n, types[TINT]); - return 0; } - - // Defaultlit still necessary for non-constant: n might be 1<<k. - defaultlit(&n, types[TINT]); - if(!isint[n->type->etype]) { + if(!isint[n->type->etype] && n->type->etype != TIDEAL) { yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type); return -1; } + + // Defaultlit still necessary for non-constant: n might be 1<<k. + defaultlit(&n, types[TINT]); + return 0; } |