This allows move-assignment for std::vector<T> when T is not
MoveAssignable but the allocator is moved or equal, as a QoI
extension.  It also makes the code a bit cleaner and simpler, so I
plan to use the same pattern as I make the rest of the library meet
the allocator-aware container requirements.

        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.

Tested x86_64-linux, committed to trunk.  After this has been on the
trunk for a while I plan to apply it to the 4.7 branch too.
commit e08d4fbd65667448fd93505acefc4828baff7a69
Author: Jonathan Wakely <jwakely....@gmail.com>
Date:   Fri Mar 16 22:22:31 2012 +0000

        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.

diff --git a/libstdc++-v3/include/bits/stl_vector.h 
b/libstdc++-v3/include/bits/stl_vector.h
index 239f8b9..31660d3 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -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
index 0000000..c018c72
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/52591.cc
@@ -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>();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
index 73de8ae..644750c 100644
--- 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
@@ -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>
 
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
index fa479c7..bbd4cfe 100644
--- 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
@@ -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>
 
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
index 231cace..d2282cc 100644
--- 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
@@ -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>
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
index b8e18bb..d2cde66 100644
--- 
a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
@@ -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>
 

Reply via email to