[libcxx-commits] [libcxx] [libc++][pstl] Implementation of parallel uninitialized_default_construct, uninitialized_value_construct and uninitialized_fill (PR #214580)

Michael G. Kazakov via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 13 02:06:16 PDT 2026


https://github.com/mikekazakov updated https://github.com/llvm/llvm-project/pull/214580

>From 470a198912352f13e40be4f23a9d814636f0b715 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 6 Aug 2026 21:58:11 +0100
Subject: [PATCH 1/9] Added uninitialized_fill() and uninitialized_fill_n()

---
 libcxx/include/__memory/pstl.h                | 28 ++++++
 libcxx/include/__pstl/backend_fwd.h           | 12 +++
 libcxx/include/__pstl/backends/default.h      | 30 ++++++
 .../pstl.iterator-requirements.verify.cpp     |  7 ++
 .../pstl.exception_handling.pass.cpp          | 10 ++
 .../pstl.uninitialized_fill_n.pass.cpp        | 93 +++++++++++++++++++
 .../pstl.uninitialized_fill.pass.cpp          | 93 +++++++++++++++++++
 7 files changed, 273 insertions(+)
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp

diff --git a/libcxx/include/__memory/pstl.h b/libcxx/include/__memory/pstl.h
index a4fc727f3bf72..40bbc070b3fed 100644
--- a/libcxx/include/__memory/pstl.h
+++ b/libcxx/include/__memory/pstl.h
@@ -55,6 +55,34 @@ _LIBCPP_HIDE_FROM_ABI void destroy_n(_ExecutionPolicy&& __policy, _ForwardIterat
   __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "uninitialized_fill requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__uninitialized_fill, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value);
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Size,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, const _Tp& __value) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "uninitialized_fill_n requires ForwardIterators");
+  using _Implementation =
+      __pstl::__dispatch<__pstl::__uninitialized_fill_n, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n, __value);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index c5a219fb59db2..e424127fad8ac 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -377,6 +377,18 @@ struct __destroy_n;
 // optional<__empty>
 // operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_fill;
+// template <class _Policy, class _ForwardIterator, class _Tp>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp &__value) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_fill_n;
+// template <class _Policy, class _ForwardIterator, class _Size, class _Tp>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, const _Tp &__value) const noexcept;
+
 } // namespace __pstl
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 43bac357efd95..23c98fb0c94c9 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -89,6 +89,8 @@ namespace __pstl {
 // - replace_if
 // - generate
 // - generate_n
+// - uninitialized_fill
+// - uninitialized_fill_n
 //
 // merge family
 // ------------
@@ -492,6 +494,34 @@ struct __generate_n<__default_backend_tag, _ExecutionPolicy> {
   }
 };
 
+template <class _ExecutionPolicy>
+struct __uninitialized_fill<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept {
+    using _ForEach   = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEach()(__policy, std::move(__first), std::move(__last), [&__value](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType(__value);
+    });
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __uninitialized_fill_n<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size, class _Tp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, const _Tp& __value) const noexcept {
+    using _ForEachN  = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEachN()(__policy, std::move(__first), __n, [&__value](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType(__value);
+    });
+  }
+};
+
 //////////////////////////////////////////////////////////////
 // stable_sort family
 //////////////////////////////////////////////////////////////
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 2d510be58e164..35ac4d54b7dfd 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -277,4 +277,11 @@ void f(non_forward_iterator non_fwd,
     (void)std::adjacent_difference(
         pol, non_fwd, non_fwd, it, func); // expected-error@*:* {{static assertion failed: adjacent_difference}}
   }
+
+  {
+    std::uninitialized_fill(
+        pol, non_fwd, non_fwd, val); // expected-error@*:* {{static assertion failed: uninitialized_fill}}
+    std::uninitialized_fill_n(
+        pol, non_fwd, n, val); // expected-error@*:* {{static assertion failed: uninitialized_fill_n}}
+  }
 }
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index 4998b02fd0650..164948aa104e5 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -454,6 +454,16 @@ int main(int, char**) {
           (void)std::adjacent_difference(policy, std::move(first1), std::move(last1), std::move(dest), op);
         });
       }
+
+      {
+        // uninitialized_fill(first, last, val)
+        assert_non_throwing([=, &policy] {
+          std::uninitialized_fill(policy, std::move(first1), std::move(last1), val);
+        });
+
+        // uninitialized_fill_n(first, n, val)
+        assert_non_throwing([=, &policy] { std::uninitialized_fill_n(policy, std::move(first1), n, val); });
+      }
     }
   });
 
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
new file mode 100644
index 0000000000000..971434dad990b
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator,
+//           class Size,
+//           class T>
+//   void uninitialized_fill_n(ExecutionPolicy&& exec, ForwardIterator first, Size n, const T& value);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_fill_n);
+
+static_assert(sfinae_test_uninitialized_fill_n<int, int*, int, int>);
+static_assert(!sfinae_test_uninitialized_fill_n<std::execution::parallel_policy, int*, int, int>);
+
+// Init payload to initialize each Counted object with a pointer to its dedicated counter
+struct CountedInit {
+  struct Counted* first_;
+  std::atomic_int* counters_;
+};
+
+// Each Counted object has a dedicated external atomic counter
+struct Counted {
+  std::atomic_int* counter_;
+  Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
+  Counted(Counted const& other) : counter_(other.counter_) { counter_->fetch_add(1); }
+  ~Counted() { counter_->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test uninitialized_fill_n() with a range of Counted objects.
+      // Ranges vary in size from 0 to 1073.
+      // Each object has its own counter.
+      std::atomic_int counters[1073];
+      std::fill_n(std::begin(counters), std::size(counters), 0); // initialize all counters to 0
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Construct the Counted object in range [0, size).
+        std::uninitialized_fill_n(policy, Iter(pool), size, CountedInit{pool, counters});
+        ASSERT_SAME_TYPE(
+            decltype(std::uninitialized_fill_n(policy, Iter(pool), size, CountedInit{pool, counters})), void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(Iter(pool), Iter(pool + size));
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
new file mode 100644
index 0000000000000..9c1812cb795d7
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator,
+//           class T>
+//   void uninitialized_fill(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_fill);
+
+static_assert(sfinae_test_uninitialized_fill<int, int*, int*, int>);
+static_assert(!sfinae_test_uninitialized_fill<std::execution::parallel_policy, int*, int*, int>);
+
+// Init payload to initialize each Counted object with a pointer to its dedicated counter
+struct CountedInit {
+  struct Counted* first_;
+  std::atomic_int* counters_;
+};
+
+// Each Counted object has a dedicated external atomic counter
+struct Counted {
+  std::atomic_int* counter_;
+  Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
+  Counted(Counted const& other) : counter_(other.counter_) { counter_->fetch_add(1); }
+  ~Counted() { counter_->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test uninitialized_fill() with a range of Counted objects.
+      // Ranges vary in size from 0 to 1073.
+      // Each object has its own counter.
+      std::atomic_int counters[1073];
+      std::fill_n(std::begin(counters), std::size(counters), 0); // initialize all counters to 0
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Construct the Counted object in range [0, size).
+        std::uninitialized_fill(policy, Iter(pool), Iter(pool + size), CountedInit{pool, counters});
+        ASSERT_SAME_TYPE(
+            decltype(std::uninitialized_fill(policy, Iter(pool), Iter(pool + size), CountedInit{pool, counters})),
+            void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(Iter(pool), Iter(pool + size));
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  return 0;
+}

>From 7f5d2949640360973286e503084efd3f95f015bb Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 8 Aug 2026 13:41:29 +0100
Subject: [PATCH 2/9] Added std::uninitialized_default_construct()

---
 libcxx/include/__memory/pstl.h                |  27 +++++
 libcxx/include/__pstl/backend_fwd.h           |  12 ++
 libcxx/include/__pstl/backends/default.h      |  30 +++++
 .../pstl.iterator-requirements.verify.cpp     |   4 +
 .../pstl.exception_handling.pass.cpp          |   8 ++
 ...l.uninitialized_default_construct.pass.cpp | 111 +++++++++++++++++
 ...uninitialized_default_construct_n.pass.cpp | 112 ++++++++++++++++++
 7 files changed, 304 insertions(+)
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp

diff --git a/libcxx/include/__memory/pstl.h b/libcxx/include/__memory/pstl.h
index 40bbc070b3fed..0c60ed730f7a6 100644
--- a/libcxx/include/__memory/pstl.h
+++ b/libcxx/include/__memory/pstl.h
@@ -55,6 +55,33 @@ _LIBCPP_HIDE_FROM_ABI void destroy_n(_ExecutionPolicy&& __policy, _ForwardIterat
   __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_default_construct(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "uninitialized_default_construct requires ForwardIterators");
+  using _Implementation =
+      __pstl::__dispatch<__pstl::__uninitialized_default_construct, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last));
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Size,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_default_construct_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(
+      _ForwardIterator, "uninitialized_default_construct_n requires ForwardIterators");
+  using _Implementation =
+      __pstl::__dispatch<__pstl::__uninitialized_default_construct_n, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator,
           class _Tp,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index e424127fad8ac..a44c5b74ee6b3 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -377,6 +377,18 @@ struct __destroy_n;
 // optional<__empty>
 // operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_default_construct;
+// template <class _Policy, class _ForwardIterator>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_default_construct_n;
+// template <class _Policy, class _ForwardIterator, class _Size>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept;
+
 template <class _Backend, class _ExecutionPolicy>
 struct __uninitialized_fill;
 // template <class _Policy, class _ForwardIterator, class _Tp>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 23c98fb0c94c9..22ef018476776 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -89,6 +89,8 @@ namespace __pstl {
 // - replace_if
 // - generate
 // - generate_n
+// - uninitialized_default_construct
+// - uninitialized_default_construct_n
 // - uninitialized_fill
 // - uninitialized_fill_n
 //
@@ -494,6 +496,34 @@ struct __generate_n<__default_backend_tag, _ExecutionPolicy> {
   }
 };
 
+template <class _ExecutionPolicy>
+struct __uninitialized_default_construct<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept {
+    using _ForEach   = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEach()(__policy, std::move(__first), std::move(__last), [](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType;
+    });
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __uninitialized_default_construct_n<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept {
+    using _ForEachN  = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEachN()(__policy, std::move(__first), __n, [](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType;
+    });
+  }
+};
+
 template <class _ExecutionPolicy>
 struct __uninitialized_fill<__default_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Tp>
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 35ac4d54b7dfd..a4d4cfb570fb4 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -279,6 +279,10 @@ void f(non_forward_iterator non_fwd,
   }
 
   {
+    std::uninitialized_default_construct(
+        pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: uninitialized_default_construct}}
+    std::uninitialized_default_construct_n(
+        pol, non_fwd, n); // expected-error@*:* {{static assertion failed: uninitialized_default_construct_n}}
     std::uninitialized_fill(
         pol, non_fwd, non_fwd, val); // expected-error@*:* {{static assertion failed: uninitialized_fill}}
     std::uninitialized_fill_n(
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index 164948aa104e5..ed0a501e4ca5d 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -456,6 +456,14 @@ int main(int, char**) {
       }
 
       {
+        // uninitialized_default_construct(first, last)
+        assert_non_throwing([=, &policy] {
+          std::uninitialized_default_construct(policy, std::move(first1), std::move(last1));
+        });
+
+        // uninitialized_default_construct_n(first, n)
+        assert_non_throwing([=, &policy] { std::uninitialized_default_construct_n(policy, std::move(first1), n); });
+
         // uninitialized_fill(first, last, val)
         assert_non_throwing([=, &policy] {
           std::uninitialized_fill(policy, std::move(first1), std::move(last1), val);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
new file mode 100644
index 0000000000000..68ebac86d2dcb
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator>
+//   void uninitialized_default_construct(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_default_construct);
+
+static_assert(sfinae_test_uninitialized_default_construct<int, int*, int*>);
+static_assert(!sfinae_test_uninitialized_default_construct<std::execution::parallel_policy, int*, int*>);
+
+// Each Counted object has a dedicated external atomic counter.
+// To be able to connect with that counter, each Counted object knows that it is located inside a single pool.
+struct Counted {
+  static std::atomic_int counters[1073];
+  static Counted* pool;
+  std::atomic_int* counter;
+  Counted() : counter(counters + (this - pool)) { counter->fetch_add(1); }
+  Counted(Counted const& other) : counter(other.counter) { counter->fetch_add(1); }
+  ~Counted() { counter->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+std::atomic_int Counted::counters[1073];
+Counted* Counted::pool = nullptr;
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      std::atomic_int(&counters)[1073] = Counted::counters;
+      Counted*(&pool)                  = Counted::pool;
+
+      // initialize all Counted counters to 0
+      std::fill_n(std::begin(counters), std::size(counters), 0);
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Default-construct the Counted objects in range [0, size).
+        std::uninitialized_default_construct(policy, Iter(pool), Iter(pool + size));
+        ASSERT_SAME_TYPE(decltype(std::uninitialized_default_construct(policy, Iter(pool), Iter(pool + size))), void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(pool, pool + size);
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_default_construct(policy, Iter(data), Iter(last));
+      for (int i = 0; i != n; ++i) {
+        data[i] = -i;
+        assert(data[i] == -i);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
new file mode 100644
index 0000000000000..61409997ab422
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator,
+//           class Size>
+//   void uninitialized_default_construct_n(ExecutionPolicy&& exec, ForwardIterator first, Size n);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_default_construct_n);
+
+static_assert(sfinae_test_uninitialized_default_construct_n<int, int*, int>);
+static_assert(!sfinae_test_uninitialized_default_construct_n<std::execution::parallel_policy, int*, int>);
+
+// Each Counted object has a dedicated external atomic counter.
+// To be able to connect with that counter, each Counted object knows that it is located inside a single pool.
+struct Counted {
+  static std::atomic_int counters[1073];
+  static Counted* pool;
+  std::atomic_int* counter;
+  Counted() : counter(counters + (this - pool)) { counter->fetch_add(1); }
+  Counted(Counted const& other) : counter(other.counter) { counter->fetch_add(1); }
+  ~Counted() { counter->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+std::atomic_int Counted::counters[1073];
+Counted* Counted::pool = nullptr;
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      std::atomic_int(&counters)[1073] = Counted::counters;
+      Counted*(&pool)                  = Counted::pool;
+
+      // initialize all Counted counters to 0
+      std::fill_n(std::begin(counters), std::size(counters), 0);
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Default-construct the Counted objects in range [0, size).
+        std::uninitialized_default_construct_n(policy, Iter(pool), size);
+        ASSERT_SAME_TYPE(decltype(std::uninitialized_default_construct_n(policy, Iter(pool), size)), void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(pool, pool + size);
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_default_construct_n(policy, Iter(data), n);
+      for (int i = 0; i != n; ++i) {
+        data[i] = -i;
+        assert(data[i] == -i);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
+  return 0;
+}

>From 88b94e4fe7155096a9f2fa8d46d9a6eda14711ab Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 8 Aug 2026 14:17:46 +0100
Subject: [PATCH 3/9] Added std::uninitialized_value_construct()

---
 libcxx/include/__memory/pstl.h                |  26 ++++
 libcxx/include/__pstl/backend_fwd.h           |  12 ++
 libcxx/include/__pstl/backends/default.h      |  28 +++++
 .../pstl.iterator-requirements.verify.cpp     |   4 +
 .../pstl.exception_handling.pass.cpp          |   8 ++
 ...l.uninitialized_default_construct.pass.cpp |   2 +-
 ...uninitialized_default_construct_n.pass.cpp |   2 +-
 ...stl.uninitialized_value_construct.pass.cpp | 110 +++++++++++++++++
 ...l.uninitialized_value_construct_n.pass.cpp | 111 ++++++++++++++++++
 9 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp

diff --git a/libcxx/include/__memory/pstl.h b/libcxx/include/__memory/pstl.h
index 0c60ed730f7a6..c06f53bed7206 100644
--- a/libcxx/include/__memory/pstl.h
+++ b/libcxx/include/__memory/pstl.h
@@ -82,6 +82,32 @@ uninitialized_default_construct_n(_ExecutionPolicy&& __policy, _ForwardIterator
   __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_value_construct(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "uninitialized_value_construct requires ForwardIterators");
+  using _Implementation =
+      __pstl::__dispatch<__pstl::__uninitialized_value_construct, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last));
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Size,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+uninitialized_value_construct_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "uninitialized_value_construct_n requires ForwardIterators");
+  using _Implementation =
+      __pstl::__dispatch<__pstl::__uninitialized_value_construct_n, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator,
           class _Tp,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a44c5b74ee6b3..7f570cf865386 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -389,6 +389,18 @@ struct __uninitialized_default_construct_n;
 // optional<__empty>
 // operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_value_construct;
+// template <class _Policy, class _ForwardIterator>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __uninitialized_value_construct_n;
+// template <class _Policy, class _ForwardIterator, class _Size>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept;
+
 template <class _Backend, class _ExecutionPolicy>
 struct __uninitialized_fill;
 // template <class _Policy, class _ForwardIterator, class _Tp>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 22ef018476776..e60e9116292fc 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -524,6 +524,34 @@ struct __uninitialized_default_construct_n<__default_backend_tag, _ExecutionPoli
   }
 };
 
+template <class _ExecutionPolicy>
+struct __uninitialized_value_construct<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept {
+    using _ForEach   = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEach()(__policy, std::move(__first), std::move(__last), [](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType();
+    });
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __uninitialized_value_construct_n<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept {
+    using _ForEachN  = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
+    using _ValueType = __iterator_value_type<_ForwardIterator>;
+    using _Ref       = __iterator_reference<_ForwardIterator>;
+    return _ForEachN()(__policy, std::move(__first), __n, [](_Ref __element) {
+      ::new (static_cast<void*>(std::addressof(__element))) _ValueType();
+    });
+  }
+};
+
 template <class _ExecutionPolicy>
 struct __uninitialized_fill<__default_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Tp>
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index a4d4cfb570fb4..52a46ed324642 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -283,6 +283,10 @@ void f(non_forward_iterator non_fwd,
         pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: uninitialized_default_construct}}
     std::uninitialized_default_construct_n(
         pol, non_fwd, n); // expected-error@*:* {{static assertion failed: uninitialized_default_construct_n}}
+    std::uninitialized_value_construct(
+        pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: uninitialized_value_construct}}
+    std::uninitialized_value_construct_n(
+        pol, non_fwd, n); // expected-error@*:* {{static assertion failed: uninitialized_value_construct_n}}
     std::uninitialized_fill(
         pol, non_fwd, non_fwd, val); // expected-error@*:* {{static assertion failed: uninitialized_fill}}
     std::uninitialized_fill_n(
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index ed0a501e4ca5d..6a983ae6cf4b5 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -464,6 +464,14 @@ int main(int, char**) {
         // uninitialized_default_construct_n(first, n)
         assert_non_throwing([=, &policy] { std::uninitialized_default_construct_n(policy, std::move(first1), n); });
 
+        // uninitialized_value_construct(first, last)
+        assert_non_throwing([=, &policy] {
+          std::uninitialized_value_construct(policy, std::move(first1), std::move(last1));
+        });
+
+        // uninitialized_value_construct_n(first, n)
+        assert_non_throwing([=, &policy] { std::uninitialized_value_construct_n(policy, std::move(first1), n); });
+
         // uninitialized_fill(first, last, val)
         assert_non_throwing([=, &policy] {
           std::uninitialized_fill(policy, std::move(first1), std::move(last1), val);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
index 68ebac86d2dcb..ec4837d131a6f 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
@@ -53,7 +53,7 @@ struct TestCounted {
   void operator()(ExecutionPolicy&& policy) {
     {
       std::atomic_int(&counters)[1073] = Counted::counters;
-      Counted*(&pool)                  = Counted::pool;
+      Counted*& pool                   = Counted::pool;
 
       // initialize all Counted counters to 0
       std::fill_n(std::begin(counters), std::size(counters), 0);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
index 61409997ab422..875e6a9907fe5 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
@@ -54,7 +54,7 @@ struct TestCounted {
   void operator()(ExecutionPolicy&& policy) {
     {
       std::atomic_int(&counters)[1073] = Counted::counters;
-      Counted*(&pool)                  = Counted::pool;
+      Counted*& pool                   = Counted::pool;
 
       // initialize all Counted counters to 0
       std::fill_n(std::begin(counters), std::size(counters), 0);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
new file mode 100644
index 0000000000000..6b9e77bc48067
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator>
+//   void uninitialized_value_construct(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_value_construct);
+
+static_assert(sfinae_test_uninitialized_value_construct<int, int*, int*>);
+static_assert(!sfinae_test_uninitialized_value_construct<std::execution::parallel_policy, int*, int*>);
+
+// Each Counted object has a dedicated external atomic counter.
+// To be able to connect with that counter, each Counted object knows that it is located inside a single pool.
+struct Counted {
+  static std::atomic_int counters[1073];
+  static Counted* pool;
+  std::atomic_int* counter;
+  Counted() : counter(counters + (this - pool)) { counter->fetch_add(1); }
+  Counted(Counted const& other) : counter(other.counter) { counter->fetch_add(1); }
+  ~Counted() { counter->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+std::atomic_int Counted::counters[1073];
+Counted* Counted::pool = nullptr;
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      std::atomic_int(&counters)[1073] = Counted::counters;
+      Counted*& pool                   = Counted::pool;
+
+      // initialize all Counted counters to 0
+      std::fill_n(std::begin(counters), std::size(counters), 0);
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Default-construct the Counted objects in range [0, size).
+        std::uninitialized_value_construct(policy, Iter(pool), Iter(pool + size));
+        ASSERT_SAME_TYPE(decltype(std::uninitialized_value_construct(policy, Iter(pool), Iter(pool + size))), void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(pool, pool + size);
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_value_construct(policy, Iter(data), Iter(last));
+      for (int i = 0; i != n; ++i) {
+        assert(data[i] == 0);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp
new file mode 100644
index 0000000000000..eb93631c45446
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator,
+//           class Size>
+//   void uninitialized_value_construct_n(ExecutionPolicy&& exec, ForwardIterator first, Size n);
+
+#include <atomic>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(uninitialized_value_construct_n);
+
+static_assert(sfinae_test_uninitialized_value_construct_n<int, int*, int>);
+static_assert(!sfinae_test_uninitialized_value_construct_n<std::execution::parallel_policy, int*, int>);
+
+// Each Counted object has a dedicated external atomic counter.
+// To be able to connect with that counter, each Counted object knows that it is located inside a single pool.
+struct Counted {
+  static std::atomic_int counters[1073];
+  static Counted* pool;
+  std::atomic_int* counter;
+  Counted() : counter(counters + (this - pool)) { counter->fetch_add(1); }
+  Counted(Counted const& other) : counter(other.counter) { counter->fetch_add(1); }
+  ~Counted() { counter->fetch_sub(1); }
+  friend void operator&(Counted) = delete;
+};
+std::atomic_int Counted::counters[1073];
+Counted* Counted::pool = nullptr;
+
+template <class Iter>
+struct TestCounted {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      std::atomic_int(&counters)[1073] = Counted::counters;
+      Counted*& pool                   = Counted::pool;
+
+      // initialize all Counted counters to 0
+      std::fill_n(std::begin(counters), std::size(counters), 0);
+
+      // Allocate memory for the Counted objects
+      using Alloc = std::allocator<Counted>;
+      Alloc alloc;
+      pool = std::allocator_traits<Alloc>::allocate(alloc, std::size(counters));
+
+      runway_sample(std::size(counters) + 1, [&](size_t size) {
+        // Default-construct the Counted objects in range [0, size).
+        std::uninitialized_value_construct_n(policy, Iter(pool), size);
+        ASSERT_SAME_TYPE(decltype(std::uninitialized_value_construct_n(policy, Iter(pool), size)), void);
+
+        // Verify that inside this range the counters are all 1 and outside the range they are all 0.
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+        assert(std::all_of(std::begin(counters) + size, std::end(counters), [](auto& x) { return x == 0; }));
+
+        // Destroy the constructed objects and verify that all counters are 0.
+        std::destroy(pool, pool + size);
+        assert(std::all_of(std::begin(counters), std::end(counters), [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_value_construct_n(policy, Iter(data), n);
+      for (int i = 0; i != n; ++i) {
+        assert(data[i] == 0);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
+  return 0;
+}

>From 6371df01ca8812b6efaafa84917b4ecf634d2aae Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 8 Aug 2026 14:23:35 +0100
Subject: [PATCH 4/9] Added tests with plain Ints into uninitialized_fill and
 uninitialized_fill_n tests

---
 .../pstl.uninitialized_fill_n.pass.cpp        | 22 +++++++++++++++++++
 .../pstl.uninitialized_fill.pass.cpp          | 22 +++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
index 971434dad990b..1dc64cddb1d56 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
@@ -87,7 +87,29 @@ struct TestCounted {
   }
 };
 
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_fill_n(policy, Iter(data), n, 42);
+      for (int i = 0; i != n; ++i) {
+        assert(data[i] == 42);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
   return 0;
 }
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
index 9c1812cb795d7..102407504bcca 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
@@ -87,7 +87,29 @@ struct TestCounted {
   }
 };
 
+template <class Iter>
+struct TestInt {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      constexpr int n = 1073;
+      std::allocator<int> alloc;
+      int* data = alloc.allocate(n);
+      int* last = data + n;
+
+      std::uninitialized_fill(policy, Iter(data), Iter(last), 42);
+      for (int i = 0; i != n; ++i) {
+        assert(data[i] == 42);
+      }
+
+      std::destroy(data, last);
+      alloc.deallocate(data, n);
+    }
+  }
+};
+
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+  types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestInt>{});
   return 0;
 }

>From 46d385bdb9085a70e6ec37d8aaa0b097fb676d0a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 8 Aug 2026 14:24:56 +0100
Subject: [PATCH 5/9] Updated the comment about the for_each family

---
 libcxx/include/__pstl/backends/default.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index e60e9116292fc..1163409d31774 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -91,6 +91,8 @@ namespace __pstl {
 // - generate_n
 // - uninitialized_default_construct
 // - uninitialized_default_construct_n
+// - uninitialized_value_construct
+// - uninitialized_value_construct_n
 // - uninitialized_fill
 // - uninitialized_fill_n
 //

>From b390e07f075b2026e9f9504ebb5ccc8276a79968 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 13 Aug 2026 09:20:39 +0100
Subject: [PATCH 6/9] Made aliasing easier to understand

---
 .../pstl.uninitialized_default_construct.pass.cpp          | 7 ++++---
 .../pstl.uninitialized_default_construct_n.pass.cpp        | 7 ++++---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
index ec4837d131a6f..830fa9aed1f8d 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
@@ -52,10 +52,11 @@ struct TestCounted {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
     {
-      std::atomic_int(&counters)[1073] = Counted::counters;
-      Counted*& pool                   = Counted::pool;
+      // Alias the static member variables
+      auto& counters = Counted::counters;
+      Counted*& pool = Counted::pool;
 
-      // initialize all Counted counters to 0
+      // Initialize all Counted counters to 0
       std::fill_n(std::begin(counters), std::size(counters), 0);
 
       // Allocate memory for the Counted objects
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
index 875e6a9907fe5..bdca7fe6f2f14 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
@@ -53,10 +53,11 @@ struct TestCounted {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
     {
-      std::atomic_int(&counters)[1073] = Counted::counters;
-      Counted*& pool                   = Counted::pool;
+      // Alias the static member variables
+      auto& counters = Counted::counters;
+      Counted*& pool = Counted::pool;
 
-      // initialize all Counted counters to 0
+      // Initialize all Counted counters to 0
       std::fill_n(std::begin(counters), std::size(counters), 0);
 
       // Allocate memory for the Counted objects

>From e84eca73b068ed80950969b1224cfe72f1ef1a9d Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 13 Aug 2026 09:31:08 +0100
Subject: [PATCH 7/9] Replaced a meaningless check with a comment

---
 .../pstl.uninitialized_default_construct.pass.cpp           | 6 ++----
 .../pstl.uninitialized_default_construct_n.pass.cpp         | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
index 830fa9aed1f8d..3d91cd13f1fc7 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct.pass.cpp
@@ -94,10 +94,8 @@ struct TestInt {
       int* last = data + n;
 
       std::uninitialized_default_construct(policy, Iter(data), Iter(last));
-      for (int i = 0; i != n; ++i) {
-        data[i] = -i;
-        assert(data[i] == -i);
-      }
+      // There's nothing we can meaningfully test here, since default-constructing an int is only observable in constexpr contexts,
+      // but still run the algorithm to excercise the runtime.
 
       std::destroy(data, last);
       alloc.deallocate(data, n);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
index bdca7fe6f2f14..a6e9c851f8ed5 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/pstl.uninitialized_default_construct_n.pass.cpp
@@ -95,10 +95,8 @@ struct TestInt {
       int* last = data + n;
 
       std::uninitialized_default_construct_n(policy, Iter(data), n);
-      for (int i = 0; i != n; ++i) {
-        data[i] = -i;
-        assert(data[i] == -i);
-      }
+      // There's nothing we can meaningfully test here, since default-constructing an int is only observable in constexpr contexts,
+      // but still run the algorithm to excercise the runtime.
 
       std::destroy(data, last);
       alloc.deallocate(data, n);

>From c344142029acd1c7a2d2690cef626a3fbb86302d Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 13 Aug 2026 09:45:45 +0100
Subject: [PATCH 8/9] Scribble the memory before value-initializing ints there

---
 .../pstl.uninitialized_value_construct.pass.cpp                 | 2 ++
 .../pstl.uninitialized_value_construct_n.pass.cpp               | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
index 6b9e77bc48067..b8390e6884a92 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct.pass.cpp
@@ -17,6 +17,7 @@
 #include <atomic>
 #include <algorithm>
 #include <cassert>
+#include <cstring>
 #include <functional>
 #include <iterator>
 #include <memory>
@@ -91,6 +92,7 @@ struct TestInt {
       std::allocator<int> alloc;
       int* data = alloc.allocate(n);
       int* last = data + n;
+      std::memset(data, 0xFF, n * sizeof(int));
 
       std::uninitialized_value_construct(policy, Iter(data), Iter(last));
       for (int i = 0; i != n; ++i) {
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp
index eb93631c45446..859e922c4bfa4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/pstl.uninitialized_value_construct_n.pass.cpp
@@ -18,6 +18,7 @@
 #include <atomic>
 #include <algorithm>
 #include <cassert>
+#include <cstring>
 #include <functional>
 #include <iterator>
 #include <memory>
@@ -92,6 +93,7 @@ struct TestInt {
       std::allocator<int> alloc;
       int* data = alloc.allocate(n);
       int* last = data + n;
+      std::memset(data, 0xFF, n * sizeof(int));
 
       std::uninitialized_value_construct_n(policy, Iter(data), n);
       for (int i = 0; i != n; ++i) {

>From e6f4eec553adb75a5654b8e2d31f03fd8d4eb77a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 13 Aug 2026 10:05:52 +0100
Subject: [PATCH 9/9] Made the constructor explicit in the uninitialized_fill
 unit tests

---
 .../uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp     | 2 +-
 .../uninitialized.fill/pstl.uninitialized_fill.pass.cpp         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
index 1dc64cddb1d56..b25d2a7769c5b 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/pstl.uninitialized_fill_n.pass.cpp
@@ -45,7 +45,7 @@ struct CountedInit {
 // Each Counted object has a dedicated external atomic counter
 struct Counted {
   std::atomic_int* counter_;
-  Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
+  explicit Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
   Counted(Counted const& other) : counter_(other.counter_) { counter_->fetch_add(1); }
   ~Counted() { counter_->fetch_sub(1); }
   friend void operator&(Counted) = delete;
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
index 102407504bcca..ce20e02dc3e5f 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/pstl.uninitialized_fill.pass.cpp
@@ -44,7 +44,7 @@ struct CountedInit {
 // Each Counted object has a dedicated external atomic counter
 struct Counted {
   std::atomic_int* counter_;
-  Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
+  explicit Counted(CountedInit init) : counter_(init.counters_ + (this - init.first_)) { counter_->fetch_add(1); }
   Counted(Counted const& other) : counter_(other.counter_) { counter_->fetch_add(1); }
   ~Counted() { counter_->fetch_sub(1); }
   friend void operator&(Counted) = delete;



More information about the libcxx-commits mailing list