aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-09-21 20:24:17 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-09-21 20:24:17 +0000
commitfe53b3ddeca7f359e9121b7f503f7aae4c55abd4 (patch)
treea917549ee1fdb211a2c24e67594548ec46e5ede1 /gcc
parentb17e0d797cbaceb03529e3f71ec5aa81a26ba253 (diff)
downloadgcc-fe53b3ddeca7f359e9121b7f503f7aae4c55abd4.zip
gcc-fe53b3ddeca7f359e9121b7f503f7aae4c55abd4.tar.gz
gcc-fe53b3ddeca7f359e9121b7f503f7aae4c55abd4.tar.bz2
Better error message for shift context types.
Fix shift of floating point constant to generate constant. From-SVN: r179057
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/expressions.cc69
1 files changed, 59 insertions, 10 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 4e9d8d8..bf829b5 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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;
}