compiler: Rewrite handling of untyped numeric constants.
Fixes various bugs when, e.g., using float or complex constants in integer contexts. From-SVN: r185926
This commit is contained in:
parent
23a24bba32
commit
1089b513c0
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,9 @@ class Traverse;
|
|||
class Statement_inserter;
|
||||
class Type;
|
||||
struct Type_context;
|
||||
class Integer_type;
|
||||
class Float_type;
|
||||
class Complex_type;
|
||||
class Function_type;
|
||||
class Map_type;
|
||||
class Struct_type;
|
||||
|
@ -38,6 +41,7 @@ class Field_reference_expression;
|
|||
class Interface_field_reference_expression;
|
||||
class Type_guard_expression;
|
||||
class Receive_expression;
|
||||
class Numeric_constant;
|
||||
class Named_object;
|
||||
class Export;
|
||||
class Import;
|
||||
|
@ -342,30 +346,11 @@ class Expression
|
|||
is_constant() const
|
||||
{ return this->do_is_constant(); }
|
||||
|
||||
// If this is not a constant expression with integral type, return
|
||||
// false. If it is one, return true, and set VAL to the value. VAL
|
||||
// should already be initialized. If this returns true, it sets
|
||||
// *PTYPE to the type of the value, or NULL for an abstract type.
|
||||
// If IOTA_IS_CONSTANT is true, then an iota expression is assumed
|
||||
// to have its final value.
|
||||
// If this is not a numeric constant, return false. If it is one,
|
||||
// return true, and set VAL to hold the value.
|
||||
bool
|
||||
integer_constant_value(bool iota_is_constant, mpz_t val, Type** ptype) const;
|
||||
|
||||
// If this is not a constant expression with floating point type,
|
||||
// return false. If it is one, return true, and set VAL to the
|
||||
// value. VAL should already be initialized. If this returns true,
|
||||
// it sets *PTYPE to the type of the value, or NULL for an abstract
|
||||
// type.
|
||||
bool
|
||||
float_constant_value(mpfr_t val, Type** ptype) const;
|
||||
|
||||
// If this is not a constant expression with complex type, return
|
||||
// false. If it is one, return true, and set REAL and IMAG to the
|
||||
// value. REAL and IMAG should already be initialized. If this
|
||||
// return strue, it sets *PTYPE to the type of the value, or NULL
|
||||
// for an abstract type.
|
||||
bool
|
||||
complex_constant_value(mpfr_t real, mpfr_t imag, Type** ptype) const;
|
||||
numeric_constant_value(Numeric_constant* val) const
|
||||
{ return this->do_numeric_constant_value(val); }
|
||||
|
||||
// If this is not a constant expression with string type, return
|
||||
// false. If it is one, return true, and set VAL to the value.
|
||||
|
@ -691,22 +676,10 @@ class Expression
|
|||
do_is_constant() const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is a constant expression of integral type,
|
||||
// and set VAL to the value.
|
||||
// Return whether this is a constant expression of numeric type, and
|
||||
// set the Numeric_constant to the value.
|
||||
virtual bool
|
||||
do_integer_constant_value(bool, mpz_t, Type**) const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is a constant expression of floating point
|
||||
// type, and set VAL to the value.
|
||||
virtual bool
|
||||
do_float_constant_value(mpfr_t, Type**) const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is a constant expression of complex type, and
|
||||
// set REAL and IMAGE to the value.
|
||||
virtual bool
|
||||
do_complex_constant_value(mpfr_t, mpfr_t, Type**) const
|
||||
do_numeric_constant_value(Numeric_constant*) const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is a constant expression of string type, and
|
||||
|
@ -1189,42 +1162,21 @@ class Binary_expression : public Expression
|
|||
right()
|
||||
{ return this->right_; }
|
||||
|
||||
// Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
|
||||
// LEFT_TYPE is the type of LEFT_VAL, RIGHT_TYPE is the type of
|
||||
// RIGHT_VAL; LEFT_TYPE and/or RIGHT_TYPE may be NULL. Return true
|
||||
// if this could be done, false if not.
|
||||
// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC.
|
||||
// Return true if this could be done, false if not. Issue errors at
|
||||
// LOCATION as appropriate.
|
||||
static bool
|
||||
eval_integer(Operator op, Type* left_type, mpz_t left_val,
|
||||
Type* right_type, mpz_t right_val, Location,
|
||||
mpz_t val);
|
||||
eval_constant(Operator op, Numeric_constant* left_nc,
|
||||
Numeric_constant* right_nc, Location location,
|
||||
Numeric_constant* nc);
|
||||
|
||||
// Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
|
||||
// Return true if this could be done, false if not.
|
||||
// Compare constants LEFT_NC and RIGHT_NC according to OP, setting
|
||||
// *RESULT. Return true if this could be done, false if not. Issue
|
||||
// errors at LOCATION as appropriate.
|
||||
static bool
|
||||
eval_float(Operator op, Type* left_type, mpfr_t left_val,
|
||||
Type* right_type, mpfr_t right_val, mpfr_t val,
|
||||
Location);
|
||||
|
||||
// Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and
|
||||
// RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG. Return true if this
|
||||
// could be done, false if not.
|
||||
static bool
|
||||
eval_complex(Operator op, Type* left_type, mpfr_t left_real,
|
||||
mpfr_t left_imag, Type* right_type, mpfr_t right_real,
|
||||
mpfr_t right_imag, mpfr_t real, mpfr_t imag, Location);
|
||||
|
||||
// Compare integer constants according to OP.
|
||||
static bool
|
||||
compare_integer(Operator op, mpz_t left_val, mpz_t right_val);
|
||||
|
||||
// Compare floating point constants according to OP.
|
||||
static bool
|
||||
compare_float(Operator op, Type* type, mpfr_t left_val, mpfr_t right_val);
|
||||
|
||||
// Compare complex constants according to OP.
|
||||
static bool
|
||||
compare_complex(Operator op, Type* type, mpfr_t left_real, mpfr_t left_imag,
|
||||
mpfr_t right_val, mpfr_t right_imag);
|
||||
compare_constant(Operator op, Numeric_constant* left_nc,
|
||||
Numeric_constant* right_nc, Location location,
|
||||
bool* result);
|
||||
|
||||
static Expression*
|
||||
do_import(Import*);
|
||||
|
@ -1246,13 +1198,7 @@ class Binary_expression : public Expression
|
|||
{ return this->left_->is_constant() && this->right_->is_constant(); }
|
||||
|
||||
bool
|
||||
do_integer_constant_value(bool, mpz_t val, Type**) const;
|
||||
|
||||
bool
|
||||
do_float_constant_value(mpfr_t val, Type**) const;
|
||||
|
||||
bool
|
||||
do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
|
||||
do_numeric_constant_value(Numeric_constant*) const;
|
||||
|
||||
void
|
||||
do_discarding_value();
|
||||
|
@ -1283,6 +1229,34 @@ class Binary_expression : public Expression
|
|||
do_dump_expression(Ast_dump_context*) const;
|
||||
|
||||
private:
|
||||
static bool
|
||||
operation_type(Operator op, Type* left_type, Type* right_type,
|
||||
Type** result_type);
|
||||
|
||||
static bool
|
||||
cmp_to_bool(Operator op, int cmp);
|
||||
|
||||
static bool
|
||||
eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*,
|
||||
Location, Numeric_constant*);
|
||||
|
||||
static bool
|
||||
eval_float(Operator op, const Numeric_constant*, const Numeric_constant*,
|
||||
Location, Numeric_constant*);
|
||||
|
||||
static bool
|
||||
eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*,
|
||||
Location, Numeric_constant*);
|
||||
|
||||
static bool
|
||||
compare_integer(const Numeric_constant*, const Numeric_constant*, int*);
|
||||
|
||||
static bool
|
||||
compare_float(const Numeric_constant*, const Numeric_constant *, int*);
|
||||
|
||||
static bool
|
||||
compare_complex(const Numeric_constant*, const Numeric_constant*, int*);
|
||||
|
||||
Expression*
|
||||
lower_struct_comparison(Gogo*, Statement_inserter*);
|
||||
|
||||
|
@ -2101,4 +2075,173 @@ class Receive_expression : public Expression
|
|||
Expression* channel_;
|
||||
};
|
||||
|
||||
// A numeric constant. This is used both for untyped constants and
|
||||
// for constants that have a type.
|
||||
|
||||
class Numeric_constant
|
||||
{
|
||||
public:
|
||||
Numeric_constant()
|
||||
: classification_(NC_INVALID), type_(NULL)
|
||||
{ }
|
||||
|
||||
~Numeric_constant();
|
||||
|
||||
Numeric_constant(const Numeric_constant&);
|
||||
|
||||
Numeric_constant& operator=(const Numeric_constant&);
|
||||
|
||||
// Set to an unsigned long value.
|
||||
void
|
||||
set_unsigned_long(Type*, unsigned long);
|
||||
|
||||
// Set to an integer value.
|
||||
void
|
||||
set_int(Type*, const mpz_t);
|
||||
|
||||
// Set to a rune value.
|
||||
void
|
||||
set_rune(Type*, const mpz_t);
|
||||
|
||||
// Set to a floating point value.
|
||||
void
|
||||
set_float(Type*, const mpfr_t);
|
||||
|
||||
// Set to a complex value.
|
||||
void
|
||||
set_complex(Type*, const mpfr_t, const mpfr_t);
|
||||
|
||||
// Classifiers.
|
||||
bool
|
||||
is_int() const
|
||||
{ return this->classification_ == Numeric_constant::NC_INT; }
|
||||
|
||||
bool
|
||||
is_rune() const
|
||||
{ return this->classification_ == Numeric_constant::NC_RUNE; }
|
||||
|
||||
bool
|
||||
is_float() const
|
||||
{ return this->classification_ == Numeric_constant::NC_FLOAT; }
|
||||
|
||||
bool
|
||||
is_complex() const
|
||||
{ return this->classification_ == Numeric_constant::NC_COMPLEX; }
|
||||
|
||||
// Value retrievers. These will initialize the values as well as
|
||||
// set them. GET_INT is only valid if IS_INT returns true, and
|
||||
// likewise respectively.
|
||||
void
|
||||
get_int(mpz_t*) const;
|
||||
|
||||
void
|
||||
get_rune(mpz_t*) const;
|
||||
|
||||
void
|
||||
get_float(mpfr_t*) const;
|
||||
|
||||
void
|
||||
get_complex(mpfr_t*, mpfr_t*) const;
|
||||
|
||||
// Codes returned by to_unsigned_long.
|
||||
enum To_unsigned_long
|
||||
{
|
||||
// Value is integer and fits in unsigned long.
|
||||
NC_UL_VALID,
|
||||
// Value is not integer.
|
||||
NC_UL_NOTINT,
|
||||
// Value is integer but is negative.
|
||||
NC_UL_NEGATIVE,
|
||||
// Value is non-negative integer but does not fit in unsigned
|
||||
// long.
|
||||
NC_UL_BIG
|
||||
};
|
||||
|
||||
// If the value can be expressed as an integer that fits in an
|
||||
// unsigned long, set *VAL and return NC_UL_VALID. Otherwise return
|
||||
// one of the other To_unsigned_long codes.
|
||||
To_unsigned_long
|
||||
to_unsigned_long(unsigned long* val) const;
|
||||
|
||||
// If the value can be expressed as an int, return true and
|
||||
// initialize and set VAL. This will return false for a value with
|
||||
// an explicit float or complex type, even if the value is integral.
|
||||
bool
|
||||
to_int(mpz_t* val) const;
|
||||
|
||||
// If the value can be expressed as a float, return true and
|
||||
// initialize and set VAL.
|
||||
bool
|
||||
to_float(mpfr_t* val) const;
|
||||
|
||||
// If the value can be expressed as a complex, return true and
|
||||
// initialize and set VR and VI.
|
||||
bool
|
||||
to_complex(mpfr_t* vr, mpfr_t* vi) const;
|
||||
|
||||
// Get the type.
|
||||
Type*
|
||||
type() const;
|
||||
|
||||
// If the constant can be expressed in TYPE, then set the type of
|
||||
// the constant to TYPE and return true. Otherwise return false,
|
||||
// and, if ISSUE_ERROR is true, issue an error message. LOCATION is
|
||||
// the location to use for the error.
|
||||
bool
|
||||
set_type(Type* type, bool issue_error, Location location);
|
||||
|
||||
// Return an Expression for this value.
|
||||
Expression*
|
||||
expression(Location) const;
|
||||
|
||||
private:
|
||||
void
|
||||
clear();
|
||||
|
||||
To_unsigned_long
|
||||
mpz_to_unsigned_long(const mpz_t ival, unsigned long *val) const;
|
||||
|
||||
To_unsigned_long
|
||||
mpfr_to_unsigned_long(const mpfr_t fval, unsigned long *val) const;
|
||||
|
||||
bool
|
||||
check_int_type(Integer_type*, bool, Location) const;
|
||||
|
||||
bool
|
||||
check_float_type(Float_type*, bool, Location) const;
|
||||
|
||||
bool
|
||||
check_complex_type(Complex_type*, bool, Location) const;
|
||||
|
||||
// The kinds of constants.
|
||||
enum Classification
|
||||
{
|
||||
NC_INVALID,
|
||||
NC_RUNE,
|
||||
NC_INT,
|
||||
NC_FLOAT,
|
||||
NC_COMPLEX
|
||||
};
|
||||
|
||||
// The kind of constant.
|
||||
Classification classification_;
|
||||
// The value.
|
||||
union
|
||||
{
|
||||
// If NC_INT or NC_RUNE.
|
||||
mpz_t int_val;
|
||||
// If NC_FLOAT.
|
||||
mpfr_t float_val;
|
||||
// If NC_COMPLEX.
|
||||
struct
|
||||
{
|
||||
mpfr_t real;
|
||||
mpfr_t imag;
|
||||
} complex_val;
|
||||
} u_;
|
||||
// The type if there is one. This will be NULL for an untyped
|
||||
// constant.
|
||||
Type* type_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_EXPRESSIONS_H)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
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)
|
||||
Numeric_constant nc;
|
||||
if (!at->length()->numeric_constant_value(&nc))
|
||||
return false;
|
||||
mpz_t ival;
|
||||
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))
|
||||
{
|
||||
error_at(this->length_->location(), "negative array bound");
|
||||
mpz_clear(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");
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue