[libcxx-commits] [libcxx] 0724f8b - [libc++] Implement C++20's P0784 (More constexpr containers)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 22 08:20:45 PDT 2020
Author: Louis Dionne
Date: 2020-09-22T11:20:33-04:00
New Revision: 0724f8bf47f8cb073d41e2750d45d5b05e66bf0b
URL: https://github.com/llvm/llvm-project/commit/0724f8bf47f8cb073d41e2750d45d5b05e66bf0b
DIFF: https://github.com/llvm/llvm-project/commit/0724f8bf47f8cb073d41e2750d45d5b05e66bf0b.diff
LOG: [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
Added:
libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp
libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/include/memory
libcxx/include/new
libcxx/include/version
libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp
libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp
libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp
libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp
libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
libcxx/www/cxx2a_status.html
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 66162d73727f..0f17a3a1bd54 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -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*
diff --git a/libcxx/include/memory b/libcxx/include/memory
index 0ce7d092a2e1..add0cc3e73dd 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -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));
diff --git a/libcxx/include/new b/libcxx/include/new
index 40d351e9b770..7db26b399229 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -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,37 +256,38 @@ inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t _
}
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 <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
- if (__is_overaligned_for_new(__align)) {
- const align_val_t __align_val = static_cast<align_val_t>(__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 <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
- if (__is_overaligned_for_new(__align)) {
- const align_val_t __align_val = static_cast<align_val_t>(__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 @@ struct _DeallocateCaller {
}
#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 @@ struct _DeallocateCaller {
}
#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);
+ 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_val_t>(__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_val_t>(__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
index d18da3d14690..3355e2d18c56 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -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
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
index cc9e1405b032..17becf2e5a28 100644
--- 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 @@ struct move_only
int main(int, char**)
{
std::vector<move_only> v;
- std::vector<move_only> copy = v; // expected-error at memory:* {{call to implicitly-deleted copy constructor of 'move_only'}}
+ std::vector<move_only> copy = v; // expected-error-re at 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
index 0117fd83a60c..511c688099fb 100644
--- 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
index 46b2e1f21d18..86579298afdb 100644
--- 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
index 9f923074d26b..ab354f42a1d8 100644
--- 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 <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;
}
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
index c6e03cb2ff5e..b1fc7a6bf637 100644
--- 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 <class Alloc>
// 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
index e95247163988..a8205f7d884b 100644
--- 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 <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;
+};
-int main(int, char**)
+TEST_CONSTEXPR_CXX20 bool test()
{
#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)));
- }
+ {
+ 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) == 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)));
- }
+ {
+ 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;
+}
+
- 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
index 67a2e8f4ac8b..10e8879012fc 100644
--- 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 <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;
}
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
index cc2abda6da0a..fd066b97b0f5 100644
--- 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 <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;
}
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
index 70890d8512fd..047b7c1836df 100644
--- 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 <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;
-};
+ TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
+ {
+ return std::allocator<T>().allocate(n);
+ }
-int b_destroy = 0;
+ TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
+ {
+ return std::allocator<T>().deallocate(p, n);
+ }
+};
template <class T>
-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<T>().allocate(n);
+ }
+
+ TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
+ {
+ return std::allocator<T>().deallocate(p, n);
+ }
+
template <class U>
- 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<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 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* VT;
- typedef A<VT> Alloc;
- Alloc a;
- std::aligned_storage<sizeof(VT)>::type store;
- std::allocator_traits<Alloc>::destroy(a, (VT*)&store);
+ 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);
}
-#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);
+ 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);
}
-#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
index b758c9add8c0..301078e51549 100644
--- 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 <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;
}
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
index be837670dd3f..231f173f5deb 100644
--- 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 <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;
}
diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp
new file mode 100644
index 000000000000..d97abb160740
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp
@@ -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;
+}
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
index 30f847a4cad5..0f568d6cf18b 100644
--- 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 <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;
}
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
index 000000000000..f12b6808edeb
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <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;
+}
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
index ff5287dc81a7..49c7a0b3aad8 100644
--- 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 @@
// <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;
}
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
index 48419174b661..42013de1ccdf 100644
--- 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 @@
// <memory>
// allocator:
-// T* allocate(size_t n);
+// constexpr T* allocate(size_t n);
#include <memory>
#include <cassert>
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
index 2265ed3d66fa..95ac415e3704 100644
--- 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 <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>::
diff erence_type, std::ptr
diff _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;
}
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
index 000000000000..ac0c8a138115
--- /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
+
+// <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;
+}
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
index 14651dd9c7ee..be23a43d884e 100644
--- 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 @@
// <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;
}
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
index 4c6da6dedc74..d3d1bac1376e 100644
--- 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 @@
// <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;
};
-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<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);
}
{
- 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<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 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
index 4f60367fe735..60f17331f269 100644
--- 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 @@
// <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;
}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 2eecc0d5591c..1547443cffea 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -664,6 +664,12 @@ def add_version_header(tc):
"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
index 88df02bcb117..d1bf4744b495 100644
--- a/libcxx/www/cxx2a_status.html
+++ b/libcxx/www/cxx2a_status.html
@@ -164,7 +164,7 @@ <h3>Paper Status</h3>
<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>
More information about the libcxx-commits
mailing list