diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1010,6 +1010,14 @@ # define _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_IS_CONSTANT_EVALUATED #endif +#if _LIBCPP_STD_VER > 17 && \ + !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR) && \ + defined(__cpp_constexpr_dynamic_alloc) +# define _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC constexpr +#else +# define _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC +#endif + // The _LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other // NODISCARD macros to the correct attribute. #if __has_cpp_attribute(nodiscard) || defined(_LIBCPP_COMPILER_MSVC) diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -135,7 +135,7 @@ constexpr allocator(const allocator&) noexcept; // constexpr in C++20 template constexpr allocator(const allocator&) noexcept; // constexpr in C++20 - ~allocator(); + constexpr ~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 @@ -149,10 +149,10 @@ }; template -bool operator==(const allocator&, const allocator&) noexcept; +constexpr bool operator==(const allocator&, const allocator&) noexcept; // constexpr in C++20 template -bool operator!=(const allocator&, const allocator&) noexcept; +constexpr bool operator!=(const allocator&, const allocator&) noexcept; // constexpr in C++20 template class raw_storage_iterator @@ -1866,7 +1866,9 @@ {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_WITH_CONSTEXPR_DYNAMIC_ALLOC + _Tp* allocate(size_t __n) { // TODO(mpark): Replace with `allocator_traits::max_size(*this)`. if (__n > (size_t(~0) / sizeof(_Tp))) @@ -1880,16 +1882,19 @@ _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_WITH_CONSTEXPR_DYNAMIC_ALLOC + 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) - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) template _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC void construct(_Up* __p, _Args&&... __args) { @@ -1948,7 +1953,9 @@ ::new((void*)__p) _Tp(__a0, __a1); } #endif // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY void destroy(pointer __p) {__p->~_Tp();} + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + void destroy(pointer __p) {__p->~_Tp();} #endif }; @@ -1985,7 +1992,9 @@ {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_WITH_CONSTEXPR_DYNAMIC_ALLOC + const _Tp* allocate(size_t __n) { // TODO(mpark): Replace with `allocator_traits::max_size(*this)`. if (__n > (size_t(~0) / sizeof(_Tp))) @@ -1999,16 +2008,19 @@ 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_WITH_CONSTEXPR_DYNAMIC_ALLOC + 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) - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) template _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC void construct(_Up* __p, _Args&&... __args) { @@ -2067,16 +2079,18 @@ ::new((void*) const_cast<_Tp *>(__p)) _Tp(__a0, __a1); } #endif // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY void destroy(pointer __p) {__p->~_Tp();} + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + void destroy(pointer __p) {__p->~_Tp();} #endif }; 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 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_WITH_CONSTEXPR_DYNAMIC_ALLOC +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,7 +256,40 @@ } struct _DeallocateCaller { - static inline _LIBCPP_INLINE_VISIBILITY + private: + template + static inline _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + 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 _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + 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 _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + void __do_call(void *__ptr) { +#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE + return ::operator delete(__ptr); +#else + return __builtin_operator_delete(__ptr); +#endif + } + + public: + static inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) { #if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) ((void)__align); @@ -286,7 +320,8 @@ } private: - static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) { + static inline _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + void __do_deallocate_handle_size(void* __ptr, size_t __size) { #ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION ((void)__size); return __do_call(__ptr); @@ -296,7 +331,8 @@ } #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION - static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) { + static inline _LIBCPP_CONSTEXPR_AFTER_CXX17_WITH_CONSTEXPR_DYNAMIC_ALLOC + 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); @@ -305,38 +341,10 @@ #endif } #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); -#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_WITH_CONSTEXPR_DYNAMIC_ALLOC +void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) { _DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align); } 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,24 @@ #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 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.fail.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.fail.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.fail.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.fail.cpp @@ -12,7 +12,7 @@ // // allocator: -// T* allocate(size_t n); +// constexpr T* allocate(size_t n); #include #include @@ -24,5 +24,14 @@ std::allocator a; a.allocate(3); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER > 17 && defined(__cpp_constexpr_dynamic_alloc) + static_assert([]() constexpr { // expected-error {{static_assert expression is not an integral constant expression}} + std::allocator a; + TEST_IGNORE_NODISCARD a.allocate(3); + + return true; + }()); +#endif + 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 && defined(__cpp_constexpr_dynamic_alloc) +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 && defined(__cpp_constexpr_dynamic_alloc) + 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.fail.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.fail.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 +// UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8 + +#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.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); // When back-deploying to macosx10.7, the RTTI for exception classes // incorrectly provided by libc++.dylib is mixed with the one in 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 @@ -27,7 +27,8 @@ #include "test_macros.h" -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool +test() { static_assert((std::is_same::value_type, char>::value), ""); @@ -43,5 +44,16 @@ std::allocator a3 = a2; ((void)a3); + return true; +} + +int main(int, char**) +{ + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; }