diff options
author | Jason Merrill <jason@redhat.com> | 2011-10-18 13:39:15 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2011-10-18 13:39:15 -0400 |
commit | a2e70335e27f8e348cf5c8d11765a46d82282669 (patch) | |
tree | 342e8cad633455730e78cd313f19f1e343339ffa /gcc/cp | |
parent | c5d942188b70dc182150ae9fb57d502cbf0e9e75 (diff) | |
download | gcc-a2e70335e27f8e348cf5c8d11765a46d82282669.zip gcc-a2e70335e27f8e348cf5c8d11765a46d82282669.tar.gz gcc-a2e70335e27f8e348cf5c8d11765a46d82282669.tar.bz2 |
re PR c++/50500 ([C++0x] [DR 1082] move constructor should cause copy constructor to be deleted, but still declared)
PR c++/50500
DR 1082
* class.c (type_has_user_declared_move_constructor): New.
(type_has_user_declared_move_assign): New.
(add_implicitly_declared_members): Add lazy copy ops
even if there's a move.
* method.c (lazily_declare_fn): Delete implicit copies
if there's a move.
(maybe_explain_implicit_delete): Explain this. Use inform rather
than error.
* cp-tree.h: Declare new fns.
From-SVN: r180159
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/cp/class.c | 58 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/method.c | 28 |
4 files changed, 93 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 407c684..ad46384 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2011-10-18 Jason Merrill <jason@redhat.com> + + PR c++/50500 + DR 1082 + * class.c (type_has_user_declared_move_constructor): New. + (type_has_user_declared_move_assign): New. + (add_implicitly_declared_members): Add lazy copy ops + even if there's a move. + * method.c (lazily_declare_fn): Delete implicit copies + if there's a move. + (maybe_explain_implicit_delete): Explain this. Use inform rather + than error. + * cp-tree.h: Declare new fns. + 2011-10-18 Diego Novillo <dnovillo@google.com> * parser.c: Remove ENABLE_CHECKING markers around debugging diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6185054..c8efc7e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2736,13 +2736,12 @@ add_implicitly_declared_members (tree t, If a class definition does not explicitly declare a copy constructor, one is declared implicitly. */ - if (! TYPE_HAS_COPY_CTOR (t) && ! TYPE_FOR_JAVA (t) - && !type_has_move_constructor (t)) + if (! TYPE_HAS_COPY_CTOR (t) && ! TYPE_FOR_JAVA (t)) { TYPE_HAS_COPY_CTOR (t) = 1; TYPE_HAS_CONST_COPY_CTOR (t) = !cant_have_const_cctor; CLASSTYPE_LAZY_COPY_CTOR (t) = 1; - if (cxx_dialect >= cxx0x) + if (cxx_dialect >= cxx0x && !type_has_move_constructor (t)) CLASSTYPE_LAZY_MOVE_CTOR (t) = 1; } @@ -2750,13 +2749,12 @@ add_implicitly_declared_members (tree t, when it is needed. For now, just record whether or not the type of the parameter to the assignment operator will be a const or non-const reference. */ - if (!TYPE_HAS_COPY_ASSIGN (t) && !TYPE_FOR_JAVA (t) - && !type_has_move_assign (t)) + if (!TYPE_HAS_COPY_ASSIGN (t) && !TYPE_FOR_JAVA (t)) { TYPE_HAS_COPY_ASSIGN (t) = 1; TYPE_HAS_CONST_COPY_ASSIGN (t) = !cant_have_const_assignment; CLASSTYPE_LAZY_COPY_ASSIGN (t) = 1; - if (cxx_dialect >= cxx0x) + if (cxx_dialect >= cxx0x && !type_has_move_assign (t)) CLASSTYPE_LAZY_MOVE_ASSIGN (t) = 1; } @@ -4495,6 +4493,54 @@ type_has_move_assign (tree t) return false; } +/* Returns true iff class T has a move constructor that was explicitly + declared in the class body. Note that this is different from + "user-provided", which doesn't include functions that are defaulted in + the class. */ + +bool +type_has_user_declared_move_constructor (tree t) +{ + tree fns; + + if (CLASSTYPE_LAZY_MOVE_CTOR (t)) + return false; + + if (!CLASSTYPE_METHOD_VEC (t)) + return false; + + for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns)) + { + tree fn = OVL_CURRENT (fns); + if (move_fn_p (fn) && !DECL_ARTIFICIAL (fn)) + return true; + } + + return false; +} + +/* Returns true iff class T has a move assignment operator that was + explicitly declared in the class body. */ + +bool +type_has_user_declared_move_assign (tree t) +{ + tree fns; + + if (CLASSTYPE_LAZY_MOVE_ASSIGN (t)) + return false; + + for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR)); + fns; fns = OVL_NEXT (fns)) + { + tree fn = OVL_CURRENT (fns); + if (move_fn_p (fn) && !DECL_ARTIFICIAL (fn)) + return true; + } + + return false; +} + /* Nonzero if we need to build up a constructor call when initializing an object of this class, either because it has a user-provided constructor or because it doesn't have a default constructor (so we need to give an diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bda18d9..d0e874b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4870,6 +4870,8 @@ extern bool type_has_constexpr_default_constructor (tree); extern bool type_has_virtual_destructor (tree); extern bool type_has_move_constructor (tree); extern bool type_has_move_assign (tree); +extern bool type_has_user_declared_move_constructor (tree); +extern bool type_has_user_declared_move_assign(tree); extern bool type_build_ctor_call (tree); extern void explain_non_literal_class (tree); extern void defaulted_late_check (tree); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 0718f47..bb58312 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1375,18 +1375,31 @@ maybe_explain_implicit_delete (tree decl) { informed = true; if (sfk == sfk_constructor) - error ("a lambda closure type has a deleted default constructor"); + inform (DECL_SOURCE_LOCATION (decl), + "a lambda closure type has a deleted default constructor"); else if (sfk == sfk_copy_assignment) - error ("a lambda closure type has a deleted copy assignment operator"); + inform (DECL_SOURCE_LOCATION (decl), + "a lambda closure type has a deleted copy assignment operator"); else informed = false; } + else if (DECL_ARTIFICIAL (decl) + && (sfk == sfk_copy_assignment + || sfk == sfk_copy_constructor) + && (type_has_user_declared_move_constructor (ctype) + || type_has_user_declared_move_assign (ctype))) + { + inform (0, "%q+#D is implicitly declared as deleted because %qT " + "declares a move constructor or move assignment operator", + decl, ctype); + informed = true; + } if (!informed) { tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl)); bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); tree scope = push_scope (ctype); - error ("%qD is implicitly deleted because the default " + inform (0, "%q+#D is implicitly deleted because the default " "definition would be ill-formed:", decl); pop_scope (scope); synthesized_method_walk (ctype, sfk, const_p, @@ -1743,6 +1756,15 @@ lazily_declare_fn (special_function_kind sfk, tree type) /* Declare the function. */ fn = implicitly_declare_fn (sfk, type, const_p); + /* [class.copy]/8 If the class definition declares a move constructor or + move assignment operator, the implicitly declared copy constructor is + defined as deleted.... */ + if ((sfk == sfk_copy_assignment + || sfk == sfk_copy_constructor) + && (type_has_user_declared_move_constructor (type) + || type_has_user_declared_move_assign (type))) + DECL_DELETED_FN (fn) = true; + /* For move variants, rather than declare them as deleted we just don't declare them at all. */ if (DECL_DELETED_FN (fn) |