PR libstdc++/92124 fix incorrect container move assignment
authorJonathan Wakely <jwakely@redhat.com>
Thu, 17 Oct 2019 14:21:27 +0000 (15:21 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 17 Oct 2019 14:21:27 +0000 (15:21 +0100)
The container requirements say that for move assignment "All existing
elements of [the target] are either move assigned or destroyed". Some of
our containers currently use __make_move_if_noexcept which makes the
move depend on whether the element type is nothrow move constructible.
This is incorrect, because the standard says we must move assign, not
move or copy depending on the move constructor.

Use make_move_iterator instead so that we move unconditionally. This
ensures existing elements won't be copy assigned.

PR libstdc++/92124
* include/bits/forward_list.h
(_M_move_assign(forward_list&&, false_type)): Do not use
__make_move_if_noexcept, instead move unconditionally.
* include/bits/stl_deque.h (_M_move_assign2(deque&&, false_type)):
Likewise.
* include/bits/stl_list.h (_M_move_assign(list&&, false_type)):
Likewise.
* include/bits/stl_vector.h (_M_move_assign(vector&&, false_type)):
Likewise.
* testsuite/23_containers/vector/92124.cc: New test.

From-SVN: r277113

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/forward_list.h
libstdc++-v3/include/bits/stl_deque.h
libstdc++-v3/include/bits/stl_list.h
libstdc++-v3/include/bits/stl_vector.h
libstdc++-v3/testsuite/23_containers/deque/92124.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/forward_list/92124.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/list/92124.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/92124.cc [new file with mode: 0644]

index c95aa32120b4da6c3932c6fc88f434b47ce5d98c..4c268795fdd1464e2900bce5094f02e74b256c9d 100644 (file)
@@ -1,3 +1,17 @@
+2019-10-17  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/92124
+       * include/bits/forward_list.h
+       (_M_move_assign(forward_list&&, false_type)): Do not use
+       __make_move_if_noexcept, instead move unconditionally.
+       * include/bits/stl_deque.h (_M_move_assign2(deque&&, false_type)):
+       Likewise.
+       * include/bits/stl_list.h (_M_move_assign(list&&, false_type)):
+       Likewise.
+       * include/bits/stl_vector.h (_M_move_assign(vector&&, false_type)):
+       Likewise.
+       * testsuite/23_containers/vector/92124.cc: New test.
+
 2019-10-16  Jonathan Wakely  <jwakely@redhat.com>
 
        * include/bits/c++config (_GLIBCXX_BUILTIN_IS_SAME_AS): Define to
index e686283a43242ad876c428b652cddf6c9a3a8084..cab2ae788a75c68c0e33690621554f8a6f102f36 100644 (file)
@@ -1336,8 +1336,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        else
          // The rvalue's allocator cannot be moved, or is not equal,
          // so we need to individually move each element.
-         this->assign(std::__make_move_if_noexcept_iterator(__list.begin()),
-                      std::__make_move_if_noexcept_iterator(__list.end()));
+         this->assign(std::make_move_iterator(__list.begin()),
+                      std::make_move_iterator(__list.end()));
       }
 
       // Called by assign(_InputIterator, _InputIterator) if _Tp is
index ac76d681ff00625e1bbe67b82d64ecf1275a2111..50491e76ff5e7ce8fdf749db309eef91d05c2fce 100644 (file)
@@ -2256,8 +2256,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          {
            // The rvalue's allocator cannot be moved and is not equal,
            // so we need to individually move each element.
-           _M_assign_aux(std::__make_move_if_noexcept_iterator(__x.begin()),
-                         std::__make_move_if_noexcept_iterator(__x.end()),
+           _M_assign_aux(std::make_move_iterator(__x.begin()),
+                         std::make_move_iterator(__x.end()),
                          std::random_access_iterator_tag());
            __x.clear();
          }
index 701982538dfe4d980b6b5865415d61bd07bca67a..328a79851a812dd0175a990a3ecd108b50765b7c 100644 (file)
@@ -1957,8 +1957,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        else
          // The rvalue's allocator cannot be moved, or is not equal,
          // so we need to individually move each element.
-         _M_assign_dispatch(std::__make_move_if_noexcept_iterator(__x.begin()),
-                            std::__make_move_if_noexcept_iterator(__x.end()),
+         _M_assign_dispatch(std::make_move_iterator(__x.begin()),
+                            std::make_move_iterator(__x.end()),
                             __false_type{});
       }
 #endif
index d33e589498a9151fbb128a4ae9edb95b961f6bf0..ff08b26669220017c1ce3366c60d97485f028e27 100644 (file)
@@ -1828,8 +1828,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          {
            // The rvalue's allocator cannot be moved and is not equal,
            // so we need to individually move each element.
-           this->assign(std::__make_move_if_noexcept_iterator(__x.begin()),
-                        std::__make_move_if_noexcept_iterator(__x.end()));
+           this->_M_assign_aux(std::make_move_iterator(__x.begin()),
+                               std::make_move_iterator(__x.end()),
+                               std::random_access_iterator_tag());
            __x.clear();
          }
       }
diff --git a/libstdc++-v3/testsuite/23_containers/deque/92124.cc b/libstdc++-v3/testsuite/23_containers/deque/92124.cc
new file mode 100644 (file)
index 0000000..6f8cf55
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <deque>
+#include <testsuite_allocator.h>
+
+struct X {
+    X() = default;
+    X(const X&) = default;
+
+    // Move constructor might throw
+    X(X&&) noexcept(false) {}
+
+    // Tracking calls to assignment functions
+    X& operator=(const X&) { throw 1; }
+
+    X& operator=(X&&) noexcept(true) { return *this; }
+};
+
+void
+test01()
+{
+  using A = __gnu_test::propagating_allocator<X, false>;
+  A a1(1), a2(2);
+  std::deque<X, A> v1(1, a1), v2(1, a2);
+  v1 = std::move(v2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc b/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc
new file mode 100644 (file)
index 0000000..52a2807
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <forward_list>
+#include <testsuite_allocator.h>
+
+struct X {
+    X() = default;
+    X(const X&) = default;
+
+    // Move constructor might throw
+    X(X&&) noexcept(false) {}
+
+    // Tracking calls to assignment functions
+    X& operator=(const X&) { throw 1; }
+
+    X& operator=(X&&) noexcept(true) { return *this; }
+};
+
+void
+test01()
+{
+  using A = __gnu_test::propagating_allocator<X, false>;
+  A a1(1), a2(2);
+  std::forward_list<X, A> v1(1, a1), v2(1, a2);
+  v1 = std::move(v2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/92124.cc b/libstdc++-v3/testsuite/23_containers/list/92124.cc
new file mode 100644 (file)
index 0000000..117cb71
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <list>
+#include <testsuite_allocator.h>
+
+struct X {
+    X() = default;
+    X(const X&) = default;
+
+    // Move constructor might throw
+    X(X&&) noexcept(false) {}
+
+    // Tracking calls to assignment functions
+    X& operator=(const X&) { throw 1; }
+
+    X& operator=(X&&) noexcept(true) { return *this; }
+};
+
+void
+test01()
+{
+  using A = __gnu_test::propagating_allocator<X, false>;
+  A a1(1), a2(2);
+  std::list<X, A> v1(1, a1), v2(1, a2);
+  v1 = std::move(v2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/92124.cc b/libstdc++-v3/testsuite/23_containers/vector/92124.cc
new file mode 100644 (file)
index 0000000..3cb487d
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <vector>
+#include <testsuite_allocator.h>
+
+struct X {
+    X() = default;
+    X(const X&) = default;
+
+    // Move constructor might throw
+    X(X&&) noexcept(false) {}
+
+    // Tracking calls to assignment functions
+    X& operator=(const X&) { throw 1; }
+
+    X& operator=(X&&) noexcept(true) { return *this; }
+};
+
+void
+test01()
+{
+  using A = __gnu_test::propagating_allocator<X, false>;
+  A a1(1), a2(2);
+  std::vector<X, A> v1(1, a1), v2(1, a2);
+  v1 = std::move(v2);
+}
+
+int
+main()
+{
+  test01();
+}