Commit 5caf63ca by Ian Lance Taylor

compiler: Rewrite handling of untyped numeric constants.

Fixes various bugs when, e.g., using float or complex
constants in integer contexts.

From-SVN: r185925
parent b59e9071
...@@ -3214,10 +3214,9 @@ class Case_clauses::Hash_integer_value ...@@ -3214,10 +3214,9 @@ class Case_clauses::Hash_integer_value
size_t size_t
Case_clauses::Hash_integer_value::operator()(Expression* pe) const Case_clauses::Hash_integer_value::operator()(Expression* pe) const
{ {
Type* itype; Numeric_constant nc;
mpz_t ival; mpz_t ival;
mpz_init(ival); if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
if (!pe->integer_constant_value(true, ival, &itype))
go_unreachable(); go_unreachable();
size_t ret = mpz_get_ui(ival); size_t ret = mpz_get_ui(ival);
mpz_clear(ival); mpz_clear(ival);
...@@ -3236,14 +3235,14 @@ class Case_clauses::Eq_integer_value ...@@ -3236,14 +3235,14 @@ class Case_clauses::Eq_integer_value
bool bool
Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
{ {
Type* atype; Numeric_constant anc;
Type* btype;
mpz_t aval; mpz_t aval;
Numeric_constant bnc;
mpz_t bval; mpz_t bval;
mpz_init(aval); if (!a->numeric_constant_value(&anc)
mpz_init(bval); || !anc.to_int(&aval)
if (!a->integer_constant_value(true, aval, &atype) || !b->numeric_constant_value(&bnc)
|| !b->integer_constant_value(true, bval, &btype)) || !bnc.to_int(&bval))
go_unreachable(); go_unreachable();
bool ret = mpz_cmp(aval, bval) == 0; bool ret = mpz_cmp(aval, bval) == 0;
mpz_clear(aval); mpz_clear(aval);
...@@ -3431,18 +3430,17 @@ Case_clauses::Case_clause::get_backend(Translate_context* context, ...@@ -3431,18 +3430,17 @@ Case_clauses::Case_clause::get_backend(Translate_context* context,
Expression* e = *p; Expression* e = *p;
if (e->classification() != Expression::EXPRESSION_INTEGER) if (e->classification() != Expression::EXPRESSION_INTEGER)
{ {
Type* itype; Numeric_constant nc;
mpz_t ival; mpz_t ival;
mpz_init(ival); if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
if (!(*p)->integer_constant_value(true, ival, &itype))
{ {
// Something went wrong. This can happen with a // Something went wrong. This can happen with a
// negative constant and an unsigned switch value. // negative constant and an unsigned switch value.
go_assert(saw_errors()); go_assert(saw_errors());
continue; continue;
} }
go_assert(itype != NULL); go_assert(nc.type() != NULL);
e = Expression::make_integer(&ival, itype, e->location()); e = Expression::make_integer(&ival, nc.type(), e->location());
mpz_clear(ival); mpz_clear(ival);
} }
......
...@@ -2230,15 +2230,13 @@ Type::is_backend_type_size_known(Gogo* gogo) ...@@ -2230,15 +2230,13 @@ Type::is_backend_type_size_known(Gogo* gogo)
return true; return true;
else else
{ {
Numeric_constant nc;
if (!at->length()->numeric_constant_value(&nc))
return false;
mpz_t ival; mpz_t ival;
mpz_init(ival); if (!nc.to_int(&ival))
Type* dummy;
bool length_known = at->length()->integer_constant_value(true,
ival,
&dummy);
mpz_clear(ival);
if (!length_known)
return false; return false;
mpz_clear(ival);
return at->element_type()->is_backend_type_size_known(gogo); return at->element_type()->is_backend_type_size_known(gogo);
} }
} }
...@@ -5106,17 +5104,22 @@ Array_type::is_identical(const Array_type* t, bool errors_are_identical) const ...@@ -5106,17 +5104,22 @@ Array_type::is_identical(const Array_type* t, bool errors_are_identical) const
// Try to determine the lengths. If we can't, assume the arrays // Try to determine the lengths. If we can't, assume the arrays
// are not identical. // are not identical.
bool ret = false; bool ret = false;
mpz_t v1; Numeric_constant nc1, nc2;
mpz_init(v1); if (l1->numeric_constant_value(&nc1)
Type* type1; && l2->numeric_constant_value(&nc2))
mpz_t v2; {
mpz_init(v2); mpz_t v1;
Type* type2; if (nc1.to_int(&v1))
if (l1->integer_constant_value(true, v1, &type1) {
&& l2->integer_constant_value(true, v2, &type2)) mpz_t v2;
ret = mpz_cmp(v1, v2) == 0; if (nc2.to_int(&v2))
mpz_clear(v1); {
mpz_clear(v2); ret = mpz_cmp(v1, v2) == 0;
mpz_clear(v2);
}
mpz_clear(v1);
}
}
return ret; return ret;
} }
...@@ -5154,58 +5157,44 @@ Array_type::verify_length() ...@@ -5154,58 +5157,44 @@ Array_type::verify_length()
return false; return false;
} }
mpz_t val; Numeric_constant nc;
mpz_init(val); if (!this->length_->numeric_constant_value(&nc))
Type* vt;
if (!this->length_->integer_constant_value(true, val, &vt))
{ {
mpfr_t fval; if (this->length_->type()->integer_type() != NULL
mpfr_init(fval); || this->length_->type()->float_type() != NULL)
if (!this->length_->float_constant_value(fval, &vt)) error_at(this->length_->location(), "array bound is not constant");
{ else
if (this->length_->type()->integer_type() != NULL error_at(this->length_->location(), "array bound is not numeric");
|| this->length_->type()->float_type() != NULL) return false;
error_at(this->length_->location(),
"array bound is not constant");
else
error_at(this->length_->location(),
"array bound is not numeric");
mpfr_clear(fval);
mpz_clear(val);
return false;
}
if (!mpfr_integer_p(fval))
{
error_at(this->length_->location(),
"array bound truncated to integer");
mpfr_clear(fval);
mpz_clear(val);
return false;
}
mpz_init(val);
mpfr_get_z(val, fval, GMP_RNDN);
mpfr_clear(fval);
} }
if (mpz_sgn(val) < 0) unsigned long val;
switch (nc.to_unsigned_long(&val))
{ {
case Numeric_constant::NC_UL_VALID:
break;
case Numeric_constant::NC_UL_NOTINT:
error_at(this->length_->location(), "array bound truncated to integer");
return false;
case Numeric_constant::NC_UL_NEGATIVE:
error_at(this->length_->location(), "negative array bound"); error_at(this->length_->location(), "negative array bound");
mpz_clear(val);
return false; return false;
case Numeric_constant::NC_UL_BIG:
error_at(this->length_->location(), "array bound overflows");
return false;
default:
go_unreachable();
} }
Type* int_type = Type::lookup_integer_type("int"); Type* int_type = Type::lookup_integer_type("int");
int tbits = int_type->integer_type()->bits(); unsigned int tbits = int_type->integer_type()->bits();
int vbits = mpz_sizeinbase(val, 2); if (sizeof(val) <= tbits * 8
if (vbits + 1 > tbits) && val >> (tbits - 1) != 0)
{ {
error_at(this->length_->location(), "array bound overflows"); error_at(this->length_->location(), "array bound overflows");
mpz_clear(val);
return false; return false;
} }
mpz_clear(val);
return true; return true;
} }
...@@ -5457,11 +5446,11 @@ Array_type::get_length_tree(Gogo* gogo) ...@@ -5457,11 +5446,11 @@ Array_type::get_length_tree(Gogo* gogo)
go_assert(this->length_ != NULL); go_assert(this->length_ != NULL);
if (this->length_tree_ == NULL_TREE) if (this->length_tree_ == NULL_TREE)
{ {
Numeric_constant nc;
mpz_t val; mpz_t val;
mpz_init(val); if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
Type* t;
if (this->length_->integer_constant_value(true, val, &t))
{ {
Type* t = nc.type();
if (t == NULL) if (t == NULL)
t = Type::lookup_integer_type("int"); t = Type::lookup_integer_type("int");
else if (t->is_abstract()) else if (t->is_abstract())
...@@ -5472,8 +5461,6 @@ Array_type::get_length_tree(Gogo* gogo) ...@@ -5472,8 +5461,6 @@ Array_type::get_length_tree(Gogo* gogo)
} }
else else
{ {
mpz_clear(val);
// Make up a translation context for the array length // Make up a translation context for the array length
// expression. FIXME: This won't work in general. // expression. FIXME: This won't work in general.
Translate_context context(gogo, NULL, NULL, NULL); Translate_context context(gogo, NULL, NULL, NULL);
...@@ -5824,23 +5811,17 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const ...@@ -5824,23 +5811,17 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->push_back('['); ret->push_back('[');
if (this->length_ != NULL) if (this->length_ != NULL)
{ {
mpz_t val; Numeric_constant nc;
mpz_init(val); unsigned long val;
Type* type; if (!this->length_->numeric_constant_value(&nc)
if (!this->length_->integer_constant_value(true, val, &type)) || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
error_at(this->length_->location(), error_at(this->length_->location(), "invalid array length");
"array length must be integer constant expression");
else if (mpz_cmp_si(val, 0) < 0)
error_at(this->length_->location(), "array length is negative");
else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
error_at(this->length_->location(), "array length is too large");
else else
{ {
char buf[50]; char buf[50];
snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val)); snprintf(buf, sizeof buf, "%lu", val);
ret->append(buf); ret->append(buf);
} }
mpz_clear(val);
} }
ret->push_back(']'); ret->push_back(']');
...@@ -5856,23 +5837,17 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const ...@@ -5856,23 +5837,17 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
this->append_mangled_name(this->element_type_, gogo, ret); this->append_mangled_name(this->element_type_, gogo, ret);
if (this->length_ != NULL) if (this->length_ != NULL)
{ {
mpz_t val; Numeric_constant nc;
mpz_init(val); unsigned long val;
Type* type; if (!this->length_->numeric_constant_value(&nc)
if (!this->length_->integer_constant_value(true, val, &type)) || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
error_at(this->length_->location(), error_at(this->length_->location(), "invalid array length");
"array length must be integer constant expression");
else if (mpz_cmp_si(val, 0) < 0)
error_at(this->length_->location(), "array length is negative");
else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
error_at(this->length_->location(), "array size is too large");
else else
{ {
char buf[50]; char buf[50];
snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val)); snprintf(buf, sizeof buf, "%lu", val);
ret->append(buf); ret->append(buf);
} }
mpz_clear(val);
} }
ret->push_back('e'); ret->push_back('e');
} }
......
...@@ -680,6 +680,14 @@ class Type ...@@ -680,6 +680,14 @@ class Type
complex_type() const complex_type() const
{ return this->convert<const Complex_type, TYPE_COMPLEX>(); } { return this->convert<const Complex_type, TYPE_COMPLEX>(); }
// Return whether this is a numeric type.
bool
is_numeric_type() const
{
Type_classification tc = this->base()->classification_;
return tc == TYPE_INTEGER || tc == TYPE_FLOAT || tc == TYPE_COMPLEX;
}
// Return true if this is a boolean type. // Return true if this is a boolean type.
bool bool
is_boolean_type() const is_boolean_type() const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment