PR c++/91369 Implement P0784R7 changes to allocation and construction
This patch is the first part of library support for constexpr std::vector and std::string. This only includes the changes to std::allocator, std::allocator_traits, std::construct_at, std::destroy_at, std::destroy and std::destroy_n. std::allocator::allocate and std::allocator::deallocate need to be added so that they can be intercepted by the compiler during constant evaluation. Outside of constant evaluation those new member functions just forward to the existing implementation in the base class. PR c++/91369 Implement P0784R7 changes to allocation and construction * include/bits/alloc_traits.h: Include <bits/stl_construct.h>. (allocator_traits::_S_allocate, allocator_traits::_S_construct) (allocator_traits::_S_destroy, allocator_traits::_S_max_size) (allocator_traits::_S_select, allocator_traits::allocate) (allocator_traits::deallocate, allocator_traits::construct) (allocator_traits::destroy, allocator_traits::max_size) (allocator_traits::select_on_container_copy_construction) (allocator_traits<allocator<T>>): Add constexpr specifier for C++20. (allocator_traits<allocator<T>>::construct): Use construct_at. (allocator_traits<allocator<T>>::destroy): Use destroy_at. (__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr specifier. (_Destroy(ForwardIterator, ForwardIterator, Alloc&)) (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move here from <bits/stl_construct.h>. * include/bits/allocator.h (allocator::~allocator): Remove for C++20. (allocator::allocate, allocate::deallocate): Define for C++20 and up. (operator==, operator!=): Add constexpr specifier for C++20. * include/bits/stl_construct.h: Don't include <ext/alloc_traits.h>. (destroy_at): For C++20 add constexpr specifier and support for destroying arrays. (construct_at): Define new function for C++20. (_Construct): Return result of placement new-expression. For C++11 and up add constexpr. For C++20 dispatch to std::construct_at during constant evaluation. (_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to std::destroy_at during constant evaluation. (_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr specifier for C++20. (_Destroy(ForwardIterator, ForwardIterator)) (_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial destructors during constant evaluation. (destroy, destroy_n): Add constexpr specifier for C++20. (_Destroy(ForwardIterator, ForwardIterator, Alloc&)) (_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move to <bits/alloc_traits.h>, to remove dependency on allocators. * include/bits/stl_uninitialized.h: Include <ext/alloc_traits.h>. Include <bits/stl_pair.h> instead of <utility>. * include/ext/alloc_traits.h: Always include <bits/alloc_traits.h>. (__alloc_traits::construct, __alloc_traits::destroy) (__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add constexpr specifier. * include/ext/malloc_allocator.h (operator==, operator!=): Add constexpr specifier for C++20. * include/ext/new_allocator.h (operator==, operator!=): Likewise. * testsuite/20_util/headers/memory/synopsis.cc: Add constexpr. * testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional errors due to constexpr function called after failed static_assert. * testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test. * testsuite/23_containers/vector/cons/destructible_debug_neg.cc: Ignore additional errors due to constexpr function called after failed static_assert. * testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise. From-SVN: r277342
This commit is contained in:
parent
0744333e5a
commit
85f2411493
13 changed files with 343 additions and 111 deletions
|
@ -1,5 +1,60 @@
|
|||
2019-10-23 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR c++/91369 Implement P0784R7 changes to allocation and construction
|
||||
* include/bits/alloc_traits.h: Include <bits/stl_construct.h>.
|
||||
(allocator_traits::_S_allocate, allocator_traits::_S_construct)
|
||||
(allocator_traits::_S_destroy, allocator_traits::_S_max_size)
|
||||
(allocator_traits::_S_select, allocator_traits::allocate)
|
||||
(allocator_traits::deallocate, allocator_traits::construct)
|
||||
(allocator_traits::destroy, allocator_traits::max_size)
|
||||
(allocator_traits::select_on_container_copy_construction)
|
||||
(allocator_traits<allocator<T>>): Add constexpr specifier for C++20.
|
||||
(allocator_traits<allocator<T>>::construct): Use construct_at.
|
||||
(allocator_traits<allocator<T>>::destroy): Use destroy_at.
|
||||
(__alloc_on_copy, __alloc_on_move, __alloc_on_swap): Add constexpr
|
||||
specifier.
|
||||
(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
|
||||
(_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move here
|
||||
from <bits/stl_construct.h>.
|
||||
* include/bits/allocator.h (allocator::~allocator): Remove for C++20.
|
||||
(allocator::allocate, allocate::deallocate): Define for C++20 and up.
|
||||
(operator==, operator!=): Add constexpr specifier for C++20.
|
||||
* include/bits/stl_construct.h: Don't include <ext/alloc_traits.h>.
|
||||
(destroy_at): For C++20 add constexpr specifier and support for
|
||||
destroying arrays.
|
||||
(construct_at): Define new function for C++20.
|
||||
(_Construct): Return result of placement new-expression. For C++11 and
|
||||
up add constexpr. For C++20 dispatch to std::construct_at during
|
||||
constant evaluation.
|
||||
(_Destroy(pointer)): Add constexpr specifier. For C++20 dispatch to
|
||||
std::destroy_at during constant evaluation.
|
||||
(_Destroy_aux::__destroy, _Destroy_n_aux::__destroy_n): Add constexpr
|
||||
specifier for C++20.
|
||||
(_Destroy(ForwardIterator, ForwardIterator))
|
||||
(_Destroy(ForwardIterator, Size)): Likewise. Do not elide trivial
|
||||
destructors during constant evaluation.
|
||||
(destroy, destroy_n): Add constexpr specifier for C++20.
|
||||
(_Destroy(ForwardIterator, ForwardIterator, Alloc&))
|
||||
(_Destroy(ForwardIterator, ForwardIterator, allocator<T>&)): Move to
|
||||
<bits/alloc_traits.h>, to remove dependency on allocators.
|
||||
* include/bits/stl_uninitialized.h: Include <ext/alloc_traits.h>.
|
||||
Include <bits/stl_pair.h> instead of <utility>.
|
||||
* include/ext/alloc_traits.h: Always include <bits/alloc_traits.h>.
|
||||
(__alloc_traits::construct, __alloc_traits::destroy)
|
||||
(__alloc_traits::_S_select_on_copy, __alloc_traits::_S_on_swap): Add
|
||||
constexpr specifier.
|
||||
* include/ext/malloc_allocator.h (operator==, operator!=): Add
|
||||
constexpr specifier for C++20.
|
||||
* include/ext/new_allocator.h (operator==, operator!=): Likewise.
|
||||
* testsuite/20_util/headers/memory/synopsis.cc: Add constexpr.
|
||||
* testsuite/20_util/scoped_allocator/69293_neg.cc: Ignore additional
|
||||
errors due to constexpr function called after failed static_assert.
|
||||
* testsuite/20_util/specialized_algorithms/construct_at/1.cc: New test.
|
||||
* testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
|
||||
Ignore additional errors due to constexpr function called after failed
|
||||
static_assert.
|
||||
* testsuite/23_containers/vector/cons/destructible_neg.cc: Likewise.
|
||||
|
||||
* testsuite/20_util/bind/91371.cc: Fix test to compile as C++11.
|
||||
|
||||
* include/debug/helper_functions.h (__valid_range): Change
|
||||
|
|
|
@ -30,18 +30,21 @@
|
|||
#ifndef _ALLOC_TRAITS_H
|
||||
#define _ALLOC_TRAITS_H 1
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
#include <bits/stl_construct.h>
|
||||
#include <bits/memoryfwd.h>
|
||||
#include <bits/ptr_traits.h>
|
||||
#include <ext/numeric_traits.h>
|
||||
|
||||
#define __cpp_lib_allocator_traits_is_always_equal 201411
|
||||
#if __cplusplus >= 201103L
|
||||
# include <bits/allocator.h>
|
||||
# include <bits/ptr_traits.h>
|
||||
# include <ext/numeric_traits.h>
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define __cpp_lib_allocator_traits_is_always_equal 201411
|
||||
|
||||
struct __allocator_traits_base
|
||||
{
|
||||
template<typename _Tp, typename _Up, typename = void>
|
||||
|
@ -209,13 +212,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
private:
|
||||
template<typename _Alloc2>
|
||||
static auto
|
||||
static constexpr auto
|
||||
_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint, int)
|
||||
-> decltype(__a.allocate(__n, __hint))
|
||||
{ return __a.allocate(__n, __hint); }
|
||||
|
||||
template<typename _Alloc2>
|
||||
static pointer
|
||||
static constexpr pointer
|
||||
_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer, ...)
|
||||
{ return __a.allocate(__n); }
|
||||
|
||||
|
@ -238,41 +241,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
= typename __construct_helper<_Tp, _Args...>::type;
|
||||
|
||||
template<typename _Tp, typename... _Args>
|
||||
static _Require<__has_construct<_Tp, _Args...>>
|
||||
static constexpr _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
|
||||
static constexpr
|
||||
_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)...); }
|
||||
{ std::_Construct(__p, std::forward<_Args>(__args)...); }
|
||||
|
||||
template<typename _Alloc2, typename _Tp>
|
||||
static auto
|
||||
static constexpr 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
|
||||
static constexpr void
|
||||
_S_destroy(_Alloc2&, _Tp* __p, ...)
|
||||
noexcept(noexcept(__p->~_Tp()))
|
||||
{ __p->~_Tp(); }
|
||||
{ std::_Destroy(__p); }
|
||||
|
||||
template<typename _Alloc2>
|
||||
static auto
|
||||
static constexpr auto
|
||||
_S_max_size(_Alloc2& __a, int)
|
||||
-> decltype(__a.max_size())
|
||||
{ return __a.max_size(); }
|
||||
|
||||
template<typename _Alloc2>
|
||||
static size_type
|
||||
static constexpr size_type
|
||||
_S_max_size(_Alloc2&, ...)
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
|
@ -282,13 +285,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
|
||||
template<typename _Alloc2>
|
||||
static auto
|
||||
static constexpr auto
|
||||
_S_select(_Alloc2& __a, int)
|
||||
-> decltype(__a.select_on_container_copy_construction())
|
||||
{ return __a.select_on_container_copy_construction(); }
|
||||
|
||||
template<typename _Alloc2>
|
||||
static _Alloc2
|
||||
static constexpr _Alloc2
|
||||
_S_select(_Alloc2& __a, ...)
|
||||
{ return __a; }
|
||||
|
||||
|
@ -301,7 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
*
|
||||
* Calls @c a.allocate(n)
|
||||
*/
|
||||
_GLIBCXX_NODISCARD static pointer
|
||||
_GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
|
||||
allocate(_Alloc& __a, size_type __n)
|
||||
{ return __a.allocate(__n); }
|
||||
|
||||
|
@ -316,7 +319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Returns <tt> a.allocate(n, hint) </tt> if that expression is
|
||||
* well-formed, otherwise returns @c a.allocate(n)
|
||||
*/
|
||||
_GLIBCXX_NODISCARD static pointer
|
||||
_GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
|
||||
allocate(_Alloc& __a, size_type __n, const_void_pointer __hint)
|
||||
{ return _S_allocate(__a, __n, __hint, 0); }
|
||||
|
||||
|
@ -328,7 +331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
*
|
||||
* Calls <tt> a.deallocate(p, n) </tt>
|
||||
*/
|
||||
static void
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
deallocate(_Alloc& __a, pointer __p, size_type __n)
|
||||
{ __a.deallocate(__p, __n); }
|
||||
|
||||
|
@ -344,7 +347,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* arguments @a __args...
|
||||
*/
|
||||
template<typename _Tp, typename... _Args>
|
||||
static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
|
||||
static _GLIBCXX20_CONSTEXPR 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)...))
|
||||
|
@ -359,7 +363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* otherwise calls @c __p->~_Tp()
|
||||
*/
|
||||
template<typename _Tp>
|
||||
static void destroy(_Alloc& __a, _Tp* __p)
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
destroy(_Alloc& __a, _Tp* __p)
|
||||
noexcept(noexcept(_S_destroy(__a, __p, 0)))
|
||||
{ _S_destroy(__a, __p, 0); }
|
||||
|
||||
|
@ -371,7 +376,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Returns @c __a.max_size() if that expression is well-formed,
|
||||
* otherwise returns @c numeric_limits<size_type>::max()
|
||||
*/
|
||||
static size_type max_size(const _Alloc& __a) noexcept
|
||||
static _GLIBCXX20_CONSTEXPR size_type
|
||||
max_size(const _Alloc& __a) noexcept
|
||||
{ return _S_max_size(__a, 0); }
|
||||
|
||||
/**
|
||||
|
@ -382,7 +388,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Returns @c __rhs.select_on_container_copy_construction() if that
|
||||
* expression is well-formed, otherwise returns @a __rhs
|
||||
*/
|
||||
static _Alloc
|
||||
static _GLIBCXX20_CONSTEXPR _Alloc
|
||||
select_on_container_copy_construction(const _Alloc& __rhs)
|
||||
{ return _S_select(__rhs, 0); }
|
||||
};
|
||||
|
@ -440,7 +446,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
*
|
||||
* Calls @c a.allocate(n)
|
||||
*/
|
||||
_GLIBCXX_NODISCARD static pointer
|
||||
_GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
|
||||
allocate(allocator_type& __a, size_type __n)
|
||||
{ return __a.allocate(__n); }
|
||||
|
||||
|
@ -454,7 +460,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
*
|
||||
* Returns <tt> a.allocate(n, hint) </tt>
|
||||
*/
|
||||
_GLIBCXX_NODISCARD static pointer
|
||||
_GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
|
||||
allocate(allocator_type& __a, size_type __n, const_void_pointer __hint)
|
||||
{
|
||||
#if __cplusplus <= 201703L
|
||||
|
@ -472,27 +478,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
*
|
||||
* Calls <tt> a.deallocate(p, n) </tt>
|
||||
*/
|
||||
static void
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
deallocate(allocator_type& __a, pointer __p, size_type __n)
|
||||
{ __a.deallocate(__p, __n); }
|
||||
|
||||
/**
|
||||
* @brief Construct an object of type @a _Up
|
||||
* @brief Construct an object of type `_Up`
|
||||
* @param __a An allocator.
|
||||
* @param __p Pointer to memory of suitable size and alignment for Tp
|
||||
* @param __p Pointer to memory of suitable size and alignment for
|
||||
* an object of type `_Up`.
|
||||
* @param __args Constructor arguments.
|
||||
*
|
||||
* Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
|
||||
* Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
|
||||
* in C++11, C++14 and C++17. Changed in C++20 to call
|
||||
* `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
|
||||
*/
|
||||
template<typename _Up, typename... _Args>
|
||||
static void
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
construct(allocator_type& __a, _Up* __p, _Args&&... __args)
|
||||
noexcept(noexcept(::new((void*)__p) _Up(std::forward<_Args>(__args)...)))
|
||||
{
|
||||
#if __cplusplus <= 201703L
|
||||
__a.construct(__p, std::forward<_Args>(__args)...);
|
||||
#else
|
||||
::new((void*)__p) _Up(std::forward<_Args>(__args)...);
|
||||
std::construct_at(__p, std::forward<_Args>(__args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -504,14 +513,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* Calls @c __a.destroy(__p).
|
||||
*/
|
||||
template<typename _Up>
|
||||
static void
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
destroy(allocator_type& __a, _Up* __p)
|
||||
noexcept(is_nothrow_destructible<_Up>::value)
|
||||
{
|
||||
#if __cplusplus <= 201703L
|
||||
__a.destroy(__p);
|
||||
#else
|
||||
__p->~_Up();
|
||||
std::destroy_at(__p);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -520,7 +529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @param __a An allocator.
|
||||
* @return @c __a.max_size()
|
||||
*/
|
||||
static size_type
|
||||
static _GLIBCXX20_CONSTEXPR size_type
|
||||
max_size(const allocator_type& __a) noexcept
|
||||
{
|
||||
#if __cplusplus <= 201703L
|
||||
|
@ -535,7 +544,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* @param __rhs An allocator.
|
||||
* @return @c __rhs
|
||||
*/
|
||||
static allocator_type
|
||||
static _GLIBCXX20_CONSTEXPR allocator_type
|
||||
select_on_container_copy_construction(const allocator_type& __rhs)
|
||||
{ return __rhs; }
|
||||
};
|
||||
|
@ -553,7 +562,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
|
||||
template<typename _Alloc>
|
||||
inline void __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
|
||||
constexpr void
|
||||
__alloc_on_copy(_Alloc& __one, const _Alloc& __two)
|
||||
{
|
||||
typedef allocator_traits<_Alloc> __traits;
|
||||
typedef typename __traits::propagate_on_container_copy_assignment __pocca;
|
||||
|
@ -566,7 +576,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
|
||||
template<typename _Alloc>
|
||||
inline _Alloc __alloc_on_copy(const _Alloc& __a)
|
||||
constexpr _Alloc
|
||||
__alloc_on_copy(const _Alloc& __a)
|
||||
{
|
||||
typedef allocator_traits<_Alloc> __traits;
|
||||
return __traits::select_on_container_copy_construction(__a);
|
||||
|
@ -583,7 +594,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
|
||||
template<typename _Alloc>
|
||||
inline void __alloc_on_move(_Alloc& __one, _Alloc& __two)
|
||||
constexpr void
|
||||
__alloc_on_move(_Alloc& __one, _Alloc& __two)
|
||||
{
|
||||
typedef allocator_traits<_Alloc> __traits;
|
||||
typedef typename __traits::propagate_on_container_move_assignment __pocma;
|
||||
|
@ -609,7 +621,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
|
||||
template<typename _Alloc>
|
||||
inline void __alloc_on_swap(_Alloc& __one, _Alloc& __two)
|
||||
constexpr void
|
||||
__alloc_on_swap(_Alloc& __one, _Alloc& __two)
|
||||
{
|
||||
typedef allocator_traits<_Alloc> __traits;
|
||||
typedef typename __traits::propagate_on_container_swap __pocs;
|
||||
|
@ -685,8 +698,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template<typename _Alloc>
|
||||
using _RequireNotAllocator
|
||||
= typename enable_if<!__is_allocator<_Alloc>::value, _Alloc>::type;
|
||||
#endif // C++11
|
||||
|
||||
/**
|
||||
* Destroy a range of objects using the supplied allocator. For
|
||||
* non-default allocators we do not optimize away invocation of
|
||||
* destroy() even if _Tp has a trivial destructor.
|
||||
*/
|
||||
|
||||
template<typename _ForwardIterator, typename _Allocator>
|
||||
void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last,
|
||||
_Allocator& __alloc)
|
||||
{
|
||||
for (; __first != __last; ++__first)
|
||||
#if __cplusplus < 201103L
|
||||
__alloc.destroy(std::__addressof(*__first));
|
||||
#else
|
||||
allocator_traits<_Allocator>::destroy(__alloc,
|
||||
std::__addressof(*__first));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename _ForwardIterator, typename _Tp>
|
||||
inline void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last,
|
||||
allocator<_Tp>&)
|
||||
{
|
||||
_Destroy(__first, __last);
|
||||
}
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
#endif // C++11
|
||||
#endif // _ALLOC_TRAITS_H
|
||||
|
|
|
@ -154,13 +154,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_GLIBCXX20_CONSTEXPR
|
||||
allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { }
|
||||
|
||||
#if __cplusplus <= 201703L
|
||||
~allocator() _GLIBCXX_NOTHROW { }
|
||||
#endif
|
||||
|
||||
friend bool
|
||||
#if __cplusplus > 201703L
|
||||
[[nodiscard,__gnu__::__always_inline__]]
|
||||
constexpr _Tp*
|
||||
allocate(size_t __n)
|
||||
{
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated())
|
||||
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
|
||||
#endif
|
||||
return __allocator_base<_Tp>::allocate(__n, 0);
|
||||
}
|
||||
|
||||
[[__gnu__::__always_inline__]]
|
||||
constexpr void
|
||||
deallocate(_Tp* __p, size_t __n)
|
||||
{
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated())
|
||||
{
|
||||
::operator delete(__p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
__allocator_base<_Tp>::deallocate(__p, __n);
|
||||
}
|
||||
#endif // C++20
|
||||
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator==(const allocator&, const allocator&) _GLIBCXX_NOTHROW
|
||||
{ return true; }
|
||||
|
||||
friend bool
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator!=(const allocator&, const allocator&) _GLIBCXX_NOTHROW
|
||||
{ return false; }
|
||||
|
||||
|
@ -168,13 +197,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
};
|
||||
|
||||
template<typename _T1, typename _T2>
|
||||
inline bool
|
||||
inline _GLIBCXX20_CONSTEXPR bool
|
||||
operator==(const allocator<_T1>&, const allocator<_T2>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return true; }
|
||||
|
||||
template<typename _T1, typename _T2>
|
||||
inline bool
|
||||
inline _GLIBCXX20_CONSTEXPR bool
|
||||
operator!=(const allocator<_T1>&, const allocator<_T2>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return false; }
|
||||
|
|
|
@ -58,29 +58,69 @@
|
|||
|
||||
#include <new>
|
||||
#include <bits/move.h>
|
||||
#include <ext/alloc_traits.h>
|
||||
#include <bits/stl_iterator_base_types.h> // for iterator_traits
|
||||
#include <bits/stl_iterator_base_funcs.h> // for advance
|
||||
|
||||
/* This file provides the C++17 functions std::destroy_at, std::destroy, and
|
||||
* std::destroy_n, and the C++20 function std::construct_at.
|
||||
* It also provides std::_Construct, std::_Destroy,and std::_Destroy_n functions
|
||||
* which are defined in all standard modes and so can be used in C++98-14 code.
|
||||
* The _Construct and _Destroy functions will dispatch to construct_at and
|
||||
* destroy_at during constant evaluation, because calls to those functions are
|
||||
* intercepted by the compiler to allow use in constant expressions.
|
||||
*/
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
template <typename _Tp>
|
||||
_GLIBCXX20_CONSTEXPR inline void
|
||||
destroy_at(_Tp* __location)
|
||||
{
|
||||
if constexpr (__cplusplus > 201703L && is_array_v<_Tp>)
|
||||
{
|
||||
for (auto& __x : *__location)
|
||||
std::destroy_at(std::__addressof(__x));
|
||||
}
|
||||
else
|
||||
__location->~_Tp();
|
||||
}
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
template<typename _Tp, typename... _Args>
|
||||
constexpr auto
|
||||
construct_at(_Tp* __location, _Args&&... __args)
|
||||
noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
|
||||
-> decltype(::new((void*)0) _Tp(std::declval<_Args>()...))
|
||||
{ return ::new((void*)__location) _Tp(std::forward<_Args>(__args)...); }
|
||||
#endif // C++20
|
||||
#endif// C++17
|
||||
|
||||
/**
|
||||
* Constructs an object in existing memory by invoking an allocated
|
||||
* object's constructor with an initializer.
|
||||
*/
|
||||
#if __cplusplus >= 201103L
|
||||
template<typename _T1, typename... _Args>
|
||||
inline void
|
||||
_Construct(_T1* __p, _Args&&... __args)
|
||||
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
|
||||
template<typename _Tp, typename... _Args>
|
||||
constexpr _Tp*
|
||||
_Construct(_Tp* __p, _Args&&... __args)
|
||||
{
|
||||
#if __cplusplus > 201703L
|
||||
return std::construct_at(__p, std::forward<_Args>(__args)...);
|
||||
#else
|
||||
return ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
template<typename _T1, typename _T2>
|
||||
inline void
|
||||
inline _T1*
|
||||
_Construct(_T1* __p, const _T2& __value)
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 402. wrong new expression in [some_]allocator::construct
|
||||
::new(static_cast<void*>(__p)) _T1(__value);
|
||||
return ::new(static_cast<void*>(__p)) _T1(__value);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -89,20 +129,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_Construct_novalue(_T1* __p)
|
||||
{ ::new(static_cast<void*>(__p)) _T1; }
|
||||
|
||||
template<typename _ForwardIterator>
|
||||
_GLIBCXX20_CONSTEXPR void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last);
|
||||
|
||||
/**
|
||||
* Destroy the object pointed to by a pointer type.
|
||||
*/
|
||||
template<typename _Tp>
|
||||
inline void
|
||||
_GLIBCXX_CONSTEXPR inline void
|
||||
_Destroy(_Tp* __pointer)
|
||||
{ __pointer->~_Tp(); }
|
||||
{
|
||||
#if __cplusplus > 201703L
|
||||
std::destroy_at(__pointer);
|
||||
#else
|
||||
__pointer->~_Tp();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<bool>
|
||||
struct _Destroy_aux
|
||||
{
|
||||
template<typename _ForwardIterator>
|
||||
static void
|
||||
__destroy(_ForwardIterator __first, _ForwardIterator __last)
|
||||
static _GLIBCXX20_CONSTEXPR void
|
||||
__destroy(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
for (; __first != __last; ++__first)
|
||||
std::_Destroy(std::__addressof(*__first));
|
||||
|
@ -123,7 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* away, otherwise the objects' destructors must be invoked.
|
||||
*/
|
||||
template<typename _ForwardIterator>
|
||||
inline void
|
||||
_GLIBCXX20_CONSTEXPR inline void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type
|
||||
|
@ -132,6 +182,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// A deleted destructor is trivial, this ensures we reject such types:
|
||||
static_assert(is_destructible<_Value_type>::value,
|
||||
"value type is destructible");
|
||||
#endif
|
||||
#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated())
|
||||
return _Destroy_aux<false>::__destroy(__first, __last);
|
||||
#endif
|
||||
std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
|
||||
__destroy(__first, __last);
|
||||
|
@ -141,8 +195,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct _Destroy_n_aux
|
||||
{
|
||||
template<typename _ForwardIterator, typename _Size>
|
||||
static _ForwardIterator
|
||||
__destroy_n(_ForwardIterator __first, _Size __count)
|
||||
static _GLIBCXX20_CONSTEXPR _ForwardIterator
|
||||
__destroy_n(_ForwardIterator __first, _Size __count)
|
||||
{
|
||||
for (; __count > 0; (void)++__first, --__count)
|
||||
std::_Destroy(std::__addressof(*__first));
|
||||
|
@ -168,7 +222,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
* away, otherwise the objects' destructors must be invoked.
|
||||
*/
|
||||
template<typename _ForwardIterator, typename _Size>
|
||||
inline _ForwardIterator
|
||||
_GLIBCXX20_CONSTEXPR inline _ForwardIterator
|
||||
_Destroy_n(_ForwardIterator __first, _Size __count)
|
||||
{
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type
|
||||
|
@ -177,60 +231,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// A deleted destructor is trivial, this ensures we reject such types:
|
||||
static_assert(is_destructible<_Value_type>::value,
|
||||
"value type is destructible");
|
||||
#endif
|
||||
#if __cplusplus > 201703L && defined __cpp_lib_is_constant_evaluated
|
||||
if (std::is_constant_evaluated())
|
||||
return _Destroy_n_aux<false>::__destroy_n(__first, __count);
|
||||
#endif
|
||||
return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
|
||||
__destroy_n(__first, __count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a range of objects using the supplied allocator. For
|
||||
* nondefault allocators we do not optimize away invocation of
|
||||
* destroy() even if _Tp has a trivial destructor.
|
||||
*/
|
||||
|
||||
template<typename _ForwardIterator, typename _Allocator>
|
||||
void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last,
|
||||
_Allocator& __alloc)
|
||||
{
|
||||
typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
|
||||
for (; __first != __last; ++__first)
|
||||
__traits::destroy(__alloc, std::__addressof(*__first));
|
||||
}
|
||||
|
||||
template<typename _ForwardIterator, typename _Tp>
|
||||
inline void
|
||||
_Destroy(_ForwardIterator __first, _ForwardIterator __last,
|
||||
allocator<_Tp>&)
|
||||
{
|
||||
_Destroy(__first, __last);
|
||||
}
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
template <typename _Tp>
|
||||
inline void
|
||||
destroy_at(_Tp* __location)
|
||||
{
|
||||
std::_Destroy(__location);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
template <typename _ForwardIterator>
|
||||
inline void
|
||||
_GLIBCXX20_CONSTEXPR inline void
|
||||
destroy(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
std::_Destroy(__first, __last);
|
||||
}
|
||||
|
||||
template <typename _ForwardIterator, typename _Size>
|
||||
inline _ForwardIterator
|
||||
_GLIBCXX20_CONSTEXPR inline _ForwardIterator
|
||||
destroy_n(_ForwardIterator __first, _Size __count)
|
||||
{
|
||||
return std::_Destroy_n(__first, __count);
|
||||
}
|
||||
#endif
|
||||
#endif // C++17
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
#endif /* _STL_CONSTRUCT_H */
|
||||
|
||||
|
|
|
@ -57,13 +57,15 @@
|
|||
#define _STL_UNINITIALIZED_H 1
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
#include <utility>
|
||||
#include <bits/stl_pair.h>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#include <ext/alloc_traits.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
|
|
@ -31,10 +31,8 @@
|
|||
|
||||
#pragma GCC system_header
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
# include <bits/move.h>
|
||||
# include <bits/alloc_traits.h>
|
||||
#else
|
||||
#if __cplusplus < 201103L
|
||||
# include <bits/allocator.h> // for __alloc_swap
|
||||
#endif
|
||||
|
||||
|
@ -78,7 +76,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
|
|||
public:
|
||||
// overload construct for non-standard pointer types
|
||||
template<typename _Ptr, typename... _Args>
|
||||
static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
|
||||
static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
|
||||
construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
|
||||
noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
|
||||
std::forward<_Args>(__args)...)))
|
||||
|
@ -89,15 +87,15 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
|
|||
|
||||
// overload destroy for non-standard pointer types
|
||||
template<typename _Ptr>
|
||||
static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
|
||||
static constexpr std::__enable_if_t<__is_custom_pointer<_Ptr>::value>
|
||||
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)
|
||||
static constexpr _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)
|
||||
static constexpr void _S_on_swap(_Alloc& __a, _Alloc& __b)
|
||||
{ std::__alloc_on_swap(__a, __b); }
|
||||
|
||||
static constexpr bool _S_propagate_on_copy_assign()
|
||||
|
@ -118,7 +116,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
|
|||
template<typename _Tp>
|
||||
struct rebind
|
||||
{ typedef typename _Base_type::template rebind_alloc<_Tp> other; };
|
||||
#else
|
||||
#else // ! C++11
|
||||
|
||||
typedef typename _Alloc::pointer pointer;
|
||||
typedef typename _Alloc::const_pointer const_pointer;
|
||||
|
@ -162,7 +160,7 @@ template<typename _Alloc, typename = typename _Alloc::value_type>
|
|||
template<typename _Tp>
|
||||
struct rebind
|
||||
{ typedef typename _Alloc::template rebind<_Tp>::other other; };
|
||||
#endif
|
||||
#endif // C++11
|
||||
};
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
|
|
|
@ -169,13 +169,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif // ! C++20
|
||||
|
||||
template<typename _Up>
|
||||
friend bool
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator==(const malloc_allocator&, const malloc_allocator<_Up>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return true; }
|
||||
|
||||
template<typename _Up>
|
||||
friend bool
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator!=(const malloc_allocator&, const malloc_allocator<_Up>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return false; }
|
||||
|
|
|
@ -168,13 +168,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif // ! C++20
|
||||
|
||||
template<typename _Up>
|
||||
friend bool
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator==(const new_allocator&, const new_allocator<_Up>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return true; }
|
||||
|
||||
template<typename _Up>
|
||||
friend bool
|
||||
friend _GLIBCXX20_CONSTEXPR bool
|
||||
operator!=(const new_allocator&, const new_allocator<_Up>&)
|
||||
_GLIBCXX_NOTHROW
|
||||
{ return false; }
|
||||
|
|
|
@ -25,8 +25,14 @@ namespace std {
|
|||
template <class T> class allocator;
|
||||
template <> class allocator<void>;
|
||||
template <class T, class U>
|
||||
#if __cplusplus > 201703L
|
||||
constexpr
|
||||
#endif
|
||||
bool operator==(const allocator<T>&, const allocator<U>&) throw();
|
||||
template <class T, class U>
|
||||
#if __cplusplus > 201703L
|
||||
constexpr
|
||||
#endif
|
||||
bool operator!=(const allocator<T>&, const allocator<U>&) throw();
|
||||
|
||||
// lib.storage.iterator, raw storage iterator:
|
||||
|
|
|
@ -48,3 +48,6 @@ test01()
|
|||
sa.construct(p); // this is required to be ill-formed
|
||||
// { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }
|
||||
}
|
||||
|
||||
// Needed because of PR c++/92193
|
||||
// { dg-prune-output "no matching function for call to" }
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (C) 2019 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++2a" }
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
#include <memory>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
template<typename T, typename... Args>
|
||||
concept can_construct_at = requires(T* p, Args&&... args)
|
||||
{
|
||||
p = std::construct_at(p, std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
static_assert( can_construct_at<int> );
|
||||
static_assert( can_construct_at<int, int> );
|
||||
static_assert( !can_construct_at<int, int, int> );
|
||||
|
||||
// Not required by C++20:
|
||||
static_assert( noexcept(std::construct_at(std::declval<int*>(), 1)) );
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
int i = -1;
|
||||
auto p = std::construct_at(&i);
|
||||
VERIFY( p == &i );
|
||||
VERIFY( i == 0 );
|
||||
p = std::construct_at(&i, 42);
|
||||
VERIFY( p == &i );
|
||||
VERIFY( i == 42 );
|
||||
}
|
||||
|
||||
struct X {
|
||||
X(char&, void*) { }
|
||||
};
|
||||
|
||||
static_assert( can_construct_at<X, char&, void*> );
|
||||
static_assert( !can_construct_at<X> );
|
||||
static_assert( !can_construct_at<X, char> );
|
||||
static_assert( !can_construct_at<X, char&, const void*> );
|
||||
|
||||
static_assert( !noexcept(std::construct_at(std::declval<X*>(), std::declval<char&>(), std::declval<void*>())) );
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
}
|
|
@ -47,3 +47,7 @@ test02()
|
|||
|
||||
// In Debug Mode the "required from here" errors come from <debug/vector>
|
||||
// { dg-error "required from here" "" { target *-*-* } 163 }
|
||||
|
||||
// Needed because of PR c++/92193
|
||||
// { dg-prune-output "deleted function" }
|
||||
// { dg-prune-output "private within this context" }
|
||||
|
|
|
@ -43,3 +43,7 @@ test02()
|
|||
}
|
||||
|
||||
// { dg-error "value type is destructible" "" { target *-*-* } 0 }
|
||||
|
||||
// Needed because of PR c++/92193
|
||||
// { dg-prune-output "deleted function" }
|
||||
// { dg-prune-output "private within this context" }
|
||||
|
|
Loading…
Add table
Reference in a new issue