Relocation (= move+destroy)
authorMarc Glisse <marc.glisse@inria.fr>
Thu, 25 Oct 2018 13:03:13 +0000 (15:03 +0200)
committerMarc Glisse <glisse@gcc.gnu.org>
Thu, 25 Oct 2018 13:03:13 +0000 (13:03 +0000)
2018-10-25  Marc Glisse  <marc.glisse@inria.fr>

PR libstdc++/87106
* include/bits/alloc_traits.h (_S_construct, _S_destroy, construct,
destroy): Add noexcept specification.
* include/bits/allocator.h (construct, destroy): Likewise.
* include/ext/alloc_traits.h (construct, destroy): Likewise.
* include/ext/malloc_allocator.h (construct, destroy): Likewise.
* include/ext/new_allocator.h (construct, destroy): Likewise.
* include/bits/stl_uninitialized.h (__relocate_object_a, __relocate_a,
__relocate_a_1): New functions.
(__is_trivially_relocatable): New class.
* include/bits/stl_vector.h (__use_relocate): New static member.
* include/bits/vector.tcc (reserve, _M_realloc_insert,
_M_default_append): Use __relocate_a.
(reserve, _M_assign_aux, _M_realloc_insert, _M_fill_insert,
_M_default_append, _M_range_insert): Move _GLIBCXX_ASAN_ANNOTATE_REINIT
after _Destroy.
* testsuite/23_containers/vector/modifiers/push_back/49836.cc:
Replace CopyConsOnlyType with DelAnyAssign.

From-SVN: r265485

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/alloc_traits.h
libstdc++-v3/include/bits/allocator.h
libstdc++-v3/include/bits/stl_uninitialized.h
libstdc++-v3/include/bits/stl_vector.h
libstdc++-v3/include/bits/vector.tcc
libstdc++-v3/include/ext/alloc_traits.h
libstdc++-v3/include/ext/malloc_allocator.h
libstdc++-v3/include/ext/new_allocator.h
libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc

index 9285a6becf51e4a5a84607efad47520095a47aa4..575e52a70b6edbc547d8385c0575ae5d260c653f 100644 (file)
@@ -1,3 +1,24 @@
+2018-10-25  Marc Glisse  <marc.glisse@inria.fr>
+
+       PR libstdc++/87106
+       * include/bits/alloc_traits.h (_S_construct, _S_destroy, construct,
+       destroy): Add noexcept specification.
+       * include/bits/allocator.h (construct, destroy): Likewise.
+       * include/ext/alloc_traits.h (construct, destroy): Likewise.
+       * include/ext/malloc_allocator.h (construct, destroy): Likewise.
+       * include/ext/new_allocator.h (construct, destroy): Likewise.
+       * include/bits/stl_uninitialized.h (__relocate_object_a, __relocate_a,
+       __relocate_a_1): New functions.
+       (__is_trivially_relocatable): New class.
+       * include/bits/stl_vector.h (__use_relocate): New static member.
+       * include/bits/vector.tcc (reserve, _M_realloc_insert,
+       _M_default_append): Use __relocate_a.
+       (reserve, _M_assign_aux, _M_realloc_insert, _M_fill_insert,
+       _M_default_append, _M_range_insert): Move _GLIBCXX_ASAN_ANNOTATE_REINIT
+       after _Destroy.
+       * testsuite/23_containers/vector/modifiers/push_back/49836.cc:
+       Replace CopyConsOnlyType with DelAnyAssign.
+
 2018-10-24  François Dumont  <fdumont@gcc.gnu.org>
 
        * include/debug/safe_unordered_container.h
index 742fdd0447d9201e26094be9685178e5be80d5c3..9321fdff352cc6e13ad53841ea87894a2e95dae1 100644 (file)
@@ -240,6 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Tp, typename... _Args>
        static _Require<__has_construct<_Tp, _Args...>>
        _S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+       noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
        { __a.construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Tp, typename... _Args>
@@ -247,17 +248,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
                               is_constructible<_Tp, _Args...>>>
        _S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
+       noexcept(noexcept(::new((void*)__p)
+                         _Tp(std::forward<_Args>(__args)...)))
        { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
 
       template<typename _Alloc2, typename _Tp>
        static auto
        _S_destroy(_Alloc2& __a, _Tp* __p, int)
+       noexcept(noexcept(__a.destroy(__p)))
        -> decltype(__a.destroy(__p))
        { __a.destroy(__p); }
 
       template<typename _Alloc2, typename _Tp>
        static void
        _S_destroy(_Alloc2&, _Tp* __p, ...)
+       noexcept(noexcept(__p->~_Tp()))
        { __p->~_Tp(); }
 
       template<typename _Alloc2>
@@ -340,6 +345,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       */
       template<typename _Tp, typename... _Args>
        static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+       noexcept(noexcept(_S_construct(__a, __p,
+                                      std::forward<_Args>(__args)...)))
        -> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
        { _S_construct(__a, __p, std::forward<_Args>(__args)...); }
 
@@ -353,6 +360,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       */
       template<typename _Tp>
        static void destroy(_Alloc& __a, _Tp* __p)
+       noexcept(noexcept(_S_destroy(__a, __p, 0)))
        { _S_destroy(__a, __p, 0); }
 
       /**
@@ -472,6 +480,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename... _Args>
        static void
        construct(allocator_type& __a, _Up* __p, _Args&&... __args)
+       noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
        { __a.construct(__p, std::forward<_Args>(__args)...); }
 
       /**
@@ -484,6 +493,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up>
        static void
        destroy(allocator_type& __a, _Up* __p)
+       noexcept(noexcept(__a.destroy(__p)))
        { __a.destroy(__p); }
 
       /**
index d9d1d26e13aafd5f79a71078303b26747665063a..9f018ea239c6cb40282f75ade1eb807a8054946e 100644 (file)
@@ -88,11 +88,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename... _Args>
        void
        construct(_Up* __p, _Args&&... __args)
+       noexcept(noexcept(::new((void *)__p)
+                           _Up(std::forward<_Args>(__args)...)))
        { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
        void
-       destroy(_Up* __p) { __p->~_Up(); }
+       destroy(_Up* __p)
+       noexcept(noexcept(__p->~_Up()))
+       { __p->~_Up(); }
 #endif
     };
 
index c740503052b52e2081700d6c2c89ba6ea52852b2..94c7e151e29abcbc3804c0e3333ff5ab4f480f04 100644 (file)
@@ -879,6 +879,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 #endif
 
+#if __cplusplus >= 201103L
+  template<typename _Tp, typename _Up, typename _Allocator>
+    inline void
+    __relocate_object_a(_Tp* __dest, _Up* __orig, _Allocator& __alloc)
+    noexcept(noexcept(std::allocator_traits<_Allocator>::construct(__alloc,
+                        __dest, std::move(*__orig)))
+            && noexcept(std::allocator_traits<_Allocator>::destroy(
+                           __alloc, std::__addressof(*__orig))))
+    {
+      typedef std::allocator_traits<_Allocator> __traits;
+      __traits::construct(__alloc, __dest, std::move(*__orig));
+      __traits::destroy(__alloc, std::__addressof(*__orig));
+    }
+
+  // This class may be specialized for specific types.
+  template<typename _Tp>
+    struct __is_trivially_relocatable
+    : is_trivial<_Tp> { };
+
+  template <typename _Tp, typename _Up>
+    inline __enable_if_t<std::__is_trivially_relocatable<_Tp>::value, _Tp*>
+    __relocate_a_1(_Tp* __first, _Tp* __last,
+                  _Tp* __result, allocator<_Up>& __alloc)
+    {
+      ptrdiff_t __count = __last - __first;
+      __builtin_memmove(__result, __first, __count * sizeof(_Tp));
+      return __result + __count;
+    }
+
+  template <typename _InputIterator, typename _ForwardIterator,
+           typename _Allocator>
+    inline _ForwardIterator
+    __relocate_a_1(_InputIterator __first, _InputIterator __last,
+                  _ForwardIterator __result, _Allocator& __alloc)
+    {
+      typedef typename iterator_traits<_InputIterator>::value_type
+       _ValueType;
+      typedef typename iterator_traits<_ForwardIterator>::value_type
+       _ValueType2;
+      static_assert(std::is_same<_ValueType, _ValueType2>::value);
+      static_assert(noexcept(std::__relocate_object_a(std::addressof(*__result),
+                                                     std::addressof(*__first),
+                                                     __alloc)));
+      _ForwardIterator __cur = __result;
+      for (; __first != __last; ++__first, (void)++__cur)
+       std::__relocate_object_a(std::__addressof(*__cur),
+                                std::__addressof(*__first), __alloc);
+      return __cur;
+    }
+
+  template <typename _InputIterator, typename _ForwardIterator,
+           typename _Allocator>
+    inline _ForwardIterator
+    __relocate_a(_InputIterator __first, _InputIterator __last,
+                _ForwardIterator __result, _Allocator& __alloc)
+    {
+      return __relocate_a_1(std::__niter_base(__first),
+                           std::__niter_base(__last),
+                           std::__niter_base(__result), __alloc);
+    }
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
index 37607417d087caae3b7a70db8d2d207bba245ada..40debd62396ed30402dd20963c5da43f3fb87a31 100644 (file)
@@ -421,6 +421,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef ptrdiff_t                                        difference_type;
       typedef _Alloc                                   allocator_type;
 
+    private:
+#if __cplusplus >= 201103L
+      static constexpr bool __use_relocate =
+       noexcept(std::__relocate_object_a(
+                       std::addressof(*std::declval<pointer>()),
+                       std::addressof(*std::declval<pointer>()),
+                       std::declval<_Tp_alloc_type&>()));
+#endif
+
     protected:
       using _Base::_M_allocate;
       using _Base::_M_deallocate;
index a1d114a0a9a7f2620b9946e8a7404cf1501f04cc..8df0f4180d4c1d304b2248ed50e25b623af1d4e1 100644 (file)
@@ -71,12 +71,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->capacity() < __n)
        {
          const size_type __old_size = size();
-         pointer __tmp = _M_allocate_and_copy(__n,
-           _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
-           _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+         pointer __tmp;
+#if __cplusplus >= 201103L
+         if constexpr (__use_relocate)
+           {
+             __tmp = this->_M_allocate(__n);
+             std::__relocate_a(this->_M_impl._M_start,
+                               this->_M_impl._M_finish,
+                               __tmp, _M_get_Tp_allocator());
+           }
+         else
+#endif
+           {
+             __tmp = _M_allocate_and_copy(__n,
+               _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
+               _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+             std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+                           _M_get_Tp_allocator());
+           }
          _GLIBCXX_ASAN_ANNOTATE_REINIT;
-         std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-                       _M_get_Tp_allocator());
          _M_deallocate(this->_M_impl._M_start,
                        this->_M_impl._M_end_of_storage
                        - this->_M_impl._M_start);
@@ -295,9 +308,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          {
            _S_check_init_len(__len, _M_get_Tp_allocator());
            pointer __tmp(_M_allocate_and_copy(__len, __first, __last));
-           _GLIBCXX_ASAN_ANNOTATE_REINIT;
            std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                          _M_get_Tp_allocator());
+           _GLIBCXX_ASAN_ANNOTATE_REINIT;
            _M_deallocate(this->_M_impl._M_start,
                          this->_M_impl._M_end_of_storage
                          - this->_M_impl._M_start);
@@ -443,17 +456,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif
          __new_finish = pointer();
 
-         __new_finish
-           = std::__uninitialized_move_if_noexcept_a
-           (__old_start, __position.base(),
-            __new_start, _M_get_Tp_allocator());
+#if __cplusplus >= 201103L
+         if constexpr (__use_relocate)
+           {
+             __new_finish
+               = std::__relocate_a
+               (__old_start, __position.base(),
+                __new_start, _M_get_Tp_allocator());
+
+             ++__new_finish;
+
+             __new_finish
+               = std::__relocate_a
+               (__position.base(), __old_finish,
+                __new_finish, _M_get_Tp_allocator());
+           }
+         else
+#endif
+           {
+             __new_finish
+               = std::__uninitialized_move_if_noexcept_a
+               (__old_start, __position.base(),
+                __new_start, _M_get_Tp_allocator());
 
-         ++__new_finish;
+             ++__new_finish;
 
-         __new_finish
-           = std::__uninitialized_move_if_noexcept_a
-           (__position.base(), __old_finish,
-            __new_finish, _M_get_Tp_allocator());
+             __new_finish
+               = std::__uninitialized_move_if_noexcept_a
+               (__position.base(), __old_finish,
+                __new_finish, _M_get_Tp_allocator());
+           }
        }
       __catch(...)
        {
@@ -465,8 +497,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          _M_deallocate(__new_start, __len);
          __throw_exception_again;
        }
+#if __cplusplus >= 201103L
+      if constexpr (!__use_relocate)
+#endif
+       std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
       _GLIBCXX_ASAN_ANNOTATE_REINIT;
-      std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
       _M_deallocate(__old_start,
                    this->_M_impl._M_end_of_storage - __old_start);
       this->_M_impl._M_start = __new_start;
@@ -562,9 +597,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
                  _M_deallocate(__new_start, __len);
                  __throw_exception_again;
                }
-             _GLIBCXX_ASAN_ANNOTATE_REINIT;
              std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                            _M_get_Tp_allocator());
+             _GLIBCXX_ASAN_ANNOTATE_REINIT;
              _M_deallocate(this->_M_impl._M_start,
                            this->_M_impl._M_end_of_storage
                            - this->_M_impl._M_start);
@@ -603,27 +638,48 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
              const size_type __len =
                _M_check_len(__n, "vector::_M_default_append");
              pointer __new_start(this->_M_allocate(__len));
-             pointer __destroy_from = pointer();
-             __try
+#if __cplusplus >= 201103L
+             if constexpr (__use_relocate)
                {
-                 std::__uninitialized_default_n_a(__new_start + __size,
-                                                  __n, _M_get_Tp_allocator());
-                 __destroy_from = __new_start + __size;
-                 std::__uninitialized_move_if_noexcept_a(
-                     this->_M_impl._M_start, this->_M_impl._M_finish,
-                     __new_start, _M_get_Tp_allocator());
+                 __try
+                   {
+                     std::__uninitialized_default_n_a(__new_start + __size,
+                             __n, _M_get_Tp_allocator());
+                   }
+                 __catch(...)
+                   {
+                     _M_deallocate(__new_start, __len);
+                     __throw_exception_again;
+                   }
+                 std::__relocate_a(this->_M_impl._M_start,
+                                   this->_M_impl._M_finish,
+                                   __new_start, _M_get_Tp_allocator());
                }
-             __catch(...)
+             else
+#endif
                {
-                 if (__destroy_from)
-                   std::_Destroy(__destroy_from, __destroy_from + __n,
-                                 _M_get_Tp_allocator());
-                 _M_deallocate(__new_start, __len);
-                 __throw_exception_again;
+                 pointer __destroy_from = pointer();
+                 __try
+                   {
+                     std::__uninitialized_default_n_a(__new_start + __size,
+                             __n, _M_get_Tp_allocator());
+                     __destroy_from = __new_start + __size;
+                     std::__uninitialized_move_if_noexcept_a(
+                             this->_M_impl._M_start, this->_M_impl._M_finish,
+                             __new_start, _M_get_Tp_allocator());
+                   }
+                 __catch(...)
+                   {
+                     if (__destroy_from)
+                       std::_Destroy(__destroy_from, __destroy_from + __n,
+                                     _M_get_Tp_allocator());
+                     _M_deallocate(__new_start, __len);
+                     __throw_exception_again;
+                   }
+                 std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+                               _M_get_Tp_allocator());
                }
              _GLIBCXX_ASAN_ANNOTATE_REINIT;
-             std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-                           _M_get_Tp_allocator());
              _M_deallocate(this->_M_impl._M_start,
                            this->_M_impl._M_end_of_storage
                            - this->_M_impl._M_start);
@@ -742,9 +798,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
                    _M_deallocate(__new_start, __len);
                    __throw_exception_again;
                  }
-               _GLIBCXX_ASAN_ANNOTATE_REINIT;
                std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                              _M_get_Tp_allocator());
+               _GLIBCXX_ASAN_ANNOTATE_REINIT;
                _M_deallocate(this->_M_impl._M_start,
                              this->_M_impl._M_end_of_storage
                              - this->_M_impl._M_start);
index 2570c59d81ffde641a4b3fb3176f9e3f1640cbf3..f16853743665fef2372ec8bc689e756480789afd 100644 (file)
@@ -80,6 +80,8 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
     template<typename _Ptr, typename... _Args>
       static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
       construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
+      noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
+                                             std::forward<_Args>(__args)...)))
       {
        _Base_type::construct(__a, std::__to_address(__p),
                              std::forward<_Args>(__args)...);
@@ -89,6 +91,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
     template<typename _Ptr>
       static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
       destroy(_Alloc& __a, _Ptr __p)
+      noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
       { _Base_type::destroy(__a, std::__to_address(__p)); }
 
     static _Alloc _S_select_on_copy(const _Alloc& __a)
index 1ae53b11ddb536898831a36ba58a3023beeb85ff..5f91fe08af467a9f45a7b6aecad3eda3aee39144 100644 (file)
@@ -151,11 +151,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename... _Args>
         void
         construct(_Up* __p, _Args&&... __args)
+       noexcept(noexcept(::new((void *)__p)
+                         _Up(std::forward<_Args>(__args)...)))
        { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
         void 
-        destroy(_Up* __p) { __p->~_Up(); }
+        destroy(_Up* __p)
+       noexcept(noexcept(__p->~_Up()))
+       { __p->~_Up(); }
 #else
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 402. wrong new expression in [some_] allocator::construct
index 83c894ce0a778d70c6e287378dfa6cab5724cf41..18a45cd75f1089b470e8580fbfcf0db67dca4658 100644 (file)
@@ -142,11 +142,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up, typename... _Args>
        void
        construct(_Up* __p, _Args&&... __args)
+       noexcept(noexcept(::new((void *)__p)
+                           _Up(std::forward<_Args>(__args)...)))
        { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
        void
-       destroy(_Up* __p) { __p->~_Up(); }
+       destroy(_Up* __p)
+       noexcept(noexcept( __p->~_Up()))
+       { __p->~_Up(); }
 #else
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 402. wrong new expression in [some_] allocator::construct
index eb39e41cfac8fc7f16dee88cc13d5abf846d7393..85925ab756e33b6b17837a7f49a8830566983591 100644 (file)
 // libstdc++/49836
 void test01()
 {
-  using __gnu_test::CopyConsOnlyType;
+  using __gnu_test::assign::DelAnyAssign;
   using __gnu_test::MoveConsOnlyType;
 
-  std::vector<CopyConsOnlyType> v1;
-  CopyConsOnlyType t1(1);
+  std::vector<DelAnyAssign> v1;
+  DelAnyAssign t1;
   v1.push_back(t1);
   v1.push_back(t1);
   v1.push_back(t1);