diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -192,6 +192,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_concepts`` *unimplemented* ------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_dynamic_alloc`` ``201907L`` + ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_misc`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_swap_algorithms`` *unimplemented* diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -83,21 +83,19 @@ template using rebind_alloc = Alloc::rebind::other | Alloc; template using rebind_traits = allocator_traits>; - 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 - 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 - 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 @@ constexpr allocator(const allocator&) noexcept; // constexpr in C++20 template constexpr allocator(const allocator&) 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 void construct(U* p, Args&&... args); // deprecated in C++17, removed in C++20 @@ -149,10 +147,10 @@ }; template -bool operator==(const allocator&, const allocator&) noexcept; +bool operator==(const allocator&, const allocator&) noexcept; // constexpr in C++20 template -bool operator!=(const allocator&, const allocator&) noexcept; +bool operator!=(const allocator&, const allocator&) noexcept; // constexpr in C++20 template class raw_storage_iterator @@ -191,14 +189,17 @@ ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x); +template +constexpr T* construct_at(T* location, Args&& ...args); // since C++20 + template -void destroy_at(T* location); +void destroy_at(T* location); // constexpr in C++20 template - void destroy(ForwardIterator first, ForwardIterator last); +void destroy(ForwardIterator first, ForwardIterator last); // constexpr in C++20 template - ForwardIterator destroy_n(ForwardIterator first, Size n); +ForwardIterator destroy_n(ForwardIterator first, Size n); // constexpr in C++20 template ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result); @@ -886,6 +887,39 @@ #endif }; +// construct_at + +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_CONSTEXPR_AFTER_CXX17 void* __voidify(_Tp& __ptr) noexcept { + return const_cast(static_cast(_VSTD::addressof(__ptr))); +} + +template()) _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 +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 @@ -1390,34 +1424,34 @@ {typedef allocator_traits::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());} - _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 - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void construct(allocator_type& __a, _Tp* __p, _Args&&... __args) {__construct(__has_construct(), __a, __p, _VSTD::forward<_Args>(__args)...);} template - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void destroy(allocator_type& __a, _Tp* __p) {__destroy(__has_destroy(), __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(), __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 @@ 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 @@ 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 - _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 @@ } template - _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 - _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 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP } template - _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 @@ _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::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 @@ {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::max_size(*this)`. - if (__n > (size_t(~0) / sizeof(_Tp))) + if (__n > allocator_traits::max_size(*this)) __throw_length_error("allocator::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 @@ _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 @@ {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::max_size(*this)`. - if (__n > (size_t(~0) / sizeof(_Tp))) + if (__n > allocator_traits::max_size(*this)) __throw_length_error("allocator::allocate(size_t n)" " 'n' exceeds maximum supported size"); return static_cast(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); @@ -1729,7 +1772,8 @@ 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 @@ }; template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;} template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator!=(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return false;} template @@ -2938,22 +2982,15 @@ #if _LIBCPP_STD_VER > 14 -template -inline _LIBCPP_INLINE_VISIBILITY -void destroy_at(_Tp* __loc) { - _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); - __loc->~_Tp(); -} - template -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 -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)); diff --git a/libcxx/include/new b/libcxx/include/new --- a/libcxx/include/new +++ b/libcxx/include/new @@ -234,7 +234,8 @@ #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); @@ -255,37 +256,38 @@ } struct _DeallocateCaller { - static inline _LIBCPP_INLINE_VISIBILITY - void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) { -#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) - ((void)__align); - return __do_deallocate_handle_size(__ptr, __size); + template + _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 - if (__is_overaligned_for_new(__align)) { - const align_val_t __align_val = static_cast(__align); - return __do_deallocate_handle_size(__ptr, __size, __align_val); - } else { - return __do_deallocate_handle_size(__ptr, __size); - } + return __builtin_operator_delete(__ptr, __a1, __a2); #endif } - static inline _LIBCPP_INLINE_VISIBILITY - void __do_deallocate_handle_align(void *__ptr, size_t __align) { -#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) - ((void)__align); - return __do_call(__ptr); + template + _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 - if (__is_overaligned_for_new(__align)) { - const align_val_t __align_val = static_cast(__align); - return __do_call(__ptr, __align_val); - } else { - return __do_call(__ptr); - } + 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 } - private: + _LIBCPP_CONSTEXPR_AFTER_CXX17 static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) { #ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION ((void)__size); @@ -296,6 +298,7 @@ } #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); @@ -306,37 +309,39 @@ } #endif -private: - template - 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 - 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); + 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); + return __do_deallocate_handle_size(__ptr, __size); #else - return __builtin_operator_delete(__ptr, __a1); + if (__is_overaligned_for_new(__align)) { + const align_val_t __align_val = static_cast(__align); + return __do_deallocate_handle_size(__ptr, __size, __align_val); + } else { + return __do_deallocate_handle_size(__ptr, __size); + } #endif } - static inline void __do_call(void *__ptr) { -#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE - return ::operator delete(__ptr); + 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); + return __do_call(__ptr); #else - return __builtin_operator_delete(__ptr); + if (__is_overaligned_for_new(__align)) { + const align_val_t __align_val = static_cast(__align); + return __do_call(__ptr, __align_val); + } else { + return __do_call(__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); } diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -45,6 +45,7 @@ __cpp_lib_clamp 201603L __cpp_lib_complex_udls 201309L __cpp_lib_concepts 201806L +__cpp_lib_constexpr_dynamic_alloc 201907L __cpp_lib_constexpr_misc 201811L __cpp_lib_constexpr_swap_algorithms 201806L @@ -250,6 +251,7 @@ # 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 diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp @@ -22,6 +22,6 @@ int main(int, char**) { std::vector v; - std::vector copy = v; // expected-error@memory:* {{call to implicitly-deleted copy constructor of 'move_only'}} + std::vector 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; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp @@ -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 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -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" diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp @@ -11,7 +11,7 @@ // template // 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 @@ { 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(static_cast(0xDEADBEEF)); + return &storage; } + + value_type storage; }; +TEST_CONSTEXPR_CXX20 bool test() +{ + { + A a; + assert(std::allocator_traits >::allocate(a, 10) == &a.storage); + } + { + typedef A Alloc; + Alloc a; + assert(std::allocator_traits::allocate(a, 10) == &a.storage); + } + + return true; +} + int main(int, char**) { - { - A a; - assert(std::allocator_traits >::allocate(a, 10) == reinterpret_cast(static_cast(0xDEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef A Alloc; - Alloc a; - assert(std::allocator_traits::allocate(a, 10) == reinterpret_cast(static_cast(0xDEADBEEF))); - } - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp @@ -11,7 +11,7 @@ // template // struct allocator_traits // { -// static pointer allocate(allocator_type& a, size_type n); +// static constexpr pointer allocate(allocator_type& a, size_type n); // ... // }; diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp @@ -11,7 +11,7 @@ // template // 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 @@ { 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(static_cast(0xDEADBEEF)); + return &storage; } + + value_type storage; }; template @@ -39,44 +43,48 @@ { typedef T value_type; - value_type* allocate(std::size_t n) - { - assert(n == 12); - return reinterpret_cast(static_cast(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(static_cast(0xFEADBEEF)); + assert(p == nullptr); + return &storage; } -}; + value_type storage; +}; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { #if TEST_STD_VER >= 11 - { - A a; - assert(std::allocator_traits >::allocate(a, 10, nullptr) == reinterpret_cast(static_cast(0xDEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef A Alloc; - Alloc a; - assert(std::allocator_traits::allocate(a, 10, nullptr) == reinterpret_cast(static_cast(0xDEADBEEF))); - } + { + A a; + assert(std::allocator_traits >::allocate(a, 10, nullptr) == &a.storage); + } + { + typedef A Alloc; + Alloc a; + assert(std::allocator_traits::allocate(a, 10, nullptr) == &a.storage); + } #endif - { - B b; - assert(std::allocator_traits >::allocate(b, 11, nullptr) == reinterpret_cast(static_cast(0xFEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef B Alloc; - Alloc b; - assert(std::allocator_traits::allocate(b, 11, nullptr) == reinterpret_cast(static_cast(0xFEADBEEF))); - } + { + B b; + assert(std::allocator_traits >::allocate(b, 11, nullptr) == &b.storage); + } + { + typedef B Alloc; + Alloc b; + assert(std::allocator_traits::allocate(b, 11, nullptr) == &b.storage); + } + + return true; +} + - return 0; +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp @@ -12,7 +12,7 @@ // struct allocator_traits // { // template -// 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 @@ }; -int b_construct = 0; - template struct B { typedef T value_type; + TEST_CONSTEXPR_CXX20 B(int& count) : count(count) {} + #if TEST_STD_VER >= 11 template - 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)...); +#else ::new ((void*)p) U(std::forward(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 a; - std::aligned_storage::type a0; - assert(A0::count == 0); - std::allocator_traits >::construct(a, (A0*)&a0); - assert(A0::count == 1); + int A0_count = 0; + A a; + std::allocator alloc; + A0* a0 = alloc.allocate(1); + assert(A0_count == 0); + std::allocator_traits >::construct(a, a0, &A0_count); + assert(A0_count == 1); + alloc.deallocate(a0, 1); } { - A1::count = 0; - A a; - std::aligned_storage::type a1; - assert(A1::count == 0); - std::allocator_traits >::construct(a, (A1*)&a1, 'c'); - assert(A1::count == 1); + int A1_count = 0; + A a; + std::allocator alloc; + A1* a1 = alloc.allocate(1); + assert(A1_count == 0); + std::allocator_traits >::construct(a, a1, &A1_count, 'c'); + assert(A1_count == 1); + alloc.deallocate(a1, 1); } { - A2::count = 0; - A a; - std::aligned_storage::type a2; - assert(A2::count == 0); - std::allocator_traits >::construct(a, (A2*)&a2, 'd', 5); - assert(A2::count == 1); + int A2_count = 0; + A a; + std::allocator alloc; + A2* a2 = alloc.allocate(1); + assert(A2_count == 0); + std::allocator_traits >::construct(a, a2, &A2_count, 'd', 5); + assert(A2_count == 1); + alloc.deallocate(a2, 1); } { typedef IncompleteHolder* VT; typedef A Alloc; Alloc a; - std::aligned_storage::type store; - std::allocator_traits::construct(a, (VT*)&store, nullptr); + std::allocator alloc; + VT* vt = alloc.allocate(1); + std::allocator_traits::construct(a, vt, nullptr); + alloc.deallocate(vt, 1); } + #if TEST_STD_VER >= 11 { - A0::count = 0; - b_construct = 0; - B b; - std::aligned_storage::type a0; - assert(A0::count == 0); + int A0_count = 0; + int b_construct = 0; + B b(b_construct); + std::allocator alloc; + A0* a0 = alloc.allocate(1); + assert(A0_count == 0); assert(b_construct == 0); - std::allocator_traits >::construct(b, (A0*)&a0); - assert(A0::count == 1); + std::allocator_traits >::construct(b, a0, &A0_count); + assert(A0_count == 1); assert(b_construct == 1); + alloc.deallocate(a0, 1); } { - A1::count = 0; - b_construct = 0; - B b; - std::aligned_storage::type a1; - assert(A1::count == 0); + int A1_count = 0; + int b_construct = 0; + B b(b_construct); + std::allocator alloc; + A1* a1 = alloc.allocate(1); + assert(A1_count == 0); assert(b_construct == 0); - std::allocator_traits >::construct(b, (A1*)&a1, 'c'); - assert(A1::count == 1); + std::allocator_traits >::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 b; - std::aligned_storage::type a2; - assert(A2::count == 0); + int A2_count = 0; + int b_construct = 0; + B b(b_construct); + std::allocator alloc; + A2* a2 = alloc.allocate(1); + assert(A2_count == 0); assert(b_construct == 0); - std::allocator_traits >::construct(b, (A2*)&a2, 'd', 5); - assert(A2::count == 1); + std::allocator_traits >::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; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp @@ -11,47 +11,60 @@ // template // 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 -#include #include +#include #include "test_macros.h" #include "incomplete_type_helper.h" -int called = 0; - template 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(static_cast(0xDEADBEEF))); + assert(p == &storage); assert(n == 10); ++called; } + + int& called; + + value_type storage; }; +TEST_CONSTEXPR_CXX20 bool test() +{ + { + int called = 0; + A a(called); + std::allocator_traits >::deallocate(a, &a.storage, 10); + assert(called == 1); + } + { + int called = 0; + typedef A Alloc; + Alloc a(called); + std::allocator_traits::deallocate(a, &a.storage, 10); + assert(called == 1); + } + + return true; +} + int main(int, char**) { - { - A a; - std::allocator_traits >::deallocate(a, reinterpret_cast(static_cast(0xDEADBEEF)), 10); - assert(called == 1); - } - called = 0; - { - typedef IncompleteHolder* VT; - typedef A Alloc; - Alloc a; - std::allocator_traits::deallocate(a, reinterpret_cast(static_cast(0xDEADBEEF)), 10); - assert(called == 1); - } - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp @@ -12,80 +12,123 @@ // struct allocator_traits // { // template -// static void destroy(allocator_type& a, Ptr p); +// static constexpr void destroy(allocator_type& a, Ptr p); // ... // }; #include -#include -#include #include +#include #include "test_macros.h" #include "incomplete_type_helper.h" template -struct A +struct NoDestroy { typedef T value_type; -}; + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) + { + return std::allocator().allocate(n); + } -int b_destroy = 0; + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) + { + return std::allocator().deallocate(p, n); + } +}; template -struct B +struct CountDestroy { + TEST_CONSTEXPR explicit CountDestroy(int* counter) + : counter_(counter) + { } + typedef T value_type; + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) + { + return std::allocator().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) + { + return std::allocator().deallocate(p, n); + } + template - void destroy(U* p) + TEST_CONSTEXPR_CXX20 void destroy(U* p) { - ++b_destroy; + ++*counter_; p->~U(); } + + int* counter_; }; -struct A0 +struct CountDestructor { - static int count; - ~A0() {++count;} -}; + TEST_CONSTEXPR explicit CountDestructor(int* counter) + : counter_(counter) + { } -int A0::count = 0; + TEST_CONSTEXPR_CXX20 ~CountDestructor() { ++*counter_; } -int main(int, char**) + int* counter_; +}; + +TEST_CONSTEXPR_CXX20 bool test() { { - A0::count = 0; - A a; - std::aligned_storage::type a0; - std::allocator_traits >::construct(a, (A0*)&a0); - assert(A0::count == 0); - std::allocator_traits >::destroy(a, (A0*)&a0); - assert(A0::count == 1); + typedef NoDestroy Alloc; + int destructors = 0; + Alloc alloc; + CountDestructor* pool = std::allocator_traits::allocate(alloc, 1); + + std::allocator_traits::construct(alloc, pool, &destructors); + assert(destructors == 0); + + std::allocator_traits::destroy(alloc, pool); + assert(destructors == 1); + + std::allocator_traits::deallocate(alloc, pool, 1); } { - typedef IncompleteHolder* VT; - typedef A Alloc; - Alloc a; - std::aligned_storage::type store; - std::allocator_traits::destroy(a, (VT*)&store); + typedef IncompleteHolder* T; + typedef NoDestroy Alloc; + Alloc alloc; + T* pool = std::allocator_traits::allocate(alloc, 1); + std::allocator_traits::construct(alloc, pool, nullptr); + std::allocator_traits::destroy(alloc, pool); + std::allocator_traits::deallocate(alloc, pool, 1); } -#if defined(_LIBCPP_VERSION) || TEST_STD_VER >= 11 { - A0::count = 0; - b_destroy = 0; - B b; - std::aligned_storage::type a0; - std::allocator_traits >::construct(b, (A0*)&a0); - assert(A0::count == 0); - assert(b_destroy == 0); - std::allocator_traits >::destroy(b, (A0*)&a0); - assert(A0::count == 1); - assert(b_destroy == 1); + typedef CountDestroy Alloc; + int destroys_called = 0; + int destructors_called = 0; + Alloc alloc(&destroys_called); + + CountDestructor* pool = std::allocator_traits::allocate(alloc, 1); + std::allocator_traits::construct(alloc, pool, &destructors_called); + assert(destroys_called == 0); + assert(destructors_called == 0); + + std::allocator_traits::destroy(alloc, pool); + assert(destroys_called == 1); + assert(destructors_called == 1); + + std::allocator_traits::deallocate(alloc, pool, 1); } -#endif + return true; +} - return 0; +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp @@ -11,7 +11,7 @@ // template // 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 @@ { 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 b; @@ -75,5 +75,16 @@ } #endif - return 0; + return true; +} + +int main(int, char**) +{ + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + + return 0; } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp @@ -11,7 +11,7 @@ // template // struct allocator_traits // { -// static allocator_type +// static constexpr allocator_type // select_on_container_copy_construction(const allocator_type& a); // ... // }; @@ -29,7 +29,7 @@ { 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 @@ 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 a; @@ -74,5 +74,14 @@ } #endif - return 0; + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp copy from libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp copy to libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp @@ -6,29 +6,30 @@ // //===----------------------------------------------------------------------===// -// +// UNSUPPORTED: c++03, c++11, c++14, c++17 -// allocator: - -// template -// bool -// operator==(const allocator&, const allocator&) throw(); -// -// template -// bool -// operator!=(const allocator&, const allocator&) throw(); +// template +// constexpr allocator::~allocator(); #include -#include -#include "test_macros.h" + +template +constexpr bool test() { + std::allocator alloc; + (void)alloc; + + // destructor called here + return true; +} int main(int, char**) { - std::allocator a1; - std::allocator a2; - assert(a1 == a2); - assert(!(a1 != a2)); + test(); + test(); + + static_assert(test()); + static_assert(test()); - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp @@ -11,11 +11,11 @@ // allocator: // template -// bool +// constexpr bool // operator==(const allocator&, const allocator&) throw(); // // template -// bool +// constexpr bool // operator!=(const allocator&, const allocator&) throw(); #include @@ -23,12 +23,23 @@ #include "test_macros.h" -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { std::allocator a1; std::allocator 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; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp @@ -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 +// +//===----------------------------------------------------------------------===// + +// + +// allocator: +// constexpr T* allocate(size_type n); + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include + +#include "test_macros.h" + +template +constexpr bool test() +{ + typedef std::allocator A; + typedef std::allocator_traits 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()); // expected-error {{static_assert expression is not an integral constant expression}} + LIBCPP_STATIC_ASSERT(test()); // expected-error {{static_assert expression is not an integral constant expression}} + return 0; +} diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp @@ -9,7 +9,7 @@ // // allocator: -// T* allocate(size_t n); +// constexpr T* allocate(size_t n); #include #include @@ -77,6 +77,18 @@ } } +#if TEST_STD_VER > 17 +template +constexpr bool test_aligned_constexpr() { + typedef AlignedType T; + std::allocator 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 @@ test_aligned(); test_aligned(); +#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()); + static_assert(test_aligned_constexpr()); + static_assert(test_aligned_constexpr()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp @@ -10,7 +10,7 @@ // // allocator: -// T* allocate(size_t n); +// constexpr T* allocate(size_t n); #include #include diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" template -void check() +TEST_CONSTEXPR_CXX20 bool test() { static_assert((std::is_same::size_type, std::size_t>::value), ""); static_assert((std::is_same::difference_type, std::ptrdiff_t>::value), ""); @@ -43,11 +43,17 @@ a2 = a; std::allocator a3 = a2; (void)a3; + + return true; } int main(int, char**) { - check(); - check(); + test(); + test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp @@ -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 + +// + +// template +// constexpr T* construct_at(T* location, Args&& ...args); + +#include +#include + + +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 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 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 +constexpr bool test_sfinae(int) { return false; } +template +constexpr bool test_sfinae(...) { return true; } +static_assert(test_sfinae(int())); + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp @@ -11,38 +11,50 @@ // // template -// void destroy(ForwardIt, ForwardIt); +// constexpr void destroy(ForwardIt, ForwardIt); #include -#include #include #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; + int counter = 0; + int const N = 5; + Alloc alloc; + Counted* pool = std::allocator_traits::allocate(alloc, N); + + for (Counted* p = pool; p != pool + N; ++p) + std::allocator_traits::construct(alloc, p, &counter); + assert(counter == 5); + + std::destroy(pool, pool + 1); + assert(counter == 4); + + std::destroy(forward_iterator(pool + 1), forward_iterator(pool + 5)); + assert(counter == 0); + + std::allocator_traits::deallocate(alloc, pool, N); + + return true; +} int main(int, char**) { - using It = forward_iterator; - 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; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp @@ -10,72 +10,84 @@ // -// template -// void destroy_at(_Tp*); +// template +// constexpr void destroy_at(T*); #include -#include #include #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; }; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { - 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); + using Alloc = std::allocator; + Alloc alloc; + Counted* ptr1 = std::allocator_traits::allocate(alloc, 1); + Counted* ptr2 = std::allocator_traits::allocate(alloc, 1); + + int counter = 0; + std::allocator_traits::construct(alloc, ptr1, &counter); + std::allocator_traits::construct(alloc, ptr2, &counter); + assert(counter == 2); + + std::destroy_at(ptr1); + assert(counter == 1); + + std::destroy_at(ptr2); + assert(counter == 0); + + std::allocator_traits::deallocate(alloc, ptr1, 1); + std::allocator_traits::deallocate(alloc, ptr2, 1); } { - 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); + using Alloc = std::allocator; + Alloc alloc; + DerivedCounted* ptr1 = std::allocator_traits::allocate(alloc, 1); + DerivedCounted* ptr2 = std::allocator_traits::allocate(alloc, 1); + + int counter = 0; + std::allocator_traits::construct(alloc, ptr1, &counter); + std::allocator_traits::construct(alloc, ptr2, &counter); + assert(counter == 2); + + std::destroy_at(ptr1); + assert(counter == 1); + + std::destroy_at(ptr2); + assert(counter == 0); + + std::allocator_traits::deallocate(alloc, ptr1, 1); + std::allocator_traits::deallocate(alloc, ptr2, 1); } - return 0; + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp @@ -11,40 +11,52 @@ // // template -// ForwardIt destroy_n(ForwardIt, Size s); +// constexpr ForwardIt destroy_n(ForwardIt, Size s); #include -#include #include #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; + int counter = 0; + int const N = 5; + Alloc alloc; + Counted* pool = std::allocator_traits::allocate(alloc, N); + + for (Counted* p = pool; p != pool + N; ++p) + std::allocator_traits::construct(alloc, p, &counter); + assert(counter == 5); + + Counted* np = std::destroy_n(pool, 1); + assert(np == pool + 1); + assert(counter == 4); + + forward_iterator it = std::destroy_n(forward_iterator(pool + 1), 4); + assert(it == forward_iterator(pool + 5)); + assert(counter == 0); + + std::allocator_traits::deallocate(alloc, pool, N); + + return true; +} int main(int, char**) { - using It = forward_iterator; - 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; } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -664,6 +664,12 @@ "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(): diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -164,7 +164,7 @@ P0631LWGMath ConstantsCologneComplete11.0 P0645LWGText FormattingCologne P0660LWGStop Token and Joining Thread, Rev 10Cologne - P0784CWGMore constexpr containersCologne + P0784CWGMore constexpr containersCologneComplete12.0 P0980LWGMaking std::string constexprCologne P1004LWGMaking std::vector constexprCologne P1035LWGInput Range AdaptorsCologne