aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-10-18 13:39:15 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-10-18 13:39:15 -0400
commita2e70335e27f8e348cf5c8d11765a46d82282669 (patch)
tree342e8cad633455730e78cd313f19f1e343339ffa /gcc/cp
parentc5d942188b70dc182150ae9fb57d502cbf0e9e75 (diff)
downloadgcc-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/ChangeLog14
-rw-r--r--gcc/cp/class.c58
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/method.c28
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)