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
size_t
Case_clauses::Hash_integer_value::operator()(Expression* pe) const
{
Type* itype;
Numeric_constant nc;
mpz_t ival;
mpz_init(ival);
if (!pe->integer_constant_value(true, ival, &itype))
if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
go_unreachable();
size_t ret = mpz_get_ui(ival);
mpz_clear(ival);
......@@ -3236,14 +3235,14 @@ class Case_clauses::Eq_integer_value
bool
Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
{
Type* atype;
Type* btype;
Numeric_constant anc;
mpz_t aval;
Numeric_constant bnc;
mpz_t bval;
mpz_init(aval);
mpz_init(bval);
if (!a->integer_constant_value(true, aval, &atype)
|| !b->integer_constant_value(true, bval, &btype))
if (!a->numeric_constant_value(&anc)
|| !anc.to_int(&aval)
|| !b->numeric_constant_value(&bnc)
|| !bnc.to_int(&bval))
go_unreachable();
bool ret = mpz_cmp(aval, bval) == 0;
mpz_clear(aval);
......@@ -3431,18 +3430,17 @@ Case_clauses::Case_clause::get_backend(Translate_context* context,
Expression* e = *p;
if (e->classification() != Expression::EXPRESSION_INTEGER)
{
Type* itype;
Numeric_constant nc;
mpz_t ival;
mpz_init(ival);
if (!(*p)->integer_constant_value(true, ival, &itype))
if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
{
// Something went wrong. This can happen with a
// negative constant and an unsigned switch value.
go_assert(saw_errors());
continue;
}
go_assert(itype != NULL);
e = Expression::make_integer(&ival, itype, e->location());
go_assert(nc.type() != NULL);
e = Expression::make_integer(&ival, nc.type(), e->location());
mpz_clear(ival);
}
......
......@@ -2230,15 +2230,13 @@ Type::is_backend_type_size_known(Gogo* gogo)
return true;
else
{
Numeric_constant nc;
if (!at->length()->numeric_constant_value(&nc))
return false;
mpz_t ival;
mpz_init(ival);
Type* dummy;
bool length_known = at->length()->integer_constant_value(true,
ival,
&dummy);
mpz_clear(ival);
if (!length_known)
if (!nc.to_int(&ival))
return false;
mpz_clear(ival);
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
// Try to determine the lengths. If we can't, assume the arrays
// are not identical.
bool ret = false;
mpz_t v1;
mpz_init(v1);
Type* type1;
mpz_t v2;
mpz_init(v2);
Type* type2;
if (l1->integer_constant_value(true, v1, &type1)
&& l2->integer_constant_value(true, v2, &type2))
ret = mpz_cmp(v1, v2) == 0;
mpz_clear(v1);
mpz_clear(v2);
Numeric_constant nc1, nc2;
if (l1->numeric_constant_value(&nc1)
&& l2->numeric_constant_value(&nc2))
{
mpz_t v1;
if (nc1.to_int(&v1))
{
mpz_t v2;
if (nc2.to_int(&v2))
{
ret = mpz_cmp(v1, v2) == 0;
mpz_clear(v2);
}
mpz_clear(v1);
}
}
return ret;
}
......@@ -5154,58 +5157,44 @@ Array_type::verify_length()
return false;
}
mpz_t val;
mpz_init(val);
Type* vt;
if (!this->length_->integer_constant_value(true, val, &vt))
Numeric_constant nc;
if (!this->length_->numeric_constant_value(&nc))
{
mpfr_t fval;
mpfr_init(fval);
if (!this->length_->float_constant_value(fval, &vt))
{
if (this->length_->type()->integer_type() != NULL
|| this->length_->type()->float_type() != NULL)
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 (this->length_->type()->integer_type() != NULL
|| this->length_->type()->float_type() != NULL)
error_at(this->length_->location(), "array bound is not constant");
else
error_at(this->length_->location(), "array bound is not numeric");
return false;
}
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");
mpz_clear(val);
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");
int tbits = int_type->integer_type()->bits();
int vbits = mpz_sizeinbase(val, 2);
if (vbits + 1 > tbits)
unsigned int tbits = int_type->integer_type()->bits();
if (sizeof(val) <= tbits * 8
&& val >> (tbits - 1) != 0)
{
error_at(this->length_->location(), "array bound overflows");
mpz_clear(val);
return false;
}
mpz_clear(val);
return true;
}
......@@ -5457,11 +5446,11 @@ Array_type::get_length_tree(Gogo* gogo)
go_assert(this->length_ != NULL);
if (this->length_tree_ == NULL_TREE)
{
Numeric_constant nc;
mpz_t val;
mpz_init(val);
Type* t;
if (this->length_->integer_constant_value(true, val, &t))
if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
{
Type* t = nc.type();
if (t == NULL)
t = Type::lookup_integer_type("int");
else if (t->is_abstract())
......@@ -5472,8 +5461,6 @@ Array_type::get_length_tree(Gogo* gogo)
}
else
{
mpz_clear(val);
// Make up a translation context for the array length
// expression. FIXME: This won't work in general.
Translate_context context(gogo, NULL, NULL, NULL);
......@@ -5824,23 +5811,17 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->push_back('[');
if (this->length_ != NULL)
{
mpz_t val;
mpz_init(val);
Type* type;
if (!this->length_->integer_constant_value(true, val, &type))
error_at(this->length_->location(),
"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");
Numeric_constant nc;
unsigned long val;
if (!this->length_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
error_at(this->length_->location(), "invalid array length");
else
{
char buf[50];
snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
snprintf(buf, sizeof buf, "%lu", val);
ret->append(buf);
}
mpz_clear(val);
}
ret->push_back(']');
......@@ -5856,23 +5837,17 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
this->append_mangled_name(this->element_type_, gogo, ret);
if (this->length_ != NULL)
{
mpz_t val;
mpz_init(val);
Type* type;
if (!this->length_->integer_constant_value(true, val, &type))
error_at(this->length_->location(),
"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");
Numeric_constant nc;
unsigned long val;
if (!this->length_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
error_at(this->length_->location(), "invalid array length");
else
{
char buf[50];
snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
snprintf(buf, sizeof buf, "%lu", val);
ret->append(buf);
}
mpz_clear(val);
}
ret->push_back('e');
}
......
......@@ -680,6 +680,14 @@ class Type
complex_type() const
{ 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.
bool
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