diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-21 20:24:17 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-21 20:24:17 +0000 |
commit | fe53b3ddeca7f359e9121b7f503f7aae4c55abd4 (patch) | |
tree | a917549ee1fdb211a2c24e67594548ec46e5ede1 | |
parent | b17e0d797cbaceb03529e3f71ec5aa81a26ba253 (diff) | |
download | gcc-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
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 69 |
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; } |