From 0f317ef76269a989ae751a808f946d15b740baf9 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 25 Oct 2018 15:03:13 +0200 Subject: [PATCH] Relocation (= move+destroy) 2018-10-25 Marc Glisse 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 | 21 +++ libstdc++-v3/include/bits/alloc_traits.h | 10 ++ libstdc++-v3/include/bits/allocator.h | 6 +- libstdc++-v3/include/bits/stl_uninitialized.h | 62 +++++++++ libstdc++-v3/include/bits/stl_vector.h | 9 ++ libstdc++-v3/include/bits/vector.tcc | 124 +++++++++++++----- libstdc++-v3/include/ext/alloc_traits.h | 3 + libstdc++-v3/include/ext/malloc_allocator.h | 6 +- libstdc++-v3/include/ext/new_allocator.h | 6 +- .../vector/modifiers/push_back/49836.cc | 6 +- 10 files changed, 213 insertions(+), 40 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9285a6becf5..575e52a70b6 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,24 @@ +2018-10-25 Marc Glisse + + 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 * include/debug/safe_unordered_container.h diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h index 742fdd0447d..9321fdff352 100644 --- a/libstdc++-v3/include/bits/alloc_traits.h +++ b/libstdc++-v3/include/bits/alloc_traits.h @@ -240,6 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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 @@ -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 static auto _S_destroy(_Alloc2& __a, _Tp* __p, int) + noexcept(noexcept(__a.destroy(__p))) -> decltype(__a.destroy(__p)) { __a.destroy(__p); } template static void _S_destroy(_Alloc2&, _Tp* __p, ...) + noexcept(noexcept(__p->~_Tp())) { __p->~_Tp(); } template @@ -340,6 +345,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template 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 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 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 static void destroy(allocator_type& __a, _Up* __p) + noexcept(noexcept(__a.destroy(__p))) { __a.destroy(__p); } /** diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index d9d1d26e13a..9f018ea239c 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -88,11 +88,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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 void - destroy(_Up* __p) { __p->~_Up(); } + destroy(_Up* __p) + noexcept(noexcept(__p->~_Up())) + { __p->~_Up(); } #endif }; diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index c740503052b..94c7e151e29 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -879,6 +879,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __cplusplus >= 201103L + template + 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 + struct __is_trivially_relocatable + : is_trivial<_Tp> { }; + + template + inline __enable_if_t::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 + 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 + 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 diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 37607417d08..40debd62396 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -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()), + std::addressof(*std::declval()), + std::declval<_Tp_alloc_type&>())); +#endif + protected: using _Base::_M_allocate; using _Base::_M_deallocate; diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index a1d114a0a9a..8df0f4180d4 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -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); diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h index 2570c59d81f..f1685374366 100644 --- a/libstdc++-v3/include/ext/alloc_traits.h +++ b/libstdc++-v3/include/ext/alloc_traits.h @@ -80,6 +80,8 @@ template template 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 template 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) diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h index 1ae53b11ddb..5f91fe08af4 100644 --- a/libstdc++-v3/include/ext/malloc_allocator.h +++ b/libstdc++-v3/include/ext/malloc_allocator.h @@ -151,11 +151,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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 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 diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 83c894ce0a7..18a45cd75f1 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -142,11 +142,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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 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 diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc index eb39e41cfac..85925ab756e 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc @@ -24,11 +24,11 @@ // libstdc++/49836 void test01() { - using __gnu_test::CopyConsOnlyType; + using __gnu_test::assign::DelAnyAssign; using __gnu_test::MoveConsOnlyType; - std::vector v1; - CopyConsOnlyType t1(1); + std::vector v1; + DelAnyAssign t1; v1.push_back(t1); v1.push_back(t1); v1.push_back(t1); -- 2.30.2