re PR c++/66501 (Default move assignment does not move array members)
authorJason Merrill <jason@redhat.com>
Tue, 23 Jun 2015 14:08:25 +0000 (10:08 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 23 Jun 2015 14:08:25 +0000 (10:08 -0400)
PR c++/66501
* class.c (type_has_nontrivial_assignment): New.
* init.c (build_vec_init): Use it.
* cp-tree.h: Declare it.
* method.c (trivial_fn_p): Templates aren't trivial.

From-SVN: r224843

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

index 194d764469c5a68b4c8da46f930934228ca93e7a..de8fdacdedf046758e18bbc3fb8f1fade038df88 100644 (file)
@@ -1,5 +1,11 @@
 2015-06-23  Jason Merrill  <jason@redhat.com>
 
+       PR c++/66501
+       * class.c (type_has_nontrivial_assignment): New.
+       * init.c (build_vec_init): Use it.
+       * cp-tree.h: Declare it.
+       * method.c (trivial_fn_p): Templates aren't trivial.
+
        PR c++/66542
        * decl.c (expand_static_init): Make sure the destructor is callable
        here even if we have an initializer.
index 9da532e18dd4eb204b0fd3263ebea5f755da1da7..88f1022dcd308f7edd8981fe4903bd03d0037c16 100644 (file)
@@ -5136,6 +5136,24 @@ type_has_non_user_provided_default_constructor (tree t)
   return false;
 }
 
+/* Return true if TYPE has some non-trivial assignment operator.  */
+
+bool
+type_has_nontrivial_assignment (tree type)
+{
+  gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
+  if (CLASS_TYPE_P (type))
+    for (tree fns
+          = lookup_fnfields_slot_nolazy (type, ansi_assopname (NOP_EXPR));
+        fns; fns = OVL_NEXT (fns))
+      {
+       tree fn = OVL_CURRENT (fns);
+       if (!trivial_fn_p (fn))
+         return true;
+      }
+  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
index b53aa9028e23f9e107f2de86264b05bf566815ec..8eb74748fdab6b49cd1f380d3c98a8fbfba232cb 100644 (file)
@@ -5295,6 +5295,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_non_user_provided_default_constructor (tree);
+extern bool type_has_nontrivial_assignment     (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);
index fc30fef6dedee354800709d237e6430c36272e97..08c6c0ee0cf3bb50b732b5951085fcd365fc50f2 100644 (file)
@@ -3460,8 +3460,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       && TREE_CODE (atype) == ARRAY_TYPE
       && TREE_CONSTANT (maxindex)
       && (from_array == 2
-         ? (!CLASS_TYPE_P (inner_elt_type)
-            || !TYPE_HAS_COMPLEX_COPY_ASSIGN (inner_elt_type))
+         ? !type_has_nontrivial_assignment (inner_elt_type)
          : !TYPE_NEEDS_CONSTRUCTING (type))
       && ((TREE_CODE (init) == CONSTRUCTOR
           /* Don't do this if the CONSTRUCTOR might contain something
index 79e4bbc06304cfe7ec870419ee2a8dbd2de0bce3..da03c365a9ab08209dc027a76c6e5f201d125ee9 100644 (file)
@@ -476,6 +476,8 @@ type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
 bool
 trivial_fn_p (tree fn)
 {
+  if (TREE_CODE (fn) == TEMPLATE_DECL)
+    return false;
   if (!DECL_DEFAULTED_FN (fn))
     return false;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-array1.C b/gcc/testsuite/g++.dg/cpp0x/rv-array1.C
new file mode 100644 (file)
index 0000000..9075764
--- /dev/null
@@ -0,0 +1,55 @@
+// PR c++/66501
+// { dg-do run { target c++11 } }
+
+int total_size;
+
+struct Object
+{
+  int size = 0;
+
+  Object () = default;
+
+  ~Object () {
+    total_size -= size;
+  }
+
+  Object (const Object &) = delete;
+  Object & operator= (const Object &) = delete;
+
+  Object (Object && b) {
+    size = b.size;
+    b.size = 0;
+  }
+
+  Object & operator= (Object && b) {
+    if (this != & b) {
+      total_size -= size;
+      size = b.size;
+      b.size = 0;
+    }
+    return * this;
+  }
+
+  void grow () {
+    size ++;
+    total_size ++;
+  }
+};
+
+struct Container {
+  Object objects[2];
+};
+
+int main (void)
+{
+  Container container;
+
+  // grow some objects in the container
+  for (auto & object : container.objects)
+    object.grow ();
+
+  // now empty it
+  container = Container ();
+
+  return total_size;
+}