Commit 55e5bf21 by Jason Merrill Committed by Jason Merrill

DR 1402 PR c++/53733

	DR 1402
	PR c++/53733
	* cp-tree.h (FNDECL_SUPPRESS_IMPLICIT_DECL): New.
	(struct lang_decl_fn): Add suppress_implicit_decl field.
	* method.c (implicitly_declare_fn): Check it.
	(process_subob_fn): Add no_implicit_p parm.
	(walk_field_subobs, synthesized_method_walk): Likewise.
	(maybe_explain_implicit_delete): Adjust.
	(explain_implicit_non_constexpr): Adjust.

From-SVN: r189396
parent 60b9991b
2012-07-10 Jason Merrill <jason@redhat.com> 2012-07-10 Jason Merrill <jason@redhat.com>
DR 1402
PR c++/53733
* cp-tree.h (FNDECL_SUPPRESS_IMPLICIT_DECL): New.
(struct lang_decl_fn): Add suppress_implicit_decl field.
* method.c (implicitly_declare_fn): Check it.
(process_subob_fn): Add no_implicit_p parm.
(walk_field_subobs, synthesized_method_walk): Likewise.
(maybe_explain_implicit_delete): Adjust.
(explain_implicit_non_constexpr): Adjust.
* method.c (synthesized_method_walk): Avoid changing * method.c (synthesized_method_walk): Avoid changing
EH spec based on cleanups in other places, too. EH spec based on cleanups in other places, too.
......
...@@ -1940,7 +1940,7 @@ struct GTY(()) lang_decl_fn { ...@@ -1940,7 +1940,7 @@ struct GTY(()) lang_decl_fn {
unsigned thunk_p : 1; unsigned thunk_p : 1;
unsigned this_thunk_p : 1; unsigned this_thunk_p : 1;
unsigned hidden_friend_p : 1; unsigned hidden_friend_p : 1;
/* 1 spare bit. */ unsigned suppress_implicit_decl : 1;
/* For a non-thunk function decl, this is a tree list of /* For a non-thunk function decl, this is a tree list of
friendly classes. For a thunk function decl, it is the friendly classes. For a thunk function decl, it is the
...@@ -3107,6 +3107,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3107,6 +3107,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_HIDDEN_FRIEND_P(NODE) \ #define DECL_HIDDEN_FRIEND_P(NODE) \
(LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p) (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p)
/* Nonzero if NODE is a FUNCTION_DECL generated by implicitly_declare_fn
that we shouldn't actually declare implicitly; it is only used for
comparing to an =default declaration. */
#define FNDECL_SUPPRESS_IMPLICIT_DECL(NODE) \
(LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->suppress_implicit_decl)
/* Nonzero if DECL has been declared threadprivate by /* Nonzero if DECL has been declared threadprivate by
#pragma omp threadprivate. */ #pragma omp threadprivate. */
#define CP_DECL_THREADPRIVATE_P(DECL) \ #define CP_DECL_THREADPRIVATE_P(DECL) \
......
...@@ -922,7 +922,7 @@ get_copy_assign (tree type) ...@@ -922,7 +922,7 @@ get_copy_assign (tree type)
static void static void
process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
const char *msg, tree arg) const char *msg, tree arg)
{ {
if (!fn || fn == error_mark_node) if (!fn || fn == error_mark_node)
...@@ -948,12 +948,10 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, ...@@ -948,12 +948,10 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
} }
} }
/* Core 1402: A non-trivial copy op suppresses the implicit
declaration of the move ctor/op=. */
if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn)) if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
{ *no_implicit_p = true;
if (msg)
error (msg, arg);
goto bad;
}
if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn)) if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
{ {
...@@ -980,8 +978,8 @@ static void ...@@ -980,8 +978,8 @@ static void
walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
int quals, bool copy_arg_p, bool move_p, int quals, bool copy_arg_p, bool move_p,
bool assign_p, tree *spec_p, bool *trivial_p, bool assign_p, tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p, const char *msg, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
int flags, tsubst_flags_t complain) const char *msg, int flags, tsubst_flags_t complain)
{ {
tree field; tree field;
for (field = fields; field; field = DECL_CHAIN (field)) for (field = fields; field; field = DECL_CHAIN (field))
...@@ -1079,7 +1077,8 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1079,7 +1077,8 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
{ {
walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals, walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p, copy_arg_p, move_p, assign_p, spec_p, trivial_p,
deleted_p, constexpr_p, msg, flags, complain); deleted_p, constexpr_p, no_implicit_p,
msg, flags, complain);
continue; continue;
} }
...@@ -1096,7 +1095,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1096,7 +1095,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain); rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, msg, field); constexpr_p, no_implicit_p, msg, field);
} }
} }
...@@ -1110,7 +1109,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1110,7 +1109,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
static void static void
synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
tree *spec_p, bool *trivial_p, bool *deleted_p, tree *spec_p, bool *trivial_p, bool *deleted_p,
bool *constexpr_p, bool diag) bool *constexpr_p, bool *no_implicit_p, bool diag)
{ {
tree binfo, base_binfo, scope, fnname, rval, argtype; tree binfo, base_binfo, scope, fnname, rval, argtype;
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor; bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
...@@ -1198,6 +1197,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1198,6 +1197,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
if (trivial_p) if (trivial_p)
*trivial_p = expected_trivial; *trivial_p = expected_trivial;
if (no_implicit_p)
*no_implicit_p = false;
/* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base /* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base
class versions and other properties of the type. But a subobject class versions and other properties of the type. But a subobject
class can be trivially copyable and yet have overload resolution class can be trivially copyable and yet have overload resolution
...@@ -1256,7 +1258,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1256,7 +1258,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, msg, basetype); constexpr_p, no_implicit_p, msg, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{ {
/* In a constructor we also need to check the subobject /* In a constructor we also need to check the subobject
...@@ -1269,7 +1271,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1269,7 +1271,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
throw) or exception-specification (a throw from one of the throw) or exception-specification (a throw from one of the
dtors would be a double-fault). */ dtors would be a double-fault). */
process_subob_fn (rval, false, NULL, NULL, process_subob_fn (rval, false, NULL, NULL,
deleted_p, NULL, NULL, deleted_p, NULL, NULL, NULL,
basetype); basetype);
} }
...@@ -1310,13 +1312,13 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1310,13 +1312,13 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
constexpr_p, msg, basetype); constexpr_p, no_implicit_p, msg, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{ {
rval = locate_fn_flags (base_binfo, complete_dtor_identifier, rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
NULL_TREE, flags, complain); NULL_TREE, flags, complain);
process_subob_fn (rval, false, NULL, NULL, process_subob_fn (rval, false, NULL, NULL,
deleted_p, NULL, NULL, deleted_p, NULL, NULL, NULL,
basetype); basetype);
} }
} }
...@@ -1331,13 +1333,14 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, ...@@ -1331,13 +1333,14 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
"constructor or trivial copy constructor"); "constructor or trivial copy constructor");
walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals, walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p, copy_arg_p, move_p, assign_p, spec_p, trivial_p,
deleted_p, constexpr_p, msg, flags, complain); deleted_p, constexpr_p, no_implicit_p,
msg, flags, complain);
if (ctor_p) if (ctor_p)
walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier, walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier,
sfk_destructor, TYPE_UNQUALIFIED, false, sfk_destructor, TYPE_UNQUALIFIED, false,
false, false, NULL, NULL, false, false, NULL, NULL,
deleted_p, NULL, deleted_p, NULL,
NULL, flags, complain); NULL, NULL, flags, complain);
pop_scope (scope); pop_scope (scope);
...@@ -1407,7 +1410,7 @@ maybe_explain_implicit_delete (tree decl) ...@@ -1407,7 +1410,7 @@ maybe_explain_implicit_delete (tree decl)
"definition would be ill-formed:", decl); "definition would be ill-formed:", decl);
pop_scope (scope); pop_scope (scope);
synthesized_method_walk (ctype, sfk, const_p, synthesized_method_walk (ctype, sfk, const_p,
NULL, NULL, NULL, NULL, true); NULL, NULL, NULL, NULL, NULL, true);
} }
input_location = loc; input_location = loc;
...@@ -1427,7 +1430,7 @@ explain_implicit_non_constexpr (tree decl) ...@@ -1427,7 +1430,7 @@ explain_implicit_non_constexpr (tree decl)
bool dummy; bool dummy;
synthesized_method_walk (DECL_CLASS_CONTEXT (decl), synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
special_function_p (decl), const_p, special_function_p (decl), const_p,
NULL, NULL, NULL, &dummy, true); NULL, NULL, NULL, &dummy, NULL, true);
} }
/* Implicitly declare the special function indicated by KIND, as a /* Implicitly declare the special function indicated by KIND, as a
...@@ -1451,6 +1454,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) ...@@ -1451,6 +1454,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
bool deleted_p; bool deleted_p;
bool trivial_p; bool trivial_p;
bool constexpr_p; bool constexpr_p;
bool no_implicit_p;
/* Because we create declarations for implicitly declared functions /* Because we create declarations for implicitly declared functions
lazily, we may be creating the declaration for a member of TYPE lazily, we may be creating the declaration for a member of TYPE
...@@ -1520,7 +1524,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) ...@@ -1520,7 +1524,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
} }
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p, synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
&deleted_p, &constexpr_p, false); &deleted_p, &constexpr_p, &no_implicit_p, false);
/* Don't bother marking a deleted constructor as constexpr. */ /* Don't bother marking a deleted constructor as constexpr. */
if (deleted_p) if (deleted_p)
constexpr_p = false; constexpr_p = false;
...@@ -1585,6 +1589,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) ...@@ -1585,6 +1589,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
DECL_DELETED_FN (fn) = deleted_p; DECL_DELETED_FN (fn) = deleted_p;
DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p; DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p;
} }
FNDECL_SUPPRESS_IMPLICIT_DECL (fn) = no_implicit_p;
DECL_EXTERNAL (fn) = true; DECL_EXTERNAL (fn) = true;
DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1;
...@@ -1777,6 +1782,10 @@ lazily_declare_fn (special_function_kind sfk, tree type) ...@@ -1777,6 +1782,10 @@ lazily_declare_fn (special_function_kind sfk, tree type)
|| sfk == sfk_move_assignment)) || sfk == sfk_move_assignment))
return NULL_TREE; return NULL_TREE;
/* We also suppress implicit move if it would call a non-trivial copy. */
if (FNDECL_SUPPRESS_IMPLICIT_DECL (fn))
return NULL_TREE;
/* A destructor may be virtual. */ /* A destructor may be virtual. */
if (sfk == sfk_destructor if (sfk == sfk_destructor
|| sfk == sfk_move_assignment || sfk == sfk_move_assignment
......
2012-07-10 Jason Merrill <jason@redhat.com> 2012-07-10 Jason Merrill <jason@redhat.com>
PR c++/53733
* g++.dg/cpp0x/defaulted36.C: New.
* g++.dg/cpp0x/defaulted21.C: Adjust.
* g++.dg/cpp0x/implicit13.C: Add vbase and member tests. * g++.dg/cpp0x/implicit13.C: Add vbase and member tests.
2012-07-09 Sterling Augustine <saugustine@google.com> 2012-07-09 Sterling Augustine <saugustine@google.com>
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
struct U { struct U {
U(); U();
U(U const&); private:
U(U const&); // { dg-error "private" }
}; };
struct X { struct X {
...@@ -13,7 +14,7 @@ struct X { ...@@ -13,7 +14,7 @@ struct X {
}; };
X::X(X&&)=default; // { dg-message "implicitly deleted" } X::X(X&&)=default; // { dg-message "implicitly deleted" }
// { dg-error "does not have a move constructor" "" { target *-*-* } 15 } // { dg-prune-output "within this context" }
X f() { X f() {
return X(); return X();
......
// PR c++/53733
// { dg-do compile { target c++11 } }
template<typename T>
struct wrap
{
wrap() = default;
wrap(wrap&&) = default; // Line 5
wrap(const wrap&) = default;
T t;
};
struct S {
S() = default;
S(const S&){}
S(S&&) = default;
};
typedef wrap<const S> W;
W get() { return W(); } // Line 19
int main() {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment