Make std::deque meet C++11 allocator requirements.
authorJonathan Wakely <jwakely@redhat.com>
Tue, 9 Sep 2014 17:29:32 +0000 (18:29 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 9 Sep 2014 17:29:32 +0000 (18:29 +0100)
* 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.

From-SVN: r215090

19 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/deque.tcc
libstdc++-v3/include/bits/stl_deque.h
libstdc++-v3/include/debug/deque
libstdc++-v3/include/profile/deque
libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc
libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc
libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc
libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc
libstdc++-v3/testsuite/23_containers/vector/52591.cc

index bf3f48db3fbe1d173d36327727ceb17f0b7fad31..a5acf92b2dc04de53d79299856f86bcbe011c3e7 100644 (file)
@@ -1,3 +1,39 @@
+2014-09-09  Jonathan Wakely  <jwakely@redhat.com>
+
+       * 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.
+
 2014-09-06  François Dumont  <fdumont@gcc.gnu.org>
 
        * include/bits/hashtable_policy.h (_Prime_rehash_policy): Constructor
index ebf5d3a0ab95f26757ee3c85c37b109c521260f2..9c8dd36f1f5590a3d620777857e2e3c0e54df730 100644 (file)
@@ -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;
index add8742a102c268a9569f803ca45df811ec0a0a7..acb7715f71773e5c89e641ae9a452b5769402a98 100644 (file)
@@ -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
     };
 
 
index 75be7489b1a6490f5bd58fc999431334baf3a77a..824cb289112a4f0518e1db1f77def2fcaa4551df 100644 (file)
@@ -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())
index 13513f4bdc76d0200a174983499fd9373ee0bbce..c825cbe2ad9183181ed074e9346cb4e16caca29a 100644 (file)
@@ -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 (file)
index 0000000..f33349c
--- /dev/null
@@ -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 (file)
index 0000000..83ebc7b
--- /dev/null
@@ -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 (file)
index 0000000..e17c084
--- /dev/null
@@ -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 (file)
index 0000000..70ca09d
--- /dev/null
@@ -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 (file)
index 0000000..1e8d848
--- /dev/null
@@ -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 (file)
index 0000000..5f337a0
--- /dev/null
@@ -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 (file)
index 0000000..2b5febc
--- /dev/null
@@ -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 (file)
index 0000000..6d199cc
--- /dev/null
@@ -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 (file)
index 0000000..c504581
--- /dev/null
@@ -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;
+}
index 4de8f2d0fb9d72fa9a23f90b650f1701a9aa57e7..8092ead6d41df1f2f30f4044d9c791585fb9cf8b 100644 (file)
@@ -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>
 
index 41f29056198c712c4b9779e6aa8e726aeca278d7..4abdf4682bea8c85e05238f56292377432e6d910 100644 (file)
@@ -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>
 
index f77b1267890fcf1280f6f828e47e9a5ee1fad8e3..61bce4eb049a1628e3254624c6f58611ec841fa7 100644 (file)
@@ -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>
index e7d5b1ee654b12d08cd614e0152bcd3ccfb41c7a..a0ca00caf8ad67ab5aca908fafd23eac3a997f33 100644 (file)
@@ -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>
 
index 81a86c5c3c7e2affcc6d6ea32350eedec16b2348..073d29adb905ad63a9793bccc4653fe7e290852f 100644 (file)
@@ -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");
 }