From patchwork Tue Jun 22 21:50:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 56573 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 45804B6F19 for ; Wed, 23 Jun 2010 07:50:32 +1000 (EST) Received: (qmail 7637 invoked by alias); 22 Jun 2010 21:50:31 -0000 Received: (qmail 7626 invoked by uid 22791); 22 Jun 2010 21:50:30 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CC, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 22 Jun 2010 21:50:23 +0000 Received: from wpaz37.hot.corp.google.com (wpaz37.hot.corp.google.com [172.24.198.101]) by smtp-out.google.com with ESMTP id o5MLoLOM011097 for ; Tue, 22 Jun 2010 14:50:21 -0700 Received: from pvg7 (pvg7.prod.google.com [10.241.210.135]) by wpaz37.hot.corp.google.com with ESMTP id o5MLoAWs011330 for ; Tue, 22 Jun 2010 14:50:21 -0700 Received: by pvg7 with SMTP id 7so1376562pvg.29 for ; Tue, 22 Jun 2010 14:50:20 -0700 (PDT) Received: by 10.142.121.5 with SMTP id t5mr6006857wfc.277.1277243420666; Tue, 22 Jun 2010 14:50:20 -0700 (PDT) Received: from coign.google.com (dhcp-172-22-126-240.mtv.corp.google.com [172.22.126.240]) by mx.google.com with ESMTPS id w39sm1376004wfh.15.2010.06.22.14.50.19 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 22 Jun 2010 14:50:19 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [gccgo] Permit passing a floating point constant to make From: Ian Lance Taylor Date: Tue, 22 Jun 2010 14:50:12 -0700 Message-ID: User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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*);