diff options
Diffstat (limited to 'src/cmd/gc/const.c')
-rw-r--r-- | src/cmd/gc/const.c | 359 |
1 files changed, 277 insertions, 82 deletions
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index e27c88338..4f1ff6778 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -87,8 +87,12 @@ convlit1(Node **np, Type *t, int explicit) switch(n->op) { default: - if(n->type == idealbool) - n->type = types[TBOOL]; + if(n->type == idealbool) { + if(t->etype == TBOOL) + n->type = t; + else + n->type = types[TBOOL]; + } if(n->type->etype == TIDEAL) { convlit(&n->left, t); convlit(&n->right, t); @@ -162,6 +166,16 @@ convlit1(Node **np, Type *t, int explicit) case TFUNC: case TUNSAFEPTR: break; + + case TUINTPTR: + // A nil literal may be converted to uintptr + // if it is an unsafe.Pointer + if(n->type->etype == TUNSAFEPTR) { + n->val.u.xval = mal(sizeof(*n->val.u.xval)); + mpmovecfix(n->val.u.xval, 0); + n->val.ctype = CTINT; + } else + goto bad; } break; @@ -230,7 +244,8 @@ convlit1(Node **np, Type *t, int explicit) bad: if(!n->diag) { - yyerror("cannot convert %N to type %T", n, t); + if(!t->broke) + yyerror("cannot convert %N to type %T", n, t); n->diag = 1; } if(isideal(n->type)) { @@ -348,13 +363,9 @@ toint(Val v) return v; } -void -overflow(Val v, Type *t) +int +doesoverflow(Val v, Type *t) { - // v has already been converted - // to appropriate form for t. - if(t == T || t->etype == TIDEAL) - return; switch(v.ctype) { case CTINT: case CTRUNE: @@ -362,14 +373,14 @@ overflow(Val v, Type *t) fatal("overflow: %T integer constant", t); if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 || mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0) - yyerror("constant %B overflows %T", v.u.xval, t); + return 1; break; case CTFLT: if(!isfloat[t->etype]) fatal("overflow: %T floating-point constant", t); if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 || mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0) - yyerror("constant %#F overflows %T", v.u.fval, t); + return 1; break; case CTCPLX: if(!iscomplex[t->etype]) @@ -378,7 +389,33 @@ overflow(Val v, Type *t) mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 || mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 || mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0) - yyerror("constant %#F overflows %T", v.u.fval, t); + return 1; + break; + } + return 0; +} + +void +overflow(Val v, Type *t) +{ + // v has already been converted + // to appropriate form for t. + if(t == T || t->etype == TIDEAL) + return; + + if(!doesoverflow(v, t)) + return; + + switch(v.ctype) { + case CTINT: + case CTRUNE: + yyerror("constant %B overflows %T", v.u.xval, t); + break; + case CTFLT: + yyerror("constant %#F overflows %T", v.u.fval, t); + break; + case CTCPLX: + yyerror("constant %#F overflows %T", v.u.fval, t); break; } } @@ -437,6 +474,20 @@ isconst(Node *n, int ct) return t == ct || (ct == CTINT && t == CTRUNE); } +static Node* +saveorig(Node *n) +{ + Node *n1; + + if(n == n->orig) { + // duplicate node for n->orig. + n1 = nod(OLITERAL, N, N); + n->orig = n1; + *n1 = *n; + } + return n->orig; +} + /* * if n is constant, rewrite as OLITERAL node. */ @@ -902,12 +953,7 @@ unary: } ret: - if(n == n->orig) { - // duplicate node for n->orig. - norig = nod(OLITERAL, N, N); - *norig = *n; - } else - norig = n->orig; + norig = saveorig(n); *n = *nl; // restore value of n->orig. n->orig = norig; @@ -924,11 +970,15 @@ ret: return; settrue: + norig = saveorig(n); *n = *nodbool(1); + n->orig = norig; return; setfalse: + norig = saveorig(n); *n = *nodbool(0); + n->orig = norig; return; } @@ -984,79 +1034,88 @@ nodcplxlit(Val r, Val i) return n; } -// TODO(rsc): combine with convlit +// idealkind returns a constant kind like consttype +// but for an arbitrary "ideal" expression. +static int +idealkind(Node *n) +{ + int k1, k2; + + if(n == N || !isideal(n->type)) + return CTxxx; + + switch(n->op) { + default: + return CTxxx; + case OLITERAL: + return n->val.ctype; + case OADD: + case OAND: + case OANDNOT: + case OCOM: + case ODIV: + case OMINUS: + case OMOD: + case OMUL: + case OSUB: + case OXOR: + case OOR: + case OPLUS: + // numeric kinds. + k1 = idealkind(n->left); + k2 = idealkind(n->right); + if(k1 > k2) + return k1; + else + return k2; + case OADDSTR: + return CTSTR; + case OANDAND: + case OEQ: + case OGE: + case OGT: + case OLE: + case OLT: + case ONE: + case ONOT: + case OOROR: + case OCMPSTR: + case OCMPIFACE: + return CTBOOL; + case OLSH: + case ORSH: + // shifts (beware!). + return idealkind(n->left); + } +} + void defaultlit(Node **np, Type *t) { int lno; + int ctype; Node *n, *nn; + Type *t1; n = *np; if(n == N || !isideal(n->type)) return; - switch(n->op) { - case OLITERAL: + if(n->op == OLITERAL) { nn = nod(OXXX, N, N); *nn = *n; n = nn; *np = n; - break; - case OLSH: - case ORSH: - defaultlit(&n->left, t); - t = n->left->type; - if(t != T && !isint[t->etype]) { - yyerror("invalid operation: %N (shift of type %T)", n, t); - t = T; - } - n->type = t; - return; - case ONOT: - defaultlit(&n->left, t); - n->type = n->left->type; - return; - default: - if(n->left == N) { - dump("defaultlit", n); - fatal("defaultlit"); - } - // n is ideal, so left and right must both be ideal. - // n has not been computed as a constant value, - // so either left or right must not be constant. - // The only 'ideal' non-constant expressions are shifts. Ugh. - // If one of these is a shift and the other is not, use that type. - // When compiling x := 1<<i + 3.14, this means we try to push - // the float64 down into the 1<<i, producing the correct error - // (cannot shift float64). - if(t == T && (n->right->op == OLSH || n->right->op == ORSH)) { - defaultlit(&n->left, T); - defaultlit(&n->right, n->left->type); - } else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) { - defaultlit(&n->right, T); - defaultlit(&n->left, n->right->type); - } else if(iscmp[n->op]) { - defaultlit2(&n->left, &n->right, 1); - } else { - defaultlit(&n->left, t); - defaultlit(&n->right, t); - } - if(n->type == idealbool || n->type == idealstring) { - if(t != T && t->etype == n->type->etype) - n->type = t; - else - n->type = types[n->type->etype]; - } else - n->type = n->left->type; - return; } lno = setlineno(n); - switch(n->val.ctype) { + ctype = idealkind(n); + t1 = T; + switch(ctype) { default: if(t != T) { convlit(np, t); - break; + return; } if(n->val.ctype == CTNIL) { lineno = lno; @@ -1065,46 +1124,52 @@ defaultlit(Node **np, Type *t) break; } if(n->val.ctype == CTSTR) { - n->type = types[TSTRING]; + t1 = types[TSTRING]; + convlit(np, t1); break; } yyerror("defaultlit: unknown literal: %N", n); break; + case CTxxx: + fatal("defaultlit: idealkind is CTxxx: %+N", n); + break; case CTBOOL: - n->type = types[TBOOL]; + t1 = types[TBOOL]; if(t != T && t->etype == TBOOL) - n->type = t; + t1 = t; + convlit(np, t1); break; case CTINT: - n->type = types[TINT]; + t1 = types[TINT]; goto num; case CTRUNE: - n->type = runetype; + t1 = runetype; goto num; case CTFLT: - n->type = types[TFLOAT64]; + t1 = types[TFLOAT64]; goto num; case CTCPLX: - n->type = types[TCOMPLEX128]; + t1 = types[TCOMPLEX128]; goto num; num: if(t != T) { if(isint[t->etype]) { - n->type = t; + t1 = t; n->val = toint(n->val); } else if(isfloat[t->etype]) { - n->type = t; + t1 = t; n->val = toflt(n->val); } else if(iscomplex[t->etype]) { - n->type = t; + t1 = t; n->val = tocplx(n->val); } } - overflow(n->val, n->type); + overflow(n->val, t1); + convlit(np, t1); break; } lineno = lno; @@ -1206,6 +1271,7 @@ smallintconst(Node *n) case TIDEAL: case TINT64: case TUINT64: + case TPTR64: if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0 || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0) break; @@ -1392,3 +1458,132 @@ cmplxdiv(Mpcplx *v, Mpcplx *rv) mpsubfltflt(&v->imag, &ad); // bc-ad mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd) } + +static int hascallchan(Node*); + +// Is n a Go language constant (as opposed to a compile-time constant)? +// Expressions derived from nil, like string([]byte(nil)), while they +// may be known at compile time, are not Go language constants. +// Only called for expressions known to evaluated to compile-time +// constants. +int +isgoconst(Node *n) +{ + Node *l; + Type *t; + + if(n->orig != N) + n = n->orig; + + switch(n->op) { + case OADD: + case OADDSTR: + case OAND: + case OANDAND: + case OANDNOT: + case OCOM: + case ODIV: + case OEQ: + case OGE: + case OGT: + case OLE: + case OLSH: + case OLT: + case OMINUS: + case OMOD: + case OMUL: + case ONE: + case ONOT: + case OOR: + case OOROR: + case OPLUS: + case ORSH: + case OSUB: + case OXOR: + case OCONV: + case OIOTA: + case OCOMPLEX: + case OREAL: + case OIMAG: + if(isgoconst(n->left) && (n->right == N || isgoconst(n->right))) + return 1; + break; + + case OLEN: + case OCAP: + l = n->left; + if(isgoconst(l)) + return 1; + // Special case: len/cap is constant when applied to array or + // pointer to array when the expression does not contain + // function calls or channel receive operations. + t = l->type; + if(t != T && isptr[t->etype]) + t = t->type; + if(isfixedarray(t) && !hascallchan(l)) + return 1; + break; + + case OLITERAL: + if(n->val.ctype != CTNIL) + return 1; + break; + + case ONAME: + l = n->sym->def; + if(l->op == OLITERAL && n->val.ctype != CTNIL) + return 1; + break; + + case ONONAME: + if(n->sym->def != N && n->sym->def->op == OIOTA) + return 1; + break; + + case OCALL: + // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof. + l = n->left; + while(l->op == OPAREN) + l = l->left; + if(l->op != ONAME || l->sym->pkg != unsafepkg) + break; + if(strcmp(l->sym->name, "Alignof") == 0 || + strcmp(l->sym->name, "Offsetof") == 0 || + strcmp(l->sym->name, "Sizeof") == 0) + return 1; + break; + } + + //dump("nonconst", n); + return 0; +} + +static int +hascallchan(Node *n) +{ + NodeList *l; + + if(n == N) + return 0; + switch(n->op) { + case OCALL: + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + case ORECV: + return 1; + } + + if(hascallchan(n->left) || + hascallchan(n->right)) + return 1; + + for(l=n->list; l; l=l->next) + if(hascallchan(l->n)) + return 1; + for(l=n->rlist; l; l=l->next) + if(hascallchan(l->n)) + return 1; + + return 0; +} |