diff mbox

Make std::deque meet C++11 allocator requirements

Message ID 20140909173103.GF22778@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Sept. 9, 2014, 5:31 p.m. UTC
This was a tricky one, because std::deque always has a map of nodes
allocated, so needs to re-allocate in its move constructor. That makes
move assignment complicated, as the rvalue object must be left in a
valid state owning memory that can be freed by its (possibly
moved-from) allocator.

The _M_replace_map(_Args&&...) function constructs a new deque from
its arguments, rips the guts out of that new deque and then destroys
it. When the argument to the new deque is an rvalue deque the move
constructor takes care of leaving the rvalue in a valid state with
memory that can be freed by its allocator.

The common case with std::allocator allows move-assignment to be
noexcept, because it only involves swapping a few pointers and calling
clear().

As an extension we support move assignment of std::deque even if the
element types are not assignable, as long as the allocator type
propagates (as we do for std::vector, see PR52591).

Tested x86_64-linux, normal, debug and profile modes.

Committed to trunk.
diff mbox

Patch

commit 79a3c8ca1c14069e9756350c334bc3ee5e66a61a
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Fri Nov 23 21:25:07 2012 +0000

    Make std::deque meet C++11 allocator requirements.
    
    	* include/bits/deque.tcc (deque::operator=(const deque&)): Handle
    	allocator propagation.
    	(deque::emplace_front, deque::emplace_back): Use allocator traits.
    	(deque::_M_push_back_aux, deque::_M_push_front_aux): Likewise.
    	(deque::_M_pop_back_aux, deque::_M_pop_front_aux): Likewise.
    	* include/bits/stl_deque.h (__deque_buf_size): Add constexpr.
    	(_Deque_iterator): Handle allocators with custom pointers.
    	(_Deque_base): Likewise. Use allocator traits.
    	(deque): Likewise. Add allocator-extended constructors.
    	(deque::_M_move_assign1, deque::_M_move_assign2): Implement move
    	assignment via tag dispatching.
    	(deque::_M_replace_map): Replace existing data.
    	* include/debug/deque (deque): Add allocator-extended constructors.
    	* include/profile/deque (deque): Likewise.
    	* testsuite/23_containers/deque/allocator/copy.cc: New.
    	* testsuite/23_containers/deque/allocator/copy_assign.cc: New.
    	* testsuite/23_containers/deque/allocator/ext_ptr.cc: New.
    	* testsuite/23_containers/deque/allocator/minimal.cc: New.
    	* testsuite/23_containers/deque/allocator/move.cc: New.
    	* testsuite/23_containers/deque/allocator/move_assign-2.cc: New.
    	* testsuite/23_containers/deque/allocator/move_assign.cc: New.
    	* testsuite/23_containers/deque/allocator/noexcept.cc: New.
    	* testsuite/23_containers/deque/allocator/swap.cc: New.
    	* testsuite/23_containers/deque/requirements/dr438/assign_neg.cc:
    	Adjust dg-error line number.
    	* testsuite/23_containers/deque/requirements/dr438/
    	constructor_1_neg.cc: Likewise.
    	* testsuite/23_containers/deque/requirements/dr438/
    	constructor_2_neg.cc: Likewise.
    	* testsuite/23_containers/deque/requirements/dr438/insert_neg.cc:
    	Likewise.
    	* testsuite/23_containers/vector/52591.cc: Test both the propagating
    	and always-equal cases.

diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index ebf5d3a..9c8dd36 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -92,9 +92,26 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     deque<_Tp, _Alloc>::
     operator=(const deque& __x)
     {
-      const size_type __len = size();
       if (&__x != this)
 	{
+#if __cplusplus >= 201103L
+	  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,
+		  // so deallocate everything and take copy of __x's data.
+		  _M_replace_map(__x, __x.get_allocator());
+		  std::__alloc_on_copy(_M_get_Tp_allocator(),
+				       __x._M_get_Tp_allocator());
+		  return *this;
+		}
+	      std::__alloc_on_copy(_M_get_Tp_allocator(),
+				   __x._M_get_Tp_allocator());
+	    }
+#endif
+	  const size_type __len = size();
 	  if (__len >= __x.size())
 	    _M_erase_at_end(std::copy(__x.begin(), __x.end(),
 				      this->_M_impl._M_start));
@@ -117,8 +134,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_start._M_cur - 1,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_start._M_cur - 1,
+			             std::forward<_Args>(__args)...);
 	    --this->_M_impl._M_start._M_cur;
 	  }
 	else
@@ -134,8 +152,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_impl._M_finish._M_cur
 	    != this->_M_impl._M_finish._M_last - 1)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_finish._M_cur,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_finish._M_cur,
+			             std::forward<_Args>(__args)...);
 	    ++this->_M_impl._M_finish._M_cur;
 	  }
 	else
@@ -453,8 +472,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	__try
 	  {
 #if __cplusplus >= 201103L
-	    this->_M_impl.construct(this->_M_impl._M_finish._M_cur,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_finish._M_cur,
+			             std::forward<_Args>(__args)...);
 #else
 	    this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __t);
 #endif
@@ -490,8 +510,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 					       - 1);
 	    this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_last - 1;
 #if __cplusplus >= 201103L
-	    this->_M_impl.construct(this->_M_impl._M_start._M_cur,
-				    std::forward<_Args>(__args)...);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_start._M_cur,
+			             std::forward<_Args>(__args)...);
 #else
 	    this->_M_impl.construct(this->_M_impl._M_start._M_cur, __t);
 #endif
@@ -512,7 +533,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _M_deallocate_node(this->_M_impl._M_finish._M_first);
       this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node - 1);
       this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_last - 1;
-      this->_M_impl.destroy(this->_M_impl._M_finish._M_cur);
+      _Alloc_traits::destroy(_M_get_Tp_allocator(),
+			     this->_M_impl._M_finish._M_cur);
     }
 
   // Called only if _M_impl._M_start._M_cur == _M_impl._M_start._M_last - 1.
@@ -524,7 +546,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     void deque<_Tp, _Alloc>::
     _M_pop_front_aux()
     {
-      this->_M_impl.destroy(this->_M_impl._M_start._M_cur);
+      _Alloc_traits::destroy(_M_get_Tp_allocator(),
+			     this->_M_impl._M_start._M_cur);
       _M_deallocate_node(this->_M_impl._M_start._M_first);
       this->_M_impl._M_start._M_set_node(this->_M_impl._M_start._M_node + 1);
       this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_first;
diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h
index add8742..acb7715 100644
--- a/libstdc++-v3/include/bits/stl_deque.h
+++ b/libstdc++-v3/include/bits/stl_deque.h
@@ -85,7 +85,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #define _GLIBCXX_DEQUE_BUF_SIZE 512
 #endif
 
-  inline size_t
+  _GLIBCXX_CONSTEXPR inline size_t
   __deque_buf_size(size_t __size)
   { return (__size < _GLIBCXX_DEQUE_BUF_SIZE
 	    ? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); }
@@ -105,8 +105,23 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   template<typename _Tp, typename _Ref, typename _Ptr>
     struct _Deque_iterator
     {
+#if __cplusplus < 201103L
       typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
       typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
+      typedef _Tp*                                         _Elt_pointer;
+      typedef _Tp**                                        _Map_pointer;
+#else
+    private:
+      template<typename _Up>
+	using __ptr_to = typename pointer_traits<_Ptr>::template rebind<_Up>;
+      template<typename _CvTp>
+	using __iter = _Deque_iterator<_Tp, _CvTp&, __ptr_to<_CvTp>>;
+    public:
+      typedef __iter<_Tp>		iterator;
+      typedef __iter<const _Tp>		const_iterator;
+      typedef __ptr_to<_Tp>		_Elt_pointer;
+      typedef __ptr_to<_Elt_pointer>	_Map_pointer;
+#endif
 
       static size_t _S_buffer_size() _GLIBCXX_NOEXCEPT
       { return __deque_buf_size(sizeof(_Tp)); }
@@ -117,20 +132,19 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef _Ref                            reference;
       typedef size_t                          size_type;
       typedef ptrdiff_t                       difference_type;
-      typedef _Tp**                           _Map_pointer;
       typedef _Deque_iterator                 _Self;
 
-      _Tp* _M_cur;
-      _Tp* _M_first;
-      _Tp* _M_last;
+      _Elt_pointer _M_cur;
+      _Elt_pointer _M_first;
+      _Elt_pointer _M_last;
       _Map_pointer _M_node;
 
-      _Deque_iterator(_Tp* __x, _Map_pointer __y) _GLIBCXX_NOEXCEPT
+      _Deque_iterator(_Elt_pointer __x, _Map_pointer __y) _GLIBCXX_NOEXCEPT
       : _M_cur(__x), _M_first(*__y),
         _M_last(*__y + _S_buffer_size()), _M_node(__y) { }
 
       _Deque_iterator() _GLIBCXX_NOEXCEPT
-      : _M_cur(0), _M_first(0), _M_last(0), _M_node(0) { }
+      : _M_cur(), _M_first(), _M_last(), _M_node() { }
 
       _Deque_iterator(const iterator& __x) _GLIBCXX_NOEXCEPT
       : _M_cur(__x._M_cur), _M_first(__x._M_first),
@@ -443,15 +457,33 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   template<typename _Tp, typename _Alloc>
     class _Deque_base
     {
+    protected:
+      typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
+	rebind<_Tp>::other _Tp_alloc_type;
+      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>	 _Alloc_traits;
+
+#if __cplusplus < 201103L
+      typedef _Tp*					_Ptr;
+      typedef const _Tp*				_Ptr_const;
+#else
+      typedef typename _Alloc_traits::pointer		_Ptr;
+      typedef typename _Alloc_traits::const_pointer	_Ptr_const;
+#endif
+
+      typedef typename _Alloc_traits::template rebind<_Ptr>::other
+	_Map_alloc_type;
+      typedef __gnu_cxx::__alloc_traits<_Map_alloc_type> _Map_alloc_traits;
+
     public:
       typedef _Alloc                  allocator_type;
+      typedef typename _Alloc_traits::size_type size_type;
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
-      typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
+      typedef _Deque_iterator<_Tp, _Tp&, _Ptr>          iterator;
+      typedef _Deque_iterator<_Tp, const _Tp&, _Ptr_const>   const_iterator;
 
       _Deque_base()
       : _M_impl()
@@ -467,19 +499,43 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Deque_base(const allocator_type& __a)
       : _M_impl(__a)
-      { }
+      { /* Caller must initialize map. */ }
 
 #if __cplusplus >= 201103L
       _Deque_base(_Deque_base&& __x)
       : _M_impl(std::move(__x._M_get_Tp_allocator()))
       {
-	_M_initialize_map(0);
 	if (__x._M_impl._M_map)
 	  {
-	    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_map, __x._M_impl._M_map);
-	    std::swap(this->_M_impl._M_map_size, __x._M_impl._M_map_size);
+	    this->_M_impl._M_swap_data(__x._M_impl);
+	    __try
+	      {
+		// Re-initialize __x using its moved-from allocator.
+		__x._M_initialize_map(0);
+	      }
+	    __catch (...)
+	      {
+		this->_M_impl._M_swap_data(__x._M_impl);
+		__x._M_get_Tp_allocator() = std::move(_M_get_Tp_allocator());
+		__throw_exception_again;
+	      }
+	  }
+      }
+
+      _Deque_base(_Deque_base&& __x, const allocator_type& __a, size_type __n)
+      : _M_impl(__a)
+      {
+	if (__x.get_allocator() == __a)
+	  {
+	    if (__x._M_impl._M_map)
+	      {
+		_M_initialize_map(0);
+		this->_M_impl._M_swap_data(__x._M_impl);
+	      }
+	  }
+	else
+	  {
+	    _M_initialize_map(__n);
 	  }
       }
 #endif
@@ -487,9 +543,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       ~_Deque_base() _GLIBCXX_NOEXCEPT;
 
     protected:
-      typedef typename _Alloc::template rebind<_Tp*>::other _Map_alloc_type;
-
-      typedef typename _Alloc::template rebind<_Tp>::other  _Tp_alloc_type;
+      typedef typename iterator::_Map_pointer _Map_pointer;
 
       //This struct encapsulates the implementation of the std::deque
       //standard container and at the same time makes use of the EBO
@@ -497,27 +551,35 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       struct _Deque_impl
       : public _Tp_alloc_type
       {
-	_Tp** _M_map;
+	_Map_pointer _M_map;
 	size_t _M_map_size;
 	iterator _M_start;
 	iterator _M_finish;
 
 	_Deque_impl()
-	: _Tp_alloc_type(), _M_map(0), _M_map_size(0),
+	: _Tp_alloc_type(), _M_map(), _M_map_size(0),
 	  _M_start(), _M_finish()
 	{ }
 
 	_Deque_impl(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_map(0), _M_map_size(0),
+	: _Tp_alloc_type(__a), _M_map(), _M_map_size(0),
 	  _M_start(), _M_finish()
 	{ }
 
 #if __cplusplus >= 201103L
 	_Deque_impl(_Tp_alloc_type&& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(std::move(__a)), _M_map(0), _M_map_size(0),
+	: _Tp_alloc_type(std::move(__a)), _M_map(), _M_map_size(0),
 	  _M_start(), _M_finish()
 	{ }
 #endif
+
+	void _M_swap_data(_Deque_impl& __x)
+	{
+	  std::swap(this->_M_start, __x._M_start);
+	  std::swap(this->_M_finish, __x._M_finish);
+	  std::swap(this->_M_map, __x._M_map);
+	  std::swap(this->_M_map_size, __x._M_map_size);
+	}
       };
 
       _Tp_alloc_type&
@@ -532,30 +594,39 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _M_get_map_allocator() const _GLIBCXX_NOEXCEPT
       { return _Map_alloc_type(_M_get_Tp_allocator()); }
 
-      _Tp*
+      _Ptr
       _M_allocate_node()
       { 
-	return _M_impl._Tp_alloc_type::allocate(__deque_buf_size(sizeof(_Tp)));
+	typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits;
+	return _Traits::allocate(_M_impl, __deque_buf_size(sizeof(_Tp)));
       }
 
       void
-      _M_deallocate_node(_Tp* __p) _GLIBCXX_NOEXCEPT
+      _M_deallocate_node(_Ptr __p) _GLIBCXX_NOEXCEPT
       {
-	_M_impl._Tp_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp)));
+	typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits;
+	_Traits::deallocate(_M_impl, __p, __deque_buf_size(sizeof(_Tp)));
       }
 
-      _Tp**
+      _Map_pointer
       _M_allocate_map(size_t __n)
-      { return _M_get_map_allocator().allocate(__n); }
+      {
+	_Map_alloc_type __map_alloc = _M_get_map_allocator();
+	return _Map_alloc_traits::allocate(__map_alloc, __n);
+      }
 
       void
-      _M_deallocate_map(_Tp** __p, size_t __n) _GLIBCXX_NOEXCEPT
-      { _M_get_map_allocator().deallocate(__p, __n); }
+      _M_deallocate_map(_Map_pointer __p, size_t __n) _GLIBCXX_NOEXCEPT
+      {
+	_Map_alloc_type __map_alloc = _M_get_map_allocator();
+	_Map_alloc_traits::deallocate(__map_alloc, __p, __n);
+      }
 
     protected:
       void _M_initialize_map(size_t);
-      void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish);
-      void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) _GLIBCXX_NOEXCEPT;
+      void _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish);
+      void _M_destroy_nodes(_Map_pointer __nstart,
+			    _Map_pointer __nfinish) _GLIBCXX_NOEXCEPT;
       enum { _S_initial_map_size = 8 };
 
       _Deque_impl _M_impl;
@@ -576,7 +647,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   /**
    *  @brief Layout storage.
    *  @param  __num_elements  The count of T's for which to allocate space
-   *                        at first.
+   *                          at first.
    *  @return   Nothing.
    *
    *  The initial underlying memory layout is a bit complicated...
@@ -598,16 +669,16 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // the beginning of _M_map, but for small maps it may be as far in as
       // _M_map+3.
 
-      _Tp** __nstart = (this->_M_impl._M_map
-			+ (this->_M_impl._M_map_size - __num_nodes) / 2);
-      _Tp** __nfinish = __nstart + __num_nodes;
+      _Map_pointer __nstart = (this->_M_impl._M_map
+			       + (this->_M_impl._M_map_size - __num_nodes) / 2);
+      _Map_pointer __nfinish = __nstart + __num_nodes;
 
       __try
 	{ _M_create_nodes(__nstart, __nfinish); }
       __catch(...)
 	{
 	  _M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);
-	  this->_M_impl._M_map = 0;
+	  this->_M_impl._M_map = _Map_pointer();
 	  this->_M_impl._M_map_size = 0;
 	  __throw_exception_again;
 	}
@@ -623,9 +694,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   template<typename _Tp, typename _Alloc>
     void
     _Deque_base<_Tp, _Alloc>::
-    _M_create_nodes(_Tp** __nstart, _Tp** __nfinish)
+    _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish)
     {
-      _Tp** __cur;
+      _Map_pointer __cur;
       __try
 	{
 	  for (__cur = __nstart; __cur < __nfinish; ++__cur)
@@ -641,9 +712,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   template<typename _Tp, typename _Alloc>
     void
     _Deque_base<_Tp, _Alloc>::
-    _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) _GLIBCXX_NOEXCEPT
+    _M_destroy_nodes(_Map_pointer __nstart,
+		     _Map_pointer __nfinish) _GLIBCXX_NOEXCEPT
     {
-      for (_Tp** __n = __nstart; __n < __nfinish; ++__n)
+      for (_Map_pointer __n = __nstart; __n < __nfinish; ++__n)
 	_M_deallocate_node(*__n);
     }
 
@@ -739,15 +811,17 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       __glibcxx_class_requires(_Tp, _SGIAssignableConcept)
       __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept)
 
-      typedef _Deque_base<_Tp, _Alloc>           _Base;
-      typedef typename _Base::_Tp_alloc_type	 _Tp_alloc_type;
+      typedef _Deque_base<_Tp, _Alloc>			_Base;
+      typedef typename _Base::_Tp_alloc_type		_Tp_alloc_type;
+      typedef typename _Base::_Alloc_traits		_Alloc_traits;
+      typedef typename _Base::_Map_pointer		_Map_pointer;
 
     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 _Alloc_traits::pointer            pointer;
+      typedef typename _Alloc_traits::const_pointer      const_pointer;
+      typedef typename _Alloc_traits::reference          reference;
+      typedef typename _Alloc_traits::const_reference    const_reference;
       typedef typename _Base::iterator                   iterator;
       typedef typename _Base::const_iterator             const_iterator;
       typedef std::reverse_iterator<const_iterator>      const_reverse_iterator;
@@ -757,8 +831,6 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef _Alloc                             allocator_type;
 
     protected:
-      typedef pointer*                           _Map_pointer;
-
       static size_t _S_buffer_size() _GLIBCXX_NOEXCEPT
       { return __deque_buf_size(sizeof(_Tp)); }
 
@@ -804,8 +876,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  constructed elements.
        */
       explicit
-      deque(size_type __n)
-      : _Base(__n)
+      deque(size_type __n, const allocator_type& __a = allocator_type())
+      : _Base(__a, __n)
       { _M_default_initialize(); }
 
       /**
@@ -844,7 +916,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  by @a __x.
        */
       deque(const deque& __x)
-      : _Base(__x._M_get_Tp_allocator(), __x.size())
+      : _Base(_Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()),
+	      __x.size())
       { std::__uninitialized_copy_a(__x.begin(), __x.end(), 
 				    this->_M_impl._M_start,
 				    _M_get_Tp_allocator()); }
@@ -860,6 +933,26 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       deque(deque&& __x)
       : _Base(std::move(__x)) { }
 
+      /// Copy constructor with alternative allocator
+      deque(const deque& __x, const allocator_type& __a)
+      : _Base(__a, __x.size())
+      { std::__uninitialized_copy_a(__x.begin(), __x.end(),
+				    this->_M_impl._M_start,
+				    _M_get_Tp_allocator()); }
+
+      /// Move constructor with alternative allocator
+      deque(deque&& __x, const allocator_type& __a)
+      : _Base(std::move(__x), __a, __x.size())
+      {
+	if (__x.get_allocator() != __a)
+	  {
+	    std::__uninitialized_move_a(__x.begin(), __x.end(),
+					this->_M_impl._M_start,
+					_M_get_Tp_allocator());
+	    __x.clear();
+	  }
+      }
+
       /**
        *  @brief  Builds a %deque from an initializer list.
        *  @param  __l  An initializer_list.
@@ -919,7 +1012,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  themselves are pointers, the pointed-to memory is not touched in any
        *  way.  Managing the pointer is the user's responsibility.
        */
-      ~deque() _GLIBCXX_NOEXCEPT
+      ~deque()
       { _M_destroy_data(begin(), end(), _M_get_Tp_allocator()); }
 
       /**
@@ -937,16 +1030,16 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  @brief  %Deque move assignment operator.
        *  @param  __x  A %deque of identical element and allocator types.
        *
-       *  The contents of @a __x are moved into this deque (without copying).
+       *  The contents of @a __x are moved into this deque (without copying,
+       *  if the allocators permit it).
        *  @a __x is a valid, but unspecified %deque.
        */
       deque&
-      operator=(deque&& __x) noexcept
+      operator=(deque&& __x) noexcept(_Alloc_traits::_S_always_equal())
       {
-	// NB: DR 1204.
-	// NB: DR 675.
-	this->clear();
-	this->swap(__x);
+	constexpr bool __always_equal = _Alloc_traits::_S_always_equal();
+	_M_move_assign1(std::move(__x),
+		        integral_constant<bool, __always_equal>());
 	return *this;
       }
 
@@ -1150,7 +1243,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**  Returns the size() of the largest possible %deque.  */
       size_type
       max_size() const _GLIBCXX_NOEXCEPT
-      { return _M_get_Tp_allocator().max_size(); }
+      { return _Alloc_traits::max_size(_M_get_Tp_allocator()); }
 
 #if __cplusplus >= 201103L
       /**
@@ -1368,7 +1461,9 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_start._M_cur - 1, __x);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_start._M_cur - 1,
+	                             __x);
 	    --this->_M_impl._M_start._M_cur;
 	  }
 	else
@@ -1400,7 +1495,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_impl._M_finish._M_cur
 	    != this->_M_impl._M_finish._M_last - 1)
 	  {
-	    this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __x);
+	    _Alloc_traits::construct(this->_M_impl,
+	                             this->_M_impl._M_finish._M_cur, __x);
 	    ++this->_M_impl._M_finish._M_cur;
 	  }
 	else
@@ -1431,7 +1527,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_impl._M_start._M_cur
 	    != this->_M_impl._M_start._M_last - 1)
 	  {
-	    this->_M_impl.destroy(this->_M_impl._M_start._M_cur);
+	    _Alloc_traits::destroy(this->_M_impl,
+	                           this->_M_impl._M_start._M_cur);
 	    ++this->_M_impl._M_start._M_cur;
 	  }
 	else
@@ -1453,7 +1550,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    != this->_M_impl._M_finish._M_first)
 	  {
 	    --this->_M_impl._M_finish._M_cur;
-	    this->_M_impl.destroy(this->_M_impl._M_finish._M_cur);
+	    _Alloc_traits::destroy(this->_M_impl,
+	                           this->_M_impl._M_finish._M_cur);
 	  }
 	else
 	  _M_pop_back_aux();
@@ -1659,17 +1757,14 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  std::swap(d1,d2) will feed to this function.
        */
       void
-      swap(deque& __x) _GLIBCXX_NOEXCEPT
+      swap(deque& __x)
+#if __cplusplus >= 201103L
+      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_map, __x._M_impl._M_map);
-	std::swap(this->_M_impl._M_map_size, __x._M_impl._M_map_size);
-
-	// _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());
+	_M_impl._M_swap_data(__x._M_impl);
+	_Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
+				  __x._M_get_Tp_allocator());
       }
 
       /**
@@ -2011,6 +2106,79 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       void
       _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front);
       //@}
+
+#if __cplusplus >= 201103L
+      // Constant-time, nothrow move assignment when source object's memory
+      // can be moved because the allocators are equal.
+      void
+      _M_move_assign1(deque&& __x, /* always equal: */ true_type) noexcept
+      {
+	this->_M_impl._M_swap_data(__x._M_impl);
+	__x.clear();
+	std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator());
+      }
+
+      void
+      _M_move_assign1(deque&& __x, /* always equal: */ false_type)
+      {
+	constexpr bool __move_storage =
+	  _Alloc_traits::_S_propagate_on_move_assign();
+	_M_move_assign2(std::move(__x),
+			integral_constant<bool, __move_storage>());
+      }
+
+      // Destroy all elements and deallocate all memory, then replace
+      // with elements created from __args.
+      template<typename... _Args>
+      void
+      _M_replace_map(_Args&&... __args)
+      {
+	// Create new data first, so if allocation fails there are no effects.
+	deque __newobj(std::forward<_Args>(__args)...);
+	// Free existing storage using existing allocator.
+	clear();
+	_M_deallocate_node(*begin()._M_node); // one node left after clear()
+	_M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);
+	this->_M_impl._M_map = nullptr;
+	this->_M_impl._M_map_size = 0;
+	// Take ownership of replacement memory.
+	this->_M_impl._M_swap_data(__newobj._M_impl);
+      }
+
+      // Do move assignment when the allocator propagates.
+      void
+      _M_move_assign2(deque&& __x, /* propagate: */ true_type)
+      {
+	// Make a copy of the original allocator state.
+	auto __alloc = __x._M_get_Tp_allocator();
+	// The allocator propagates so storage can be moved from __x,
+	// leaving __x in a valid empty state with a moved-from allocator.
+	_M_replace_map(std::move(__x));
+	// Move the corresponding allocator state too.
+	_M_get_Tp_allocator() = std::move(__alloc);
+      }
+
+      // Do move assignment when it may not be possible to move source
+      // object's memory, resulting in a linear-time operation.
+      void
+      _M_move_assign2(deque&& __x, /* propagate: */ false_type)
+      {
+	if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
+	  {
+	    // The allocators are equal so storage can be moved from __x,
+	    // leaving __x in a valid empty state with its current allocator.
+	    _M_replace_map(std::move(__x), __x.get_allocator());
+	  }
+	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/include/debug/deque b/libstdc++-v3/include/debug/deque
index 75be748..824cb28 100644
--- a/libstdc++-v3/include/debug/deque
+++ b/libstdc++-v3/include/debug/deque
@@ -88,6 +88,12 @@  namespace __debug
       deque(const deque&) = default;
       deque(deque&&) = default;
 
+      deque(const deque& __d, const _Allocator& __a)
+      : _Base(__d, __a) { }
+
+      deque(deque&& __d, const _Allocator& __a)
+      : _Safe(std::move(__d)), _Base(std::move(__d), __a) { }
+
       deque(initializer_list<value_type> __l,
 	    const allocator_type& __a = allocator_type())
       : _Base(__l, __a) { }
@@ -101,8 +107,8 @@  namespace __debug
 
 #if __cplusplus >= 201103L
       explicit
-      deque(size_type __n)
-      : _Base(__n) { }
+      deque(size_type __n, const _Allocator& __a = _Allocator())
+      : _Base(__n, __a) { }
 
       deque(size_type __n, const _Tp& __value,
 	    const _Allocator& __a = _Allocator())
diff --git a/libstdc++-v3/include/profile/deque b/libstdc++-v3/include/profile/deque
index 13513f4..c825cbe 100644
--- a/libstdc++-v3/include/profile/deque
+++ b/libstdc++-v3/include/profile/deque
@@ -60,6 +60,12 @@  namespace __profile
       deque(const deque&) = default;
       deque(deque&&) = default;
 
+      deque(const deque& __d, const _Allocator& __a)
+      : _Base(__d, __a) { }
+
+      deque(deque&& __d, const _Allocator& __a)
+      : _Base(std::move(__d), __a) { }
+
       ~deque() = default;
 
       deque(initializer_list<value_type> __l,
@@ -73,8 +79,8 @@  namespace __profile
 
 #if __cplusplus >= 201103L
       explicit
-      deque(size_type __n)
-      : _Base(__n) { }
+      deque(size_type __n, const _Allocator& __a = _Allocator())
+      : _Base(__n, __a) { }
 
       deque(size_type __n, const _Tp& __value,
 	    const _Allocator& __a = _Allocator())
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc
new file mode 100644
index 0000000..f33349c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc
@@ -0,0 +1,67 @@ 
+// Copyright (C) 2014 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++11" }
+
+#include <deque>
+#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::deque<T, alloc_type> test_type;
+  test_type v1(1, 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::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(v1, alloc_type(2));
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc
new file mode 100644
index 0000000..83ebc7b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2014 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++11" }
+
+#include <deque>
+#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::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(1, 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::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(1, 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;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc
new file mode 100644
index 0000000..e17c084
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc
@@ -0,0 +1,43 @@ 
+// Copyright (C) 2014 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-options "-std=gnu++11" }
+
+#include <deque>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::CustomPointerAlloc;
+
+template class std::deque<T, CustomPointerAlloc<T>>;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef CustomPointerAlloc<T> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v(1);
+  VERIFY( ++v.begin() == v.end() );
+}
+
+int main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc
new file mode 100644
index 0000000..70ca09d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc
@@ -0,0 +1,45 @@ 
+// Copyright (C) 2014 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-options "-std=gnu++11" }
+
+#include <deque>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::SimpleAllocator;
+
+template class std::deque<T, SimpleAllocator<T>>;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef SimpleAllocator<T> alloc_type;
+  typedef std::allocator_traits<alloc_type> traits_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v(1, alloc_type{});
+  VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc
new file mode 100644
index 0000000..1e8d848
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2014 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-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::uneq_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef uneq_allocator<T> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  auto it = v1.begin();
+  test_type v2(std::move(v1));
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+  VERIFY( it == v2.begin() );
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef uneq_allocator<T> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(std::move(v1), alloc_type(2));
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc
new file mode 100644
index 0000000..5f337a0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc
@@ -0,0 +1,78 @@ 
+// Copyright (C) 2012-2014 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++11 -fno-access-control" }
+
+// libstdc++/52591
+
+#include <deque>
+#include <memory>
+#include <type_traits>
+
+
+// As an extension we allow move-assignment of std::deque 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;
+};
+
+template<typename T>
+struct A1 : std::allocator<T>
+{
+  template<typename U> struct rebind { typedef A1<U> other; };
+
+  A1() = default;
+  template<typename U> A1(const A1<U>&) { }
+
+  using propagate_on_container_move_assignment = std::true_type;
+};
+
+void test01()
+{
+  using test_type = std::deque<C, A1<C>>;
+  static_assert(std::is_move_assignable<test_type>::value,
+      "deque is move-assignable if allocator propagates");
+}
+
+template<typename T>
+struct A2 : std::allocator<T>
+{
+  template<typename U> struct rebind { typedef A2<U> other; };
+
+  A2() = default;
+  template<typename U> A2(const A2<U>&) { }
+
+  using propagate_on_container_move_assignment = std::false_type;
+};
+
+namespace __gnu_cxx
+{
+  template<typename T>
+    struct __allocator_always_compares_equal<A2<T>> : std::true_type
+    { };
+}
+
+void test02()
+{
+  using test_type = std::deque<C, A2<C>>;
+  static_assert(std::is_nothrow_move_assignable<test_type>::value,
+      "deque is nothrow move-assignable if allocator is always equal");
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc
new file mode 100644
index 0000000..2b5febc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc
@@ -0,0 +1,74 @@ 
+// Copyright (C) 2014 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++11" }
+
+#include <deque>
+#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::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(1, 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::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  auto it = v1.begin();
+  test_type v2(1, alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY( it == v2.begin() );
+  VERIFY(0 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  auto it = v1.begin();
+  test_type v2(1, alloc_type(1));
+  v2 = std::move(v1);
+  VERIFY( it == v2.begin() );
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc
new file mode 100644
index 0000000..6d199cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc
@@ -0,0 +1,67 @@ 
+// Copyright (C) 2014 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++11" }
+
+#include <deque>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+namespace __gnu_test
+{
+  template<typename U>
+    inline void
+    swap(propagating_allocator<U, true>& l, propagating_allocator<U, true>& r)
+    noexcept(false)
+    { }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  typedef std::allocator<T> alloc_type;
+  typedef std::deque<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::deque<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::deque<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" );
+  // noexcept spec of deque::swap depends on swap overload at top of this file
+  static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc
new file mode 100644
index 0000000..c504581
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc
@@ -0,0 +1,77 @@ 
+// Copyright (C) 2013 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++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+           const propagating_allocator<T, false>&)
+{
+  return false;
+}
+
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(1, alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+  // swap back so assertions in uneq_allocator::deallocate don't fail
+  std::swap(v1, v2);
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::deque<T, alloc_type> test_type;
+  test_type v1(1, alloc_type(1));
+  test_type v2(1, 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;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc
index 4de8f2d..8092ead 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1764 }
+// { dg-error "no matching" "" { target *-*-* } 1859 }
 
 #include <deque>
 
diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc
index 41f2905..4abdf46 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1697 }
+// { dg-error "no matching" "" { target *-*-* } 1792 }
 
 #include <deque>
 
diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc
index f77b126..61bce4e 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1697 }
+// { dg-error "no matching" "" { target *-*-* } 1792 }
 
 #include <deque>
 #include <utility>
diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc
index e7d5b1e..a0ca00c 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1848 }
+// { dg-error "no matching" "" { target *-*-* } 1943 }
 
 #include <deque>
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/52591.cc b/libstdc++-v3/testsuite/23_containers/vector/52591.cc
index 81a86c5..073d29a 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/52591.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/52591.cc
@@ -21,6 +21,8 @@ 
 // libstdc++/52591
 
 #include <vector>
+#include <memory>
+#include <type_traits>
 
 // 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
@@ -31,8 +33,45 @@  struct C
     C& operator=(C&&) = delete;
 };
 
+template<typename T>
+struct A1 : std::allocator<T>
+{
+  template<typename U> struct rebind { typedef A1<U> other; };
+
+  A1() = default;
+  template<typename U> A1(const A1<U>&) { }
+
+  using propagate_on_container_move_assignment = std::true_type;
+};
+
 void test01()
 {
-    std::vector<C> a;
-    a = std::vector<C>();
+  using test_type = std::vector<C, A1<C>>;
+  static_assert(std::is_nothrow_move_assignable<test_type>::value,
+      "vector is nothrow move-assignable if allocator propagates");
+}
+
+template<typename T>
+struct A2 : std::allocator<T>
+{
+  template<typename U> struct rebind { typedef A1<U> other; };
+
+  A2() = default;
+  template<typename U> A2(const A2<U>&) { }
+
+  using propagate_on_container_move_assignment = std::false_type;
+};
+
+namespace __gnu_cxx
+{
+  template<typename T>
+    struct __allocator_always_compares_equal<A2<T>> : std::true_type
+    { };
+}
+
+void test02()
+{
+  using test_type = std::vector<C, A2<C>>;
+  static_assert(std::is_nothrow_move_assignable<test_type>::value,
+      "vector is nothrow move-assignable if allocator is always equal");
 }