From 225a658415367be2700835fec916c091cd6a6945 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Reis Date: Wed, 27 Oct 2010 16:11:29 -0400 Subject: [PATCH] method.c (synthesized_method_walk): Track constexprness too. * method.c (synthesized_method_walk): Track constexprness too. (process_subob_fn, walk_field_subobs): Likewise. (implicitly_declare_fn): Set DECL_DECLARED_CONSTEXPR_P. (defaulted_late_check): Handle DECL_DECLARED_CONSTEXPR_P. * class.c (add_implicitly_declared_members): Handle constexpr default ctor. Co-Authored-By: Jason Merrill From-SVN: r166014 --- gcc/cp/ChangeLog | 7 + gcc/cp/class.c | 15 +- gcc/cp/method.c | 133 ++++++++++++------ gcc/testsuite/g++.dg/cpp0x/constexpr-delete.C | 3 + 4 files changed, 114 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-delete.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5fe0f17592c..8402c720236 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6 +1,13 @@ 2010-10-27 Gabriel Dos Reis Jason Merrill + * method.c (synthesized_method_walk): Track constexprness too. + (process_subob_fn, walk_field_subobs): Likewise. + (implicitly_declare_fn): Set DECL_DECLARED_CONSTEXPR_P. + (defaulted_late_check): Handle DECL_DECLARED_CONSTEXPR_P. + * class.c (add_implicitly_declared_members): Handle + constexpr default ctor. + * parser.c (cp_parser_ctor_initializer_opt_and_function_body): Make sure a constexpr ctor has an empty body. * class.c (type_has_constexpr_default_constructor): New. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c3e3c53afe6..a31aad3aba7 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2672,7 +2672,20 @@ add_implicitly_declared_members (tree t, if (! TYPE_HAS_USER_CONSTRUCTOR (t)) { TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1; - CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; + if (TYPE_HAS_TRIVIAL_DFLT (t)) + { + /* A trivial default constructor is constexpr + if there is nothing to initialize. */ + if (cxx_dialect >= cxx0x && is_really_empty_class (t)) + TYPE_HAS_CONSTEXPR_CTOR (t) = 1; + CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; + } + else if (cxx_dialect >= cxx0x) + /* We need to go ahead and declare this to set + TYPE_HAS_CONSTEXPR_CTOR. */ + lazily_declare_fn (sfk_constructor, t); + else + CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; } /* [class.ctor] diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 1083e16dc55..6687c75f2a3 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -903,7 +903,8 @@ get_copy_assign (tree type) static void process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, - bool *deleted_p, const char *msg, tree arg) + bool *deleted_p, bool *constexpr_p, + const char *msg, tree arg) { if (!fn || fn == error_mark_node) goto bad; @@ -935,6 +936,9 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, goto bad; } + if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn)) + *constexpr_p = false; + return; bad: @@ -949,7 +953,7 @@ static void walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, int quals, bool copy_arg_p, bool move_p, bool assign_p, tree *spec_p, bool *trivial_p, - bool *deleted_p, const char *msg, + bool *deleted_p, bool *constexpr_p, const char *msg, int flags, tsubst_flags_t complain) { tree field; @@ -1005,6 +1009,13 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, if (bad && deleted_p) *deleted_p = true; + + /* For an implicitly-defined default constructor to be constexpr, + every member must have a user-provided default constructor. */ + /* FIXME will need adjustment for non-static data member + initializers. */ + if (constexpr_p && !CLASS_TYPE_P (mem_type)) + *constexpr_p = false; } if (!CLASS_TYPE_P (mem_type)) @@ -1014,7 +1025,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, { walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals, copy_arg_p, move_p, assign_p, spec_p, trivial_p, - deleted_p, msg, flags, complain); + deleted_p, constexpr_p, msg, flags, complain); continue; } @@ -1031,7 +1042,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - msg, field); + constexpr_p, msg, field); } } @@ -1044,7 +1055,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, static void synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, tree *spec_p, bool *trivial_p, bool *deleted_p, - bool diag) + bool *constexpr_p, bool diag) { tree binfo, base_binfo, scope, fnname, rval, argtype; bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor; @@ -1078,6 +1089,41 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, *deleted_p = false; } + ctor_p = false; + assign_p = false; + check_vdtor = false; + switch (sfk) + { + case sfk_move_assignment: + case sfk_copy_assignment: + assign_p = true; + fnname = ansi_assopname (NOP_EXPR); + break; + + case sfk_destructor: + check_vdtor = true; + /* The synthesized method will call base dtors, but check complete + here to avoid having to deal with VTT. */ + fnname = complete_dtor_identifier; + break; + + case sfk_constructor: + case sfk_move_constructor: + case sfk_copy_constructor: + ctor_p = true; + fnname = complete_ctor_identifier; + break; + + default: + gcc_unreachable (); + } + + /* If that user-written default constructor would satisfy the + requirements of a constexpr constructor (7.1.5), the + implicitly-defined default constructor is constexpr. */ + if (constexpr_p) + *constexpr_p = ctor_p; + move_p = false; switch (sfk) { @@ -1114,35 +1160,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, return; #endif - ctor_p = false; - assign_p = false; - check_vdtor = false; - switch (sfk) - { - case sfk_move_assignment: - case sfk_copy_assignment: - assign_p = true; - fnname = ansi_assopname (NOP_EXPR); - break; - - case sfk_destructor: - check_vdtor = true; - /* The synthesized method will call base dtors, but check complete - here to avoid having to deal with VTT. */ - fnname = complete_dtor_identifier; - break; - - case sfk_constructor: - case sfk_move_constructor: - case sfk_copy_constructor: - ctor_p = true; - fnname = complete_ctor_identifier; - break; - - default: - gcc_unreachable (); - } - ++cp_unevaluated_operand; ++c_inhibit_evaluation_warnings; @@ -1183,7 +1200,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - msg, basetype); + constexpr_p, msg, basetype); if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) { /* In a constructor we also need to check the subobject @@ -1191,7 +1208,8 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, rval = locate_fn_flags (base_binfo, complete_dtor_identifier, NULL_TREE, flags, complain); process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial, - &cleanup_deleted, NULL, basetype); + &cleanup_deleted, NULL, NULL, + basetype); } if (check_vdtor && type_has_virtual_destructor (basetype)) @@ -1221,6 +1239,8 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, if (diag) msg = ("virtual base %qT does not have a move constructor " "or trivial copy constructor"); + if (vbases && constexpr_p) + *constexpr_p = false; FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo) { tree basetype = BINFO_TYPE (base_binfo); @@ -1229,13 +1249,14 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - msg, basetype); + constexpr_p, msg, basetype); if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) { rval = locate_fn_flags (base_binfo, complete_dtor_identifier, NULL_TREE, flags, complain); process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial, - &cleanup_deleted, NULL, basetype); + &cleanup_deleted, NULL, NULL, + basetype); } } } @@ -1249,12 +1270,13 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, "constructor or trivial copy constructor"); walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals, copy_arg_p, move_p, assign_p, spec_p, trivial_p, - deleted_p, msg, flags, complain); + deleted_p, constexpr_p, msg, flags, complain); if (ctor_p) walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier, sfk_destructor, TYPE_UNQUALIFIED, false, false, false, &cleanup_spec, &cleanup_trivial, - &cleanup_deleted, NULL, flags, complain); + &cleanup_deleted, NULL, + NULL, flags, complain); pop_scope (scope); @@ -1333,7 +1355,7 @@ maybe_explain_implicit_delete (tree decl) "definition would be ill-formed:", decl); pop_scope (scope); synthesized_method_walk (ctype, sfk, const_p, - NULL, NULL, NULL, true); + NULL, NULL, NULL, NULL, true); } input_location = loc; @@ -1362,6 +1384,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) HOST_WIDE_INT saved_processing_template_decl; bool deleted_p; bool trivial_p; + bool constexpr_p; /* Because we create declarations for implicitly declared functions lazily, we may be creating the declaration for a member of TYPE @@ -1431,7 +1454,15 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) } synthesized_method_walk (type, kind, const_p, &raises, &trivial_p, - &deleted_p, false); + &deleted_p, &constexpr_p, false); + /* Don't bother marking a deleted constructor as constexpr. */ + if (deleted_p) + constexpr_p = false; + /* A trivial copy/move constructor is also a constexpr constructor. */ + else if (trivial_p && cxx_dialect >= cxx0x + && (kind == sfk_copy_constructor + || kind == sfk_move_constructor)) + gcc_assert (constexpr_p); if (!trivial_p && type_has_trivial_fn (type, kind)) type_set_nontrivial_flag (type, kind); @@ -1481,7 +1512,10 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) DECL_ARTIFICIAL (fn) = 1; DECL_DEFAULTED_FN (fn) = 1; if (cxx_dialect >= cxx0x) - DECL_DELETED_FN (fn) = deleted_p; + { + DECL_DELETED_FN (fn) = deleted_p; + DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p; + } DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; gcc_assert (!TREE_USED (fn)); @@ -1521,6 +1555,19 @@ defaulted_late_check (tree fn) { tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec); + if (DECL_DECLARED_CONSTEXPR_P (implicit_fn)) + /* Hmm...should we do this for out-of-class too? Should it be OK to + add constexpr later like inline, rather than requiring + declarations to match? */ + DECL_DECLARED_CONSTEXPR_P (fn) = true; + } + + if (!DECL_DECLARED_CONSTEXPR_P (implicit_fn) + && DECL_DECLARED_CONSTEXPR_P (fn)) + { + if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx)) + error ("%qD cannot be declared as constexpr", fn); + DECL_DECLARED_CONSTEXPR_P (fn) = false; } if (DECL_DELETED_FN (implicit_fn)) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-delete.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-delete.C new file mode 100644 index 00000000000..67c9503025b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-delete.C @@ -0,0 +1,3 @@ +// { dg-options -std=c++0x } + +constexpr bool never() = delete; // useless, but OK -- 2.30.2