[libcxx-commits] [libcxx] [libc++][pstl] Implementation of parallel std::destroy() and std::destroy_n() (PR #211888)

Michael G. Kazakov via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 30 13:48:06 PDT 2026


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

>From 723b523e8e9f681c3271275bb5b1724d858fbb1a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 24 Jul 2026 19:58:22 +0100
Subject: [PATCH 1/9] Added an implementation of destroy() and destroy_n()

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__memory/pstl.h                |  64 ++++++++
 libcxx/include/__pstl/backend_fwd.h           |  12 ++
 libcxx/include/__pstl/backends/default.h      |  29 ++++
 libcxx/include/memory                         |   1 +
 .../pstl.iterator-requirements.verify.cpp     |   6 +
 .../test/libcxx/transitive_includes/cxx26.csv |   7 +
 .../pstl.exception_handling.pass.cpp          |   9 ++
 .../specialized.destroy/pstl.destroy.pass.cpp | 149 ++++++++++++++++++
 .../pstl.destroy_n.pass.cpp                   | 149 ++++++++++++++++++
 10 files changed, 427 insertions(+)
 create mode 100644 libcxx/include/__memory/pstl.h
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy.pass.cpp
 create mode 100644 libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy_n.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b40f586161e62..d87a708998798 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -608,6 +608,7 @@ set(files
   __memory/noexcept_move_assign_container.h
   __memory/out_ptr.h
   __memory/pointer_traits.h
+  __memory/pstl.h  
   __memory/ranges_construct_at.h
   __memory/ranges_destroy.h
   __memory/ranges_uninitialized_algorithms.h
diff --git a/libcxx/include/__memory/pstl.h b/libcxx/include/__memory/pstl.h
new file mode 100644
index 0000000000000..a4fc727f3bf72
--- /dev/null
+++ b/libcxx/include/__memory/pstl.h
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MEMORY_PSTL_H
+#define _LIBCPP___MEMORY_PSTL_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
+
+#  include <__iterator/cpp17_iterator_concepts.h>
+#  include <__iterator/iterator_traits.h>
+#  include <__pstl/backend.h>
+#  include <__pstl/dispatch.h>
+#  include <__pstl/handle_exception.h>
+#  include <__type_traits/enable_if.h>
+#  include <__type_traits/is_execution_policy.h>
+#  include <__type_traits/remove_cvref.h>
+#  include <__utility/forward.h>
+#  include <__utility/move.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+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 destroy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "destroy requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__destroy, __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 destroy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "destroy_n requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__destroy_n, __pstl::__current_configuration, _RawPolicy>;
+  __pstl::__handle_exception<_Implementation>(std::forward<_ExecutionPolicy>(__policy), std::move(__first), __n);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MEMORY_PSTL_H
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 2ba5b4434fc33..3372d7c5b3a9b 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -324,6 +324,18 @@ struct __adjacent_difference;
 // operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
 //                                _ForwardIterator2 __first2, _BinaryOperation &&__op) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __destroy;
+// template <class _Policy, class _ForwardIterator>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __destroy_n;
+// template <class _Policy, class _ForwardIterator, class Size>
+// optional<__empty>
+// operator()(_Policy&& __policy, _ForwardIterator __first, Size __n) 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 28bc75be147aa..affcea6a678e1 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -24,6 +24,8 @@
 #include <__iterator/iterator_traits.h>
 #include <__iterator/next.h>
 #include <__iterator/reverse_iterator.h>
+#include <__memory/addressof.h>
+#include <__memory/construct_at.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
 #include <__type_traits/desugars_to.h>
@@ -65,6 +67,8 @@ namespace __pstl {
 //
 // for_each family
 // ---------------
+// - destroy
+// - destroy_n
 // - for_each_n
 // - fill
 // - fill_n
@@ -215,6 +219,31 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
 //////////////////////////////////////////////////////////////
 // for_each family
 //////////////////////////////////////////////////////////////
+
+template <class _ExecutionPolicy>
+struct __destroy<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator>
+  optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last) const noexcept {
+    using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
+    using _Ref     = __iterator_reference<_ForwardIterator>;
+    return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) {
+      std::destroy_at(std::addressof(__element));
+    });
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __destroy_n<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class Size>
+  optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, Size __n) const noexcept {
+    using _ForEachN = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
+    using _Ref      = __iterator_reference<_ForwardIterator>;
+    return _ForEachN()(__policy, std::move(__first), __n, [&](_Ref __element) {
+      std::destroy_at(std::addressof(__element));
+    });
+  }
+};
+
 template <class _ExecutionPolicy>
 struct __for_each_n<__default_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Size, class _Function>
diff --git a/libcxx/include/memory b/libcxx/include/memory
index d5d48ed9a9e6d..29666746f13ec 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -963,6 +963,7 @@ template<class Pointer = void, class Smart, class... Args>
 #  if _LIBCPP_STD_VER >= 17
 #    include <__memory/construct_at.h>
 #    include <__memory/destroy.h>
+#    include <__memory/pstl.h>
 #  endif
 
 #  if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 402d8fbf9131a..baedbf4addb21 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -28,6 +28,7 @@
 #include <cstddef>
 #include <execution>
 #include <numeric>
+#include <memory>
 
 #include "test_iterators.h"
 
@@ -70,6 +71,11 @@ void f(non_forward_iterator non_fwd,
     (void)std::count_if(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: count_if}}
   }
 
+  {
+    (void)std::destroy(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: destroy}}
+    (void)std::destroy_n(pol, non_fwd, n);     // expected-error@*:* {{static assertion failed: destroy_n}}
+  }
+
   {
     (void)std::equal(pol, non_fwd, non_fwd, it);       // expected-error@*:* {{static assertion failed: equal}}
     (void)std::equal(pol, it, it, non_fwd);            // expected-error@*:* {{static assertion failed: equal}}
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index f712f36caa9fc..e8e7e6680af0b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -625,11 +625,18 @@ mdspan limits
 mdspan span
 mdspan stdexcept
 mdspan version
+memory cctype
+memory climits
 memory compare
 memory cstdint
 memory cstring
+memory ctime
+memory cwchar
+memory cwctype
 memory initializer_list
 memory limits
+memory optional
+memory ratio
 memory tuple
 memory typeinfo
 memory version
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index e00046fdb1dd6..bbe27b6ef42a6 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -21,6 +21,7 @@
 
 #include <algorithm>
 #include <numeric>
+#include <memory>
 
 #include "check_assertion.h"
 #include "test_execution_policies.h"
@@ -127,6 +128,14 @@ int main(int, char**) {
         assert_non_throwing([=, &policy] { (void)std::count_if(policy, std::move(first1), std::move(last1), pred); });
       }
 
+      {
+        // destroy(first, last)
+        assert_non_throwing([=, &policy] { (void)std::destroy(policy, std::move(first1), std::move(last1)); });
+
+        // destroy_n(first, n)
+        assert_non_throwing([=, &policy] { (void)std::destroy_n(policy, std::move(first1), n); });
+      }
+
       {
         auto binary_pred = maybe_throw(tokens[5], [](int x, int y) -> bool { return x == y; });
 
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy.pass.cpp
new file mode 100644
index 0000000000000..a2ffccefb8608
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 destroy(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last);
+
+#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(destroy);
+
+static_assert(sfinae_test_destroy<int, int*, int*>);
+static_assert(!sfinae_test_destroy<std::execution::parallel_policy, int*, int*>);
+
+struct Counted {
+  std::atomic_int* counter_;
+  Counted(std::atomic_int* counter) : counter_(counter) { 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 destroy() 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);
+
+      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) {
+        for (std::size_t i = 0; i < size; ++i) {
+          std::allocator_traits<Alloc>::construct(alloc, std::addressof(pool[i]), &counters[i]);
+        }
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+
+        std::destroy(policy, Iter(pool), Iter(pool + size));
+        ASSERT_SAME_TYPE(decltype(std::destroy(policy, Iter(pool), Iter(pool + size))), void);
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+#if TEST_STD_VER > 17
+template <class Iter>
+struct TestArrayCounted3 {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test destroy() with a range of 5 Counted[3] objects.
+      // A shared counter is used for all objects.
+      using Array             = Counted[3];
+      using Alloc             = std::allocator<Array>;
+      std::atomic_int counter = 0;
+      Alloc alloc;
+      Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
+
+      for (Array* p = pool; p != pool + 5; ++p) {
+        Array& arr = *p;
+        for (int i = 0; i != 3; ++i) {
+          std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i]), &counter);
+        }
+      }
+      assert(counter == 5 * 3);
+
+      std::destroy(policy, Iter(pool), Iter(pool + 5));
+      ASSERT_SAME_TYPE(decltype(std::destroy(policy, Iter(pool), Iter(pool + 5))), void);
+      assert(counter == 0);
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
+    }
+  }
+};
+
+template <class Iter>
+struct TestArrayCounted32 {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test destroy() with a range of 5 Counted[3][2] objects.
+      // A shared counter is used for all objects.
+      using Array             = Counted[3][2];
+      using Alloc             = std::allocator<Array>;
+      std::atomic_int counter = 0;
+      Alloc alloc;
+      Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
+
+      for (Array* p = pool; p != pool + 5; ++p) {
+        Array& arr = *p;
+        for (int i = 0; i != 3; ++i) {
+          for (int j = 0; j != 2; ++j) {
+            std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i][j]), &counter);
+          }
+        }
+      }
+      assert(counter == 5 * 3 * 2);
+
+      std::destroy(policy, Iter(pool), Iter(pool + 5));
+      ASSERT_SAME_TYPE(decltype(std::destroy(policy, Iter(pool), Iter(pool + 5))), void);
+      assert(counter == 0);
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
+    }
+  }
+};
+#endif // TEST_STD_VER > 17
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+#if TEST_STD_VER > 17
+  using CountedArray3 = Counted[3];
+  types::for_each(types::forward_iterator_list<CountedArray3*>{}, TestIteratorWithPolicies<TestArrayCounted3>{});
+  using CountedArray32 = Counted[3][2];
+  types::for_each(types::forward_iterator_list<CountedArray32*>{}, TestIteratorWithPolicies<TestArrayCounted32>{});
+#endif // TEST_STD_VER > 17
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy_n.pass.cpp
new file mode 100644
index 0000000000000..e48e3010373df
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/pstl.destroy_n.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 destroy_n(ExecutionPolicy&& exec, ForwardIterator first, Size n);
+
+#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(destroy_n);
+
+static_assert(sfinae_test_destroy_n<int, int*, int>);
+static_assert(!sfinae_test_destroy_n<std::execution::parallel_policy, int*, int>);
+
+struct Counted {
+  std::atomic_int* counter_;
+  Counted(std::atomic_int* counter) : counter_(counter) { 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 destroy_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);
+
+      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) {
+        for (std::size_t i = 0; i < size; ++i) {
+          std::allocator_traits<Alloc>::construct(alloc, std::addressof(pool[i]), &counters[i]);
+        }
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 1; }));
+
+        std::destroy_n(policy, Iter(pool), size);
+        ASSERT_SAME_TYPE(decltype(std::destroy_n(policy, Iter(pool), size)), void);
+        assert(std::all_of(std::begin(counters), std::begin(counters) + size, [](auto& x) { return x == 0; }));
+      });
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, std::size(counters));
+    }
+  }
+};
+
+#if TEST_STD_VER > 17
+template <class Iter>
+struct TestArrayCounted3 {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test destroy_n() with a range of 5 Counted[3] objects.
+      // A shared counter is used for all objects.
+      using Array             = Counted[3];
+      using Alloc             = std::allocator<Array>;
+      std::atomic_int counter = 0;
+      Alloc alloc;
+      Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
+
+      for (Array* p = pool; p != pool + 5; ++p) {
+        Array& arr = *p;
+        for (int i = 0; i != 3; ++i) {
+          std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i]), &counter);
+        }
+      }
+      assert(counter == 5 * 3);
+
+      std::destroy_n(policy, Iter(pool), 5);
+      ASSERT_SAME_TYPE(decltype(std::destroy_n(policy, Iter(pool), 5)), void);
+      assert(counter == 0);
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
+    }
+  }
+};
+
+template <class Iter>
+struct TestArrayCounted32 {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // Test destroy_n() with a range of 5 Counted[3][2] objects.
+      // A shared counter is used for all objects.
+      using Array             = Counted[3][2];
+      using Alloc             = std::allocator<Array>;
+      std::atomic_int counter = 0;
+      Alloc alloc;
+      Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
+
+      for (Array* p = pool; p != pool + 5; ++p) {
+        Array& arr = *p;
+        for (int i = 0; i != 3; ++i) {
+          for (int j = 0; j != 2; ++j) {
+            std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i][j]), &counter);
+          }
+        }
+      }
+      assert(counter == 5 * 3 * 2);
+      std::destroy_n(policy, Iter(pool), 5);
+      ASSERT_SAME_TYPE(decltype(std::destroy_n(policy, Iter(pool), 5)), void);
+      assert(counter == 0);
+
+      std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
+    }
+  }
+};
+#endif // TEST_STD_VER > 17
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<Counted*>{}, TestIteratorWithPolicies<TestCounted>{});
+#if TEST_STD_VER > 17
+  using CountedArray3 = Counted[3];
+  types::for_each(types::forward_iterator_list<CountedArray3*>{}, TestIteratorWithPolicies<TestArrayCounted3>{});
+  using CountedArray32 = Counted[3][2];
+  types::for_each(types::forward_iterator_list<CountedArray32*>{}, TestIteratorWithPolicies<TestArrayCounted32>{});
+#endif // TEST_STD_VER > 17
+  return 0;
+}

>From 057406a814308225558a511309a6f71fe733634d Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 24 Jul 2026 20:13:21 +0100
Subject: [PATCH 2/9] Added pstl.h to the modulemap

---
 libcxx/include/module.modulemap.in | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 39b4e0bb986c6..f0fcf72f178e5 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1682,6 +1682,7 @@ module std {
     module noexcept_move_assign_container     { header "__memory/noexcept_move_assign_container.h" }
     module out_ptr                            { header "__memory/out_ptr.h" }
     module pointer_traits                     { header "__memory/pointer_traits.h" }
+    module pstl                               { header "__memory/pstl.h" }    
     module ranges_construct_at                { header "__memory/ranges_construct_at.h" }
     module ranges_destroy                     { header "__memory/ranges_destroy.h" }
     module ranges_uninitialized_algorithms {

>From 7833b7f53352b74379d9f49ed2de3e2f7821aa68 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 24 Jul 2026 20:37:17 +0100
Subject: [PATCH 3/9] Added a missing underscore

---
 libcxx/include/__pstl/backend_fwd.h      | 4 ++--
 libcxx/include/__pstl/backends/default.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 3372d7c5b3a9b..6cb6b2b36bc9f 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -332,9 +332,9 @@ struct __destroy;
 
 template <class _Backend, class _ExecutionPolicy>
 struct __destroy_n;
-// template <class _Policy, class _ForwardIterator, class Size>
+// template <class _Policy, class _ForwardIterator, class _Size>
 // optional<__empty>
-// operator()(_Policy&& __policy, _ForwardIterator __first, Size __n) const noexcept;
+// operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) 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 affcea6a678e1..01f641c63d99c 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -234,8 +234,8 @@ struct __destroy<__default_backend_tag, _ExecutionPolicy> {
 
 template <class _ExecutionPolicy>
 struct __destroy_n<__default_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class Size>
-  optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, Size __n) const noexcept {
+  template <class _Policy, class _ForwardIterator, class _Size>
+  optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n) const noexcept {
     using _ForEachN = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
     using _Ref      = __iterator_reference<_ForwardIterator>;
     return _ForEachN()(__policy, std::move(__first), __n, [&](_Ref __element) {

>From 458d0e5321ecf96d050e32c28971df5a3449a6e1 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 25 Jul 2026 13:13:59 +0100
Subject: [PATCH 4/9] transitive_includes updates

---
 libcxx/test/libcxx/transitive_includes/cxx17.csv | 16 ++++++++++++++++
 libcxx/test/libcxx/transitive_includes/cxx20.csv |  6 ++++++
 libcxx/test/libcxx/transitive_includes/cxx23.csv |  7 +++++++
 3 files changed, 29 insertions(+)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index a93fb1e26196b..b1319b212d73d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -143,6 +143,7 @@ barrier iterator
 barrier limits
 barrier memory
 barrier new
+barrier optional
 barrier ratio
 barrier stdexcept
 barrier tuple
@@ -1389,7 +1390,9 @@ memory initializer_list
 memory iosfwd
 memory iterator
 memory limits
+memory memory
 memory new
+memory optional
 memory ratio
 memory stdexcept
 memory tuple
@@ -1550,6 +1553,7 @@ optional iterator
 optional limits
 optional memory
 optional new
+optional optional
 optional ratio
 optional stdexcept
 optional tuple
@@ -1855,6 +1859,7 @@ scoped_allocator iterator
 scoped_allocator limits
 scoped_allocator memory
 scoped_allocator new
+scoped_allocator optional
 scoped_allocator ratio
 scoped_allocator stdexcept
 scoped_allocator tuple
@@ -2120,8 +2125,19 @@ stdexcept new
 stdexcept type_traits
 stdexcept typeinfo
 stdexcept version
+stop_token atomic
+stop_token climits
+stop_token cmath
+stop_token compare
 stop_token cstddef
+stop_token cstdint
+stop_token cstdlib
+stop_token cstring
+stop_token ctime
 stop_token iosfwd
+stop_token limits
+stop_token ratio
+stop_token type_traits
 stop_token version
 streambuf algorithm
 streambuf atomic
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index ded0dd1a51c16..e1c6d88a9f8f9 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -50,6 +50,7 @@ any iterator
 any limits
 any memory
 any new
+any optional
 any ratio
 any stdexcept
 any tuple
@@ -123,6 +124,7 @@ barrier iterator
 barrier limits
 barrier memory
 barrier new
+barrier optional
 barrier ratio
 barrier stdexcept
 barrier tuple
@@ -1378,7 +1380,9 @@ memory initializer_list
 memory iosfwd
 memory iterator
 memory limits
+memory memory
 memory new
+memory optional
 memory ratio
 memory stdexcept
 memory tuple
@@ -1539,6 +1543,7 @@ optional iterator
 optional limits
 optional memory
 optional new
+optional optional
 optional ratio
 optional stdexcept
 optional tuple
@@ -1869,6 +1874,7 @@ scoped_allocator iterator
 scoped_allocator limits
 scoped_allocator memory
 scoped_allocator new
+scoped_allocator optional
 scoped_allocator ratio
 scoped_allocator stdexcept
 scoped_allocator tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 53ae6c9b4e591..4fa3fab31f46e 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -673,11 +673,18 @@ mdspan limits
 mdspan span
 mdspan stdexcept
 mdspan version
+memory cctype
+memory climits
 memory compare
 memory cstdint
 memory cstring
+memory ctime
+memory cwchar
+memory cwctype
 memory initializer_list
 memory limits
+memory optional
+memory ratio
 memory tuple
 memory typeinfo
 memory version

>From 6dbcf3159fbb3c2488c8a81f9ed29a82cb138bb0 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 26 Jul 2026 17:00:20 +0100
Subject: [PATCH 5/9] Update Cxx20Issues.csv

---
 libcxx/docs/Status/Cxx20Issues.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index f43a56f99f025..7bdbc018c479e 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -231,7 +231,7 @@
 "`LWG3300 <https://wg21.link/LWG3300>`__","Non-array ``ssize``\  overload is underconstrained","2020-02 (Prague)","|Nothing To Do|","","`#103929 <https://github.com/llvm/llvm-project/issues/103929>`__",""
 "`LWG3301 <https://wg21.link/LWG3301>`__","``transform_view::iterator``\  has incorrect ``iterator_category``\ ","2020-02 (Prague)","|Complete|","15","`#103932 <https://github.com/llvm/llvm-project/issues/103932>`__",""
 "`LWG3302 <https://wg21.link/LWG3302>`__","Range adaptor objects ``keys``\  and ``values``\  are unspecified","2020-02 (Prague)","|Complete|","16","`#103933 <https://github.com/llvm/llvm-project/issues/103933>`__",""
-"`LWG3303 <https://wg21.link/LWG3303>`__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","2020-02 (Prague)","","","`#101693 <https://github.com/llvm/llvm-project/issues/101693>`__",""
+"`LWG3303 <https://wg21.link/LWG3303>`__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","2020-02 (Prague)","|Complete|","24","`#101693 <https://github.com/llvm/llvm-project/issues/101693>`__",""
 "`LWG3304 <https://wg21.link/LWG3304>`__","Allocate functions of ``std::polymorphic_allocator``\  should require ``[[nodiscard]]``\ ","2020-02 (Prague)","|Complete|","16","`#103934 <https://github.com/llvm/llvm-project/issues/103934>`__",""
 "`LWG3307 <https://wg21.link/LWG3307>`__","``std::allocator<void>().allocate(n)``\ ","2020-02 (Prague)","|Complete|","20","`#100422 <https://github.com/llvm/llvm-project/issues/100422>`__",""
 "`LWG3310 <https://wg21.link/LWG3310>`__","Replace ``SIZE_MAX``\  with ``numeric_limits<size_t>::max()``\ ","2020-02 (Prague)","|Complete|","16","`#103936 <https://github.com/llvm/llvm-project/issues/103936>`__",""

>From cd87ec150239b0f2b690b0de4bc81c24ee6b3e29 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 30 Jul 2026 20:03:22 +0100
Subject: [PATCH 6/9] Use <__optional/optional.h>

---
 libcxx/include/__pstl/backends/default.h           | 2 +-
 libcxx/include/__pstl/backends/libdispatch.h       | 2 +-
 libcxx/include/__pstl/backends/serial.h            | 2 +-
 libcxx/include/__pstl/backends/std_thread.h        | 2 +-
 libcxx/include/__pstl/cpu_algos/any_of.h           | 2 +-
 libcxx/include/__pstl/cpu_algos/fill.h             | 2 +-
 libcxx/include/__pstl/cpu_algos/find_if.h          | 2 +-
 libcxx/include/__pstl/cpu_algos/for_each.h         | 2 +-
 libcxx/include/__pstl/cpu_algos/merge.h            | 2 +-
 libcxx/include/__pstl/cpu_algos/mismatch.h         | 2 +-
 libcxx/include/__pstl/cpu_algos/stable_sort.h      | 2 +-
 libcxx/include/__pstl/cpu_algos/transform.h        | 2 +-
 libcxx/include/__pstl/cpu_algos/transform_reduce.h | 2 +-
 libcxx/include/__pstl/handle_exception.h           | 2 +-
 libcxx/test/libcxx/transitive_includes/cxx17.csv   | 5 -----
 libcxx/test/libcxx/transitive_includes/cxx20.csv   | 6 ------
 libcxx/test/libcxx/transitive_includes/cxx23.csv   | 3 ---
 libcxx/test/libcxx/transitive_includes/cxx26.csv   | 3 ---
 18 files changed, 14 insertions(+), 31 deletions(-)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 91c51a6bb2d79..e3130f10b0768 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -29,13 +29,13 @@
 #include <__iterator/reverse_iterator.h>
 #include <__memory/addressof.h>
 #include <__memory/construct_at.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
 #include <__type_traits/desugars_to.h>
 #include <__utility/empty.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 5e89c6fe31cd8..b2f25a2ffb513 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -30,6 +30,7 @@
 #include <__memory/unique_ptr.h>
 #include <__new/exceptions.h>
 #include <__numeric/reduce.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/any_of.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
@@ -45,7 +46,6 @@
 #include <__utility/exception_guard.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <optional>
 
 _LIBCPP_PUSH_MACROS
 #include <__undef_macros>
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index d90022ee37145..fe4b9da14dcf5 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -18,11 +18,11 @@
 #include <__algorithm/transform.h>
 #include <__config>
 #include <__numeric/transform_reduce.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__utility/empty.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index 93935d22b9442..8aca740e649d6 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___PSTL_BACKENDS_STD_THREAD_H
 
 #include <__config>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/any_of.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
@@ -23,7 +24,6 @@
 #include <__pstl/cpu_algos/transform_reduce.h>
 #include <__utility/empty.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/any_of.h b/libcxx/include/__pstl/cpu_algos/any_of.h
index 803db7974eca7..3d3d2c15bfa50 100644
--- a/libcxx/include/__pstl/cpu_algos/any_of.h
+++ b/libcxx/include/__pstl/cpu_algos/any_of.h
@@ -15,13 +15,13 @@
 #include <__atomic/memory_order.h>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <cstdint>
-#include <optional>
 
 _LIBCPP_PUSH_MACROS
 #include <__undef_macros>
diff --git a/libcxx/include/__pstl/cpu_algos/fill.h b/libcxx/include/__pstl/cpu_algos/fill.h
index 3e5936589a6a6..83993669014e8 100644
--- a/libcxx/include/__pstl/cpu_algos/fill.h
+++ b/libcxx/include/__pstl/cpu_algos/fill.h
@@ -13,11 +13,11 @@
 #include <__assert>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/empty.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/find_if.h b/libcxx/include/__pstl/cpu_algos/find_if.h
index aae64b66eb0c0..a560cd0ec1d96 100644
--- a/libcxx/include/__pstl/cpu_algos/find_if.h
+++ b/libcxx/include/__pstl/cpu_algos/find_if.h
@@ -16,12 +16,12 @@
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/for_each.h b/libcxx/include/__pstl/cpu_algos/for_each.h
index cec719bc47b88..908f82f01e6c8 100644
--- a/libcxx/include/__pstl/cpu_algos/for_each.h
+++ b/libcxx/include/__pstl/cpu_algos/for_each.h
@@ -13,11 +13,11 @@
 #include <__assert>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/empty.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/merge.h b/libcxx/include/__pstl/cpu_algos/merge.h
index a9069ca51de2f..5534f2d058257 100644
--- a/libcxx/include/__pstl/cpu_algos/merge.h
+++ b/libcxx/include/__pstl/cpu_algos/merge.h
@@ -13,11 +13,11 @@
 #include <__assert>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
index 3d702b03d3afe..add576324b52b 100644
--- a/libcxx/include/__pstl/cpu_algos/mismatch.h
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -15,13 +15,13 @@
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__pstl/cpu_algos/find_if.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/stable_sort.h b/libcxx/include/__pstl/cpu_algos/stable_sort.h
index 5afdd3fd629ba..d8d08325564e4 100644
--- a/libcxx/include/__pstl/cpu_algos/stable_sort.h
+++ b/libcxx/include/__pstl/cpu_algos/stable_sort.h
@@ -11,11 +11,11 @@
 
 #include <__algorithm/stable_sort.h>
 #include <__config>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/empty.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/transform.h b/libcxx/include/__pstl/cpu_algos/transform.h
index 30d117d754b31..00e917acf1cca 100644
--- a/libcxx/include/__pstl/cpu_algos/transform.h
+++ b/libcxx/include/__pstl/cpu_algos/transform.h
@@ -14,11 +14,11 @@
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/cpu_algos/transform_reduce.h b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
index edfb28b4466fc..4299da95d9bb6 100644
--- a/libcxx/include/__pstl/cpu_algos/transform_reduce.h
+++ b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
@@ -14,13 +14,13 @@
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
 #include <__numeric/transform_reduce.h>
+#include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/desugars_to.h>
 #include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/include/__pstl/handle_exception.h b/libcxx/include/__pstl/handle_exception.h
index 3b5fca86902b0..e3541a99d11e0 100644
--- a/libcxx/include/__pstl/handle_exception.h
+++ b/libcxx/include/__pstl/handle_exception.h
@@ -11,9 +11,9 @@
 
 #include <__config>
 #include <__new/exceptions.h>
+#include <__optional/optional.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
-#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index b1319b212d73d..4378b4c6a3cb8 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -143,7 +143,6 @@ barrier iterator
 barrier limits
 barrier memory
 barrier new
-barrier optional
 barrier ratio
 barrier stdexcept
 barrier tuple
@@ -1390,9 +1389,7 @@ memory initializer_list
 memory iosfwd
 memory iterator
 memory limits
-memory memory
 memory new
-memory optional
 memory ratio
 memory stdexcept
 memory tuple
@@ -1553,7 +1550,6 @@ optional iterator
 optional limits
 optional memory
 optional new
-optional optional
 optional ratio
 optional stdexcept
 optional tuple
@@ -1859,7 +1855,6 @@ scoped_allocator iterator
 scoped_allocator limits
 scoped_allocator memory
 scoped_allocator new
-scoped_allocator optional
 scoped_allocator ratio
 scoped_allocator stdexcept
 scoped_allocator tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index e1c6d88a9f8f9..ded0dd1a51c16 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -50,7 +50,6 @@ any iterator
 any limits
 any memory
 any new
-any optional
 any ratio
 any stdexcept
 any tuple
@@ -124,7 +123,6 @@ barrier iterator
 barrier limits
 barrier memory
 barrier new
-barrier optional
 barrier ratio
 barrier stdexcept
 barrier tuple
@@ -1380,9 +1378,7 @@ memory initializer_list
 memory iosfwd
 memory iterator
 memory limits
-memory memory
 memory new
-memory optional
 memory ratio
 memory stdexcept
 memory tuple
@@ -1543,7 +1539,6 @@ optional iterator
 optional limits
 optional memory
 optional new
-optional optional
 optional ratio
 optional stdexcept
 optional tuple
@@ -1874,7 +1869,6 @@ scoped_allocator iterator
 scoped_allocator limits
 scoped_allocator memory
 scoped_allocator new
-scoped_allocator optional
 scoped_allocator ratio
 scoped_allocator stdexcept
 scoped_allocator tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index a7475a744ff6e..aa5d95e3265f1 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -687,7 +687,6 @@ memory cwchar
 memory cwctype
 memory initializer_list
 memory limits
-memory optional
 memory ratio
 memory tuple
 memory typeinfo
@@ -725,7 +724,6 @@ numeric cwchar
 numeric cwctype
 numeric initializer_list
 numeric limits
-numeric optional
 numeric ratio
 numeric tuple
 numeric version
@@ -836,7 +834,6 @@ random initializer_list
 random iosfwd
 random limits
 random numeric
-random optional
 random ratio
 random stdexcept
 random string
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 1be27d82b2554..a6f868fd4c467 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -637,7 +637,6 @@ memory cwchar
 memory cwctype
 memory initializer_list
 memory limits
-memory optional
 memory ratio
 memory tuple
 memory typeinfo
@@ -674,7 +673,6 @@ numeric cwchar
 numeric cwctype
 numeric initializer_list
 numeric limits
-numeric optional
 numeric ratio
 numeric tuple
 numeric version
@@ -772,7 +770,6 @@ random initializer_list
 random iosfwd
 random limits
 random numeric
-random optional
 random ratio
 random stdexcept
 random string

>From 8077d7156b2bc14dd1db711b8c547a24e6779aad Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 30 Jul 2026 21:10:11 +0100
Subject: [PATCH 7/9] More direct includes

---
 libcxx/include/__pstl/backends/default.h           | 1 +
 libcxx/include/__pstl/backends/libdispatch.h       | 1 +
 libcxx/include/__pstl/cpu_algos/any_of.h           | 1 +
 libcxx/include/__pstl/cpu_algos/find_if.h          | 1 +
 libcxx/include/__pstl/cpu_algos/merge.h            | 1 +
 libcxx/include/__pstl/cpu_algos/mismatch.h         | 1 +
 libcxx/include/__pstl/cpu_algos/transform_reduce.h | 1 +
 libcxx/include/__pstl/handle_exception.h           | 1 +
 8 files changed, 8 insertions(+)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index e3130f10b0768..d86d1987a4e5e 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -29,6 +29,7 @@
 #include <__iterator/reverse_iterator.h>
 #include <__memory/addressof.h>
 #include <__memory/construct_at.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index b2f25a2ffb513..20aa803a8b2b0 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -30,6 +30,7 @@
 #include <__memory/unique_ptr.h>
 #include <__new/exceptions.h>
 #include <__numeric/reduce.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/any_of.h>
diff --git a/libcxx/include/__pstl/cpu_algos/any_of.h b/libcxx/include/__pstl/cpu_algos/any_of.h
index 3d3d2c15bfa50..cb161542cbc5e 100644
--- a/libcxx/include/__pstl/cpu_algos/any_of.h
+++ b/libcxx/include/__pstl/cpu_algos/any_of.h
@@ -15,6 +15,7 @@
 #include <__atomic/memory_order.h>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
diff --git a/libcxx/include/__pstl/cpu_algos/find_if.h b/libcxx/include/__pstl/cpu_algos/find_if.h
index a560cd0ec1d96..cf54c4b0d4f52 100644
--- a/libcxx/include/__pstl/cpu_algos/find_if.h
+++ b/libcxx/include/__pstl/cpu_algos/find_if.h
@@ -16,6 +16,7 @@
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
diff --git a/libcxx/include/__pstl/cpu_algos/merge.h b/libcxx/include/__pstl/cpu_algos/merge.h
index 5534f2d058257..7628f47e40e04 100644
--- a/libcxx/include/__pstl/cpu_algos/merge.h
+++ b/libcxx/include/__pstl/cpu_algos/merge.h
@@ -13,6 +13,7 @@
 #include <__assert>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
index add576324b52b..1aaec3e047c0b 100644
--- a/libcxx/include/__pstl/cpu_algos/mismatch.h
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -15,6 +15,7 @@
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
diff --git a/libcxx/include/__pstl/cpu_algos/transform_reduce.h b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
index 4299da95d9bb6..c4a78068f7945 100644
--- a/libcxx/include/__pstl/cpu_algos/transform_reduce.h
+++ b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
@@ -18,6 +18,7 @@
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/desugars_to.h>
+#include <__type_traits/invoke.h>
 #include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
diff --git a/libcxx/include/__pstl/handle_exception.h b/libcxx/include/__pstl/handle_exception.h
index e3541a99d11e0..ac576a11ff767 100644
--- a/libcxx/include/__pstl/handle_exception.h
+++ b/libcxx/include/__pstl/handle_exception.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__new/exceptions.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>

>From 802318549aa09a8c0aff8fe122dd94e0cb36acaa Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 30 Jul 2026 21:15:06 +0100
Subject: [PATCH 8/9] Another missed include

---
 libcxx/include/__pstl/cpu_algos/transform.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__pstl/cpu_algos/transform.h b/libcxx/include/__pstl/cpu_algos/transform.h
index 00e917acf1cca..61630ea8f9d47 100644
--- a/libcxx/include/__pstl/cpu_algos/transform.h
+++ b/libcxx/include/__pstl/cpu_algos/transform.h
@@ -14,6 +14,7 @@
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>

>From fa88b5b41e9aefc4bf8c03ef596320f3ca5cba56 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 30 Jul 2026 21:47:40 +0100
Subject: [PATCH 9/9] More includes

---
 libcxx/include/__pstl/backends/libdispatch.h       | 1 +
 libcxx/include/__pstl/backends/std_thread.h        | 1 +
 libcxx/include/__pstl/cpu_algos/transform_reduce.h | 2 ++
 3 files changed, 4 insertions(+)

diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 20aa803a8b2b0..6b77940afbad4 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -21,6 +21,7 @@
 #include <__atomic/atomic.h>
 #include <__config>
 #include <__cstddef/ptrdiff_t.h>
+#include <__cstddef/size_t.h>
 #include <__exception/terminate.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/move_iterator.h>
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index 8aca740e649d6..07610ee880a88 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___PSTL_BACKENDS_STD_THREAD_H
 
 #include <__config>
+#include <__cstddef/size_t.h>
 #include <__optional/optional.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/any_of.h>
diff --git a/libcxx/include/__pstl/cpu_algos/transform_reduce.h b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
index c4a78068f7945..ecf4b0a446251 100644
--- a/libcxx/include/__pstl/cpu_algos/transform_reduce.h
+++ b/libcxx/include/__pstl/cpu_algos/transform_reduce.h
@@ -11,6 +11,7 @@
 
 #include <__assert>
 #include <__config>
+#include <__cstddef/size_t.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
 #include <__numeric/transform_reduce.h>
@@ -18,6 +19,7 @@
 #include <__pstl/backend_fwd.h>
 #include <__pstl/cpu_algos/cpu_traits.h>
 #include <__type_traits/desugars_to.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_execution_policy.h>



More information about the libcxx-commits mailing list