[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