aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2013-05-20 13:01:16 -0400
committerJason Merrill <jason@gcc.gnu.org>2013-05-20 13:01:16 -0400
commit32bfcf80647d3fd3a658c7032a5aebe767341893 (patch)
treea77eab61162ca3bdde85d7a9b12497eb29a58625 /gcc
parent9f0bdc935f2199a2247b9d30858a9262d1a6bfa8 (diff)
downloadgcc-32bfcf80647d3fd3a658c7032a5aebe767341893.zip
gcc-32bfcf80647d3fd3a658c7032a5aebe767341893.tar.gz
gcc-32bfcf80647d3fd3a658c7032a5aebe767341893.tar.bz2
re PR c++/57319 (bogus "defaulted move assignment for ... calls a non-trivial move assignment operator for virtual base ...")
PR c++/57319 * class.c (vbase_has_user_provided_move_assign): New. * method.c (synthesized_method_walk): Check it. * cp-tree.h: Declare it. From-SVN: r199114
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/class.c38
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/method.c3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/defaulted44.C24
5 files changed, 70 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5ea7a27..b08afd9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
2013-05-20 Jason Merrill <jason@redhat.com>
+ PR c++/57319
+ * class.c (vbase_has_user_provided_move_assign): New.
+ * method.c (synthesized_method_walk): Check it.
+ * cp-tree.h: Declare it.
+
PR c++/57325
* tree.c (build_cplus_array_type): Copy layout info if element
type is complete.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b936ac8..94ae567 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4831,6 +4831,44 @@ type_has_user_provided_default_constructor (tree t)
return false;
}
+/* TYPE is being used as a virtual base, and has a non-trivial move
+ assignment. Return true if this is due to there being a user-provided
+ move assignment in TYPE or one of its subobjects; if there isn't, then
+ multiple move assignment can't cause any harm. */
+
+bool
+vbase_has_user_provided_move_assign (tree type)
+{
+ /* Does the type itself have a user-provided move assignment operator? */
+ for (tree fns
+ = lookup_fnfields_slot_nolazy (type, ansi_assopname (NOP_EXPR));
+ fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ if (move_fn_p (fn) && user_provided_p (fn))
+ return true;
+ }
+
+ /* Do any of its bases? */
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo;
+ for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+ if (vbase_has_user_provided_move_assign (BINFO_TYPE (base_binfo)))
+ return true;
+
+ /* Or non-static data members? */
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL
+ && CLASS_TYPE_P (TREE_TYPE (field))
+ && vbase_has_user_provided_move_assign (TREE_TYPE (field)))
+ return true;
+ }
+
+ /* Seems not. */
+ return false;
+}
+
/* If default-initialization leaves part of TYPE uninitialized, returns
a DECL for the field or TYPE itself (DR 253). */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a2f59df..6455c69 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5090,6 +5090,7 @@ extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree);
extern bool type_has_user_provided_default_constructor (tree);
+extern bool vbase_has_user_provided_move_assign (tree);
extern tree default_init_uninitialized_part (tree);
extern bool trivial_default_constructor_is_constexpr (tree);
extern bool type_has_constexpr_default_constructor (tree);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 801b3a5..0d779a0 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1353,7 +1353,8 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
if (diag && assign_p && move_p
&& BINFO_VIRTUAL_P (base_binfo)
&& rval && TREE_CODE (rval) == FUNCTION_DECL
- && move_fn_p (rval) && !trivial_fn_p (rval))
+ && move_fn_p (rval) && !trivial_fn_p (rval)
+ && vbase_has_user_provided_move_assign (basetype))
warning (OPT_Wvirtual_move_assign,
"defaulted move assignment for %qT calls a non-trivial "
"move assignment operator for virtual base %qT",
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted44.C b/gcc/testsuite/g++.dg/cpp0x/defaulted44.C
new file mode 100644
index 0000000..213c139
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted44.C
@@ -0,0 +1,24 @@
+// PR c++/57319
+// { dg-require-effective-target c++11 }
+
+namespace N1 {
+ struct A { };
+ struct B: virtual A { };
+ struct C: virtual B { };
+
+ struct D: C
+ {
+ void operator= (D &);
+ };
+}
+
+namespace N2 {
+ struct A { A& operator=(A&&); };
+ struct B: virtual A { }; // { dg-warning "move assignment" }
+ struct C: virtual B { }; // { dg-warning "move assignment" }
+
+ struct D: C
+ {
+ void operator= (D &);
+ };
+}