[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:
Louis Dionne 2020-09-17 12:06:13 -04:00
parent 89074bdc81
commit 0724f8bf47
27 changed files with 879 additions and 412 deletions

View File

@ -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*

View File

@ -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));

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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;
}

View File

@ -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);
// ...
// };

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -10,7 +10,7 @@
// <memory>
// allocator:
// T* allocate(size_t n);
// constexpr T* allocate(size_t n);
#include <memory>
#include <cassert>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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():

View File

@ -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>