]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/57319 (bogus "defaulted move assignment for ... calls a non-trivial move...
authorJason Merrill <jason@redhat.com>
Mon, 20 May 2013 17:01:16 +0000 (13:01 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 20 May 2013 17:01:16 +0000 (13:01 -0400)
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

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/method.c
gcc/testsuite/g++.dg/cpp0x/defaulted44.C [new file with mode: 0644]

index 5ea7a27625a93b1b90d54b37fad67121b0e0d9e2..b08afd929f58606bafc56b3444bebb576eb51a82 100644 (file)
@@ -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.
index b936ac85ad7956ebbbca0b4080c648234803dcbf..94ae5672548e8a87a9bd2a2f4cc562096f210ee3 100644 (file)
@@ -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).  */
 
index a2f59df9b1a3963881adea910c775646bd7d0c3e..6455c69d87adffcd7584c1dd0a879981d4b7d70e 100644 (file)
@@ -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);
index 801b3a5422afb705e6453d90e57ffc6640c41777..0d779a089e539143c38bc6a65166db0ab8d02ac7 100644 (file)
@@ -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 (file)
index 0000000..213c139
--- /dev/null
@@ -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 &);
+  };
+}