forked from OSchip/llvm-project
[libc++] Implement C++20's P0784 (More constexpr containers)
This commit adds std::construct_at, and marks various members of std::allocator_traits and std::allocator as constexpr. It also adds tests and turns the existing tests into hybrid constexpr/runtime tests. Thanks to Richard Smith for initial work on this, and to Michael Park for D69803, D69132 and D69134, which are superseded by this patch. Differential Revision: https://reviews.llvm.org/D68364
This commit is contained in:
parent
89074bdc81
commit
0724f8bf47
libcxx
docs
include
test/std
containers/sequences/vector/vector.cons
language.support/support.limits/support.limits.general
utilities/memory
allocator.traits/allocator.traits.members
allocate.pass.cppallocate.verify.cppallocate_hint.pass.cppconstruct.pass.cppdeallocate.pass.cppdestroy.pass.cppmax_size.pass.cppselect_on_container_copy_construction.pass.cpp
default.allocator
specialized.algorithms
specialized.construct
specialized.destroy
utils
www
|
@ -192,6 +192,8 @@ Status
|
|||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_concepts`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_dynamic_alloc`` ``201907L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_misc`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_swap_algorithms`` *unimplemented*
|
||||
|
|
|
@ -83,21 +83,19 @@ struct allocator_traits
|
|||
template <class T> using rebind_alloc = Alloc::rebind<T>::other | Alloc<T, Args...>;
|
||||
template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;
|
||||
|
||||
static pointer allocate(allocator_type& a, size_type n); // [[nodiscard]] in C++20
|
||||
static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // [[nodiscard]] in C++20
|
||||
static pointer allocate(allocator_type& a, size_type n); // constexpr and [[nodiscard]] in C++20
|
||||
static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // constexpr and [[nodiscard]] in C++20
|
||||
|
||||
static void deallocate(allocator_type& a, pointer p, size_type n) noexcept;
|
||||
static void deallocate(allocator_type& a, pointer p, size_type n) noexcept; // constexpr in C++20
|
||||
|
||||
template <class T, class... Args>
|
||||
static void construct(allocator_type& a, T* p, Args&&... args);
|
||||
static void construct(allocator_type& a, T* p, Args&&... args); // constexpr in C++20
|
||||
|
||||
template <class T>
|
||||
static void destroy(allocator_type& a, T* p);
|
||||
static void destroy(allocator_type& a, T* p); // constexpr in C++20
|
||||
|
||||
static size_type max_size(const allocator_type& a); // noexcept in C++14
|
||||
|
||||
static allocator_type
|
||||
select_on_container_copy_construction(const allocator_type& a);
|
||||
static size_type max_size(const allocator_type& a); // noexcept in C++14, constexpr in C++20
|
||||
static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -135,12 +133,12 @@ public:
|
|||
constexpr allocator(const allocator&) noexcept; // constexpr in C++20
|
||||
template <class U>
|
||||
constexpr allocator(const allocator<U>&) noexcept; // constexpr in C++20
|
||||
~allocator();
|
||||
~allocator(); // constexpr in C++20
|
||||
pointer address(reference x) const noexcept; // deprecated in C++17, removed in C++20
|
||||
const_pointer address(const_reference x) const noexcept; // deprecated in C++17, removed in C++20
|
||||
T* allocate(size_t n, const void* hint); // deprecated in C++17, removed in C++20
|
||||
T* allocate(size_t n);
|
||||
void deallocate(T* p, size_t n) noexcept;
|
||||
T* allocate(size_t n); // constexpr in C++20
|
||||
void deallocate(T* p, size_t n) noexcept; // constexpr in C++20
|
||||
size_type max_size() const noexcept; // deprecated in C++17, removed in C++20
|
||||
template<class U, class... Args>
|
||||
void construct(U* p, Args&&... args); // deprecated in C++17, removed in C++20
|
||||
|
@ -149,10 +147,10 @@ public:
|
|||
};
|
||||
|
||||
template <class T, class U>
|
||||
bool operator==(const allocator<T>&, const allocator<U>&) noexcept;
|
||||
bool operator==(const allocator<T>&, const allocator<U>&) noexcept; // constexpr in C++20
|
||||
|
||||
template <class T, class U>
|
||||
bool operator!=(const allocator<T>&, const allocator<U>&) noexcept;
|
||||
bool operator!=(const allocator<T>&, const allocator<U>&) noexcept; // constexpr in C++20
|
||||
|
||||
template <class OutputIterator, class T>
|
||||
class raw_storage_iterator
|
||||
|
@ -191,14 +189,17 @@ template <class ForwardIterator, class Size, class T>
|
|||
ForwardIterator
|
||||
uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
|
||||
|
||||
template <class T, class ...Args>
|
||||
constexpr T* construct_at(T* location, Args&& ...args); // since C++20
|
||||
|
||||
template <class T>
|
||||
void destroy_at(T* location);
|
||||
void destroy_at(T* location); // constexpr in C++20
|
||||
|
||||
template <class ForwardIterator>
|
||||
void destroy(ForwardIterator first, ForwardIterator last);
|
||||
void destroy(ForwardIterator first, ForwardIterator last); // constexpr in C++20
|
||||
|
||||
template <class ForwardIterator, class Size>
|
||||
ForwardIterator destroy_n(ForwardIterator first, Size n);
|
||||
ForwardIterator destroy_n(ForwardIterator first, Size n); // constexpr in C++20
|
||||
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result);
|
||||
|
@ -886,6 +887,39 @@ struct __rebind_pointer {
|
|||
#endif
|
||||
};
|
||||
|
||||
// construct_at
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
|
||||
template<class _Tp>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 void* __voidify(_Tp& __ptr) noexcept {
|
||||
return const_cast<void*>(static_cast<const volatile void*>(_VSTD::addressof(__ptr)));
|
||||
}
|
||||
|
||||
template<class _Tp, class ..._Args, class = decltype(
|
||||
::new (_VSTD::declval<void*>()) _Tp(_VSTD::declval<_Args>()...)
|
||||
)>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
constexpr _Tp* construct_at(_Tp* __location, _Args&& ...__args) {
|
||||
_LIBCPP_ASSERT(__location, "null pointer given to construct_at");
|
||||
return ::new (_VSTD::__voidify(*__location)) _Tp(_VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// destroy_at
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void destroy_at(_Tp* __loc) {
|
||||
_LIBCPP_ASSERT(__loc, "null pointer given to destroy_at");
|
||||
__loc->~_Tp();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// allocator_traits
|
||||
|
||||
template <class _Tp, class = void>
|
||||
|
@ -1390,34 +1424,34 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
|
|||
{typedef allocator_traits<typename rebind_alloc<_Tp>::other> other;};
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static pointer allocate(allocator_type& __a, size_type __n)
|
||||
{return __a.allocate(__n);}
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static pointer allocate(allocator_type& __a, size_type __n, const_void_pointer __hint)
|
||||
{return __allocate(__a, __n, __hint,
|
||||
__has_allocate_hint<allocator_type, size_type, const_void_pointer>());}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT
|
||||
{__a.deallocate(__p, __n);}
|
||||
|
||||
template <class _Tp, class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void construct(allocator_type& __a, _Tp* __p, _Args&&... __args)
|
||||
{__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
|
||||
__a, __p, _VSTD::forward<_Args>(__args)...);}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void destroy(allocator_type& __a, _Tp* __p)
|
||||
{__destroy(__has_destroy<allocator_type, _Tp*>(), __a, __p);}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static size_type max_size(const allocator_type& __a) _NOEXCEPT
|
||||
{return __max_size(__has_max_size<const allocator_type>(), __a);}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static allocator_type
|
||||
select_on_container_copy_construction(const allocator_type& __a)
|
||||
{return __select_on_container_copy_construction(
|
||||
|
@ -1536,7 +1570,7 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
|
|||
|
||||
private:
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static pointer __allocate(allocator_type& __a, size_type __n,
|
||||
const_void_pointer __hint, true_type)
|
||||
{
|
||||
|
@ -1544,13 +1578,13 @@ private:
|
|||
return __a.allocate(__n, __hint);
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static pointer __allocate(allocator_type& __a, size_type __n,
|
||||
const_void_pointer, false_type)
|
||||
{return __a.allocate(__n);}
|
||||
|
||||
template <class _Tp, class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void __construct(true_type, allocator_type& __a, _Tp* __p, _Args&&... __args)
|
||||
{
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
|
@ -1559,14 +1593,18 @@ private:
|
|||
}
|
||||
|
||||
template <class _Tp, class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void __construct(false_type, allocator_type&, _Tp* __p, _Args&&... __args)
|
||||
{
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
_VSTD::construct_at(__p, _VSTD::forward<_Args>(__args)...);
|
||||
#else
|
||||
::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void __destroy(true_type, allocator_type& __a, _Tp* __p)
|
||||
{
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
|
@ -1574,13 +1612,17 @@ private:
|
|||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
}
|
||||
template <class _Tp>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static void __destroy(false_type, allocator_type&, _Tp* __p)
|
||||
{
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
_VSTD::destroy_at(__p);
|
||||
#else
|
||||
__p->~_Tp();
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static size_type __max_size(true_type, const allocator_type& __a) _NOEXCEPT
|
||||
{
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
|
@ -1588,15 +1630,15 @@ private:
|
|||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static size_type __max_size(false_type, const allocator_type&) _NOEXCEPT
|
||||
{return numeric_limits<size_type>::max() / sizeof(value_type);}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static allocator_type
|
||||
__select_on_container_copy_construction(true_type, const allocator_type& __a)
|
||||
{return __a.select_on_container_copy_construction();}
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static allocator_type
|
||||
__select_on_container_copy_construction(false_type, const allocator_type& __a)
|
||||
{return __a;}
|
||||
|
@ -1650,10 +1692,10 @@ public:
|
|||
{return _VSTD::addressof(__x);}
|
||||
#endif
|
||||
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _Tp* allocate(size_t __n)
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_Tp* allocate(size_t __n)
|
||||
{
|
||||
// TODO(mpark): Replace with `allocator_traits<allocator>::max_size(*this)`.
|
||||
if (__n > (size_t(~0) / sizeof(_Tp)))
|
||||
if (__n > allocator_traits<allocator>::max_size(*this))
|
||||
__throw_length_error("allocator<T>::allocate(size_t n)"
|
||||
" 'n' exceeds maximum supported size");
|
||||
return static_cast<_Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
|
||||
|
@ -1664,7 +1706,8 @@ public:
|
|||
_Tp* allocate(size_t __n, const void*) { return allocate(__n); }
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY void deallocate(_Tp* __p, size_t __n) _NOEXCEPT
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void deallocate(_Tp* __p, size_t __n) _NOEXCEPT
|
||||
{_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));}
|
||||
|
||||
#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS)
|
||||
|
@ -1715,10 +1758,10 @@ public:
|
|||
{return _VSTD::addressof(__x);}
|
||||
#endif
|
||||
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const _Tp* allocate(size_t __n)
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
const _Tp* allocate(size_t __n)
|
||||
{
|
||||
// TODO(mpark): Replace with `allocator_traits<allocator>::max_size(*this)`.
|
||||
if (__n > (size_t(~0) / sizeof(_Tp)))
|
||||
if (__n > allocator_traits<allocator>::max_size(*this))
|
||||
__throw_length_error("allocator<const T>::allocate(size_t n)"
|
||||
" 'n' exceeds maximum supported size");
|
||||
return static_cast<const _Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
|
||||
|
@ -1729,7 +1772,8 @@ public:
|
|||
const _Tp* allocate(size_t __n, const void*) { return allocate(__n); }
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY void deallocate(const _Tp* __p, size_t __n)
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void deallocate(const _Tp* __p, size_t __n)
|
||||
{_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));}
|
||||
|
||||
#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS)
|
||||
|
@ -1749,11 +1793,11 @@ public:
|
|||
};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;}
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
bool operator!=(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return false;}
|
||||
|
||||
template <class _OutputIterator, class _Tp>
|
||||
|
@ -2938,22 +2982,15 @@ uninitialized_fill_n(_ForwardIterator __f, _Size __n, const _Tp& __x)
|
|||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void destroy_at(_Tp* __loc) {
|
||||
_LIBCPP_ASSERT(__loc, "null pointer given to destroy_at");
|
||||
__loc->~_Tp();
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void destroy(_ForwardIterator __first, _ForwardIterator __last) {
|
||||
for (; __first != __last; ++__first)
|
||||
_VSTD::destroy_at(_VSTD::addressof(*__first));
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _Size>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) {
|
||||
for (; __n > 0; (void)++__first, --__n)
|
||||
_VSTD::destroy_at(_VSTD::addressof(*__first));
|
||||
|
|
|
@ -234,7 +234,8 @@ _LIBCPP_CONSTEXPR inline _LIBCPP_INLINE_VISIBILITY bool __is_overaligned_for_new
|
|||
#endif
|
||||
}
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t __align) {
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void *__libcpp_allocate(size_t __size, size_t __align) {
|
||||
#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
||||
if (__is_overaligned_for_new(__align)) {
|
||||
const align_val_t __align_val = static_cast<align_val_t>(__align);
|
||||
|
@ -255,7 +256,60 @@ inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t _
|
|||
}
|
||||
|
||||
struct _DeallocateCaller {
|
||||
static inline _LIBCPP_INLINE_VISIBILITY
|
||||
template <class _A1, class _A2>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) {
|
||||
#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
|
||||
defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
|
||||
return ::operator delete(__ptr, __a1, __a2);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr, __a1, __a2);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class _A1>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static inline void __do_call(void *__ptr, _A1 __a1) {
|
||||
#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
|
||||
defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
|
||||
return ::operator delete(__ptr, __a1);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr, __a1);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static inline void __do_call(void *__ptr) {
|
||||
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
|
||||
return ::operator delete(__ptr);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) {
|
||||
#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
((void)__size);
|
||||
return __do_call(__ptr);
|
||||
#else
|
||||
return __do_call(__ptr, __size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) {
|
||||
#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
((void)__size);
|
||||
return __do_call(__ptr, __align);
|
||||
#else
|
||||
return __do_call(__ptr, __size, __align);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) {
|
||||
#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
|
||||
((void)__align);
|
||||
|
@ -270,7 +324,7 @@ struct _DeallocateCaller {
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline _LIBCPP_INLINE_VISIBILITY
|
||||
static inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void __do_deallocate_handle_align(void *__ptr, size_t __align) {
|
||||
#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
|
||||
((void)__align);
|
||||
|
@ -282,61 +336,12 @@ struct _DeallocateCaller {
|
|||
} else {
|
||||
return __do_call(__ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) {
|
||||
#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
((void)__size);
|
||||
return __do_call(__ptr);
|
||||
#else
|
||||
return __do_call(__ptr, __size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
||||
static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) {
|
||||
#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
((void)__size);
|
||||
return __do_call(__ptr, __align);
|
||||
#else
|
||||
return __do_call(__ptr, __size, __align);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
template <class _A1, class _A2>
|
||||
static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) {
|
||||
#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
|
||||
defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
|
||||
return ::operator delete(__ptr, __a1, __a2);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr, __a1, __a2);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class _A1>
|
||||
static inline void __do_call(void *__ptr, _A1 __a1) {
|
||||
#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
|
||||
defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
|
||||
return ::operator delete(__ptr, __a1);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr, __a1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __do_call(void *__ptr) {
|
||||
#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
|
||||
return ::operator delete(__ptr);
|
||||
#else
|
||||
return __builtin_operator_delete(__ptr);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) {
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) {
|
||||
_DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ __cpp_lib_chrono_udls 201304L <chrono>
|
|||
__cpp_lib_clamp 201603L <algorithm>
|
||||
__cpp_lib_complex_udls 201309L <complex>
|
||||
__cpp_lib_concepts 201806L <concepts>
|
||||
__cpp_lib_constexpr_dynamic_alloc 201907L <memory>
|
||||
__cpp_lib_constexpr_misc 201811L <array> <functional> <iterator>
|
||||
<string_view> <tuple> <utility>
|
||||
__cpp_lib_constexpr_swap_algorithms 201806L <algorithm>
|
||||
|
@ -250,6 +251,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
|||
# define __cpp_lib_char8_t 201811L
|
||||
# endif
|
||||
// # define __cpp_lib_concepts 201806L
|
||||
# define __cpp_lib_constexpr_dynamic_alloc 201907L
|
||||
// # define __cpp_lib_constexpr_misc 201811L
|
||||
// # define __cpp_lib_constexpr_swap_algorithms 201806L
|
||||
# define __cpp_lib_constexpr_utility 201811L
|
||||
|
|
|
@ -22,6 +22,6 @@ struct move_only
|
|||
int main(int, char**)
|
||||
{
|
||||
std::vector<move_only> v;
|
||||
std::vector<move_only> copy = v; // expected-error@memory:* {{call to implicitly-deleted copy constructor of 'move_only'}}
|
||||
std::vector<move_only> copy = v; // expected-error-re@memory:* {{{{(no matching function for call to 'construct_at')|(call to implicitly-deleted copy constructor of 'move_only')}}}}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
__cpp_lib_addressof_constexpr 201603L [C++17]
|
||||
__cpp_lib_allocator_traits_is_always_equal 201411L [C++17]
|
||||
__cpp_lib_atomic_value_initialization 201911L [C++2a]
|
||||
__cpp_lib_constexpr_dynamic_alloc 201907L [C++2a]
|
||||
__cpp_lib_enable_shared_from_this 201603L [C++17]
|
||||
__cpp_lib_make_unique 201304L [C++14]
|
||||
__cpp_lib_ranges 201811L [C++2a]
|
||||
|
@ -42,6 +43,10 @@
|
|||
# error "__cpp_lib_atomic_value_initialization should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_enable_shared_from_this
|
||||
# error "__cpp_lib_enable_shared_from_this should not be defined before c++17"
|
||||
# endif
|
||||
|
@ -80,6 +85,10 @@
|
|||
# error "__cpp_lib_atomic_value_initialization should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_enable_shared_from_this
|
||||
# error "__cpp_lib_enable_shared_from_this should not be defined before c++17"
|
||||
# endif
|
||||
|
@ -133,6 +142,10 @@
|
|||
# error "__cpp_lib_atomic_value_initialization should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_enable_shared_from_this
|
||||
# error "__cpp_lib_enable_shared_from_this should be defined in c++17"
|
||||
# endif
|
||||
|
@ -213,6 +226,13 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should be defined in c++2a"
|
||||
# endif
|
||||
# if __cpp_lib_constexpr_dynamic_alloc != 201907L
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++2a"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_enable_shared_from_this
|
||||
# error "__cpp_lib_enable_shared_from_this should be defined in c++2a"
|
||||
# endif
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
__cpp_lib_clamp 201603L [C++17]
|
||||
__cpp_lib_complex_udls 201309L [C++14]
|
||||
__cpp_lib_concepts 201806L [C++2a]
|
||||
__cpp_lib_constexpr_dynamic_alloc 201907L [C++2a]
|
||||
__cpp_lib_constexpr_misc 201811L [C++2a]
|
||||
__cpp_lib_constexpr_swap_algorithms 201806L [C++2a]
|
||||
__cpp_lib_constexpr_utility 201811L [C++2a]
|
||||
|
@ -217,6 +218,10 @@
|
|||
# error "__cpp_lib_concepts should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_misc
|
||||
# error "__cpp_lib_constexpr_misc should not be defined before c++2a"
|
||||
# endif
|
||||
|
@ -601,6 +606,10 @@
|
|||
# error "__cpp_lib_concepts should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_misc
|
||||
# error "__cpp_lib_constexpr_misc should not be defined before c++2a"
|
||||
# endif
|
||||
|
@ -1099,6 +1108,10 @@
|
|||
# error "__cpp_lib_concepts should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_misc
|
||||
# error "__cpp_lib_constexpr_misc should not be defined before c++2a"
|
||||
# endif
|
||||
|
@ -1864,6 +1877,13 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_constexpr_dynamic_alloc
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should be defined in c++2a"
|
||||
# endif
|
||||
# if __cpp_lib_constexpr_dynamic_alloc != 201907L
|
||||
# error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++2a"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_constexpr_misc
|
||||
# error "__cpp_lib_constexpr_misc should be defined in c++2a"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static pointer allocate(allocator_type& a, size_type n);
|
||||
// static constexpr pointer allocate(allocator_type& a, size_type n);
|
||||
// ...
|
||||
// };
|
||||
|
||||
|
@ -27,25 +27,37 @@ struct A
|
|||
{
|
||||
typedef T value_type;
|
||||
|
||||
value_type* allocate(std::size_t n)
|
||||
TEST_CONSTEXPR_CXX20 A() {}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n)
|
||||
{
|
||||
assert(n == 10);
|
||||
return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF));
|
||||
return &storage;
|
||||
}
|
||||
|
||||
value_type storage;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
A<int> a;
|
||||
assert(std::allocator_traits<A<int> >::allocate(a, 10) == &a.storage);
|
||||
}
|
||||
{
|
||||
typedef A<IncompleteHolder*> Alloc;
|
||||
Alloc a;
|
||||
assert(std::allocator_traits<Alloc>::allocate(a, 10) == &a.storage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
A<int> a;
|
||||
assert(std::allocator_traits<A<int> >::allocate(a, 10) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF)));
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef A<VT> Alloc;
|
||||
Alloc a;
|
||||
assert(std::allocator_traits<Alloc >::allocate(a, 10) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static pointer allocate(allocator_type& a, size_type n);
|
||||
// static constexpr pointer allocate(allocator_type& a, size_type n);
|
||||
// ...
|
||||
// };
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint);
|
||||
// static constexpr pointer allocate(allocator_type& a, size_type n, const_void_pointer hint);
|
||||
// ...
|
||||
// };
|
||||
|
||||
|
@ -27,11 +27,15 @@ struct A
|
|||
{
|
||||
typedef T value_type;
|
||||
|
||||
value_type* allocate(std::size_t n)
|
||||
TEST_CONSTEXPR_CXX20 A() {}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n)
|
||||
{
|
||||
assert(n == 10);
|
||||
return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF));
|
||||
return &storage;
|
||||
}
|
||||
|
||||
value_type storage;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -39,44 +43,48 @@ struct B
|
|||
{
|
||||
typedef T value_type;
|
||||
|
||||
value_type* allocate(std::size_t n)
|
||||
{
|
||||
assert(n == 12);
|
||||
return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xEEADBEEF));
|
||||
}
|
||||
value_type* allocate(std::size_t n, const void* p)
|
||||
TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n, const void* p)
|
||||
{
|
||||
assert(n == 11);
|
||||
assert(p == 0);
|
||||
return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xFEADBEEF));
|
||||
assert(p == nullptr);
|
||||
return &storage;
|
||||
}
|
||||
|
||||
value_type storage;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
A<int> a;
|
||||
assert(std::allocator_traits<A<int> >::allocate(a, 10, nullptr) == &a.storage);
|
||||
}
|
||||
{
|
||||
typedef A<IncompleteHolder*> Alloc;
|
||||
Alloc a;
|
||||
assert(std::allocator_traits<Alloc>::allocate(a, 10, nullptr) == &a.storage);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
B<int> b;
|
||||
assert(std::allocator_traits<B<int> >::allocate(b, 11, nullptr) == &b.storage);
|
||||
}
|
||||
{
|
||||
typedef B<IncompleteHolder*> Alloc;
|
||||
Alloc b;
|
||||
assert(std::allocator_traits<Alloc>::allocate(b, 11, nullptr) == &b.storage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
A<int> a;
|
||||
assert(std::allocator_traits<A<int> >::allocate(a, 10, nullptr) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF)));
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef A<VT> Alloc;
|
||||
Alloc a;
|
||||
assert(std::allocator_traits<Alloc >::allocate(a, 10, nullptr) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF)));
|
||||
}
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
{
|
||||
B<int> b;
|
||||
assert(std::allocator_traits<B<int> >::allocate(b, 11, nullptr) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xFEADBEEF)));
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef B<VT> Alloc;
|
||||
Alloc b;
|
||||
assert(std::allocator_traits<Alloc >::allocate(b, 11, nullptr) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xFEADBEEF)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// struct allocator_traits
|
||||
// {
|
||||
// template <class Ptr, class... Args>
|
||||
// static void construct(allocator_type& a, Ptr p, Args&&... args);
|
||||
// static constexpr void construct(allocator_type& a, Ptr p, Args&&... args);
|
||||
// ...
|
||||
// };
|
||||
|
||||
|
@ -31,124 +31,147 @@ struct A
|
|||
|
||||
};
|
||||
|
||||
int b_construct = 0;
|
||||
|
||||
template <class T>
|
||||
struct B
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
TEST_CONSTEXPR_CXX20 B(int& count) : count(count) {}
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
template <class U, class ...Args>
|
||||
void construct(U* p, Args&& ...args)
|
||||
TEST_CONSTEXPR_CXX20 void construct(U* p, Args&& ...args)
|
||||
{
|
||||
++b_construct;
|
||||
++count;
|
||||
#if TEST_STD_VER > 17
|
||||
std::construct_at(p, std::forward<Args>(args)...);
|
||||
#else
|
||||
::new ((void*)p) U(std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int& count;
|
||||
};
|
||||
|
||||
struct A0
|
||||
{
|
||||
static int count;
|
||||
A0() {++count;}
|
||||
TEST_CONSTEXPR_CXX20 A0(int* count) {++*count;}
|
||||
};
|
||||
|
||||
int A0::count = 0;
|
||||
|
||||
struct A1
|
||||
{
|
||||
static int count;
|
||||
A1(char c)
|
||||
TEST_CONSTEXPR_CXX20 A1(int* count, char c)
|
||||
{
|
||||
assert(c == 'c');
|
||||
++count;
|
||||
++*count;
|
||||
}
|
||||
};
|
||||
|
||||
int A1::count = 0;
|
||||
|
||||
struct A2
|
||||
{
|
||||
static int count;
|
||||
A2(char c, int i)
|
||||
TEST_CONSTEXPR_CXX20 A2(int* count, char c, int i)
|
||||
{
|
||||
assert(c == 'd');
|
||||
assert(i == 5);
|
||||
++count;
|
||||
++*count;
|
||||
}
|
||||
};
|
||||
|
||||
int A2::count = 0;
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
A0::count = 0;
|
||||
A<int> a;
|
||||
std::aligned_storage<sizeof(A0)>::type a0;
|
||||
assert(A0::count == 0);
|
||||
std::allocator_traits<A<int> >::construct(a, (A0*)&a0);
|
||||
assert(A0::count == 1);
|
||||
int A0_count = 0;
|
||||
A<A0> a;
|
||||
std::allocator<A0> alloc;
|
||||
A0* a0 = alloc.allocate(1);
|
||||
assert(A0_count == 0);
|
||||
std::allocator_traits<A<A0> >::construct(a, a0, &A0_count);
|
||||
assert(A0_count == 1);
|
||||
alloc.deallocate(a0, 1);
|
||||
}
|
||||
{
|
||||
A1::count = 0;
|
||||
A<int> a;
|
||||
std::aligned_storage<sizeof(A1)>::type a1;
|
||||
assert(A1::count == 0);
|
||||
std::allocator_traits<A<int> >::construct(a, (A1*)&a1, 'c');
|
||||
assert(A1::count == 1);
|
||||
int A1_count = 0;
|
||||
A<A1> a;
|
||||
std::allocator<A1> alloc;
|
||||
A1* a1 = alloc.allocate(1);
|
||||
assert(A1_count == 0);
|
||||
std::allocator_traits<A<A1> >::construct(a, a1, &A1_count, 'c');
|
||||
assert(A1_count == 1);
|
||||
alloc.deallocate(a1, 1);
|
||||
}
|
||||
{
|
||||
A2::count = 0;
|
||||
A<int> a;
|
||||
std::aligned_storage<sizeof(A2)>::type a2;
|
||||
assert(A2::count == 0);
|
||||
std::allocator_traits<A<int> >::construct(a, (A2*)&a2, 'd', 5);
|
||||
assert(A2::count == 1);
|
||||
int A2_count = 0;
|
||||
A<A2> a;
|
||||
std::allocator<A2> alloc;
|
||||
A2* a2 = alloc.allocate(1);
|
||||
assert(A2_count == 0);
|
||||
std::allocator_traits<A<A2> >::construct(a, a2, &A2_count, 'd', 5);
|
||||
assert(A2_count == 1);
|
||||
alloc.deallocate(a2, 1);
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef A<VT> Alloc;
|
||||
Alloc a;
|
||||
std::aligned_storage<sizeof(VT)>::type store;
|
||||
std::allocator_traits<Alloc>::construct(a, (VT*)&store, nullptr);
|
||||
std::allocator<VT> alloc;
|
||||
VT* vt = alloc.allocate(1);
|
||||
std::allocator_traits<Alloc>::construct(a, vt, nullptr);
|
||||
alloc.deallocate(vt, 1);
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
A0::count = 0;
|
||||
b_construct = 0;
|
||||
B<int> b;
|
||||
std::aligned_storage<sizeof(A0)>::type a0;
|
||||
assert(A0::count == 0);
|
||||
int A0_count = 0;
|
||||
int b_construct = 0;
|
||||
B<A0> b(b_construct);
|
||||
std::allocator<A0> alloc;
|
||||
A0* a0 = alloc.allocate(1);
|
||||
assert(A0_count == 0);
|
||||
assert(b_construct == 0);
|
||||
std::allocator_traits<B<int> >::construct(b, (A0*)&a0);
|
||||
assert(A0::count == 1);
|
||||
std::allocator_traits<B<A0> >::construct(b, a0, &A0_count);
|
||||
assert(A0_count == 1);
|
||||
assert(b_construct == 1);
|
||||
alloc.deallocate(a0, 1);
|
||||
}
|
||||
{
|
||||
A1::count = 0;
|
||||
b_construct = 0;
|
||||
B<int> b;
|
||||
std::aligned_storage<sizeof(A1)>::type a1;
|
||||
assert(A1::count == 0);
|
||||
int A1_count = 0;
|
||||
int b_construct = 0;
|
||||
B<A1> b(b_construct);
|
||||
std::allocator<A1> alloc;
|
||||
A1* a1 = alloc.allocate(1);
|
||||
assert(A1_count == 0);
|
||||
assert(b_construct == 0);
|
||||
std::allocator_traits<B<int> >::construct(b, (A1*)&a1, 'c');
|
||||
assert(A1::count == 1);
|
||||
std::allocator_traits<B<A1> >::construct(b, a1, &A1_count, 'c');
|
||||
assert(A1_count == 1);
|
||||
assert(b_construct == 1);
|
||||
alloc.deallocate(a1, 1);
|
||||
}
|
||||
{
|
||||
A2::count = 0;
|
||||
b_construct = 0;
|
||||
B<int> b;
|
||||
std::aligned_storage<sizeof(A2)>::type a2;
|
||||
assert(A2::count == 0);
|
||||
int A2_count = 0;
|
||||
int b_construct = 0;
|
||||
B<A2> b(b_construct);
|
||||
std::allocator<A2> alloc;
|
||||
A2* a2 = alloc.allocate(1);
|
||||
assert(A2_count == 0);
|
||||
assert(b_construct == 0);
|
||||
std::allocator_traits<B<int> >::construct(b, (A2*)&a2, 'd', 5);
|
||||
assert(A2::count == 1);
|
||||
std::allocator_traits<B<A2> >::construct(b, a2, &A2_count, 'd', 5);
|
||||
assert(A2_count == 1);
|
||||
assert(b_construct == 1);
|
||||
alloc.deallocate(a2, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,47 +11,60 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static void deallocate(allocator_type& a, pointer p, size_type n);
|
||||
// static constexpr void deallocate(allocator_type& a, pointer p, size_type n);
|
||||
// ...
|
||||
// };
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "incomplete_type_helper.h"
|
||||
|
||||
int called = 0;
|
||||
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
void deallocate(value_type* p, std::size_t n)
|
||||
TEST_CONSTEXPR_CXX20 A(int& called) : called(called) {}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 void deallocate(value_type* p, std::size_t n)
|
||||
{
|
||||
assert(p == reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF)));
|
||||
assert(p == &storage);
|
||||
assert(n == 10);
|
||||
++called;
|
||||
}
|
||||
|
||||
int& called;
|
||||
|
||||
value_type storage;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
int called = 0;
|
||||
A<int> a(called);
|
||||
std::allocator_traits<A<int> >::deallocate(a, &a.storage, 10);
|
||||
assert(called == 1);
|
||||
}
|
||||
{
|
||||
int called = 0;
|
||||
typedef A<IncompleteHolder*> Alloc;
|
||||
Alloc a(called);
|
||||
std::allocator_traits<Alloc>::deallocate(a, &a.storage, 10);
|
||||
assert(called == 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
A<int> a;
|
||||
std::allocator_traits<A<int> >::deallocate(a, reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF)), 10);
|
||||
assert(called == 1);
|
||||
}
|
||||
called = 0;
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef A<VT> Alloc;
|
||||
Alloc a;
|
||||
std::allocator_traits<Alloc >::deallocate(a, reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF)), 10);
|
||||
assert(called == 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,80 +12,123 @@
|
|||
// struct allocator_traits
|
||||
// {
|
||||
// template <class Ptr>
|
||||
// static void destroy(allocator_type& a, Ptr p);
|
||||
// static constexpr void destroy(allocator_type& a, Ptr p);
|
||||
// ...
|
||||
// };
|
||||
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "incomplete_type_helper.h"
|
||||
|
||||
template <class T>
|
||||
struct A
|
||||
struct NoDestroy
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
};
|
||||
|
||||
int b_destroy = 0;
|
||||
|
||||
template <class T>
|
||||
struct B
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
template <class U>
|
||||
void destroy(U* p)
|
||||
TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
|
||||
{
|
||||
++b_destroy;
|
||||
p->~U();
|
||||
return std::allocator<T>().allocate(n);
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
return std::allocator<T>().deallocate(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
struct A0
|
||||
template <class T>
|
||||
struct CountDestroy
|
||||
{
|
||||
static int count;
|
||||
~A0() {++count;}
|
||||
TEST_CONSTEXPR explicit CountDestroy(int* counter)
|
||||
: counter_(counter)
|
||||
{ }
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
|
||||
{
|
||||
return std::allocator<T>().allocate(n);
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
return std::allocator<T>().deallocate(p, n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
TEST_CONSTEXPR_CXX20 void destroy(U* p)
|
||||
{
|
||||
++*counter_;
|
||||
p->~U();
|
||||
}
|
||||
|
||||
int* counter_;
|
||||
};
|
||||
|
||||
int A0::count = 0;
|
||||
struct CountDestructor
|
||||
{
|
||||
TEST_CONSTEXPR explicit CountDestructor(int* counter)
|
||||
: counter_(counter)
|
||||
{ }
|
||||
|
||||
TEST_CONSTEXPR_CXX20 ~CountDestructor() { ++*counter_; }
|
||||
|
||||
int* counter_;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
typedef NoDestroy<CountDestructor> Alloc;
|
||||
int destructors = 0;
|
||||
Alloc alloc;
|
||||
CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
|
||||
std::allocator_traits<Alloc>::construct(alloc, pool, &destructors);
|
||||
assert(destructors == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::destroy(alloc, pool);
|
||||
assert(destructors == 1);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* T;
|
||||
typedef NoDestroy<T> Alloc;
|
||||
Alloc alloc;
|
||||
T* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
std::allocator_traits<Alloc>::construct(alloc, pool, nullptr);
|
||||
std::allocator_traits<Alloc>::destroy(alloc, pool);
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
|
||||
}
|
||||
{
|
||||
typedef CountDestroy<CountDestructor> Alloc;
|
||||
int destroys_called = 0;
|
||||
int destructors_called = 0;
|
||||
Alloc alloc(&destroys_called);
|
||||
|
||||
CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
std::allocator_traits<Alloc>::construct(alloc, pool, &destructors_called);
|
||||
assert(destroys_called == 0);
|
||||
assert(destructors_called == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::destroy(alloc, pool);
|
||||
assert(destroys_called == 1);
|
||||
assert(destructors_called == 1);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
A0::count = 0;
|
||||
A<int> a;
|
||||
std::aligned_storage<sizeof(A0)>::type a0;
|
||||
std::allocator_traits<A<int> >::construct(a, (A0*)&a0);
|
||||
assert(A0::count == 0);
|
||||
std::allocator_traits<A<int> >::destroy(a, (A0*)&a0);
|
||||
assert(A0::count == 1);
|
||||
}
|
||||
{
|
||||
typedef IncompleteHolder* VT;
|
||||
typedef A<VT> Alloc;
|
||||
Alloc a;
|
||||
std::aligned_storage<sizeof(VT)>::type store;
|
||||
std::allocator_traits<Alloc>::destroy(a, (VT*)&store);
|
||||
}
|
||||
#if defined(_LIBCPP_VERSION) || TEST_STD_VER >= 11
|
||||
{
|
||||
A0::count = 0;
|
||||
b_destroy = 0;
|
||||
B<int> b;
|
||||
std::aligned_storage<sizeof(A0)>::type a0;
|
||||
std::allocator_traits<B<int> >::construct(b, (A0*)&a0);
|
||||
assert(A0::count == 0);
|
||||
assert(b_destroy == 0);
|
||||
std::allocator_traits<B<int> >::destroy(b, (A0*)&a0);
|
||||
assert(A0::count == 1);
|
||||
assert(b_destroy == 1);
|
||||
}
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static size_type max_size(const allocator_type& a) noexcept;
|
||||
// static constexpr size_type max_size(const allocator_type& a) noexcept;
|
||||
// ...
|
||||
// };
|
||||
|
||||
|
@ -36,13 +36,13 @@ struct B
|
|||
{
|
||||
typedef T value_type;
|
||||
|
||||
size_t max_size() const
|
||||
TEST_CONSTEXPR_CXX20 size_t max_size() const
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
B<int> b;
|
||||
|
@ -75,5 +75,16 @@ int main(int, char**)
|
|||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static allocator_type
|
||||
// static constexpr allocator_type
|
||||
// select_on_container_copy_construction(const allocator_type& a);
|
||||
// ...
|
||||
// };
|
||||
|
@ -29,7 +29,7 @@ struct A
|
|||
{
|
||||
typedef T value_type;
|
||||
int id;
|
||||
explicit A(int i = 0) : id(i) {}
|
||||
TEST_CONSTEXPR_CXX20 explicit A(int i = 0) : id(i) {}
|
||||
|
||||
};
|
||||
|
||||
|
@ -39,15 +39,15 @@ struct B
|
|||
typedef T value_type;
|
||||
|
||||
int id;
|
||||
explicit B(int i = 0) : id(i) {}
|
||||
TEST_CONSTEXPR_CXX20 explicit B(int i = 0) : id(i) {}
|
||||
|
||||
B select_on_container_copy_construction() const
|
||||
TEST_CONSTEXPR_CXX20 B select_on_container_copy_construction() const
|
||||
{
|
||||
return B(100);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
A<int> a;
|
||||
|
@ -74,5 +74,14 @@ int main(int, char**)
|
|||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// template <class T>
|
||||
// constexpr allocator<T>::~allocator();
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr bool test() {
|
||||
std::allocator<T> alloc;
|
||||
(void)alloc;
|
||||
|
||||
// destructor called here
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test<int>();
|
||||
test<int const>();
|
||||
|
||||
static_assert(test<int>());
|
||||
static_assert(test<int const>());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -11,11 +11,11 @@
|
|||
// allocator:
|
||||
|
||||
// template <class T1, class T2>
|
||||
// bool
|
||||
// constexpr bool
|
||||
// operator==(const allocator<T1>&, const allocator<T2>&) throw();
|
||||
//
|
||||
// template <class T1, class T2>
|
||||
// bool
|
||||
// constexpr bool
|
||||
// operator!=(const allocator<T1>&, const allocator<T2>&) throw();
|
||||
|
||||
#include <memory>
|
||||
|
@ -23,12 +23,23 @@
|
|||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
std::allocator<int> a1;
|
||||
std::allocator<int> a2;
|
||||
assert(a1 == a2);
|
||||
assert(!(a1 != a2));
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// allocator:
|
||||
// constexpr T* allocate(size_type n);
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename T>
|
||||
constexpr bool test()
|
||||
{
|
||||
typedef std::allocator<T> A;
|
||||
typedef std::allocator_traits<A> AT;
|
||||
A a;
|
||||
TEST_IGNORE_NODISCARD a.allocate(AT::max_size(a) + 1); // just barely too large
|
||||
TEST_IGNORE_NODISCARD a.allocate(AT::max_size(a) * 2); // significantly too large
|
||||
TEST_IGNORE_NODISCARD a.allocate(((size_t) -1) / sizeof(T) + 1); // multiply will overflow
|
||||
TEST_IGNORE_NODISCARD a.allocate((size_t) -1); // way too large
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
static_assert(test<double>()); // expected-error {{static_assert expression is not an integral constant expression}}
|
||||
LIBCPP_STATIC_ASSERT(test<const double>()); // expected-error {{static_assert expression is not an integral constant expression}}
|
||||
return 0;
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
// <memory>
|
||||
|
||||
// allocator:
|
||||
// T* allocate(size_t n);
|
||||
// constexpr T* allocate(size_t n);
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
@ -77,6 +77,18 @@ void test_aligned() {
|
|||
}
|
||||
}
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
template <size_t Align>
|
||||
constexpr bool test_aligned_constexpr() {
|
||||
typedef AlignedType<Align> T;
|
||||
std::allocator<T> a;
|
||||
T* ap = a.allocate(3);
|
||||
a.deallocate(ap, 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int, char**) {
|
||||
test_aligned<1>();
|
||||
test_aligned<2>();
|
||||
|
@ -87,5 +99,16 @@ int main(int, char**) {
|
|||
test_aligned<OverAligned>();
|
||||
test_aligned<OverAligned * 2>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test_aligned_constexpr<1>());
|
||||
static_assert(test_aligned_constexpr<2>());
|
||||
static_assert(test_aligned_constexpr<4>());
|
||||
static_assert(test_aligned_constexpr<8>());
|
||||
static_assert(test_aligned_constexpr<16>());
|
||||
static_assert(test_aligned_constexpr<MaxAligned>());
|
||||
static_assert(test_aligned_constexpr<OverAligned>());
|
||||
static_assert(test_aligned_constexpr<OverAligned * 2>());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// <memory>
|
||||
|
||||
// allocator:
|
||||
// T* allocate(size_t n);
|
||||
// constexpr T* allocate(size_t n);
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "test_macros.h"
|
||||
|
||||
template <typename T, typename U>
|
||||
void check()
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
static_assert((std::is_same<typename std::allocator<T>::size_type, std::size_t>::value), "");
|
||||
static_assert((std::is_same<typename std::allocator<T>::difference_type, std::ptrdiff_t>::value), "");
|
||||
|
@ -43,11 +43,17 @@ void check()
|
|||
a2 = a;
|
||||
std::allocator<U> a3 = a2;
|
||||
(void)a3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
check<char, int>();
|
||||
check<char const, int const>();
|
||||
test<char, int>();
|
||||
test<char const, int const>();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test<char, int>());
|
||||
static_assert(test<char const, int const>());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// <memory>
|
||||
|
||||
// template <class T, class ...Args>
|
||||
// constexpr T* construct_at(T* location, Args&& ...args);
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
struct Foo {
|
||||
int a;
|
||||
char b;
|
||||
double c;
|
||||
constexpr Foo() { }
|
||||
constexpr Foo(int a, char b, double c) : a(a), b(b), c(c) { }
|
||||
constexpr Foo(int a, char b, double c, int* count) : Foo(a, b, c) { *count += 1; }
|
||||
constexpr bool operator==(Foo const& other) const {
|
||||
return a == other.a && b == other.b && c == other.c;
|
||||
}
|
||||
};
|
||||
|
||||
struct Counted {
|
||||
int& count_;
|
||||
constexpr Counted(int& count) : count_(count) { ++count; }
|
||||
constexpr Counted(Counted const& that) : count_(that.count_) { ++count_; }
|
||||
constexpr ~Counted() { --count_; }
|
||||
};
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
int ints[1] = {0};
|
||||
int* res = std::construct_at(&ints[0], 42);
|
||||
assert(res == &ints[0]);
|
||||
assert(*res == 42);
|
||||
}
|
||||
|
||||
{
|
||||
Foo foos[1] = {};
|
||||
int count = 0;
|
||||
Foo* res = std::construct_at(&foos[0], 42, 'x', 123.89, &count);
|
||||
assert(res == &foos[0]);
|
||||
assert(*res == Foo(42, 'x', 123.89));
|
||||
assert(count == 1);
|
||||
}
|
||||
|
||||
{
|
||||
std::allocator<Counted> a;
|
||||
Counted* p = a.allocate(2);
|
||||
int count = 0;
|
||||
std::construct_at(p, count);
|
||||
assert(count == 1);
|
||||
std::construct_at(p+1, count);
|
||||
assert(count == 2);
|
||||
(p+1)->~Counted();
|
||||
assert(count == 1);
|
||||
p->~Counted();
|
||||
assert(count == 0);
|
||||
a.deallocate(p, 2);
|
||||
}
|
||||
|
||||
{
|
||||
std::allocator<Counted const> a;
|
||||
Counted const* p = a.allocate(2);
|
||||
int count = 0;
|
||||
std::construct_at(p, count);
|
||||
assert(count == 1);
|
||||
std::construct_at(p+1, count);
|
||||
assert(count == 2);
|
||||
(p+1)->~Counted();
|
||||
assert(count == 1);
|
||||
p->~Counted();
|
||||
assert(count == 0);
|
||||
a.deallocate(p, 2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure std::construct_at SFINAEs out based on the validity of calling
|
||||
// the constructor, instead of hard-erroring.
|
||||
template <typename T, typename = decltype(
|
||||
std::construct_at((T*)nullptr, 1, 2) // missing arguments for Foo(...)
|
||||
)>
|
||||
constexpr bool test_sfinae(int) { return false; }
|
||||
template <typename T>
|
||||
constexpr bool test_sfinae(...) { return true; }
|
||||
static_assert(test_sfinae<Foo>(int()));
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
|
@ -11,38 +11,50 @@
|
|||
// <memory>
|
||||
|
||||
// template <class ForwardIt>
|
||||
// void destroy(ForwardIt, ForwardIt);
|
||||
// constexpr void destroy(ForwardIt, ForwardIt);
|
||||
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct Counted {
|
||||
static int count;
|
||||
static void reset() { count = 0; }
|
||||
Counted() { ++count; }
|
||||
Counted(Counted const&) { ++count; }
|
||||
~Counted() { --count; }
|
||||
friend void operator&(Counted) = delete;
|
||||
int* counter_;
|
||||
TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; }
|
||||
TEST_CONSTEXPR Counted(Counted const& other) : counter_(other.counter_) { ++*counter_; }
|
||||
TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; }
|
||||
friend void operator&(Counted) = delete;
|
||||
};
|
||||
int Counted::count = 0;
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
using Alloc = std::allocator<Counted>;
|
||||
int counter = 0;
|
||||
int const N = 5;
|
||||
Alloc alloc;
|
||||
Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, N);
|
||||
|
||||
for (Counted* p = pool; p != pool + N; ++p)
|
||||
std::allocator_traits<Alloc>::construct(alloc, p, &counter);
|
||||
assert(counter == 5);
|
||||
|
||||
std::destroy(pool, pool + 1);
|
||||
assert(counter == 4);
|
||||
|
||||
std::destroy(forward_iterator<Counted*>(pool + 1), forward_iterator<Counted*>(pool + 5));
|
||||
assert(counter == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, pool, N);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using It = forward_iterator<Counted*>;
|
||||
const int N = 5;
|
||||
alignas(Counted) char pool[sizeof(Counted)*N] = {};
|
||||
Counted* p = (Counted*)pool;
|
||||
std::uninitialized_fill(p, p+N, Counted());
|
||||
assert(Counted::count == 5);
|
||||
std::destroy(p, p+1);
|
||||
p += 1;
|
||||
assert(Counted::count == 4);
|
||||
std::destroy(It(p), It(p + 4));
|
||||
assert(Counted::count == 0);
|
||||
|
||||
return 0;
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,72 +10,84 @@
|
|||
|
||||
// <memory>
|
||||
|
||||
// template <class _Tp>
|
||||
// void destroy_at(_Tp*);
|
||||
// template <class T>
|
||||
// constexpr void destroy_at(T*);
|
||||
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct Counted {
|
||||
static int count;
|
||||
static void reset() { count = 0; }
|
||||
Counted() { ++count; }
|
||||
Counted(Counted const&) { ++count; }
|
||||
~Counted() { --count; }
|
||||
friend void operator&(Counted) = delete;
|
||||
int* counter_;
|
||||
TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; }
|
||||
TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; }
|
||||
friend void operator&(Counted) = delete;
|
||||
};
|
||||
int Counted::count = 0;
|
||||
|
||||
struct VCounted {
|
||||
static int count;
|
||||
static void reset() { count = 0; }
|
||||
VCounted() { ++count; }
|
||||
VCounted(VCounted const&) { ++count; }
|
||||
virtual ~VCounted() { --count; }
|
||||
friend void operator&(VCounted) = delete;
|
||||
struct VirtualCounted {
|
||||
int* counter_;
|
||||
TEST_CONSTEXPR VirtualCounted(int* counter) : counter_(counter) { ++*counter_; }
|
||||
TEST_CONSTEXPR_CXX20 virtual ~VirtualCounted() { --*counter_; }
|
||||
friend void operator&(VirtualCounted) = delete;
|
||||
};
|
||||
int VCounted::count = 0;
|
||||
|
||||
struct DCounted : VCounted {
|
||||
friend void operator&(DCounted) = delete;
|
||||
struct DerivedCounted : VirtualCounted {
|
||||
TEST_CONSTEXPR DerivedCounted(int* counter) : VirtualCounted(counter) { }
|
||||
friend void operator&(DerivedCounted) = delete;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
{
|
||||
using Alloc = std::allocator<Counted>;
|
||||
Alloc alloc;
|
||||
Counted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
Counted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
|
||||
int counter = 0;
|
||||
std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter);
|
||||
std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter);
|
||||
assert(counter == 2);
|
||||
|
||||
std::destroy_at(ptr1);
|
||||
assert(counter == 1);
|
||||
|
||||
std::destroy_at(ptr2);
|
||||
assert(counter == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1);
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1);
|
||||
}
|
||||
{
|
||||
using Alloc = std::allocator<DerivedCounted>;
|
||||
Alloc alloc;
|
||||
DerivedCounted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
DerivedCounted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1);
|
||||
|
||||
int counter = 0;
|
||||
std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter);
|
||||
std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter);
|
||||
assert(counter == 2);
|
||||
|
||||
std::destroy_at(ptr1);
|
||||
assert(counter == 1);
|
||||
|
||||
std::destroy_at(ptr2);
|
||||
assert(counter == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1);
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
void* mem1 = std::malloc(sizeof(Counted));
|
||||
void* mem2 = std::malloc(sizeof(Counted));
|
||||
assert(mem1 && mem2);
|
||||
assert(Counted::count == 0);
|
||||
Counted* ptr1 = ::new(mem1) Counted();
|
||||
Counted* ptr2 = ::new(mem2) Counted();
|
||||
assert(Counted::count == 2);
|
||||
std::destroy_at(ptr1);
|
||||
assert(Counted::count == 1);
|
||||
std::destroy_at(ptr2);
|
||||
assert(Counted::count == 0);
|
||||
std::free(mem1);
|
||||
std::free(mem2);
|
||||
}
|
||||
{
|
||||
void* mem1 = std::malloc(sizeof(DCounted));
|
||||
void* mem2 = std::malloc(sizeof(DCounted));
|
||||
assert(mem1 && mem2);
|
||||
assert(DCounted::count == 0);
|
||||
DCounted* ptr1 = ::new(mem1) DCounted();
|
||||
DCounted* ptr2 = ::new(mem2) DCounted();
|
||||
assert(DCounted::count == 2);
|
||||
assert(VCounted::count == 2);
|
||||
std::destroy_at(ptr1);
|
||||
assert(VCounted::count == 1);
|
||||
std::destroy_at(ptr2);
|
||||
assert(VCounted::count == 0);
|
||||
std::free(mem1);
|
||||
std::free(mem2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,40 +11,52 @@
|
|||
// <memory>
|
||||
|
||||
// template <class ForwardIt, class Size>
|
||||
// ForwardIt destroy_n(ForwardIt, Size s);
|
||||
// constexpr ForwardIt destroy_n(ForwardIt, Size s);
|
||||
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct Counted {
|
||||
static int count;
|
||||
static void reset() { count = 0; }
|
||||
Counted() { ++count; }
|
||||
Counted(Counted const&) { ++count; }
|
||||
~Counted() { --count; }
|
||||
friend void operator&(Counted) = delete;
|
||||
int* counter_;
|
||||
TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; }
|
||||
TEST_CONSTEXPR Counted(Counted const& other) : counter_(other.counter_) { ++*counter_; }
|
||||
TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; }
|
||||
friend void operator&(Counted) = delete;
|
||||
};
|
||||
int Counted::count = 0;
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
using Alloc = std::allocator<Counted>;
|
||||
int counter = 0;
|
||||
int const N = 5;
|
||||
Alloc alloc;
|
||||
Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, N);
|
||||
|
||||
for (Counted* p = pool; p != pool + N; ++p)
|
||||
std::allocator_traits<Alloc>::construct(alloc, p, &counter);
|
||||
assert(counter == 5);
|
||||
|
||||
Counted* np = std::destroy_n(pool, 1);
|
||||
assert(np == pool + 1);
|
||||
assert(counter == 4);
|
||||
|
||||
forward_iterator<Counted*> it = std::destroy_n(forward_iterator<Counted*>(pool + 1), 4);
|
||||
assert(it == forward_iterator<Counted*>(pool + 5));
|
||||
assert(counter == 0);
|
||||
|
||||
std::allocator_traits<Alloc>::deallocate(alloc, pool, N);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using It = forward_iterator<Counted*>;
|
||||
const int N = 5;
|
||||
alignas(Counted) char pool[sizeof(Counted)*N] = {};
|
||||
Counted* p = (Counted*)pool;
|
||||
std::uninitialized_fill(p, p+N, Counted());
|
||||
assert(Counted::count == 5);
|
||||
Counted* np = std::destroy_n(p, 1);
|
||||
assert(np == p+1);
|
||||
assert(Counted::count == 4);
|
||||
p += 1;
|
||||
It it = std::destroy_n(It(p), 4);
|
||||
assert(it == It(p+4));
|
||||
assert(Counted::count == 0);
|
||||
|
||||
return 0;
|
||||
test();
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -664,6 +664,12 @@ feature_test_macros = sorted([ add_version_header(x) for x in [
|
|||
"depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
||||
"internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
||||
},
|
||||
{"name": "__cpp_lib_constexpr_dynamic_alloc",
|
||||
"values": {
|
||||
"c++2a": int(201907)
|
||||
},
|
||||
"headers": ["memory"]
|
||||
},
|
||||
]], key=lambda tc: tc["name"])
|
||||
|
||||
def get_std_dialects():
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<tr><td><a href="https://wg21.link/P0631">P0631</a></td><td>LWG</td><td>Math Constants</td><td>Cologne</td><td>Complete</td><td>11.0</td></tr>
|
||||
<tr><td><a href="https://wg21.link/P0645">P0645</a></td><td>LWG</td><td>Text Formatting</td><td>Cologne</td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/P0660">P0660</a></td><td>LWG</td><td>Stop Token and Joining Thread, Rev 10</td><td>Cologne</td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/P0784">P0784</a></td><td>CWG</td><td>More constexpr containers</td><td>Cologne</td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/P0784">P0784</a></td><td>CWG</td><td>More constexpr containers</td><td>Cologne</td><td>Complete</td><td>12.0</td></tr>
|
||||
<tr><td><a href="https://wg21.link/P0980">P0980</a></td><td>LWG</td><td>Making std::string constexpr</td><td>Cologne</td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/P1004">P1004</a></td><td>LWG</td><td>Making std::vector constexpr</td><td>Cologne</td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/P1035">P1035</a></td><td>LWG</td><td>Input Range Adaptors</td><td>Cologne</td><td></td><td></td></tr>
|
||||
|
|
Loading…
Reference in New Issue