From patchwork Wed May 18 17:14:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 96199 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 B2CB51007D8 for ; Thu, 19 May 2011 03:14:45 +1000 (EST) Received: (qmail 14246 invoked by alias); 18 May 2011 17:14:42 -0000 Received: (qmail 14226 invoked by uid 22791); 18 May 2011 17:14:39 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_CX, TW_FN, TW_KF, TW_TM, T_RP_MATCHES_RCVD 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; Wed, 18 May 2011 17:14:24 +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 p4IHENmQ017322 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 18 May 2011 13:14:24 -0400 Received: from [127.0.0.1] (ovpn-113-120.phx2.redhat.com [10.3.113.120]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p4IHEMhA006621 for ; Wed, 18 May 2011 13:14:22 -0400 Message-ID: <4DD3FE6D.5010300@redhat.com> Date: Wed, 18 May 2011 13:14:21 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 To: gcc-patches List Subject: Re: C++ PATCH for c++/48948 (rejecting constexpr friend that takes the current class) References: <4DCAFF44.3000801@redhat.com> In-Reply-To: <4DCAFF44.3000801@redhat.com> 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 On 05/11/2011 05:27 PM, Jason Merrill wrote: > We want to allow a constexpr friend function that takes the current > class, so we need to defer checking the literality of parameter types > until any classes involved are complete. It was pointed out to me that the restriction already only applies to function definitions, not declarations, which dramatically simplifies the code. This patch reverts most of the previous one, and only checks return/parameter types at the point of definition. Tested x86_64-pc-linux-gnu, applying to trunk. commit f2a2c7b6af06123b5f81bd474b60bddfe9b58550 Author: Jason Merrill Date: Mon May 16 17:21:17 2011 -0400 PR c++/48948 PR c++/49015 * class.c (finalize_literal_type_property): Do check for constexpr member functions of non-literal class. (finish_struct): Don't call check_deferred_constexpr_decls. * cp-tree.h: Don't declare it. (DECL_DEFERRED_CONSTEXPR_CHECK): Remove. * decl.c (grok_special_member_properties): Don't check it (grokfnedcl): Don't call validate_constexpr_fundecl. (start_preparsed_function): Do call it. * pt.c (tsubst_decl): Don't call it. (instantiate_class_template_1): Don't call check_deferred_constexpr_decls. * semantics.c (literal_type_p): Check for any incompleteness. (ensure_literal_type_for_constexpr_object): Likewise. (is_valid_constexpr_fn): Revert deferral changes. (validate_constexpr_fundecl): Likewise. (register_constexpr_fundef): Likewise. (check_deferred_constexpr_decls): Remove. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index dc2c509..4e52b18 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4582,6 +4582,8 @@ type_requires_array_cookie (tree type) static void finalize_literal_type_property (tree t) { + tree fn; + if (cxx_dialect < cxx0x || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) /* FIXME These constraints seem unnecessary; remove from standard. @@ -4591,6 +4593,18 @@ finalize_literal_type_property (tree t) else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t) && !TYPE_HAS_CONSTEXPR_CTOR (t)) CLASSTYPE_LITERAL_P (t) = false; + + if (!CLASSTYPE_LITERAL_P (t)) + for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn)) + if (DECL_DECLARED_CONSTEXPR_P (fn) + && TREE_CODE (fn) != TEMPLATE_DECL + && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && !DECL_CONSTRUCTOR_P (fn)) + { + DECL_DECLARED_CONSTEXPR_P (fn) = false; + if (!DECL_TEMPLATE_INFO (fn)) + error ("enclosing class of %q+#D is not a literal type", fn); + } } /* Check the validity of the bases and members declared in T. Add any @@ -5831,8 +5845,6 @@ finish_struct (tree t, tree attributes) else error ("trying to finish struct, but kicked out due to previous parse errors"); - check_deferred_constexpr_decls (); - if (processing_template_decl && at_function_scope_p ()) add_stmt (build_min (TAG_DEFN, t)); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c0b5290..dfb2b66 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -93,7 +93,6 @@ c-common.h, not after. TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR) TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) - DECL_DEFERRED_CONSTEXPR_CHECK (in FUNCTION_DECL) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -2345,11 +2344,6 @@ struct GTY((variable_size)) lang_decl { #define DECL_DECLARED_CONSTEXPR_P(DECL) \ DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL))) -/* True if we can't tell yet whether the argument/return types of DECL - are literal because one is still being defined. */ -#define DECL_DEFERRED_CONSTEXPR_CHECK(DECL) \ - TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL))) - /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a template function. */ #define DECL_PRETTY_FUNCTION_P(NODE) \ @@ -5337,7 +5331,6 @@ extern void finish_handler_parms (tree, tree); extern void finish_handler (tree); extern void finish_cleanup (tree, tree); extern bool literal_type_p (tree); -extern void check_deferred_constexpr_decls (void); extern tree validate_constexpr_fundecl (tree); extern tree register_constexpr_fundef (tree, tree); extern bool check_constexpr_ctor_body (tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7939140..e950c43 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7200,10 +7200,7 @@ grokfndecl (tree ctype, if (inlinep) DECL_DECLARED_INLINE_P (decl) = 1; if (inlinep & 2) - { - DECL_DECLARED_CONSTEXPR_P (decl) = true; - validate_constexpr_fundecl (decl); - } + DECL_DECLARED_CONSTEXPR_P (decl) = true; DECL_EXTERNAL (decl) = 1; if (quals && TREE_CODE (type) == FUNCTION_TYPE) @@ -10681,9 +10678,6 @@ grok_special_member_properties (tree decl) TYPE_HAS_LIST_CTOR (class_type) = 1; if (DECL_DECLARED_CONSTEXPR_P (decl) - /* It doesn't count if we can't tell yet whether or not - the constructor is actually constexpr. */ - && !DECL_DEFERRED_CONSTEXPR_CHECK (decl) && !copy_fn_p (decl) && !move_fn_p (decl)) TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1; } @@ -12524,6 +12518,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags) maybe_apply_pragma_weak (decl1); } + /* constexpr functions must have literal argument types and + literal return type. */ + validate_constexpr_fundecl (decl1); + /* Reset this in case the call to pushdecl changed it. */ current_function_decl = decl1; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index cc14f02..75d0674 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8595,8 +8595,6 @@ instantiate_class_template_1 (tree type) pop_deferring_access_checks (); pop_tinst_level (); - check_deferred_constexpr_decls (); - /* The vtable for a template class can be emitted in any translation unit in which the class is instantiated. When there is no key method, however, finish_struct_1 will already have added TYPE to @@ -9743,7 +9741,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) && !processing_template_decl) defaulted_late_check (r); - validate_constexpr_fundecl (r); apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0, args, complain, in_decl); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 56d2411..8d0cce1 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5337,9 +5337,9 @@ literal_type_p (tree t) return true; if (CLASS_TYPE_P (t)) { - /* We can't answer this question until the class is complete. */ - gcc_assert (!TYPE_BEING_DEFINED (t) || errorcount); - return CLASSTYPE_LITERAL_P (complete_type (t)); + t = complete_type (t); + gcc_assert (COMPLETE_TYPE_P (t) || errorcount); + return CLASSTYPE_LITERAL_P (t); } if (TREE_CODE (t) == ARRAY_TYPE) return literal_type_p (strip_array_types (t)); @@ -5356,7 +5356,7 @@ ensure_literal_type_for_constexpr_object (tree decl) if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl) && !processing_template_decl) { - if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (type)) + if (CLASS_TYPE_P (type) && !COMPLETE_TYPE_P (complete_type (type))) /* Don't complain here, we'll complain about incompleteness when we try to initialize the variable. */; else if (!literal_type_p (type)) @@ -5417,22 +5417,15 @@ retrieve_constexpr_fundef (tree fun) } /* Check whether the parameter and return types of FUN are valid for a - constexpr function, and complain if COMPLAIN. If DEFER_OK is true, - return -1 if we can't tell yet because some of the types are still being - defined. */ + constexpr function, and complain if COMPLAIN. */ -static int -is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) +static bool +is_valid_constexpr_fn (tree fun, bool complain) { -#define IF_NON_LITERAL(TYPE) \ - if (defer_ok && CLASS_TYPE_P (TYPE) && TYPE_BEING_DEFINED (TYPE)) \ - return -1; \ - else if (!literal_type_p (TYPE)) - tree parm = FUNCTION_FIRST_USER_PARM (fun); bool ret = true; for (; parm != NULL; parm = TREE_CHAIN (parm)) - IF_NON_LITERAL (TREE_TYPE (parm)) + if (!literal_type_p (TREE_TYPE (parm))) { ret = false; if (complain) @@ -5443,7 +5436,7 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) if (!DECL_CONSTRUCTOR_P (fun)) { tree rettype = TREE_TYPE (TREE_TYPE (fun)); - IF_NON_LITERAL (rettype) + if (!literal_type_p (rettype)) { ret = false; if (complain) @@ -5451,54 +5444,19 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) rettype, fun); } - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) + /* Check this again here for cxx_eval_call_expression. */ + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) + && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) { - IF_NON_LITERAL (DECL_CONTEXT (fun)) - { - ret = false; - if (complain) - error ("enclosing class of %q+#D is not a literal type", fun); - } + ret = false; + if (complain) + error ("enclosing class of %q+#D is not a literal type", fun); } } return ret; } -/* We can't check the parameter and return types of a constexpr function - for literality until any open classes are complete, so we defer checking - of any constexpr functions declared in a class. */ - -static GTY(()) VEC(tree,gc) *deferred_constexpr_decls; - -void -check_deferred_constexpr_decls (void) -{ - unsigned i; - tree fn; - - /* Some of the deferred decls might still need to be deferred, - so move the vector out of the way. */ - VEC(tree,gc) *vec = deferred_constexpr_decls; - deferred_constexpr_decls = NULL; - - FOR_EACH_VEC_ELT (tree, vec, i, fn) - { - DECL_DEFERRED_CONSTEXPR_CHECK (fn) = false; - validate_constexpr_fundecl (fn); - } - - if (deferred_constexpr_decls == NULL) - { - /* If we didn't need to re-defer any, keep the same vector. */ - VEC_truncate (tree, vec, 0); - deferred_constexpr_decls = vec; - } - else - /* Otherwise, discard the old vector. */ - release_tree_vector (vec); -} - /* Return non-null if FUN certainly designates a valid constexpr function declaration. Otherwise return NULL. Issue appropriate diagnostics if necessary. Note that we only check the declaration, not the body @@ -5507,23 +5465,13 @@ check_deferred_constexpr_decls (void) tree validate_constexpr_fundecl (tree fun) { - int valid; - if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun)) return NULL; else if (DECL_CLONED_FUNCTION_P (fun)) /* We already checked the original function. */ return fun; - valid = is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun), - /*defer_ok=*/true); - if (valid < 0) - { - DECL_DEFERRED_CONSTEXPR_CHECK (fun) = true; - VEC_safe_push (tree, gc, deferred_constexpr_decls, fun); - return NULL; - } - else if (valid == 0) + if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun))) { DECL_DECLARED_CONSTEXPR_P (fun) = false; return NULL; @@ -5768,9 +5716,6 @@ register_constexpr_fundef (tree fun, tree body) constexpr_fundef entry; constexpr_fundef **slot; - gcc_assert (DECL_DECLARED_CONSTEXPR_P (fun) - && !DECL_DEFERRED_CONSTEXPR_CHECK (fun)); - if (DECL_CONSTRUCTOR_P (fun)) body = build_constexpr_constructor_member_initializers (DECL_CONTEXT (fun), body); @@ -6143,7 +6088,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, if (DECL_TEMPLATE_INFO (fun) && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fun)))) - is_valid_constexpr_fn (fun, true, /*defer_ok=*/false); + is_valid_constexpr_fn (fun, true); } *non_constant_p = true; return t; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C index 7a9a24d..dc0b742 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C @@ -1,4 +1,4 @@ -// A constructor that might or might not be constexpr doesn't make +// A constructor that might or might not be constexpr still makes // its class literal. // { dg-options -std=c++0x } @@ -28,4 +28,4 @@ struct D C c; }; -constexpr D d {}; // { dg-error "not literal" } +constexpr D d {}; // { dg-error "not a constexpr function" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C new file mode 100644 index 0000000..81822b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C @@ -0,0 +1,12 @@ +// PR c++/49015 +// { dg-options -std=c++0x } + +class A; + +class B { + friend constexpr B f(A); // Line 5 +}; + +class A {}; + +constexpr B f(A) { return B(); } // Line 10 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C index 4646f82..ef7ac6b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C @@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; } struct Y { Y() { } - constexpr Y f(Y y); // { dg-error "constexpr" } - static constexpr Y g(Y y); // { dg-error "constexpr" } + constexpr Y f(Y y); // { dg-error "not a literal type" } + static constexpr Y g(Y y) {} // { dg-error "constexpr" } };