Patchwork [v3] C++0x allocator support for std::vector

login
register
mail settings
Submitter Jonathan Wakely
Date July 9, 2011, 1:08 p.m.
Message ID <CAH6eHdTy15VRi6TVKOWAcgPJJZA_7gqEmJuzHuRsxA2S6axJ2Q@mail.gmail.com>
Download mbox | patch
Permalink /patch/103977/
State New
Headers show

Comments

Jonathan Wakely - July 9, 2011, 1:08 p.m.
This patch adds full C++0x allocator support to std::vector, building
on the alloc_traits work I've been committing recently.

This is the easiest of the allocator-aware containers, I'm planning to
do the same for std::deque soon.

        * include/bits/stl_vector.h: Use new allocator model in C++0x mode.
        * include/bits/vector.tcc: Likewise.
        * testsuite/util/testsuite_allocator.h (propagating_allocator): Define.
        * testsuite/23_containers/vector/allocator/copy_assign.cc: New.
        * testsuite/23_containers/vector/allocator/noexcept.cc: New.
        * testsuite/23_containers/vector/allocator/copy.cc: New.
        * testsuite/23_containers/vector/allocator/swap.cc: New.
        * testsuite/23_containers/vector/allocator/move_assign.cc: New.
        * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
        Adjust dg-error line numbers.
        * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
        Likewise.
        * testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
        Likewise.
        * testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
        Likewise.

Tested x86_64-linux, committed to trunk.

Patch

Index: include/bits/stl_vector.h
===================================================================
--- include/bits/stl_vector.h	(revision 176072)
+++ include/bits/stl_vector.h	(working copy)
@@ -71,13 +71,15 @@ 
     struct _Vector_base
     {
       typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
+      typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
+       	pointer;
 
       struct _Vector_impl 
       : public _Tp_alloc_type
       {
-	typename _Tp_alloc_type::pointer _M_start;
-	typename _Tp_alloc_type::pointer _M_finish;
-	typename _Tp_alloc_type::pointer _M_end_of_storage;
+	pointer _M_start;
+	pointer _M_finish;
+	pointer _M_end_of_storage;
 
 	_Vector_impl()
 	: _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0)
@@ -93,6 +95,13 @@ 
 	  _M_start(0), _M_finish(0), _M_end_of_storage(0)
 	{ }
 #endif
+
+	void _M_swap_data(_Vector_impl& __x)
+	{
+	  std::swap(_M_start, __x._M_start);
+	  std::swap(_M_finish, __x._M_finish);
+	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
+	}
       };
       
     public:
@@ -118,30 +127,30 @@ 
 
       _Vector_base(size_t __n)
       : _M_impl()
-      {
-	this->_M_impl._M_start = this->_M_allocate(__n);
-	this->_M_impl._M_finish = this->_M_impl._M_start;
-	this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
-      }
+      { _M_create_storage(__n); }
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
-      {
-	this->_M_impl._M_start = this->_M_allocate(__n);
-	this->_M_impl._M_finish = this->_M_impl._M_start;
-	this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
-      }
+      { _M_create_storage(__n); }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
+      _Vector_base(_Tp_alloc_type&& __a)
+      : _M_impl(std::move(__a)) { }
+
       _Vector_base(_Vector_base&& __x)
       : _M_impl(std::move(__x._M_get_Tp_allocator()))
+      { this->_M_impl._M_swap_data(__x._M_impl); }
+
+      _Vector_base(_Vector_base&& __x, const allocator_type& __a)
+      : _M_impl(__a)
       {
-	this->_M_impl._M_start = __x._M_impl._M_start;
-	this->_M_impl._M_finish = __x._M_impl._M_finish;
-	this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage;
-	__x._M_impl._M_start = 0;
-	__x._M_impl._M_finish = 0;
-	__x._M_impl._M_end_of_storage = 0;
+	if (__x.get_allocator() == __a)
+	  this->_M_impl._M_swap_data(__x._M_impl);
+	else
+	  {
+	    size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;
+	    _M_create_storage(__n);
+	  }
       }
 #endif
 
@@ -152,16 +161,25 @@ 
     public:
       _Vector_impl _M_impl;
 
-      typename _Tp_alloc_type::pointer
+      pointer
       _M_allocate(size_t __n)
       { return __n != 0 ? _M_impl.allocate(__n) : 0; }
 
       void
-      _M_deallocate(typename _Tp_alloc_type::pointer __p, size_t __n)
+      _M_deallocate(pointer __p, size_t __n)
       {
 	if (__p)
 	  _M_impl.deallocate(__p, __n);
       }
+
+    private:
+      void
+      _M_create_storage(size_t __n)
+      {
+	this->_M_impl._M_start = this->_M_allocate(__n);
+	this->_M_impl._M_finish = this->_M_impl._M_start;
+	this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
+      }
     };
 
 
@@ -196,10 +214,11 @@ 
 
     public:
       typedef _Tp					 value_type;
-      typedef typename _Tp_alloc_type::pointer           pointer;
-      typedef typename _Tp_alloc_type::const_pointer     const_pointer;
-      typedef typename _Tp_alloc_type::reference         reference;
-      typedef typename _Tp_alloc_type::const_reference   const_reference;
+      typedef typename _Base::pointer                    pointer;
+      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>  _Alloc_traits;
+      typedef typename _Alloc_traits::const_pointer      const_pointer;
+      typedef typename _Alloc_traits::reference          reference;
+      typedef typename _Alloc_traits::const_reference    const_reference;
       typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
       typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
       const_iterator;
@@ -283,7 +302,8 @@ 
        *  @a x (for fast expansion) will not be copied.
        */
       vector(const vector& __x)
-      : _Base(__x.size(), __x._M_get_Tp_allocator())
+      : _Base(__x.size(),
+        _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()))
       { this->_M_impl._M_finish =
 	  std::__uninitialized_copy_a(__x.begin(), __x.end(),
 				      this->_M_impl._M_start,
@@ -301,6 +321,29 @@ 
       vector(vector&& __x) noexcept
       : _Base(std::move(__x)) { }
 
+      /// Copy constructor with alternative allocator
+      vector(const vector& __x, const allocator_type& __a)
+      : _Base(__x.size(), __a)
+      { this->_M_impl._M_finish =
+	  std::__uninitialized_copy_a(__x.begin(), __x.end(),
+				      this->_M_impl._M_start,
+				      _M_get_Tp_allocator());
+      }
+
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+      : _Base(std::move(__rv), __m)
+      {
+	if (__rv.get_allocator() != __m)
+	  {
+	    this->_M_impl._M_finish =
+	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
+					  this->_M_impl._M_start,
+					  _M_get_Tp_allocator());
+	    __rv.clear();
+	  }
+      }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  l  An initializer_list.
@@ -377,12 +420,32 @@ 
        *  @a x is a valid, but unspecified %vector.
        */
       vector&
-      operator=(vector&& __x)
+      operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-	// NB: DR 1204.
-	// NB: DR 675.
-	this->clear();
-	this->swap(__x);
+	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();
+	  }
 	return *this;
       }
 
@@ -834,7 +897,8 @@ 
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_finish, __x);
+	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+	                             __x);
 	    ++this->_M_impl._M_finish;
 	  }
 	else
@@ -864,7 +928,7 @@ 
       pop_back()
       {
 	--this->_M_impl._M_finish;
-	this->_M_impl.destroy(this->_M_impl._M_finish);
+	_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
       }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
@@ -1024,16 +1088,13 @@ 
        */
       void
       swap(vector& __x)
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+			noexcept(_Alloc_traits::_S_nothrow_swap())
+#endif
       {
-	std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
-	std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
-	std::swap(this->_M_impl._M_end_of_storage,
-		  __x._M_impl._M_end_of_storage);
-
-	// _GLIBCXX_RESOLVE_LIB_DEFECTS
-	// 431. Swapping containers with unequal allocators.
-	std::__alloc_swap<_Tp_alloc_type>::_S_do_it(_M_get_Tp_allocator(),
-						    __x._M_get_Tp_allocator());
+	this->_M_impl._M_swap_data(__x._M_impl);
+	_Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
+	                          __x._M_get_Tp_allocator());
       }
 
       /**
Index: include/bits/vector.tcc
===================================================================
--- include/bits/vector.tcc	(revision 176072)
+++ include/bits/vector.tcc	(working copy)
@@ -94,8 +94,8 @@ 
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_finish,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+				     std::forward<_Args>(__args)...);
 	    ++this->_M_impl._M_finish;
 	  }
 	else
@@ -112,7 +112,7 @@ 
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
 	  && __position == end())
 	{
-	  this->_M_impl.construct(this->_M_impl._M_finish, __x);
+	  _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x);
 	  ++this->_M_impl._M_finish;
 	}
       else
@@ -138,7 +138,7 @@ 
       if (__position + 1 != end())
 	_GLIBCXX_MOVE3(__position + 1, end(), __position);
       --this->_M_impl._M_finish;
-      this->_M_impl.destroy(this->_M_impl._M_finish);
+      _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
       return __position;
     }
 
@@ -160,6 +160,22 @@ 
     {
       if (&__x != this)
 	{
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+	  if (_Alloc_traits::_S_propagate_on_copy_assign())
+	    {
+	      if (!_Alloc_traits::_S_always_equal()
+	          && _M_get_Tp_allocator() != __x._M_get_Tp_allocator())
+	        {
+		  // replacement allocator cannot free existing storage
+		  this->clear();
+		  _M_deallocate(this->_M_impl._M_start,
+				this->_M_impl._M_end_of_storage
+				- this->_M_impl._M_start);
+		}
+	      std::__alloc_on_copy(_M_get_Tp_allocator(),
+				   __x._M_get_Tp_allocator());
+	    }
+#endif
 	  const size_type __xlen = __x.size();
 	  if (__xlen > capacity())
 	    {
@@ -277,8 +293,8 @@ 
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
 	    && __position == end())
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_finish,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+				     std::forward<_Args>(__args)...);
 	    ++this->_M_impl._M_finish;
 	  }
 	else
@@ -300,9 +316,9 @@ 
     {
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	{
-	  this->_M_impl.construct(this->_M_impl._M_finish,
-				  _GLIBCXX_MOVE(*(this->_M_impl._M_finish
-						  - 1)));
+	  _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+			           _GLIBCXX_MOVE(*(this->_M_impl._M_finish
+				                   - 1)));
 	  ++this->_M_impl._M_finish;
 #ifndef __GXX_EXPERIMENTAL_CXX0X__
 	  _Tp __x_copy = __x;
@@ -329,11 +345,12 @@ 
 	      // case, where the moves could alter a new element belonging
 	      // to the existing vector.  This is an issue only for callers
 	      // taking the element by const lvalue ref (see 23.1/13).
-	      this->_M_impl.construct(__new_start + __elems_before,
+	      _Alloc_traits::construct(this->_M_impl,
+		                       __new_start + __elems_before,
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
-				      std::forward<_Args>(__args)...);
+				       std::forward<_Args>(__args)...);
 #else
-	                              __x);
+	                               __x);
 #endif
 	      __new_finish = 0;
 
@@ -352,7 +369,8 @@ 
           __catch(...)
 	    {
 	      if (!__new_finish)
-		this->_M_impl.destroy(__new_start + __elems_before);
+		_Alloc_traits::destroy(this->_M_impl,
+		                       __new_start + __elems_before);
 	      else
 		std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
 	      _M_deallocate(__new_start, __len);
Index: testsuite/util/testsuite_allocator.h
===================================================================
--- testsuite/util/testsuite_allocator.h	(revision 176072)
+++ testsuite/util/testsuite_allocator.h	(working copy)
@@ -371,6 +371,68 @@ 
       
       int personality;
     };
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+  // An uneq_allocator which can be used to test allocator propagation.
+  template<typename Tp, bool Propagate>
+    class propagating_allocator : public uneq_allocator<Tp>
+    {
+      typedef uneq_allocator<Tp> base_alloc;
+      base_alloc& base() { return *this; }
+      const base_alloc& base() const  { return *this; }
+      void swap_base(base_alloc& b) { swap(b, this->base()); }
+
+      typedef std::integral_constant<bool, Propagate> trait_type;
+
+    public:
+      template<typename Up>
+	struct rebind { typedef propagating_allocator<Up, Propagate> other; };
+
+      propagating_allocator(int i) noexcept
+      : base_alloc(i)
+      { }
+
+      template<typename Up>
+	propagating_allocator(const propagating_allocator<Up, Propagate>& a)
+       	noexcept
+	: base_alloc(a)
+	{ }
+
+      propagating_allocator() noexcept = default;
+
+      propagating_allocator(const propagating_allocator&) noexcept = default;
+
+      template<bool P2>
+  	propagating_allocator&
+  	operator=(const propagating_allocator<Tp, P2>& a) noexcept
+  	{
+	  static_assert(P2, "assigning propagating_allocator<T, true>");
+	  propagating_allocator(a).swap_base(*this);
+  	}
+
+      // postcondition: a.get_personality() == 0
+      propagating_allocator(propagating_allocator&& a) noexcept
+      : base_alloc()
+      { swap_base(a); }
+
+      // postcondition: a.get_personality() == 0
+      propagating_allocator&
+      operator=(propagating_allocator&& a) noexcept
+      {
+	propagating_allocator(std::move(a)).swap_base(*this);
+	return *this;
+      }
+
+      typedef trait_type propagate_on_container_copy_assignment;
+      typedef trait_type propagate_on_container_move_assignment;
+      typedef trait_type propagate_on_container_swap;
+
+      propagating_allocator select_on_container_copy_construction() const
+      { return Propagate ? *this : propagating_allocator(); }
+    };
+
+#endif
+
 } // namespace __gnu_test
 
 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H
Index: testsuite/23_containers/vector/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/vector/allocator/copy_assign.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/copy_assign.cc	(revision 0)
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+ 
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/vector/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/vector/allocator/noexcept.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/noexcept.cc	(revision 0)
@@ -0,0 +1,76 @@ 
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+ 
+struct T { int i; };
+
+namespace __gnu_test
+{
+  inline void
+  swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+  noexcept(false)
+  {
+    typedef uneq_allocator<T> base_alloc;
+    swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+  }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  typedef std::allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1;
+  test_type v2;
+  // this is a GNU extension for std::allocator
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
Index: testsuite/23_containers/vector/allocator/copy.cc
===================================================================
--- testsuite/23_containers/vector/allocator/copy.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/copy.cc	(revision 0)
@@ -0,0 +1,55 @@ 
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+ 
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/vector/allocator/swap.cc
===================================================================
--- testsuite/23_containers/vector/allocator/swap.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/swap.cc	(revision 0)
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+ 
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(2 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/vector/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/vector/allocator/move_assign.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/move_assign.cc	(revision 0)
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+ 
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(0 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1157 }
+// { dg-error "no matching" "" { target *-*-* } 1218 }
 
 #include <vector>
 
Index: testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1198 }
+// { dg-error "no matching" "" { target *-*-* } 1259 }
 
 #include <vector>
 
Index: testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1087 }
+// { dg-error "no matching" "" { target *-*-* } 1148 }
 
 #include <vector>
 
Index: testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1087 }
+// { dg-error "no matching" "" { target *-*-* } 1148 }
 
 #include <vector>
 #include <utility>