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 <jason@redhat.com> From-SVN: r166014
This commit is contained in:
parent
91ea6df357
commit
225a658415
|
@ -1,6 +1,13 @@
|
|||
2010-10-27 Gabriel Dos Reis <gdr@cse.tamu.edu>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
|
|
@ -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]
|
||||
|
|
133
gcc/cp/method.c
133
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))
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr bool never() = delete; // useless, but OK
|
Loading…
Reference in New Issue