Better error message for shift context types.

Fix shift of floating point constant to generate constant.

From-SVN: r179057
This commit is contained in:
Ian Lance Taylor 2011-09-21 20:24:17 +00:00
parent b17e0d797c
commit fe53b3ddec

View file

@ -5671,6 +5671,50 @@ Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
return Expression::make_string(left_string + right_string, location);
}
// Special case for shift of a floating point constant.
if (op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT)
{
mpfr_t left_val;
mpfr_init(left_val);
Type* left_type;
mpz_t right_val;
mpz_init(right_val);
Type* right_type;
if (left->float_constant_value(left_val, &left_type)
&& right->integer_constant_value(false, right_val, &right_type)
&& mpfr_integer_p(left_val)
&& (left_type == NULL
|| left_type->is_abstract()
|| left_type->integer_type() != NULL))
{
mpz_t left_int;
mpz_init(left_int);
mpfr_get_z(left_int, left_val, GMP_RNDN);
mpz_t val;
mpz_init(val);
Expression* ret = NULL;
if (Binary_expression::eval_integer(op, left_type, left_int,
right_type, right_val,
location, val))
ret = Expression::make_integer(&val, left_type, location);
mpz_clear(left_int);
mpz_clear(val);
if (ret != NULL)
{
mpfr_clear(left_val);
mpz_clear(right_val);
return ret;
}
}
mpfr_clear(left_val);
mpz_clear(right_val);
}
return this;
}
@ -5939,14 +5983,8 @@ Binary_expression::do_determine_type(const Type_context* context)
// Set the context for the left hand operand.
if (is_shift_op)
{
// The right hand operand plays no role in determining the type
// of the left hand operand. A shift of an abstract integer in
// a string context gets special treatment, which may be a
// language bug.
if (subcontext.type != NULL
&& subcontext.type->is_string_type()
&& tleft->is_abstract())
error_at(this->location(), "shift of non-integer operand");
// The right hand operand of a shift plays no role in
// determining the type of the left hand operand.
}
else if (!tleft->is_abstract())
subcontext.type = tleft;
@ -5979,10 +6017,21 @@ Binary_expression::do_determine_type(const Type_context* context)
this->left_->determine_type(&subcontext);
// The context for the right hand operand is the same as for the
// left hand operand, except for a shift operator.
if (is_shift_op)
{
// We may have inherited an unusable type for the shift operand.
// Give a useful error if that happened.
if (tleft->is_abstract()
&& subcontext.type != NULL
&& (this->left_->type()->integer_type() == NULL
|| (subcontext.type->integer_type() == NULL
&& subcontext.type->float_type() == NULL
&& subcontext.type->complex_type() == NULL)))
this->report_error(("invalid context-determined non-integer type "
"for shift operand"));
// The context for the right hand operand is the same as for the
// left hand operand, except for a shift operator.
subcontext.type = Type::lookup_integer_type("uint");
subcontext.may_be_abstract = false;
}