re PR libstdc++/52591 ([C++0x] [4.7 Regression] moving std::vector relies on movable...
authorJonathan Wakely <jwakely.gcc@gmail.com>
Sun, 1 Apr 2012 22:04:54 +0000 (22:04 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Sun, 1 Apr 2012 22:04:54 +0000 (23:04 +0100)
PR libstdc++/52591
* include/bits/stl_vector.h (vector::operator=(vector&&)): Dispatch
to _M_move_assign depending on whether allocator is moved.
(vector::_M_move_assign): Add overloaded functions.
* testsuite/23_containers/vector/52591.cc: New.
* testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
Adjust dg-error line number.
* testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
Likewise.

From-SVN: r186057

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_vector.h
libstdc++-v3/testsuite/23_containers/vector/52591.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc

index 6f4e7bf..66bf6de 100644 (file)
@@ -1,5 +1,21 @@
 2012-04-01  Jonathan Wakely  <jwakely.gcc@gmail.com>
 
+       PR libstdc++/52591
+       * include/bits/stl_vector.h (vector::operator=(vector&&)): Dispatch
+       to _M_move_assign depending on whether allocator is moved.
+       (vector::_M_move_assign): Add overloaded functions.
+       * testsuite/23_containers/vector/52591.cc: New.
+       * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
+       Adjust dg-error line number.
+       * testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
+       Likewise.
+       * testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
+       Likewise.
+       * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
+       Likewise.
+
+2012-04-01  Jonathan Wakely  <jwakely.gcc@gmail.com>
+
        * include/std/functional (__callable_functor): Overload for
        volatile-qualified pointers.
        * testsuite/20_util/function/10.cc: New.
index 239f8b9..31660d3 100644 (file)
@@ -428,36 +428,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  @brief  %Vector move assignment operator.
        *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The contents of @a __x are moved into this %vector (without copying).
+       *  The contents of @a __x are moved into this %vector (without copying,
+       *  if the allocators permit it).
        *  @a __x is a valid, but unspecified %vector.
        */
       vector&
       operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-       if (_Alloc_traits::_S_propagate_on_move_assign())
-         {
-           // We're moving the rvalue's allocator so can move the data too.
-           const vector __tmp(std::move(*this));     // discard existing data
-           this->_M_impl._M_swap_data(__x._M_impl);
-           std::__alloc_on_move(_M_get_Tp_allocator(),
-                                __x._M_get_Tp_allocator());
-         }
-       else if (_Alloc_traits::_S_always_equal()
-                || __x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
-         {
-           // The rvalue's allocator can free our storage and vice versa,
-           // so can swap the data storage after destroying our contents.
-           this->clear();
-           this->_M_impl._M_swap_data(__x._M_impl);
-         }
-       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(__x.begin()),
-                        std::__make_move_if_noexcept_iterator(__x.end()));
-           __x.clear();
-         }
+        constexpr bool __move_storage =
+          _Alloc_traits::_S_propagate_on_move_assign()
+          || _Alloc_traits::_S_always_equal();
+        _M_move_assign(std::move(__x),
+                       integral_constant<bool, __move_storage>());
        return *this;
       }
 
@@ -1363,6 +1345,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator());
        this->_M_impl._M_finish = __pos;
       }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    private:
+      // Constant-time move assignment when source object's memory can be
+      // moved, either because the source's allocator will move too
+      // or because the allocators are equal.
+      void
+      _M_move_assign(vector&& __x, std::true_type) noexcept
+      {
+       const vector __tmp(std::move(*this));
+       this->_M_impl._M_swap_data(__x._M_impl);
+       if (_Alloc_traits::_S_propagate_on_move_assign())
+         std::__alloc_on_move(_M_get_Tp_allocator(),
+                              __x._M_get_Tp_allocator());
+      }
+
+      // Do move assignment when it might not be possible to move source
+      // object's memory, resulting in a linear-time operation.
+      void
+      _M_move_assign(vector&& __x, std::false_type)
+      {
+       if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
+         _M_move_assign(std::move(__x), std::true_type());
+       else
+         {
+           // 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()));
+           __x.clear();
+         }
+      }
+#endif
     };
 
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/52591.cc b/libstdc++-v3/testsuite/23_containers/vector/52591.cc
new file mode 100644 (file)
index 0000000..c018c72
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (C) 2012 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 compile }
+// { dg-options "-std=gnu++0x" }
+
+// libstdc++/52591
+
+#include <vector>
+
+// As an extension we allow move-assignment of std::vector when the element
+// type is not MoveAssignable, as long as the allocator type propagates or
+// is known to always compare equal.
+
+struct C
+{
+    C& operator=(C&&) = delete;
+};
+
+void test01()
+{
+    std::vector<C> a;
+    a = std::vector<C>();
+}
index 73de8ae..644750c 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1251 }
+// { dg-error "no matching" "" { target *-*-* } 1233 }
 
 #include <vector>
 
index fa479c7..bbd4cfe 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1181 }
+// { dg-error "no matching" "" { target *-*-* } 1163 }
 
 #include <vector>
 
index 231cace..d2282cc 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1181 }
+// { dg-error "no matching" "" { target *-*-* } 1163 }
 
 #include <vector>
 #include <utility>
index b8e18bb..d2cde66 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1292 }
+// { dg-error "no matching" "" { target *-*-* } 1274 }
 
 #include <vector>