I forgot to attach the "diff -w" version of the patch, which may be a bit
more readable.
--
Marc Glisse
Index: include/bits/alloc_traits.h
===================================================================
--- include/bits/alloc_traits.h (revision 264027)
+++ include/bits/alloc_traits.h (working copy)
@@ -233,38 +233,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using type = decltype(__test<_Alloc>(0));
};
template<typename _Tp, typename... _Args>
using __has_construct
= typename __construct_helper<_Tp, _Args...>::type;
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>
static
_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>
static auto
_S_max_size(_Alloc2& __a, int)
-> decltype(__a.max_size())
{ return __a.max_size(); }
template<typename _Alloc2>
static size_type
@@ -333,33 +338,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @param __p Pointer to memory of suitable size and alignment for Tp
* @param __args Constructor arguments.
*
* Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
* if that expression is well-formed, otherwise uses placement-new
* to construct an object of type @a _Tp at location @a __p from the
* arguments @a __args...
*/
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)...); }
/**
* @brief Destroy an object of type @a _Tp
* @param __a An allocator.
* @param __p Pointer to the object to destroy
*
* Calls @c __a.destroy(__p) if that expression is well-formed,
* otherwise calls @c __p->~_Tp()
*/
template<typename _Tp>
static void destroy(_Alloc& __a, _Tp* __p)
+ noexcept(noexcept(_S_destroy(__a, __p, 0)))
{ _S_destroy(__a, __p, 0); }
/**
* @brief The maximum supported allocation size
* @param __a An allocator.
* @return @c __a.max_size() or @c numeric_limits<size_type>::max()
*
* Returns @c __a.max_size() if that expression is well-formed,
* otherwise returns @c numeric_limits<size_type>::max()
*/
@@ -465,32 +473,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @brief Construct an object of type @a _Up
* @param __a An allocator.
* @param __p Pointer to memory of suitable size and alignment for Tp
* @param __args Constructor arguments.
*
* Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
*/
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)...); }
/**
* @brief Destroy an object of type @a _Up
* @param __a An allocator.
* @param __p Pointer to the object to destroy
*
* Calls @c __a.destroy(__p).
*/
template<typename _Up>
static void
destroy(allocator_type& __a, _Up* __p)
+ noexcept(noexcept(__a.destroy(__p)))
{ __a.destroy(__p); }
/**
* @brief The maximum supported allocation size
* @param __a An allocator.
* @return @c __a.max_size()
*/
static size_type
max_size(const allocator_type& __a) noexcept
{ return __a.max_size(); }
Index: include/bits/allocator.h
===================================================================
--- include/bits/allocator.h (revision 264027)
+++ include/bits/allocator.h (working copy)
@@ -81,25 +81,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201103L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2103. std::allocator propagate_on_container_move_assignment
typedef true_type propagate_on_container_move_assignment;
typedef true_type is_always_equal;
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
};
/**
* @brief The @a standard allocator, as per [20.4].
*
* See https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator
* for further details.
*
* @tparam _Tp Type of allocated object.
Index: include/bits/stl_uninitialized.h
===================================================================
--- include/bits/stl_uninitialized.h (revision 264027)
+++ include/bits/stl_uninitialized.h (working copy)
@@ -872,14 +872,85 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
uninitialized_move_n(_InputIterator __first, _Size __count,
_ForwardIterator __result)
{
auto __res = std::__uninitialized_copy_n_pair
(_GLIBCXX_MAKE_MOVE_ITERATOR(__first),
__count, __result);
return {__res.first.base(), __res.second};
}
#endif
+#if __cplusplus >= 201703L
+ template<typename _Tp, typename _Up>
+ inline void
+ __relocate(_Tp* __dest, _Up* __orig)
+ noexcept(is_nothrow_constructible<_Tp, _Up&&>::value)
+ {
+ ::new((void*)__dest) _Tp(std::move(*__orig));
+ __orig->~_Up();
+ }
+
+ template<typename _Tp, typename _Up, typename _Allocator>
+ inline void
+ __relocate_a(_Tp* __dest, _Up* __orig, _Allocator& __alloc)
+ // people who oppose noexcept(auto) clearly never write C++ themselves
+ noexcept(noexcept(__gnu_cxx::__alloc_traits<_Allocator>::construct(__alloc,
+ __dest, std::move(*__orig)))
+ && noexcept(__gnu_cxx::__alloc_traits<_Allocator>::destroy(
+ __alloc, std::__addressof(*__orig))))
+ {
+ typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+ __traits::construct(__alloc, __dest, std::move(*__orig));
+ __traits::destroy(__alloc, std::__addressof(*__orig));
+ }
+
+ template<typename _Tp>
+ struct __is_trivially_relocatable
+ : is_trivially_move_constructible<_Tp> { };
+
+ template <typename _Tp, typename _Up>
+ inline std::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_v<_ValueType, _ValueType2>);
+ static_assert(noexcept(std::__relocate_a(std::addressof(*__result),
+ std::addressof(*__first),
+ __alloc)));
+ _ForwardIterator __cur = __result;
+ for (; __first != __last; ++__first, (void)++__cur)
+ std::__relocate_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
#endif /* _STL_UNINITIALIZED_H */
Index: include/bits/stl_vector.h
===================================================================
--- include/bits/stl_vector.h (revision 264027)
+++ include/bits/stl_vector.h (working copy)
@@ -398,20 +398,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
"std::vector must have a non-const, non-volatile value_type");
# ifdef __STRICT_ANSI__
static_assert(is_same<typename _Alloc::value_type, _Tp>::value,
"std::vector must have the same value_type as its allocator");
# endif
#endif
typedef _Vector_base<_Tp, _Alloc> _Base;
typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;
+#if __cplusplus >= 201703L
+ static constexpr bool __use_relocate =
+ noexcept(std::__relocate_a(std::declval<_Tp*>(),
+ std::declval<_Tp*>(),
+ std::declval<_Tp_alloc_type&>()));
+#endif
public:
typedef _Tp value_type;
typedef typename _Base::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 __gnu_cxx::__normal_iterator<pointer, vector> iterator;
typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
const_iterator;
Index: include/bits/vector.tcc
===================================================================
--- include/bits/vector.tcc (revision 264027)
+++ include/bits/vector.tcc (working copy)
@@ -64,26 +64,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
template<typename _Tp, typename _Alloc>
void
vector<_Tp, _Alloc>::
reserve(size_type __n)
{
if (__n > this->max_size())
__throw_length_error(__N("vector::reserve"));
if (this->capacity() < __n)
{
const size_type __old_size = size();
- pointer __tmp = _M_allocate_and_copy(__n,
+ pointer __tmp;
+#if __cplusplus >= 201703L
+ 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));
- _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);
this->_M_impl._M_start = __tmp;
this->_M_impl._M_finish = __tmp + __old_size;
this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
}
}
#if __cplusplus >= 201103L
@@ -288,23 +301,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
vector<_Tp, _Alloc>::
_M_assign_aux(_ForwardIterator __first, _ForwardIterator __last,
std::forward_iterator_tag)
{
const size_type __len = std::distance(__first, __last);
if (__len > capacity())
{
_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);
this->_M_impl._M_start = __tmp;
this->_M_impl._M_finish = this->_M_impl._M_start + __len;
this->_M_impl._M_end_of_storage = this->_M_impl._M_finish;
}
else if (size() >= __len)
_M_erase_at_end(std::copy(__first, __last, this->_M_impl._M_start));
else
@@ -436,44 +449,66 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
// [res.on.arguments]).
_Alloc_traits::construct(this->_M_impl,
__new_start + __elems_before,
#if __cplusplus >= 201103L
std::forward<_Args>(__args)...);
#else
__x);
#endif
__new_finish = pointer();
+#if __cplusplus >= 201703L
+ 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
= std::__uninitialized_move_if_noexcept_a
(__position.base(), __old_finish,
__new_finish, _M_get_Tp_allocator());
}
+ }
__catch(...)
{
if (!__new_finish)
_Alloc_traits::destroy(this->_M_impl,
__new_start + __elems_before);
else
std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
_M_deallocate(__new_start, __len);
__throw_exception_again;
}
- _GLIBCXX_ASAN_ANNOTATE_REINIT;
+#if __cplusplus >= 201703L
+ if constexpr (!__use_relocate)
+#endif
std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
+ _GLIBCXX_ASAN_ANNOTATE_REINIT;
_M_deallocate(__old_start,
this->_M_impl._M_end_of_storage - __old_start);
this->_M_impl._M_start = __new_start;
this->_M_impl._M_finish = __new_finish;
this->_M_impl._M_end_of_storage = __new_start + __len;
}
template<typename _Tp, typename _Alloc>
void
vector<_Tp, _Alloc>::
@@ -555,23 +590,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
if (!__new_finish)
std::_Destroy(__new_start + __elems_before,
__new_start + __elems_before + __n,
_M_get_Tp_allocator());
else
std::_Destroy(__new_start, __new_finish,
_M_get_Tp_allocator());
_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);
this->_M_impl._M_start = __new_start;
this->_M_impl._M_finish = __new_finish;
this->_M_impl._M_end_of_storage = __new_start + __len;
}
}
}
@@ -596,41 +631,62 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
this->_M_impl._M_finish =
std::__uninitialized_default_n_a(this->_M_impl._M_finish,
__n, _M_get_Tp_allocator());
_GLIBCXX_ASAN_ANNOTATE_GREW(__n);
}
else
{
const size_type __len =
_M_check_len(__n, "vector::_M_default_append");
pointer __new_start(this->_M_allocate(__len));
+#if __cplusplus >= 201703L
+ if constexpr (__use_relocate)
+ {
+ __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());
+ }
+ else
+#endif
+ {
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;
}
- _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);
this->_M_impl._M_start = __new_start;
this->_M_impl._M_finish = __new_start + __size + __n;
this->_M_impl._M_end_of_storage = __new_start + __len;
}
}
}
@@ -735,23 +791,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
(__position.base(), this->_M_impl._M_finish,
__new_finish, _M_get_Tp_allocator());
}
__catch(...)
{
std::_Destroy(__new_start, __new_finish,
_M_get_Tp_allocator());
_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);
this->_M_impl._M_start = __new_start;
this->_M_impl._M_finish = __new_finish;
this->_M_impl._M_end_of_storage = __new_start + __len;
}
}
}
Index: include/ext/alloc_traits.h
===================================================================
--- include/ext/alloc_traits.h (revision 264027)
+++ include/ext/alloc_traits.h (working copy)
@@ -73,29 +73,32 @@ template<typename _Alloc, typename = typ
template<typename _Ptr>
using __is_custom_pointer
= std::__and_<std::is_same<pointer, _Ptr>,
std::__not_<std::is_pointer<_Ptr>>>;
public:
// overload construct for non-standard pointer types
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)...);
}
// overload destroy for non-standard pointer types
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)
{ return _Base_type::select_on_container_copy_construction(__a); }
static void _S_on_swap(_Alloc& __a, _Alloc& __b)
{ std::__alloc_on_swap(__a, __b); }
static constexpr bool _S_propagate_on_copy_assign()
{ return _Base_type::propagate_on_container_copy_assignment::value; }
Index: include/ext/malloc_allocator.h
===================================================================
--- include/ext/malloc_allocator.h (revision 264027)
+++ include/ext/malloc_allocator.h (working copy)
@@ -138,25 +138,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::free(static_cast<void*>(__p)); }
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
#if __cplusplus >= 201103L
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
void
construct(pointer __p, const _Tp& __val)
{ ::new((void *)__p) value_type(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
#endif
Index: include/ext/new_allocator.h
===================================================================
--- include/ext/new_allocator.h (revision 264027)
+++ include/ext/new_allocator.h (working copy)
@@ -129,25 +129,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
#if __cplusplus >= 201103L
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
void
construct(pointer __p, const _Tp& __val)
{ ::new((void *)__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
#endif