[libcxx-commits] [libcxx] 44cc797 - [libc++] P3369R0: constexpr for `uninitialized_default_construct` (#200163)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 12 18:57:01 PDT 2026
Author: A. Jiang
Date: 2026-06-13T09:56:56+08:00
New Revision: 44cc7971ff6d87e924abaf1ff12599e91d077faf
URL: https://github.com/llvm/llvm-project/commit/44cc7971ff6d87e924abaf1ff12599e91d077faf
DIFF: https://github.com/llvm/llvm-project/commit/44cc7971ff6d87e924abaf1ff12599e91d077faf.diff
LOG: [libc++] P3369R0: constexpr for `uninitialized_default_construct` (#200163)
Remarks:
- Tests also verify that `uninitialized_default_construct(_n)`
algorithms do not initialize trivially default-constructible elements
(`int` in these tests) to determined values during constant evaluation.
Added:
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/ReleaseNotes/23.rst
libcxx/docs/Status/Cxx2cPapers.csv
libcxx/include/__memory/ranges_uninitialized_algorithms.h
libcxx/include/__memory/uninitialized_algorithms.h
libcxx/include/version
libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct_n.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 1b748e37293df..8e26bdcd860c1 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -514,6 +514,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_ratio`` ``202306L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_raw_memory_algorithms`` ``202411L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_rcu`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_reference_wrapper`` ``202403L``
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index c8f7cf5455d92..7823c2db39867 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -50,6 +50,7 @@ Implemented Papers
- P4144R1: Remove ``span``'s ``initializer_list`` constructor for C++26 (`Github <https://llvm.org/PR189612>`__)
- P2542R8: ``views::concat`` (`Github <https://llvm.org/PR105419>`__)
- P3383R3: ``mdspan.at()`` (`Github <https://llvm.org/PR175213>`__)
+- P3369R0: constexpr for ``uninitialized_default_construct`` (`Github <https://llvm.org/PR118380>`__)
- P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__)
Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 2132e80251657..a951ac4c6c833 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -88,7 +88,7 @@
"`P2835R7 <https://wg21.link/P2835R7>`__","Expose ``std::atomic_ref``'s object address","2024-11 (Wrocław)","|Complete|","22","`#118377 <https://github.com/llvm/llvm-project/issues/118377>`__",""
"`P3323R1 <https://wg21.link/P3323R1>`__","cv-qualified types in ``atomic`` and ``atomic_ref``","2024-11 (Wrocław)","","","`#118378 <https://github.com/llvm/llvm-project/issues/118378>`__",""
"`P3508R0 <https://wg21.link/P3508R0>`__","Wording for ""constexpr for specialized memory algorithms""","2024-11 (Wrocław)","|Complete|","23","`#118379 <https://github.com/llvm/llvm-project/issues/118379>`__",""
-"`P3369R0 <https://wg21.link/P3369R0>`__","constexpr for ``uninitialized_default_construct``","2024-11 (Wrocław)","","","`#118380 <https://github.com/llvm/llvm-project/issues/118380>`__",""
+"`P3369R0 <https://wg21.link/P3369R0>`__","constexpr for ``uninitialized_default_construct``","2024-11 (Wrocław)","|Complete|","23","`#118380 <https://github.com/llvm/llvm-project/issues/118380>`__",""
"`P3370R1 <https://wg21.link/P3370R1>`__","Add new library headers from C23","2024-11 (Wrocław)","","","`#118381 <https://github.com/llvm/llvm-project/issues/118381>`__",""
"`P3309R3 <https://wg21.link/P3309R3>`__","constexpr ``atomic`` and ``atomic_ref``","2024-11 (Wrocław)","","","`#118382 <https://github.com/llvm/llvm-project/issues/118382>`__",""
"`P1928R15 <https://wg21.link/P1928R15>`__","``std::simd`` — merge data-parallel types from the Parallelism TS 2","2024-11 (Wrocław)","","","`#118384 <https://github.com/llvm/llvm-project/issues/118384>`__",""
diff --git a/libcxx/include/__memory/ranges_uninitialized_algorithms.h b/libcxx/include/__memory/ranges_uninitialized_algorithms.h
index 6cfc3924d53b5..796e6175af632 100644
--- a/libcxx/include/__memory/ranges_uninitialized_algorithms.h
+++ b/libcxx/include/__memory/ranges_uninitialized_algorithms.h
@@ -44,14 +44,16 @@ namespace ranges {
struct __uninitialized_default_construct {
template <__nothrow_forward_iterator _ForwardIterator, __nothrow_sentinel_for<_ForwardIterator> _Sentinel>
requires default_initializable<iter_value_t<_ForwardIterator>>
- _LIBCPP_HIDE_FROM_ABI _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
+ operator()(_ForwardIterator __first, _Sentinel __last) const {
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
return std::__uninitialized_default_construct<_ValueType>(std::move(__first), std::move(__last));
}
template <__nothrow_forward_range _ForwardRange>
requires default_initializable<range_value_t<_ForwardRange>>
- _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_iterator_t<_ForwardRange>
+ operator()(_ForwardRange&& __range) const {
return (*this)(ranges::begin(__range), ranges::end(__range));
}
};
@@ -65,7 +67,7 @@ inline constexpr auto uninitialized_default_construct = __uninitialized_default_
struct __uninitialized_default_construct_n {
template <__nothrow_forward_iterator _ForwardIterator>
requires default_initializable<iter_value_t<_ForwardIterator>>
- _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
operator()(_ForwardIterator __first, iter_
diff erence_t<_ForwardIterator> __n) const {
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
return std::__uninitialized_default_construct_n<_ValueType>(std::move(__first), __n);
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index 329b3df45dd70..45c8b71459eef 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -148,7 +148,7 @@ uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) {
// uninitialized_default_construct
template <class _ValueType, class _ForwardIterator, class _Sentinel>
-inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
__uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) {
auto __idx = __first;
auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); });
@@ -160,7 +160,8 @@ __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) {
}
template <class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
(void)std::__uninitialized_default_construct<_ValueType>(std::move(__first), std::move(__last));
}
@@ -168,7 +169,8 @@ inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterat
// uninitialized_default_construct_n
template <class _ValueType, class _ForwardIterator, class _Size>
-inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
+__uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
auto __idx = __first;
auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); });
for (; __n > 0; ++__idx, (void)--__n)
@@ -179,7 +181,8 @@ inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_
}
template <class _ForwardIterator, class _Size>
-inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
+uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
return std::__uninitialized_default_construct_n<_ValueType>(std::move(__first), __n);
}
diff --git a/libcxx/include/version b/libcxx/include/version
index d4d29b4d31a72..7f2dc9e4b72ab 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -224,7 +224,8 @@ __cpp_lib_ranges_stride 202207L <ranges>
__cpp_lib_ranges_to_container 202202L <ranges>
__cpp_lib_ranges_zip 202110L <ranges> <tuple> <utility>
__cpp_lib_ratio 202306L <ratio>
-__cpp_lib_raw_memory_algorithms 201606L <memory>
+__cpp_lib_raw_memory_algorithms 202411L <memory>
+ 201606L // C++17
__cpp_lib_rcu 202306L <rcu>
__cpp_lib_reference_from_temporary 202202L <type_traits>
__cpp_lib_reference_wrapper 202403L <functional>
@@ -619,6 +620,8 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_ranges_concat 202403L
# define __cpp_lib_ranges_indices 202506L
# define __cpp_lib_ratio 202306L
+# undef __cpp_lib_raw_memory_algorithms
+# define __cpp_lib_raw_memory_algorithms 202411L
// # define __cpp_lib_rcu 202306L
# define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202603L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index f287e1ad9b3ad..c58357a463ffd 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -623,8 +623,8 @@
# ifndef __cpp_lib_raw_memory_algorithms
# error "__cpp_lib_raw_memory_algorithms should be defined in c++26"
# endif
-# if __cpp_lib_raw_memory_algorithms != 201606L
-# error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++26"
+# if __cpp_lib_raw_memory_algorithms != 202411L
+# error "__cpp_lib_raw_memory_algorithms should have the value 202411L in c++26"
# endif
# ifndef __cpp_lib_shared_ptr_arrays
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 20c16700ef76a..d9c78b73f7e23 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7832,8 +7832,8 @@
# ifndef __cpp_lib_raw_memory_algorithms
# error "__cpp_lib_raw_memory_algorithms should be defined in c++26"
# endif
-# if __cpp_lib_raw_memory_algorithms != 201606L
-# error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++26"
+# if __cpp_lib_raw_memory_algorithms != 202411L
+# error "__cpp_lib_raw_memory_algorithms should have the value 202411L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
index ef969190c6314..69480a1af81a4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
@@ -22,6 +22,7 @@
#include <iterator>
#include <memory>
#include <ranges>
+#include <span>
#include <type_traits>
#include "../buffer.h"
@@ -39,6 +40,179 @@ struct NotDefaultCtrable { NotDefaultCtrable() = delete; };
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_default_construct),
NotDefaultCtrable*, NotDefaultCtrable*>);
+TEST_CONSTEXPR_CXX26 bool test() {
+ struct IntWrapper {
+ int n_ = 42;
+ };
+
+ // (iter, sentinel) overload.
+ {
+ constexpr int n = 3;
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+
+ std::ranges::uninitialized_default_construct(data, last);
+ for (int i = 0; i != n; ++i) {
+ data[i] = -i;
+ assert(data[i] == -i);
+ }
+
+ std::ranges::destroy(data, last);
+ alloc.deallocate(data, n);
+ }
+ // (range) overload.
+ {
+ constexpr int n = 3;
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ auto r = std::span<int>{data, n};
+
+ std::ranges::uninitialized_default_construct(r);
+ for (int i = 0; i != n; ++i) {
+ r[i] = -i;
+ assert(r[i] == -i);
+ }
+
+ std::ranges::destroy(r);
+ alloc.deallocate(data, n);
+ }
+ // (iter, sentinel) overload.
+ {
+ constexpr int n = 3;
+ std::allocator<IntWrapper> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+
+ std::ranges::uninitialized_default_construct(data, last);
+ for (int i = 0; i != n; ++i)
+ assert(data[i].n_ == 42);
+
+ std::ranges::destroy(data, last);
+ alloc.deallocate(data, n);
+ }
+ // (range) overload.
+ {
+ constexpr int n = 3;
+ std::allocator<IntWrapper> alloc;
+ auto data = alloc.allocate(n);
+ auto r = std::span<IntWrapper>{data, n};
+
+ std::ranges::uninitialized_default_construct(r);
+ for (int i = 0; i != n; ++i)
+ assert(r[i].n_ == 42);
+
+ std::ranges::destroy(r);
+ alloc.deallocate(data, n);
+ }
+
+ // (iter, sentinel) overload.
+ {
+ using It = forward_iterator<int*>;
+ constexpr int n = 5;
+ int pool[n]{-1, -1, -1, -1, -1};
+ int* p = pool;
+ int* pend = p + n;
+
+ std::ranges::uninitialized_default_construct(It(p), It(pend));
+
+ for (int i = 0; i != n; ++i) {
+ pool[i] = i + 17;
+ assert(pool[i] == i + 17);
+ }
+ }
+ // (range) overload.
+ {
+ using It = forward_iterator<int*>;
+ constexpr int n = 5;
+ int pool[n]{-1, -1, -1, -1, -1};
+ int* p = pool;
+ int* pend = p + n;
+
+ std::ranges::uninitialized_default_construct(std::ranges::subrange(It(p), It(pend)));
+
+ for (int i = 0; i != n; ++i) {
+ pool[i] = i + 17;
+ assert(pool[i] == i + 17);
+ }
+ }
+ // (iter, sentinel) overload.
+ {
+ using It = forward_iterator<IntWrapper*>;
+ constexpr int n = 5;
+ IntWrapper pool[n]{IntWrapper{-31}, IntWrapper{-41}, IntWrapper{-59}, IntWrapper{-26}, IntWrapper{-53}};
+ IntWrapper* p = pool;
+ std::ranges::uninitialized_default_construct(It(p), It(p + 1));
+ assert(pool[0].n_ == 42);
+ assert(pool[1].n_ == -41);
+ std::ranges::uninitialized_default_construct(It(p + 1), It(p + n));
+ assert(pool[1].n_ == 42);
+ assert(pool[2].n_ == 42);
+ assert(pool[3].n_ == 42);
+ assert(pool[4].n_ == 42);
+ }
+ // (range) overload.
+ {
+ using It = forward_iterator<IntWrapper*>;
+ constexpr int n = 5;
+ IntWrapper pool[n]{IntWrapper{-31}, IntWrapper{-41}, IntWrapper{-59}, IntWrapper{-26}, IntWrapper{-53}};
+ IntWrapper* p = pool;
+ std::ranges::uninitialized_default_construct(std::ranges::subrange(It(p), It(p + 1)));
+ assert(pool[0].n_ == 42);
+ assert(pool[1].n_ == -41);
+ std::ranges::uninitialized_default_construct(std::ranges::subrange(It(p + 1), It(p + n)));
+ assert(pool[1].n_ == 42);
+ assert(pool[2].n_ == 42);
+ assert(pool[3].n_ == 42);
+ assert(pool[4].n_ == 42);
+ }
+
+ return true;
+}
+
+#if TEST_STD_VER >= 26
+// Test that std::ranges::uninitialized_default_construct initializes int elements to indeterminate values,
+// and thus can cause constant evaluation failure.
+
+enum class assign_elements : bool { no, yes };
+enum class algorithm_style { iterator_sentinel, range };
+
+constexpr int test_indeterminate_values_helper(algorithm_style style, assign_elements choice) {
+ constexpr int n = 3;
+
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+
+ if (style == algorithm_style::range)
+ std::ranges::uninitialized_default_construct(std::span<int>{data, n});
+ else
+ std::ranges::uninitialized_default_construct(data, last);
+
+ if (choice == assign_elements::yes)
+ for (int i = 0; i != n; ++i)
+ data[i] = i + 1;
+
+ int sum = 0;
+ for (int i = 0; i != n; ++i)
+ sum += data[i];
+
+ std::ranges::destroy(data, last);
+ alloc.deallocate(data, n);
+
+ return sum;
+}
+
+template <algorithm_style Style, assign_elements Choice>
+concept test_indeterminate_values_result =
+ requires { typename std::integral_constant<int, test_indeterminate_values_helper(Style, Choice)>; };
+
+static_assert(!test_indeterminate_values_result<algorithm_style::iterator_sentinel, assign_elements::no>);
+static_assert(!test_indeterminate_values_result<algorithm_style::range, assign_elements::no>);
+static_assert(test_indeterminate_values_result<algorithm_style::iterator_sentinel, assign_elements::yes>);
+static_assert(test_indeterminate_values_result<algorithm_style::range, assign_elements::yes>);
+#endif // TEST_STD_VER >= 26
+
int main(int, char**) {
// An empty range -- no default constructors should be invoked.
{
@@ -163,5 +337,10 @@ int main(int, char**) {
}
#endif // TEST_HAS_NO_EXCEPTIONS
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif // TEST_STD_VER >= 26
+
return 0;
}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
index 097547cc28d9d..a26e5f938562c 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
@@ -35,6 +35,110 @@ struct NotDefaultCtrable { NotDefaultCtrable() = delete; };
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_default_construct_n),
NotDefaultCtrable*, int>);
+TEST_CONSTEXPR_CXX26 bool test() {
+ struct IntWrapper {
+ int n_ = 42;
+ };
+
+ {
+ constexpr int n = 3;
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+
+ auto result = std::ranges::uninitialized_default_construct_n(data, n);
+ assert(result == data + n);
+ for (int i = 0; i != n; ++i) {
+ data[i] = -i;
+ assert(data[i] == -i);
+ }
+
+ std::ranges::destroy_n(data, n);
+ alloc.deallocate(data, n);
+ }
+ {
+ constexpr int n = 3;
+ std::allocator<IntWrapper> alloc;
+ auto data = alloc.allocate(n);
+
+ auto result = std::ranges::uninitialized_default_construct_n(data, n);
+ assert(result == data + n);
+ for (int i = 0; i != n; ++i)
+ assert(data[i].n_ == 42);
+
+ std::ranges::destroy_n(data, n);
+ alloc.deallocate(data, n);
+ }
+
+ {
+ using It = forward_iterator<int*>;
+ constexpr int n = 5;
+ int pool[n]{-1, -1, -1, -1, -1};
+ int* p = pool;
+ auto end1 = std::ranges::uninitialized_default_construct_n(It(p), 1);
+ assert(end1 == It(p + 1));
+ auto end2 = std::ranges::uninitialized_default_construct_n(It(p + 1), 4);
+ assert(end2 == It(p + n));
+
+ for (int i = 0; i != n; ++i) {
+ pool[i] = i + 17;
+ assert(pool[i] == i + 17);
+ }
+ }
+ {
+ using It = forward_iterator<IntWrapper*>;
+ constexpr int n = 5;
+ IntWrapper pool[n]{IntWrapper{-31}, IntWrapper{-41}, IntWrapper{-59}, IntWrapper{-26}, IntWrapper{-53}};
+ IntWrapper* p = pool;
+ auto end1 = std::ranges::uninitialized_default_construct_n(It(p), 1);
+ assert(end1 == It(p + 1));
+ assert(pool[0].n_ == 42);
+ assert(pool[1].n_ == -41);
+ auto end2 = std::ranges::uninitialized_default_construct_n(It(p + 1), 4);
+ assert(end2 == It(p + n));
+ assert(pool[1].n_ == 42);
+ assert(pool[2].n_ == 42);
+ assert(pool[3].n_ == 42);
+ assert(pool[4].n_ == 42);
+ }
+
+ return true;
+}
+
+#if TEST_STD_VER >= 26
+// Test that std::ranges::uninitialized_default_construct_n initializes int elements to indeterminate values,
+// and thus can cause constant evaluation failure.
+
+enum class assign_elements : bool { no, yes };
+
+constexpr int test_indeterminate_values_helper(assign_elements choice) {
+ constexpr int n = 3;
+
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ std::ranges::uninitialized_default_construct_n(data, n);
+
+ if (choice == assign_elements::yes)
+ for (int i = 0; i != n; ++i)
+ data[i] = i + 1;
+
+ int sum = 0;
+ for (int i = 0; i != n; ++i)
+ sum += data[i];
+
+ std::ranges::destroy_n(data, n);
+ alloc.deallocate(data, n);
+
+ return sum;
+}
+
+template <assign_elements Choice>
+concept test_indeterminate_values_result =
+ requires { typename std::integral_constant<int, test_indeterminate_values_helper(Choice)>; };
+
+static_assert(!test_indeterminate_values_result<assign_elements::no>);
+static_assert(test_indeterminate_values_result<assign_elements::yes>);
+#endif // TEST_STD_VER >= 26
+
int main(int, char**) {
// An empty range -- no default constructors should be invoked.
{
@@ -76,5 +180,10 @@ int main(int, char**) {
}
#endif // TEST_HAS_NO_EXCEPTIONS
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif // TEST_STD_VER >= 26
+
return 0;
}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp
index 89e684b970e5c..d65223c3620cd 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct.pass.cpp
@@ -85,10 +85,117 @@ void test_counted()
assert(Counted::count == 0);
}
+TEST_CONSTEXPR_CXX26 bool test() {
+ struct IntWrapper {
+ int n_ = 42;
+ };
+
+ {
+ constexpr int n = 3;
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+
+ std::uninitialized_default_construct(data, last);
+ for (int i = 0; i != n; ++i) {
+ data[i] = -i;
+ assert(data[i] == -i);
+ }
+
+ std::destroy(data, last);
+ alloc.deallocate(data, n);
+ }
+ {
+ constexpr int n = 3;
+ std::allocator<IntWrapper> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+
+ std::uninitialized_default_construct(data, last);
+ for (int i = 0; i != n; ++i)
+ assert(data[i].n_ == 42);
+
+ std::destroy(data, last);
+ alloc.deallocate(data, n);
+ }
+
+ {
+ using It = forward_iterator<int*>;
+ constexpr int n = 5;
+ int pool[n]{-1, -1, -1, -1, -1};
+ int* p = pool;
+ int* pend = p + n;
+
+ std::uninitialized_default_construct(It(p), It(pend));
+
+ for (int i = 0; i != n; ++i) {
+ pool[i] = i + 17;
+ assert(pool[i] == i + 17);
+ }
+ }
+ {
+ using It = forward_iterator<IntWrapper*>;
+ constexpr int n = 5;
+ IntWrapper pool[n]{IntWrapper{-31}, IntWrapper{-41}, IntWrapper{-59}, IntWrapper{-26}, IntWrapper{-53}};
+ IntWrapper* p = pool;
+ std::uninitialized_default_construct(It(p), It(p + 1));
+ assert(pool[0].n_ == 42);
+ assert(pool[1].n_ == -41);
+ std::uninitialized_default_construct(It(p + 1), It(p + n));
+ assert(pool[1].n_ == 42);
+ assert(pool[2].n_ == 42);
+ assert(pool[3].n_ == 42);
+ assert(pool[4].n_ == 42);
+ }
+
+ return true;
+}
+
+#if TEST_STD_VER >= 26
+// Test that std::uninitialized_default_construct initializes int elements to indeterminate values,
+// and thus can cause constant evaluation failure.
+
+enum class assign_elements : bool { no, yes };
+
+constexpr int test_indeterminate_values_helper(assign_elements choice) {
+ constexpr int n = 3;
+
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ auto last = data + n;
+ std::uninitialized_default_construct(data, last);
+
+ if (choice == assign_elements::yes)
+ for (int i = 0; i != n; ++i)
+ data[i] = i + 1;
+
+ int sum = 0;
+ for (int i = 0; i != n; ++i)
+ sum += data[i];
+
+ std::destroy(data, last);
+ alloc.deallocate(data, n);
+
+ return sum;
+}
+
+template <assign_elements Choice>
+concept test_indeterminate_values_result =
+ requires { typename std::integral_constant<int, test_indeterminate_values_helper(Choice)>; };
+
+static_assert(!test_indeterminate_values_result<assign_elements::no>);
+static_assert(test_indeterminate_values_result<assign_elements::yes>);
+#endif // TEST_STD_VER >= 26
+
int main(int, char**)
{
test_counted();
test_ctor_throws();
- return 0;
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif // TEST_STD_VER >= 26
+
+ return 0;
}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct_n.pass.cpp
index 95a664a1285b4..42a56522557b4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/uninitialized_default_construct_n.pass.cpp
@@ -89,10 +89,119 @@ void test_counted()
assert(Counted::count == 0);
}
+TEST_CONSTEXPR_CXX26 bool test() {
+ struct IntWrapper {
+ int n_ = 42;
+ };
+
+ {
+ constexpr int n = 3;
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+
+ auto result = std::uninitialized_default_construct_n(data, n);
+ assert(result == data + n);
+ for (int i = 0; i != n; ++i) {
+ data[i] = -i;
+ assert(data[i] == -i);
+ }
+
+ std::destroy_n(data, n);
+ alloc.deallocate(data, n);
+ }
+ {
+ constexpr int n = 3;
+ std::allocator<IntWrapper> alloc;
+ auto data = alloc.allocate(n);
+
+ auto result = std::uninitialized_default_construct_n(data, n);
+ assert(result == data + n);
+ for (int i = 0; i != n; ++i)
+ assert(data[i].n_ == 42);
+
+ std::destroy_n(data, n);
+ alloc.deallocate(data, n);
+ }
+
+ {
+ using It = forward_iterator<int*>;
+ constexpr int n = 5;
+ int pool[n]{-1, -1, -1, -1, -1};
+ int* p = pool;
+ auto end1 = std::uninitialized_default_construct_n(It(p), 1);
+ assert(end1 == It(p + 1));
+ auto end2 = std::uninitialized_default_construct_n(It(p + 1), 4);
+ assert(end2 == It(p + n));
+
+ for (int i = 0; i != n; ++i) {
+ pool[i] = i + 17;
+ assert(pool[i] == i + 17);
+ }
+ }
+ {
+ using It = forward_iterator<IntWrapper*>;
+ constexpr int n = 5;
+ IntWrapper pool[n]{IntWrapper{-31}, IntWrapper{-41}, IntWrapper{-59}, IntWrapper{-26}, IntWrapper{-53}};
+ IntWrapper* p = pool;
+ auto end1 = std::uninitialized_default_construct_n(It(p), 1);
+ assert(end1 == It(p + 1));
+ assert(pool[0].n_ == 42);
+ assert(pool[1].n_ == -41);
+ auto end2 = std::uninitialized_default_construct_n(It(p + 1), 4);
+ assert(end2 == It(p + n));
+ assert(pool[1].n_ == 42);
+ assert(pool[2].n_ == 42);
+ assert(pool[3].n_ == 42);
+ assert(pool[4].n_ == 42);
+ }
+
+ return true;
+}
+
+#if TEST_STD_VER >= 26
+// Test that std::uninitialized_default_construct_n initializes int elements to indeterminate values,
+// and thus can cause constant evaluation failure.
+
+enum class assign_elements : bool { no, yes };
+
+constexpr int test_indeterminate_values_helper(assign_elements choice) {
+ constexpr int n = 3;
+
+ std::allocator<int> alloc;
+ auto data = alloc.allocate(n);
+ std::uninitialized_default_construct_n(data, n);
+
+ if (choice == assign_elements::yes)
+ for (int i = 0; i != n; ++i)
+ data[i] = i + 1;
+
+ int sum = 0;
+ for (int i = 0; i != n; ++i)
+ sum += data[i];
+
+ std::destroy_n(data, n);
+ alloc.deallocate(data, n);
+
+ return sum;
+}
+
+template <assign_elements Choice>
+concept test_indeterminate_values_result =
+ requires { typename std::integral_constant<int, test_indeterminate_values_helper(Choice)>; };
+
+static_assert(!test_indeterminate_values_result<assign_elements::no>);
+static_assert(test_indeterminate_values_result<assign_elements::yes>);
+#endif // TEST_STD_VER >= 26
+
int main(int, char**)
{
test_counted();
test_ctor_throws();
- return 0;
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif // TEST_STD_VER >= 26
+
+ return 0;
}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index d8fb575b97b2f..d764a1f677ba6 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1204,7 +1204,7 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_raw_memory_algorithms",
- "values": {"c++17": 201606},
+ "values": {"c++17": 201606, "c++26": 202411},
"headers": ["memory"],
},
{
More information about the libcxx-commits
mailing list