From 0515f4d2ba0a438d1a6dadb6a88b7c6e5449a129 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 18 May 2011 13:19:15 -0400 Subject: [PATCH] re PR c++/48948 ([C++0x] constexpr friend function cannot be defined in-class) 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. From-SVN: r173869 --- gcc/cp/ChangeLog | 22 +++++ gcc/cp/class.c | 16 +++- gcc/cp/cp-tree.h | 7 -- gcc/cp/decl.c | 12 ++- gcc/cp/pt.c | 3 - gcc/cp/semantics.c | 89 ++++--------------- gcc/testsuite/ChangeLog | 6 ++ .../g++.dg/cpp0x/constexpr-incomplete2.C | 4 +- .../g++.dg/cpp0x/constexpr-incomplete3.C | 12 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C | 4 +- 10 files changed, 80 insertions(+), 95 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6260a3b085d..cc4319eeff0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2011-05-18 Jason Merrill + + 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. + 2011-05-16 Jason Merrill PR c++/48969 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index dc2c509a8cf..4e52b185488 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 c0b52908883..dfb2b66c0ba 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 793914002fe..e950c43e9cf 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 cc14f0275bc..75d0674bb40 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 56d24118540..8d0cce1c478 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/ChangeLog b/gcc/testsuite/ChangeLog index 45b3c5f2708..111a32251c0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-05-18 Jason Merrill + + * g++.dg/cpp0x/constexpr-incomplete3.C: New. + * g++.dg/cpp0x/constexpr-incomplete2.C: Adjust. + * g++.dg/cpp0x/constexpr-memfn1.C: Adjust. + 2011-05-18 Stuart Henderson * gcc.target/bfin/mcpu-bf592.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C index 7a9a24dc40a..dc0b7429dc6 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 00000000000..81822b07e2f --- /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 4646f82b904..ef7ac6b4842 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" } }; -- 2.30.2