From patchwork Tue Jun 22 21:50:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [gccgo] Permit passing a floating point constant to make X-Patchwork-Submitter: Ian Taylor X-Patchwork-Id: 56573 Message-Id: To: gcc-patches@gcc.gnu.org Date: Tue, 22 Jun 2010 14:50:12 -0700 From: Ian Lance Taylor List-Id: Some Go code passes a floating point constant to the predeclared function make, which is OK provided the floating point constant actually has an integer value (e.g., 1e2). This patch permits this in the gccgo frontend. Committed to gccgo branch. Ian diff -r 3de4aff5ab46 go/types.cc --- a/go/types.cc Tue Jun 22 13:34:56 2010 -0700 +++ b/go/types.cc Tue Jun 22 14:47:49 2010 -0700 @@ -638,6 +638,59 @@ gcc_unreachable(); } +// Return whether an expression has an integer value. Report an error +// if not. This is used when handling calls to the predeclared make +// function. + +bool +Type::check_int_value(Expression* e, const char* errmsg, + source_location location) +{ + if (e->type()->integer_type() != NULL) + return true; + + // Check for a floating point constant with integer value. + mpfr_t fval; + mpfr_init(fval); + + Type* dummy; + if (e->float_constant_value(fval, &dummy)) + { + mpz_t ival; + mpz_init(ival); + + bool ok = false; + + mpfr_clear_overflow(); + mpfr_clear_erangeflag(); + mpfr_get_z(ival, fval, GMP_RNDN); + if (!mpfr_overflow_p() + && !mpfr_erangeflag_p() + && mpz_sgn(ival) >= 0) + { + Named_type* ntype = Type::lookup_integer_type("int"); + Integer_type* inttype = ntype->integer_type(); + mpz_t max; + mpz_init_set_ui(max, 1); + mpz_mul_2exp(max, max, inttype->bits() - 1); + ok = mpz_cmp(ival, max) < 0; + mpz_clear(max); + } + mpz_clear(ival); + + if (ok) + { + mpfr_clear(fval); + return true; + } + } + + mpfr_clear(fval); + + error_at(location, errmsg); + return false; +} + // Return a tree representing this type. tree @@ -3334,21 +3387,18 @@ } else { - Type* type = (*args->begin())->type(); - if (type == NULL || type->integer_type() == NULL) - { - error_at(location, "bad type for length when making slice"); - return false; - } + if (!Type::check_int_value(args->front(), + _("bad length when making slice"), location)) + return false; + if (args->size() > 1) { - type = args->back()->type(); - if (type == NULL || type->integer_type() == NULL) - { - error_at(location, "bad type for capacity when making slice"); - return false; - } - } + if (!Type::check_int_value(args->back(), + _("bad capacity when making slice"), + location)) + return false; + } + return true; } } @@ -3546,7 +3596,7 @@ tree length_tree = args->front()->get_tree(context); if (length_tree == error_mark_node) return error_mark_node; - length_tree = fold_convert_loc(location, TREE_TYPE(count_field), length_tree); + length_tree = ::convert(TREE_TYPE(count_field), length_tree); length_tree = save_expr(length_tree); tree capacity_tree; if (args->size() == 1) @@ -3554,8 +3604,7 @@ else { capacity_tree = args->back()->get_tree(context); - capacity_tree = fold_convert_loc(location, TREE_TYPE(count_field), - capacity_tree); + capacity_tree = ::convert(TREE_TYPE(count_field), capacity_tree); capacity_tree = save_expr(capacity_tree); capacity_tree = fold_build3_loc(location, COND_EXPR, TREE_TYPE(count_field), @@ -3866,12 +3915,9 @@ { if (args != NULL && !args->empty()) { - Type* type = (*args->begin())->type(); - if (type == NULL || type->integer_type() == NULL) - { - error_at(location, "bad type for map size"); - return false; - } + if (!Type::check_int_value(args->front(), _("bad size when making map"), + location)) + return false; else if (args->size() > 1) { error_at(location, "too many arguments when making map"); @@ -3960,9 +4006,10 @@ expr_tree = size_zero_node; else { - expr_tree = (*args->begin())->get_tree(context); + expr_tree = args->front()->get_tree(context); if (expr_tree == error_mark_node) return error_mark_node; + expr_tree = ::convert(sizetype, expr_tree); } tree map_type = this->get_tree(context->gogo()); @@ -4080,12 +4127,10 @@ { if (args != NULL && !args->empty()) { - Type* type = args->front()->type(); - if (type == NULL || type->integer_type() == NULL) - { - error_at(location, "bad type for channel buffer size"); - return false; - } + if (!Type::check_int_value(args->front(), + _("bad buffer size when making channel"), + location)) + return false; else if (args->size() > 1) { error_at(location, "too many arguments when making channel"); @@ -4140,7 +4185,7 @@ tree expr_tree; if (args != NULL && !args->empty()) - expr_tree = fold_convert(sizetype, (*args->begin())->get_tree(context)); + expr_tree = ::convert(sizetype, args->front()->get_tree(context)); else expr_tree = size_zero_node; diff -r 3de4aff5ab46 go/types.h --- a/go/types.h Tue Jun 22 13:34:56 2010 -0700 +++ b/go/types.h Tue Jun 22 14:47:49 2010 -0700 @@ -932,6 +932,10 @@ virtual void do_export(Export*) const; + // Return whether an expression is an integer. + static bool + check_int_value(Expression*, const char*, source_location); + // Return whether a method expects a pointer as the receiver. static bool method_expects_pointer(const Named_object*);