From patchwork Tue Oct 11 17:50:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 119035 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 5133EB6F71 for ; Wed, 12 Oct 2011 04:51:10 +1100 (EST) Received: (qmail 14047 invoked by alias); 11 Oct 2011 17:51:06 -0000 Received: (qmail 14037 invoked by uid 22791); 11 Oct 2011 17:51:04 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_BJ, TW_CX, TW_JC X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 11 Oct 2011 17:50:46 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9BHokAY007505 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 11 Oct 2011 13:50:46 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p9BHojJY026880 for ; Tue, 11 Oct 2011 13:50:46 -0400 Received: from [0.0.0.0] (ovpn-113-114.phx2.redhat.com [10.3.113.114]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p9BHohOg028410 for ; Tue, 11 Oct 2011 13:50:44 -0400 Message-ID: <4E9481F3.4030708@redhat.com> Date: Tue, 11 Oct 2011 13:50:43 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111001 Thunderbird/7.0.1 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/49855, c++/49896 (ICE with named constants in templates) 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 The problem in both of these PRs is that G++ has assumed that we don't ever need to actually perform non-dependent conversions in a template; once we know that the conversion can be performed, we just generated a NOP_EXPR to change the type of the expression. But this isn't good enough for initializers for variables that might be used in constant expressions, since we want to reduce them to constants if possible. For conversions between scalar types, we can just go ahead and perform the conversion; this is a bit of a boundary violation, but should be harmless since such conversions are represented by a single tree code that we can just pass along at tsubst time. This is also necessary to avoid breaking checking of non-dependent OpenMP for loops in c_finish_omp_for. For C++11 constexpr conversions, it's more involved, so I've introduced a new tree code IMPLICIT_CONV_EXPR. Tested x86_64-pc-linux-gnu, applying to trunk. commit 6800169668342f9009a1001bddff8b1400245836 Author: Jason Merrill Date: Sun Oct 9 23:27:52 2011 +0100 PR c++/49855 PR c++/49896 * cp-tree.def (IMPLICIT_CONV_EXPR): New. * call.c (perform_implicit_conversion_flags): Build it instead of NOP_EXPR. * cp-objcp-common.c (cp_common_init_ts): It's typed. * cxx-pretty-print.c (pp_cxx_cast_expression): Handle it. (pp_cxx_expression): Likewise. * error.c (dump_expr): Likewise. * semantics.c (potential_constant_expression_1): Likewise. * tree.c (cp_tree_equal): Likewise. (cp_walk_subtrees): Likewise. * pt.c (iterative_hash_template_arg): Likewise. (for_each_template_parm_r): Likewise. (type_dependent_expression_p): Likewise. (tsubst_copy, tsubst_copy_and_build): Handle IMPLICIT_CONV_EXPR and CONVERT_EXPR. * cp-tree.h (IMPLICIT_CONV_EXPR_DIRECT_INIT): New. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4c03e76..7219afe 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8397,13 +8397,19 @@ perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain } expr = error_mark_node; } - else if (processing_template_decl) + else if (processing_template_decl + /* As a kludge, we always perform conversions between scalar + types, as IMPLICIT_CONV_EXPR confuses c_finish_omp_for. */ + && !(SCALAR_TYPE_P (type) && SCALAR_TYPE_P (TREE_TYPE (expr)))) { /* In a template, we are only concerned about determining the type of non-dependent expressions, so we do not have to - perform the actual conversion. */ - if (TREE_TYPE (expr) != type) - expr = build_nop (type, expr); + perform the actual conversion. But for initializers, we + need to be able to perform it at instantiation + (or fold_non_dependent_expr) time. */ + expr = build1 (IMPLICIT_CONV_EXPR, type, expr); + if (!(flags & LOOKUP_ONLYCONVERTING)) + IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true; } else expr = convert_like (conv, expr, complain); diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 1866b81..035fdcd 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -267,6 +267,7 @@ cp_common_init_ts (void) MARK_TS_TYPED (CONST_CAST_EXPR); MARK_TS_TYPED (STATIC_CAST_EXPR); MARK_TS_TYPED (DYNAMIC_CAST_EXPR); + MARK_TS_TYPED (IMPLICIT_CONV_EXPR); MARK_TS_TYPED (TEMPLATE_ID_EXPR); MARK_TS_TYPED (ARROW_EXPR); MARK_TS_TYPED (SIZEOF_EXPR); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index bb1b753..be29870 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -250,6 +250,7 @@ DEFTREECODE (REINTERPRET_CAST_EXPR, "reinterpret_cast_expr", tcc_unary, 1) DEFTREECODE (CONST_CAST_EXPR, "const_cast_expr", tcc_unary, 1) DEFTREECODE (STATIC_CAST_EXPR, "static_cast_expr", tcc_unary, 1) DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", tcc_unary, 1) +DEFTREECODE (IMPLICIT_CONV_EXPR, "implicit_conv_expr", tcc_unary, 1) DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2) DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1) DEFTREECODE (NOEXCEPT_EXPR, "noexcept_expr", tcc_unary, 1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f824f38..b53accf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -72,6 +72,7 @@ c-common.h, not after. DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE) VEC_INIT_EXPR_IS_CONSTEXPR (in VEC_INIT_EXPR) DECL_OVERRIDE_P (in FUNCTION_DECL) + IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -3233,6 +3234,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) B b{1,2}, not B b({1,2}) or B b = {1,2}. */ #define CONSTRUCTOR_IS_DIRECT_INIT(NODE) (TREE_LANG_FLAG_0 (CONSTRUCTOR_CHECK (NODE))) +/* True if NODE represents a conversion for direct-initialization in a + template. Set by perform_implicit_conversion_flags. */ +#define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \ + (TREE_LANG_FLAG_0 (IMPLICIT_CONV_EXPR_CHECK (NODE))) + /* Nonzero means that an object of this type can not be initialized using an initializer list. */ #define CLASSTYPE_NON_AGGREGATE(NODE) \ diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index c5f1ac0..708afc8 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -830,6 +830,7 @@ pp_cxx_cast_expression (cxx_pretty_printer *pp, tree t) switch (TREE_CODE (t)) { case CAST_EXPR: + case IMPLICIT_CONV_EXPR: pp_cxx_type_id (pp, TREE_TYPE (t)); pp_cxx_call_argument_list (pp, TREE_OPERAND (t, 0)); break; @@ -1084,6 +1085,7 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t) break; case CAST_EXPR: + case IMPLICIT_CONV_EXPR: pp_cxx_cast_expression (pp, t); break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 4d12a0d..7d345c9 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2052,6 +2052,7 @@ dump_expr (tree t, int flags) break; CASE_CONVERT: + case IMPLICIT_CONV_EXPR: case VIEW_CONVERT_EXPR: { tree op = TREE_OPERAND (t, 0); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c95f1cb..43c4185 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1591,6 +1591,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) return val; case CAST_EXPR: + case IMPLICIT_CONV_EXPR: case STATIC_CAST_EXPR: case REINTERPRET_CAST_EXPR: case CONST_CAST_EXPR: @@ -7702,6 +7703,7 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) case MODOP_EXPR: case CAST_EXPR: + case IMPLICIT_CONV_EXPR: case REINTERPRET_CAST_EXPR: case CONST_CAST_EXPR: case STATIC_CAST_EXPR: @@ -11714,7 +11716,7 @@ tsubst_qualified_id (tree qualified_id, tree args, /* Like tsubst, but deals with expressions. This function just replaces template parms; to finish processing the resultant expression, use - tsubst_expr. */ + tsubst_copy_and_build or tsubst_expr. */ static tree tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) @@ -11879,6 +11881,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case CONST_CAST_EXPR: case STATIC_CAST_EXPR: case DYNAMIC_CAST_EXPR: + case IMPLICIT_CONV_EXPR: + case CONVERT_EXPR: case NOP_EXPR: return build1 (code, tsubst (TREE_TYPE (t), args, complain, in_decl), @@ -13077,6 +13081,23 @@ tsubst_copy_and_build (tree t, (tsubst (TREE_TYPE (t), args, complain, in_decl), RECUR (TREE_OPERAND (t, 0))); + case IMPLICIT_CONV_EXPR: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree expr = RECUR (TREE_OPERAND (t, 0)); + int flags = LOOKUP_IMPLICIT; + if (IMPLICIT_CONV_EXPR_DIRECT_INIT (t)) + flags = LOOKUP_NORMAL; + return perform_implicit_conversion_flags (type, expr, complain, + flags); + } + + case CONVERT_EXPR: + return build1 + (CONVERT_EXPR, + tsubst (TREE_TYPE (t), args, complain, in_decl), + RECUR (TREE_OPERAND (t, 0))); + case CAST_EXPR: case REINTERPRET_CAST_EXPR: case CONST_CAST_EXPR: @@ -19172,6 +19193,7 @@ type_dependent_expression_p (tree expression) || TREE_CODE (expression) == STATIC_CAST_EXPR || TREE_CODE (expression) == CONST_CAST_EXPR || TREE_CODE (expression) == REINTERPRET_CAST_EXPR + || TREE_CODE (expression) == IMPLICIT_CONV_EXPR || TREE_CODE (expression) == CAST_EXPR) return dependent_type_p (TREE_TYPE (expression)); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 7ad1e8d..189c13a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7481,8 +7481,6 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t, return t; case LAMBDA_EXPR: - case DYNAMIC_CAST_EXPR: - case PSEUDO_DTOR_EXPR: case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: case PREDECREMENT_EXPR: @@ -8023,6 +8021,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) case CONST_CAST_EXPR: case STATIC_CAST_EXPR: case REINTERPRET_CAST_EXPR: + case IMPLICIT_CONV_EXPR: return (potential_constant_expression_1 (TREE_OPERAND (t, 0), TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags)); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f23b888..75aa265 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2384,6 +2384,7 @@ cp_tree_equal (tree t1, tree t2) case REINTERPRET_CAST_EXPR: case CONST_CAST_EXPR: case DYNAMIC_CAST_EXPR: + case IMPLICIT_CONV_EXPR: case NEW_EXPR: if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) return false; @@ -2994,6 +2995,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, case STATIC_CAST_EXPR: case CONST_CAST_EXPR: case DYNAMIC_CAST_EXPR: + case IMPLICIT_CONV_EXPR: if (TREE_TYPE (*tp)) WALK_SUBTREE (TREE_TYPE (*tp)); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-template3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-template3.C new file mode 100644 index 0000000..75b2fc4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-template3.C @@ -0,0 +1,9 @@ +// { dg-options -std=c++0x } + +struct A { constexpr operator int() { return 42; } }; + +template +struct B { + static const int versionConst = A(); + enum { versionEnum = versionConst }; +}; diff --git a/gcc/testsuite/g++.dg/template/constant1.C b/gcc/testsuite/g++.dg/template/constant1.C new file mode 100644 index 0000000..a2c5a08 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/constant1.C @@ -0,0 +1,13 @@ +// PR c++/49855 + +extern void foo(int); + +template void Basic() { + const int kT = 1.5e6; // <--- causes ICE + int size = kT*2/3; + do { + foo(size); + size = size * 0.5 - 1; + } while (size >= 0 ); + +} diff --git a/gcc/testsuite/g++.dg/template/constant2.C b/gcc/testsuite/g++.dg/template/constant2.C new file mode 100644 index 0000000..f71e4f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/constant2.C @@ -0,0 +1,22 @@ +// PR c++/49896 + +template +class test { + protected: + static const int versionConst = 0x80000000; + enum { versionEnum = versionConst }; + public: + int getVersion(); +}; + +template +int test::getVersion() { + return versionEnum; +} + +class dummy_class {}; + +int main() { + test t; + return t.getVersion(); +}