[libcxx-commits] [libcxx] aade746 - [libc++][PSTL] Overhaul exceptions handling

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 6 14:01:35 PDT 2023


Author: Nikolas Klauser
Date: 2023-10-06T23:01:30+02:00
New Revision: aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20

URL: https://github.com/llvm/llvm-project/commit/aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20
DIFF: https://github.com/llvm/llvm-project/commit/aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20.diff

LOG: [libc++][PSTL] Overhaul exceptions handling

This makes exception handling a lot simpler, since we don't have to convert any exceptions this way. Is also properly handles all the user-thrown exceptions.

Reviewed By: ldionne, #libc

Spies: arichardson, mstorsjo, libcxx-commits

Differential Revision: https://reviews.llvm.org/D154238

Added: 
    libcxx/include/__utility/empty.h
    libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp
    libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp

Modified: 
    libcxx/include/CMakeLists.txt
    libcxx/include/__algorithm/pstl_any_all_none_of.h
    libcxx/include/__algorithm/pstl_backend.h
    libcxx/include/__algorithm/pstl_backends/cpu_backend.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h
    libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
    libcxx/include/__algorithm/pstl_copy.h
    libcxx/include/__algorithm/pstl_count.h
    libcxx/include/__algorithm/pstl_fill.h
    libcxx/include/__algorithm/pstl_find.h
    libcxx/include/__algorithm/pstl_for_each.h
    libcxx/include/__algorithm/pstl_generate.h
    libcxx/include/__algorithm/pstl_is_partitioned.h
    libcxx/include/__algorithm/pstl_merge.h
    libcxx/include/__algorithm/pstl_replace.h
    libcxx/include/__algorithm/pstl_sort.h
    libcxx/include/__algorithm/pstl_stable_sort.h
    libcxx/include/__algorithm/pstl_transform.h
    libcxx/include/__numeric/pstl_reduce.h
    libcxx/include/__numeric/pstl_transform_reduce.h
    libcxx/include/module.modulemap.in
    libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp
    libcxx/test/libcxx/transitive_includes/cxx03.csv
    libcxx/test/libcxx/transitive_includes/cxx11.csv
    libcxx/test/libcxx/transitive_includes/cxx14.csv
    libcxx/test/libcxx/transitive_includes/cxx17.csv
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx23.csv
    libcxx/test/libcxx/transitive_includes/cxx26.csv
    libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp
    libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp
    libcxx/test/support/check_assertion.h
    libcxx/test/support/test_execution_policies.h
    libcxx/test/support/test_iterators.h

Removed: 
    libcxx/include/__utility/terminate_on_exception.h


################################################################################
diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 2ec755236dbaee2..340353f8ebb41c4 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -838,6 +838,7 @@ set(files
   __utility/cmp.h
   __utility/convert_to_integral.h
   __utility/declval.h
+  __utility/empty.h
   __utility/exception_guard.h
   __utility/exchange.h
   __utility/forward.h
@@ -851,7 +852,6 @@ set(files
   __utility/priority_tag.h
   __utility/rel_ops.h
   __utility/swap.h
-  __utility/terminate_on_exception.h
   __utility/to_underlying.h
   __utility/unreachable.h
   __variant/monostate.h

diff  --git a/libcxx/include/__algorithm/pstl_any_all_none_of.h b/libcxx/include/__algorithm/pstl_any_all_none_of.h
index 47d280c4314938b..d93fdba2224c9b1 100644
--- a/libcxx/include/__algorithm/pstl_any_all_none_of.h
+++ b/libcxx/include/__algorithm/pstl_any_all_none_of.h
@@ -17,7 +17,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -35,19 +35,35 @@ template <class _ExecutionPolicy,
           class _Predicate,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
-any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool> __any_of(
+    _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
-        return std::find_if(__policy, __g_first, __g_last, __g_pred) != __g_last;
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<bool> {
+        auto __res = std::__find_if(__policy, __g_first, __g_last, __g_pred);
+        if (!__res)
+          return nullopt;
+        return *__res != __g_last;
       },
       std::move(__first),
       std::move(__last),
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Predicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
+any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__any_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_all_of(); // declaration needed for the frontend dispatch below
 
@@ -56,21 +72,37 @@ template <class _ExecutionPolicy,
           class _Pred,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
-all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
+__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) {
-        return !std::any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
+        auto __res = std::__any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
           return !__g_pred(__value);
         });
+        if (!__res)
+          return nullopt;
+        return !*__res;
       },
       std::move(__first),
       std::move(__last),
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Pred,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
+all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__all_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_none_of(); // declaration needed for the frontend dispatch below
 
@@ -79,19 +111,35 @@ template <class _ExecutionPolicy,
           class _Pred,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
-none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
+__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) {
-        return !std::any_of(__policy, __g_first, __g_last, __g_pred);
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
+        auto __res = std::__any_of(__policy, __g_first, __g_last, __g_pred);
+        if (!__res)
+          return nullopt;
+        return !*__res;
       },
       std::move(__first),
       std::move(__last),
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Pred,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
+none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__none_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h
index 3d9459ef5fa23a4..94644e5c47b3952 100644
--- a/libcxx/include/__algorithm/pstl_backend.h
+++ b/libcxx/include/__algorithm/pstl_backend.h
@@ -27,13 +27,14 @@ TODO: Documentation of how backends work
 A PSTL parallel backend is a tag type to which the following functions are associated, at minimum:
 
   template <class _ExecutionPolicy, class _Iterator, class _Func>
-  void __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f);
+  optional<__empty> __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  _Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+  optional<_Iterator> __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
-  void __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
+  optional<__empty>
+  __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
 
   template <class _ExecutionPolicy,
             class _ForwardIterator1,
@@ -49,19 +50,15 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
                                    _Comp __comp);
 
   template <class _ExecutionPolicy, class _InIterator, class _OutIterator, class _UnaryOperation>
-  _OutIterator __pstl_transform(_Backend,
-                                _InIterator __first,
-                                _InIterator __last,
-                                _OutIterator __result,
-                                _UnaryOperation __op);
+  optional<_OutIterator>
+  __pstl_transform(_Backend, _InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op);
 
   template <class _ExecutionPolicy, class _InIterator1, class _InIterator2, class _OutIterator, class _BinaryOperation>
-  _OutIterator __pstl_transform(_Backend,
-                                _InIterator1 __first1,
-                                _InIterator1 __last1,
-                                _InIterator2 __first2,
-                                _OutIterator __result,
-                                _BinaryOperation __op);
+  optional<_OutIterator> __pstl_transform(_InIterator1 __first1,
+                                          _InIterator2 __first2,
+                                          _InIterator1 __last1,
+                                          _OutIterator __result,
+                                          _BinaryOperation __op);
 
   template <class _ExecutionPolicy,
             class _Iterator1,
@@ -69,22 +66,22 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
             class _Tp,
             class _BinaryOperation1,
             class _BinaryOperation2>
-  _Tp __pstl_transform_reduce(_Backend,
-                              _Iterator1 __first1,
-                              _Iterator1 __last1,
-                              _Iterator2 __first2,
-                              _Iterator2 __last2,
-                              _Tp __init,
-                              _BinaryOperation1 __reduce,
-                              _BinaryOperation2 __transform);
+  optional<_Tp> __pstl_transform_reduce(_Backend,
+                                        _Iterator1 __first1,
+                                        _Iterator1 __last1,
+                                        _Iterator2 __first2,
+                                        _Iterator2 __last2,
+                                        _Tp __init,
+                                        _BinaryOperation1 __reduce,
+                                        _BinaryOperation2 __transform);
 
   template <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
-  _Tp __pstl_transform_reduce(_Backend,
-                              _Iterator __first,
-                              _Iterator __last,
-                              _Tp __init,
-                              _BinaryOperation __reduce,
-                              _UnaryOperation __transform);
+  optional<_Tp> __pstl_transform_reduce(_Backend,
+                                        _Iterator __first,
+                                        _Iterator __last,
+                                        _Tp __init,
+                                        _BinaryOperation __reduce,
+                                        _UnaryOperation __transform);
 
 // TODO: Complete this list
 
@@ -93,86 +90,95 @@ algorithms, otherwise they are implemented in terms of other algorithms. If none
 implemented, all the algorithms will eventually forward to the basis algorithms listed above:
 
   template <class _ExecutionPolicy, class _Iterator, class _Size, class _Func>
-  void __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f);
+  optional<__empty> __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+  optional<bool> __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+  optional<bool> __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+  optional<bool> __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Tp>
-  _Iterator __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
+  optional<_Iterator> __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  _Iterator __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+  optional<_Iterator> __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Tp>
-  void __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
+  optional<__empty> __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
 
   template <class _ExecutionPolicy, class _Iterator, class _SizeT, class _Tp>
-  void __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value);
+  optional<__empty> __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value);
 
   template <class _ExecutionPolicy, class _Iterator, class _Generator>
-  void __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
+  optional<__empty> __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  void __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+  optional<__empty> __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Size, class _Generator>
-  void __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
+  optional<__empty> __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
 
   template <class _ExecutionPolicy, class _terator1, class _Iterator2, class _OutIterator, class _Comp>
-  _OutIterator __pstl_merge(_Backend,
-                            _Iterator1 __first1,
-                            _Iterator1 __last1,
-                            _Iterator2 __first2,
-                            _Iterator2 __last2,
-                            _OutIterator __result,
-                            _Comp __comp);
+  optional<_OutIterator> __pstl_merge(_Backend,
+                                      _Iterator1 __first1,
+                                      _Iterator1 __last1,
+                                      _Iterator2 __first2,
+                                      _Iterator2 __last2,
+                                      _OutIterator __result,
+                                      _Comp __comp);
 
   template <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation>
-  _Tp __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op);
+  optional<_Tp> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op);
 
   temlate <class _ExecutionPolicy, class _Iterator>
-  __iter_value_type<_Iterator> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
+  optional<__iter_value_type<_Iterator>> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
 
   template <class _ExecuitonPolicy, class _Iterator, class _Tp>
-  __iter_
diff _t<_Iterator> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
+  optional<__iter_
diff _t<_Iterator>> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
 
   template <class _ExecutionPolicy, class _Iterator, class _Predicate>
-  __iter_
diff _t<_Iterator> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+  optional<__iter_
diff _t<_Iterator>> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
 
   template <class _ExecutionPolicy, class _Iterator, class _Tp>
-  void __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value);
+  optional<__empty>
+  __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value);
 
   template <class _ExecutionPolicy, class _Iterator, class _Pred, class _Tp>
-  void __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value);
+  optional<__empty>
+  __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value);
 
   template <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Tp>
-  void __pstl_replace_copy(_Backend,
-                           _Iterator __first,
-                           _Iterator __last,
-                           _OutIterator __result,
-                           const _Tp& __old_value,
-                           const _Tp& __new_value);
+  optional<__empty> __pstl_replace_copy(_Backend,
+                                        _Iterator __first,
+                                        _Iterator __last,
+                                        _OutIterator __result,
+                                        const _Tp& __old_value,
+                                        const _Tp& __new_value);
 
   template <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Pred, class _Tp>
-  void __pstl_replace_copy_if(_Backend,
-                              _Iterator __first,
-                              _Iterator __last,
-                              _OutIterator __result,
-                              _Pred __pred,
-                              const _Tp& __new_value);
+  optional<__empty> __pstl_replace_copy_if(_Backend,
+                                           _Iterator __first,
+                                           _Iterator __last,
+                                           _OutIterator __result,
+                                           _Pred __pred,
+                                           const _Tp& __new_value);
 
   template <class _ExecutionPolicy, class _Iterator, class _Comp>
-  void __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp);
+  optional<__empty> __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp);
 
 // TODO: Complete this list
 
+Exception handling
+==================
+
+PSTL backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their
+implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned
+into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the
+frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user.
 */
 
 template <class _ExecutionPolicy>

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h
index e54f331b9430b68..6980ded189ea2a3 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h
@@ -15,10 +15,11 @@
 
   // _Functor takes a subrange for [__first, __last) that should be executed in serial
   template <class _RandomAccessIterator, class _Functor>
-  void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
+  optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
 
   template <class _Iterator, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduction>
-  _Tp __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction);
+  optional<_Tp>
+  __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction);
 
   // Cancel the execution of other jobs - they aren't needed anymore
   void __cancel_execution();
@@ -28,7 +29,7 @@
             class _RandomAccessIterator3,
             class _Compare,
             class _LeafMerge>
-  void __parallel_merge(
+  optional<void> __parallel_merge(
       _RandomAccessIterator1 __first1,
       _RandomAccessIterator1 __last1,
       _RandomAccessIterator2 __first2,
@@ -44,6 +45,14 @@
                               _LeafSort __leaf_sort);
 
   TODO: Document the parallel backend
+
+Exception handling
+==================
+
+CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their
+implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned
+into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the
+frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user.
 */
 
 #include <__algorithm/pstl_backends/cpu_backends/any_of.h>

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h
index c8a071af82ac699..13dff80086e72b2 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h
@@ -18,24 +18,30 @@
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
 #include <__utility/pair.h>
-#include <__utility/terminate_on_exception.h>
 #include <cstdint>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Index, class _Brick>
-_LIBCPP_HIDE_FROM_ABI bool __parallel_or(_Index __first, _Index __last, _Brick __f) {
+_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
   std::atomic<bool> __found(false);
-  __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) {
+  auto __ret = __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) {
     if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) {
       __found.store(true, std::memory_order_relaxed);
       __par_backend::__cancel_execution();
     }
   });
-  return __found;
+  if (!__ret)
+    return nullopt;
+  return static_cast<bool>(__found);
 }
 
 // TODO: check whether __simd_first() can be used here
@@ -64,17 +70,17 @@ _LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_LIBCPP_HIDE_FROM_ABI bool
+_LIBCPP_HIDE_FROM_ABI optional<bool>
 __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-    return std::__terminate_on_exception([&] {
-      return std::__parallel_or(
-          __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{}, __brick_first, __brick_last, __pred);
-          });
-    });
+    return std::__parallel_or(
+        __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+          auto __res = std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{}, __brick_first, __brick_last, __pred);
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          return *std::move(__res);
+        });
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
     return std::__simd_or(__first, __last - __first, __pred);
@@ -85,6 +91,8 @@ __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __la
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
index 8b531887c731808..64babe9fd2bdae8 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
@@ -14,7 +14,8 @@
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__type_traits/is_execution_policy.h>
-#include <__utility/terminate_on_exception.h>
+#include <__utility/empty.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n,
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
 __pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-    std::__terminate_on_exception([&] {
-      __par_backend::__parallel_for(
-          __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{}, __brick_first, __brick_last, __value);
-          });
-    });
+    return __par_backend::__parallel_for(
+        __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+          [[maybe_unused]] auto __res = std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{}, __brick_first, __brick_last, __value);
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+        });
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
     std::__simd_fill_n(__first, __last - __first, __value);
+    return __empty{};
   } else {
     std::fill(__first, __last, __value);
+    return __empty{};
   }
 }
 

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
index 91610c040857b79..170470e4fb7edde 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
@@ -17,9 +17,10 @@
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
 #include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
 #include <__utility/pair.h>
-#include <__utility/terminate_on_exception.h>
 #include <cstddef>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -27,31 +28,37 @@
 
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Index, class _Brick, class _Compare>
-_LIBCPP_HIDE_FROM_ABI _Index
+_LIBCPP_HIDE_FROM_ABI optional<_Index>
 __parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
   typedef typename std::iterator_traits<_Index>::
diff erence_type _DifferenceType;
   const _DifferenceType __n      = __last - __first;
   _DifferenceType __initial_dist = __b_first ? __n : -1;
   std::atomic<_DifferenceType> __extremum(__initial_dist);
   // TODO: find out what is better here: parallel_for or parallel_reduce
-  __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
-    // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
-    // why using a shared variable scales fairly well in this situation.
-    if (__comp(__i - __first, __extremum)) {
-      _Index __res = __f(__i, __j);
-      // If not '__last' returned then we found what we want so put this to extremum
-      if (__res != __j) {
-        const _DifferenceType __k = __res - __first;
-        for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
-          __extremum.compare_exchange_weak(__old, __k);
+  auto __res =
+      __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
+        // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
+        // why using a shared variable scales fairly well in this situation.
+        if (__comp(__i - __first, __extremum)) {
+          _Index __result = __f(__i, __j);
+          // If not '__last' returned then we found what we want so put this to extremum
+          if (__result != __j) {
+            const _DifferenceType __k = __result - __first;
+            for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
+              __extremum.compare_exchange_weak(__old, __k);
+            }
+          }
         }
-      }
-    }
-  });
-  return __extremum != __initial_dist ? __first + __extremum : __last;
+      });
+  if (!__res)
+    return nullopt;
+  return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
 }
 
 template <class _Index, class _DifferenceType, class _Compare>
@@ -91,21 +98,21 @@ __simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Co
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+_LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
 __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-    return std::__terminate_on_exception([&] {
-      return std::__parallel_find(
-          __first,
-          __last,
-          [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{}, __brick_first, __brick_last, __pred);
-          },
-          less<>{},
-          true);
-    });
+    return std::__parallel_find(
+        __first,
+        __last,
+        [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+          auto __res = std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{}, __brick_first, __brick_last, __pred);
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          return *std::move(__res);
+        },
+        less<>{},
+        true);
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
     using __
diff _t = __iter_
diff _t<_ForwardIterator>;
@@ -119,6 +126,8 @@ __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __l
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h
index f6f22fdd8713ced..6cfef932aa48db3 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h
@@ -14,7 +14,8 @@
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__type_traits/is_execution_policy.h>
-#include <__utility/terminate_on_exception.h>
+#include <__utility/empty.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Iterator __simd_walk_1(_Iterator __first, _DifferenceType
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
 __pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-    std::__terminate_on_exception([&] {
-      std::__par_backend::__parallel_for(
-          __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{}, __brick_first, __brick_last, __func);
-          });
-    });
+    return std::__par_backend::__parallel_for(
+        __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+          [[maybe_unused]] auto __res = std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{}, __brick_first, __brick_last, __func);
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+        });
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
     std::__simd_walk_1(__first, __last - __first, __func);
+    return __empty{};
   } else {
     std::for_each(__first, __last, __func);
+    return __empty{};
   }
 }
 

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
index 50b6e0b1d0a03f3..e885e7f225172cc 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
@@ -23,11 +23,13 @@
 #include <__memory/construct_at.h>
 #include <__memory/unique_ptr.h>
 #include <__numeric/reduce.h>
+#include <__utility/empty.h>
+#include <__utility/exception_guard.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <__utility/terminate_on_exception.h>
 #include <cstddef>
 #include <new>
+#include <optional>
 
 _LIBCPP_PUSH_MACROS
 #include <__undef_macros>
@@ -61,8 +63,9 @@ struct __chunk_partitions {
 [[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI __chunk_partitions __partition_chunks(ptr
diff _t __size) noexcept;
 
 template <class _RandomAccessIterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
 __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator __first, _Functor __func) {
+  // Perform the chunked execution.
   __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __chunk) {
     auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
     auto __index =
@@ -71,10 +74,12 @@ __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator _
             : (__chunk * __partitions.__chunk_size_) + (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
     __func(__first + __index, __first + __index + __this_chunk_size);
   });
+
+  return __empty{};
 }
 
 template <class _RandomAccessIterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
 __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func) {
   return __libdispatch::__dispatch_parallel_for(
       __libdispatch::__partition_chunks(__last - __first), std::move(__first), std::move(__func));
@@ -95,23 +100,23 @@ template <typename _RandomAccessIterator1,
           typename _RandomAccessIterator3,
           typename _Compare,
           typename _LeafMerge>
-_LIBCPP_HIDE_FROM_ABI void __parallel_merge(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge(
     _RandomAccessIterator1 __first1,
     _RandomAccessIterator1 __last1,
     _RandomAccessIterator2 __first2,
     _RandomAccessIterator2 __last2,
     _RandomAccessIterator3 __result,
     _Compare __comp,
-    _LeafMerge __leaf_merge) {
+    _LeafMerge __leaf_merge) noexcept {
   __chunk_partitions __partitions =
       __libdispatch::__partition_chunks(std::max<ptr
diff _t>(__last1 - __first1, __last2 - __first2));
 
   if (__partitions.__chunk_count_ == 0)
-    return;
+    return __empty{};
 
   if (__partitions.__chunk_count_ == 1) {
     __leaf_merge(__first1, __last1, __first2, __last2, __result, __comp);
-    return;
+    return __empty{};
   }
 
   using __merge_range_t = __merge_range<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3>;
@@ -122,61 +127,76 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
     std::destroy_n(__ptr, __n_ranges);
     std::allocator<__merge_range_t>().deallocate(__ptr, __n_ranges);
   };
+
   unique_ptr<__merge_range_t[], decltype(__destroy)> __ranges(
-      std::allocator<__merge_range_t>().allocate(__n_ranges), __destroy);
+      [&]() -> __merge_range_t* {
+#  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+        try {
+#  endif
+          return std::allocator<__merge_range_t>().allocate(__n_ranges);
+#  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+        } catch (const std::bad_alloc&) {
+          return nullptr;
+        }
+#  endif
+      }(),
+      __destroy);
+
+  if (!__ranges)
+    return nullopt;
 
   // TODO: Improve the case where the smaller range is merged into just a few (or even one) chunks of the larger case
-  std::__terminate_on_exception([&] {
-    __merge_range_t* __r = __ranges.get();
-    std::__construct_at(__r++, __first1, __first2, __result);
-
-    bool __iterate_first_range = __last1 - __first1 > __last2 - __first2;
-
-    auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t {
-      auto [__mid1, __mid2] = [&] {
-        if (__iterate_first_range) {
-          auto __m1 = __first1 + __chunk_size;
-          auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp);
-          return std::make_pair(__m1, __m2);
-        } else {
-          auto __m2 = __first2 + __chunk_size;
-          auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp);
-          return std::make_pair(__m1, __m2);
-        }
-      }();
+  __merge_range_t* __r = __ranges.get();
+  std::__construct_at(__r++, __first1, __first2, __result);
 
-      __result += (__mid1 - __first1) + (__mid2 - __first2);
-      __first1 = __mid1;
-      __first2 = __mid2;
-      return {std::move(__mid1), std::move(__mid2), __result};
-    };
+  bool __iterate_first_range = __last1 - __first1 > __last2 - __first2;
 
-    // handle first chunk
-    std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_));
-
-    // handle 2 -> N - 1 chunks
-    for (ptr
diff _t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i)
-      std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_));
-
-    // handle last chunk
-    std::__construct_at(__r, __last1, __last2, __result);
-
-    __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) {
-      auto __first_iters = __ranges[__index];
-      auto __last_iters  = __ranges[__index + 1];
-      __leaf_merge(
-          __first_iters.__mid1_,
-          __last_iters.__mid1_,
-          __first_iters.__mid2_,
-          __last_iters.__mid2_,
-          __first_iters.__result_,
-          __comp);
-    });
+  auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t {
+    auto [__mid1, __mid2] = [&] {
+      if (__iterate_first_range) {
+        auto __m1 = __first1 + __chunk_size;
+        auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp);
+        return std::make_pair(__m1, __m2);
+      } else {
+        auto __m2 = __first2 + __chunk_size;
+        auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp);
+        return std::make_pair(__m1, __m2);
+      }
+    }();
+
+    __result += (__mid1 - __first1) + (__mid2 - __first2);
+    __first1 = __mid1;
+    __first2 = __mid2;
+    return {std::move(__mid1), std::move(__mid2), __result};
+  };
+
+  // handle first chunk
+  std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_));
+
+  // handle 2 -> N - 1 chunks
+  for (ptr
diff _t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i)
+    std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_));
+
+  // handle last chunk
+  std::__construct_at(__r, __last1, __last2, __result);
+
+  __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) {
+    auto __first_iters = __ranges[__index];
+    auto __last_iters  = __ranges[__index + 1];
+    __leaf_merge(
+        __first_iters.__mid1_,
+        __last_iters.__mid1_,
+        __first_iters.__mid2_,
+        __last_iters.__mid2_,
+        __first_iters.__result_,
+        __comp);
   });
+
+  return __empty{};
 }
 
 template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
-_LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce(
+_LIBCPP_HIDE_FROM_ABI optional<_Value> __parallel_transform_reduce(
     _RandomAccessIterator __first,
     _RandomAccessIterator __last,
     _Transform __transform,
@@ -216,26 +236,26 @@ _LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce(
     }
   });
 
-  return std::__terminate_on_exception([&] {
-    return std::reduce(
-        std::make_move_iterator(__values.get()),
-        std::make_move_iterator(__values.get() + __partitions.__chunk_count_),
-        std::move(__init),
-        __combiner);
-  });
+  return std::reduce(
+      std::make_move_iterator(__values.get()),
+      std::make_move_iterator(__values.get() + __partitions.__chunk_count_),
+      std::move(__init),
+      __combiner);
 }
 
 template <class _RandomAccessIterator, class _Comp, class _LeafSort>
-_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort(
     _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
   const auto __size = __last - __first;
   auto __partitions = __libdispatch::__partition_chunks(__size);
 
   if (__partitions.__chunk_count_ == 0)
-    return;
+    return __empty{};
 
-  if (__partitions.__chunk_count_ == 1)
-    return __leaf_sort(__first, __last, __comp);
+  if (__partitions.__chunk_count_ == 1) {
+    __leaf_sort(__first, __last, __comp);
+    return __empty{};
+  }
 
   using _Value = __iter_value_type<_RandomAccessIterator>;
 
@@ -247,70 +267,70 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort(
   // TODO: use __uninitialized_buffer
   unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy);
 
-  return std::__terminate_on_exception([&] {
-    // Initialize all elements to a moved-from state
-    // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
-    std::__construct_at(__values.get(), std::move(*__first));
-    for (__iter_
diff _t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
-      std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
-    }
-    *__first = std::move(__values.get()[__size - 1]);
-
-    __libdispatch::__dispatch_parallel_for(
-        __partitions,
-        __first,
-        [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
-          __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
-        });
-
-    bool __objects_are_in_buffer = false;
-    do {
-      const auto __old_chunk_size = __partitions.__chunk_size_;
-      if (__partitions.__chunk_count_ % 2 == 1) {
-        auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) {
-          std::inplace_merge(
-              __first_chunk_begin,
-              __first_chunk_begin + __partitions.__first_chunk_size_,
-              __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_,
-              __comp);
-        };
-        if (__objects_are_in_buffer)
-          __inplace_merge_chunks(__values.get());
-        else
-          __inplace_merge_chunks(__first);
-        __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_;
-      } else {
-        __partitions.__first_chunk_size_ += __partitions.__chunk_size_;
-      }
-
-      __partitions.__chunk_size_ *= 2;
-      __partitions.__chunk_count_ /= 2;
-
-      auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) {
-        __libdispatch::__dispatch_parallel_for(
-            __partitions,
-            __from_first,
-            [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) {
-              std::merge(std::make_move_iterator(__chunk_first),
-                         std::make_move_iterator(__chunk_last - __old_chunk_size),
-                         std::make_move_iterator(__chunk_last - __old_chunk_size),
-                         std::make_move_iterator(__chunk_last),
-                         __to_first + (__chunk_first - __from_first),
-                         __comp);
-            });
+  // Initialize all elements to a moved-from state
+  // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
+  std::__construct_at(__values.get(), std::move(*__first));
+  for (__iter_
diff _t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
+    std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
+  }
+  *__first = std::move(__values.get()[__size - 1]);
+
+  __libdispatch::__dispatch_parallel_for(
+      __partitions,
+      __first,
+      [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
+        __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
+      });
+
+  bool __objects_are_in_buffer = false;
+  do {
+    const auto __old_chunk_size = __partitions.__chunk_size_;
+    if (__partitions.__chunk_count_ % 2 == 1) {
+      auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) {
+        std::inplace_merge(
+            __first_chunk_begin,
+            __first_chunk_begin + __partitions.__first_chunk_size_,
+            __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_,
+            __comp);
       };
-
       if (__objects_are_in_buffer)
-        __merge_chunks(__values.get(), __first);
+        __inplace_merge_chunks(__values.get());
       else
-        __merge_chunks(__first, __values.get());
-      __objects_are_in_buffer = !__objects_are_in_buffer;
-    } while (__partitions.__chunk_count_ > 1);
-
-    if (__objects_are_in_buffer) {
-      std::move(__values.get(), __values.get() + __size, __first);
+        __inplace_merge_chunks(__first);
+      __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_;
+    } else {
+      __partitions.__first_chunk_size_ += __partitions.__chunk_size_;
     }
-  });
+
+    __partitions.__chunk_size_ *= 2;
+    __partitions.__chunk_count_ /= 2;
+
+    auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) {
+      __libdispatch::__dispatch_parallel_for(
+          __partitions,
+          __from_first,
+          [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) {
+            std::merge(std::make_move_iterator(__chunk_first),
+                       std::make_move_iterator(__chunk_last - __old_chunk_size),
+                       std::make_move_iterator(__chunk_last - __old_chunk_size),
+                       std::make_move_iterator(__chunk_last),
+                       __to_first + (__chunk_first - __from_first),
+                       __comp);
+          });
+    };
+
+    if (__objects_are_in_buffer)
+      __merge_chunks(__values.get(), __first);
+    else
+      __merge_chunks(__first, __values.get());
+    __objects_are_in_buffer = !__objects_are_in_buffer;
+  } while (__partitions.__chunk_count_ > 1);
+
+  if (__objects_are_in_buffer) {
+    std::move(__values.get(), __values.get() + __size, __first);
+  }
+
+  return __empty{};
 }
 
 _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {}

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h
index c4b28e95024ff5b..b0db70f58b2ef48 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h
@@ -15,7 +15,7 @@
 #include <__iterator/concepts.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -23,6 +23,9 @@
 
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _ExecutionPolicy,
@@ -30,7 +33,7 @@ template <class _ExecutionPolicy,
           class _ForwardIterator2,
           class _ForwardOutIterator,
           class _Comp>
-_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge(
+_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_merge(
     __cpu_backend_tag,
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
@@ -42,31 +45,32 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge(
                 __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-    return std::__terminate_on_exception([&] {
-      __par_backend::__parallel_merge(
-          __first1,
-          __last1,
-          __first2,
-          __last2,
-          __result,
-          __comp,
-          [](_ForwardIterator1 __g_first1,
-             _ForwardIterator1 __g_last1,
-             _ForwardIterator2 __g_first2,
-             _ForwardIterator2 __g_last2,
-             _ForwardOutIterator __g_result,
-             _Comp __g_comp) {
-            return std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{},
-                std::move(__g_first1),
-                std::move(__g_last1),
-                std::move(__g_first2),
-                std::move(__g_last2),
-                std::move(__g_result),
-                std::move(__g_comp));
-          });
-      return __result + (__last1 - __first1) + (__last2 - __first2);
-    });
+    auto __res = __par_backend::__parallel_merge(
+        __first1,
+        __last1,
+        __first2,
+        __last2,
+        __result,
+        __comp,
+        [](_ForwardIterator1 __g_first1,
+           _ForwardIterator1 __g_last1,
+           _ForwardIterator2 __g_first2,
+           _ForwardIterator2 __g_last2,
+           _ForwardOutIterator __g_result,
+           _Comp __g_comp) {
+          [[maybe_unused]] auto __g_res = std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{},
+              std::move(__g_first1),
+              std::move(__g_last1),
+              std::move(__g_first2),
+              std::move(__g_last2),
+              std::move(__g_result),
+              std::move(__g_comp));
+          _LIBCPP_ASSERT_INTERNAL(__g_res, "unsed/sed should never try to allocate!");
+        });
+    if (!__res)
+      return nullopt;
+    return __result + (__last1 - __first1) + (__last2 - __first2);
   } else {
     return std::merge(__first1, __last1, __first2, __last2, __result, __comp);
   }
@@ -74,6 +78,8 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge(
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_MERGE_H

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
index f151c3b098f6748..afcc7ffb2661304 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
@@ -11,8 +11,10 @@
 #define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H
 
 #include <__config>
+#include <__utility/empty.h>
 #include <__utility/move.h>
 #include <cstddef>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -20,26 +22,32 @@
 
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace __par_backend {
 inline namespace __serial_cpu_backend {
 
 template <class _RandomAccessIterator, class _Fp>
-_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
   __f(__first, __last);
+  return __empty{};
 }
 
 template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
-_LIBCPP_HIDE_FROM_ABI _Tp
+_LIBCPP_HIDE_FROM_ABI optional<_Tp>
 __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
   return __reduce(std::move(__first), std::move(__last), std::move(__init));
 }
 
 template <class _RandomAccessIterator, class _Compare, class _LeafSort>
-_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort(
     _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
   __leaf_sort(__first, __last, __comp);
+  return __empty{};
 }
 
 _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {}
@@ -49,7 +57,7 @@ template <class _RandomAccessIterator1,
           class _RandomAccessIterator3,
           class _Compare,
           class _LeafMerge>
-_LIBCPP_HIDE_FROM_ABI void __parallel_merge(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge(
     _RandomAccessIterator1 __first1,
     _RandomAccessIterator1 __last1,
     _RandomAccessIterator2 __first2,
@@ -58,6 +66,7 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
     _Compare __comp,
     _LeafMerge __leaf_merge) {
   __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
+  return __empty{};
 }
 
 // TODO: Complete this list
@@ -67,6 +76,8 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h
index 0a701443b3c40c6..34c423586c4b742 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h
@@ -13,7 +13,8 @@
 #include <__algorithm/stable_sort.h>
 #include <__config>
 #include <__type_traits/is_execution_policy.h>
-#include <__utility/terminate_on_exception.h>
+#include <__utility/empty.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -24,17 +25,16 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
-_LIBCPP_HIDE_FROM_ABI void
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
 __pstl_stable_sort(__cpu_backend_tag, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
-    std::__terminate_on_exception([&] {
-      __par_backend::__parallel_stable_sort(
-          __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
-            std::stable_sort(__g_first, __g_last, __g_comp);
-          });
-    });
+    return __par_backend::__parallel_stable_sort(
+        __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
+          std::stable_sort(__g_first, __g_last, __g_comp);
+        });
   } else {
     std::stable_sort(__first, __last, __comp);
+    return __empty{};
   }
 }
 

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
index 30eb0ae3626d47a..eb11a961b760c30 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
@@ -11,8 +11,10 @@
 
 #include <__assert>
 #include <__config>
+#include <__utility/empty.h>
 #include <__utility/move.h>
 #include <cstddef>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -32,20 +34,23 @@ namespace __par_backend {
 inline namespace __thread_cpu_backend {
 
 template <class _RandomAccessIterator, class _Fp>
-_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
   __f(__first, __last);
+  return __empty{};
 }
 
 template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
-_LIBCPP_HIDE_FROM_ABI _Tp
+_LIBCPP_HIDE_FROM_ABI optional<_Tp>
 __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
   return __reduce(std::move(__first), std::move(__last), std::move(__init));
 }
 
 template <class _RandomAccessIterator, class _Compare, class _LeafSort>
-_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort(
     _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
   __leaf_sort(__first, __last, __comp);
+  return __empty{};
 }
 
 _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {}
@@ -55,7 +60,7 @@ template <class _RandomAccessIterator1,
           class _RandomAccessIterator3,
           class _Compare,
           class _LeafMerge>
-_LIBCPP_HIDE_FROM_ABI void __parallel_merge(
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge(
     _RandomAccessIterator1 __first1,
     _RandomAccessIterator1 __last1,
     _RandomAccessIterator2 __first2,
@@ -64,6 +69,7 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
     _Compare __comp,
     _LeafMerge __leaf_merge) {
   __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
+  return __empty{};
 }
 
 } // namespace __thread_cpu_backend

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h
index 0259d8a84bb3f76..2c7647d61a2b0a4 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h
@@ -17,7 +17,7 @@
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -25,6 +25,9 @@
 
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
@@ -37,7 +40,7 @@ __simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Fu
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
+_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform(
     __cpu_backend_tag,
     _ForwardIterator __first,
     _ForwardIterator __last,
@@ -46,13 +49,13 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-    std::__terminate_on_exception([&] {
-      std::__par_backend::__parallel_for(
-          __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op);
-          });
-    });
+    std::__par_backend::__parallel_for(
+        __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+          auto __res = std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op);
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          return *std::move(__res);
+        });
     return __result + (__last - __first);
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
@@ -83,7 +86,7 @@ template <class _ExecutionPolicy,
           class _ForwardOutIterator,
           class _BinaryOperation,
           enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
+_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform(
     __cpu_backend_tag,
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
@@ -94,20 +97,20 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
                 __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-    std::__terminate_on_exception([&] {
-      std::__par_backend::__parallel_for(
-          __first1,
-          __last1,
-          [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
-            return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{},
-                __brick_first,
-                __brick_last,
-                __first2 + (__brick_first - __first1),
-                __result + (__brick_first - __first1),
-                __op);
-          });
-    });
+    auto __res = std::__par_backend::__parallel_for(
+        __first1,
+        __last1,
+        [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+          return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{},
+              __brick_first,
+              __brick_last,
+              __first2 + (__brick_first - __first1),
+              __result + (__brick_first - __first1),
+              __op);
+        });
+    if (!__res)
+      return nullopt;
     return __result + (__last1 - __first1);
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
@@ -128,6 +131,8 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
 
 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H

diff  --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
index 2afe5c7d10483fe..a5ca9c89d1ab23b 100644
--- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
+++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
@@ -18,8 +18,8 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/operation_traits.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
 #include <new>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -98,7 +98,7 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _BinaryOperation1,
           class _BinaryOperation2>
-_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
+_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
     __cpu_backend_tag,
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
@@ -109,27 +109,25 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-    return std::__terminate_on_exception([&] {
-      return __par_backend::__parallel_transform_reduce(
-          __first1,
-          std::move(__last1),
-          [__first1, __first2, __transform](_ForwardIterator1 __iter) {
-            return __transform(*__iter, *(__first2 + (__iter - __first1)));
-          },
-          std::move(__init),
-          std::move(__reduce),
-          [__first1, __first2, __reduce, __transform](
-              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
-            return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{},
-                __brick_first,
-                std::move(__brick_last),
-                __first2 + (__brick_first - __first1),
-                std::move(__brick_init),
-                std::move(__reduce),
-                std::move(__transform));
-          });
-    });
+    return __par_backend::__parallel_transform_reduce(
+        __first1,
+        std::move(__last1),
+        [__first1, __first2, __transform](_ForwardIterator1 __iter) {
+          return __transform(*__iter, *(__first2 + (__iter - __first1)));
+        },
+        std::move(__init),
+        std::move(__reduce),
+        [__first1, __first2, __reduce, __transform](
+            _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
+          return *std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{},
+              __brick_first,
+              std::move(__brick_last),
+              __first2 + (__brick_first - __first1),
+              std::move(__brick_init),
+              std::move(__reduce),
+              std::move(__transform));
+        });
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
@@ -149,7 +147,7 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
 }
 
 template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
+_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
     __cpu_backend_tag,
     _ForwardIterator __first,
     _ForwardIterator __last,
@@ -158,23 +156,23 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
     _UnaryOperation __transform) {
   if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                 __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-    return std::__terminate_on_exception([&] {
-      return __par_backend::__parallel_transform_reduce(
-          std::move(__first),
-          std::move(__last),
-          [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
-          std::move(__init),
-          __reduce,
-          [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
-            return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>(
-                __cpu_backend_tag{},
-                std::move(__brick_first),
-                std::move(__brick_last),
-                std::move(__brick_init),
-                std::move(__reduce),
-                std::move(__transform));
-          });
-    });
+    return __par_backend::__parallel_transform_reduce(
+        std::move(__first),
+        std::move(__last),
+        [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
+        std::move(__init),
+        __reduce,
+        [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
+          auto __res = std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>(
+              __cpu_backend_tag{},
+              std::move(__brick_first),
+              std::move(__brick_last),
+              std::move(__brick_init),
+              std::move(__reduce),
+              std::move(__transform));
+          _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          return *std::move(__res);
+        });
   } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
                        __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
     return std::__simd_transform_reduce(

diff  --git a/libcxx/include/__algorithm/pstl_copy.h b/libcxx/include/__algorithm/pstl_copy.h
index e4a6e5a54e48e79..19f275a0d5d97fc 100644
--- a/libcxx/include/__algorithm/pstl_copy.h
+++ b/libcxx/include/__algorithm/pstl_copy.h
@@ -22,6 +22,7 @@
 #include <__type_traits/is_trivially_copyable.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -41,18 +42,34 @@ template <class _ExecutionPolicy,
           class _ForwardOutIterator,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
-copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+__copy(_ExecutionPolicy&& __policy,
+       _ForwardIterator&& __first,
+       _ForwardIterator&& __last,
+       _ForwardOutIterator&& __result) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result) {
-        return std::transform(__policy, __g_first, __g_last, __g_result, __identity());
+        return std::__transform(__policy, __g_first, __g_last, __g_result, __identity());
       },
       std::move(__first),
       std::move(__last),
       std::move(__result));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _ForwardOutIterator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
+copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) {
+  auto __res = std::__copy(__policy, std::move(__first), std::move(__last), std::move(__result));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_copy_n();
 
@@ -62,21 +79,36 @@ template <class _ExecutionPolicy,
           class _Size,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
-copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __copy_n(
+    _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _ForwardOutIterator&& __result) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy_n, _RawPolicy),
-      [&__policy](_ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) {
+      [&__policy](
+          _ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) -> optional<_ForwardIterator> {
         if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value)
-          return std::copy(__policy, __g_first, __g_first + __g_n, __g_result);
+          return std::__copy(__policy, std::move(__g_first), std::move(__g_first + __g_n), std::move(__g_result));
         else
           return std::copy_n(__g_first, __g_n, __g_result);
       },
       std::move(__first),
-      __n,
+      std::move(__n),
       std::move(__result));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _ForwardOutIterator,
+          class _Size,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
+copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) {
+  auto __res = std::__copy_n(__policy, std::move(__first), std::move(__n), std::move(__result));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_count.h b/libcxx/include/__algorithm/pstl_count.h
index cc1e82457006cf8..28806fca0637013 100644
--- a/libcxx/include/__algorithm/pstl_count.h
+++ b/libcxx/include/__algorithm/pstl_count.h
@@ -23,7 +23,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -41,13 +41,13 @@ template <class _ExecutionPolicy,
           class _Predicate,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI __iter_
diff _t<_ForwardIterator>
-count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_
diff _t<_ForwardIterator>> __count_if(
+    _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
   using __
diff _t = __iter_
diff _t<_ForwardIterator>;
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count_if, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
-        return std::transform_reduce(
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<__
diff _t> {
+        return std::__transform_reduce(
             __policy,
             std::move(__g_first),
             std::move(__g_last),
@@ -60,6 +60,19 @@ count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Predicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI __iter_
diff _t<_ForwardIterator>
+count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+  auto __res = std::__count_if(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_count(); // declaration needed for the frontend dispatch below
 
@@ -68,11 +81,12 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI __iter_
diff _t<_ForwardIterator>
-count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_
diff _t<_ForwardIterator>>
+__count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) {
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value)
+          -> optional<__iter_
diff _t<_ForwardIterator>> {
         return std::count_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __v) {
           return __v == __g_value;
         });
@@ -82,6 +96,19 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
       __value);
 }
 
+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 __iter_
diff _t<_ForwardIterator>
+count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+  auto __res = std::__count(__policy, std::move(__first), std::move(__last), __value);
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *__res;
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_fill.h b/libcxx/include/__algorithm/pstl_fill.h
index fc817b5c9e6ea75..3057dcc04f1ad74 100644
--- a/libcxx/include/__algorithm/pstl_fill.h
+++ b/libcxx/include/__algorithm/pstl_fill.h
@@ -20,7 +20,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -38,13 +38,13 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept {
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
-  std::__pstl_frontend_dispatch(
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill, _RawPolicy),
       [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) {
-        std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) {
+        return std::__for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) {
           __element = __g_value;
         });
       },
@@ -53,6 +53,18 @@ fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __l
       __value);
 }
 
+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
+fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  if (!std::__fill(__policy, std::move(__first), std::move(__last), __value))
+    std::__throw_bad_alloc();
+}
+
 template <class>
 void __pstl_fill_n(); // declaration needed for the frontend dispatch below
 
@@ -62,22 +74,36 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__fill_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _SizeT&& __n, const _Tp& __value) noexcept {
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
-  std::__pstl_frontend_dispatch(
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n, _RawPolicy),
       [&](_ForwardIterator __g_first, _SizeT __g_n, const _Tp& __g_value) {
         if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value)
           std::fill(__policy, __g_first, __g_first + __g_n, __g_value);
         else
           std::fill_n(__g_first, __g_n, __g_value);
+        return optional<__empty>{__empty{}};
       },
       std::move(__first),
-      __n,
+      std::move(__n),
       __value);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _SizeT,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  if (!std::__fill_n(__policy, std::move(__first), std::move(__n), __value))
+    std::__throw_bad_alloc();
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h
index c2894d08752ef27..adc05ea1a9e55a0 100644
--- a/libcxx/include/__algorithm/pstl_find.h
+++ b/libcxx/include/__algorithm/pstl_find.h
@@ -19,7 +19,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -34,13 +34,26 @@ template <class _ExecutionPolicy,
           class _Predicate,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator
-find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>>
+__find_if(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
   using _Backend = typename __select_backend<_RawPolicy>::type;
   return std::__pstl_find_if<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Predicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__find_if(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_find_if_not();
 
@@ -49,21 +62,36 @@ template <class _ExecutionPolicy,
           class _Predicate,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator
-find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>>
+__find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
-        return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
-          return !__g_pred(__value);
-        });
+      [&](_ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Predicate&& __g_pred)
+          -> optional<__remove_cvref_t<_ForwardIterator>> {
+        return std::__find_if(
+            __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __value) {
+              return !__g_pred(__value);
+            });
       },
       std::move(__first),
       std::move(__last),
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Predicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__find_if_not(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 template <class>
 void __pstl_find();
 
@@ -72,21 +100,35 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator
-find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>>
+__find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find, _RawPolicy),
-      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) {
-        return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) {
-          return __element == __g_value;
-        });
+      [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) -> optional<_ForwardIterator> {
+        return std::find_if(
+            __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __element) {
+              return __element == __g_value;
+            });
       },
       std::move(__first),
       std::move(__last),
       __value);
 }
 
+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 _ForwardIterator
+find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__find(__policy, std::move(__first), std::move(__last), __value);
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h
index 6e6c73d19f6fec7..819a43d685abed5 100644
--- a/libcxx/include/__algorithm/pstl_for_each.h
+++ b/libcxx/include/__algorithm/pstl_for_each.h
@@ -20,8 +20,9 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/void_t.h>
+#include <__utility/empty.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -31,16 +32,27 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Function,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__for_each(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Function&& __func) noexcept {
+  using _Backend = typename __select_backend<_RawPolicy>::type;
+  return std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator,
           class _Function,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
 _LIBCPP_HIDE_FROM_ABI void
-for_each(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) {
+for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) {
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
-  using _Backend = typename __select_backend<_RawPolicy>::type;
-  std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func));
+  if (!std::__for_each(__policy, std::move(__first), std::move(__last), std::move(__func)))
+    std::__throw_bad_alloc();
 }
 
 template <class>
@@ -52,23 +64,38 @@ template <class _ExecutionPolicy,
           class _Function,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __size, _Function&& __func) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n, _RawPolicy),
-      [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) {
+      [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) -> optional<__empty> {
         if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
           std::for_each(__policy, std::move(__g_first), __g_first + __g_size, std::move(__g_func));
+          return __empty{};
         } else {
           std::for_each_n(std::move(__g_first), __g_size, std::move(__g_func));
+          return __empty{};
         }
       },
-      __first,
-      __size,
+      std::move(__first),
+      std::move(__size),
       std::move(__func));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Size,
+          class _Function,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  auto __res = std::__for_each_n(__policy, std::move(__first), std::move(__size), std::move(__func));
+  if (!__res)
+    std::__throw_bad_alloc();
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_generate.h b/libcxx/include/__algorithm/pstl_generate.h
index 9a70e2e26bbf975..56538392d5b5ddd 100644
--- a/libcxx/include/__algorithm/pstl_generate.h
+++ b/libcxx/include/__algorithm/pstl_generate.h
@@ -19,6 +19,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -36,13 +37,13 @@ template <class _ExecutionPolicy,
           class _Generator,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__generate(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Generator&& __gen) {
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
-  std::__pstl_frontend_dispatch(
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Generator __g_gen) {
-        std::for_each(
+        return std::__for_each(
             __policy, std::move(__g_first), std::move(__g_last), [&](__iter_reference<_ForwardIterator> __element) {
               __element = __g_gen();
             });
@@ -52,6 +53,18 @@ generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator
       std::move(__gen));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Generator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  if (!std::__generate(__policy, std::move(__first), std::move(__last), std::move(__gen)))
+    std::__throw_bad_alloc();
+}
+
 template <class>
 void __pstl_generate_n();
 
@@ -61,21 +74,34 @@ template <class _ExecutionPolicy,
           class _Generator,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
-  std::__pstl_frontend_dispatch(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__generate_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _Generator&& __gen) {
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate_n, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _Size __g_n, _Generator __g_gen) {
-        std::for_each_n(__policy, std::move(__g_first), __g_n, [&](__iter_reference<_ForwardIterator> __element) {
-          __element = __g_gen();
-        });
+        return std::__for_each_n(
+            __policy, std::move(__g_first), std::move(__g_n), [&](__iter_reference<_ForwardIterator> __element) {
+              __element = __g_gen();
+            });
       },
       std::move(__first),
       __n,
       std::move(__gen));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Size,
+          class _Generator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
+  if (!std::__generate_n(__policy, std::move(__first), std::move(__n), std::move(__gen)))
+    std::__throw_bad_alloc();
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_is_partitioned.h b/libcxx/include/__algorithm/pstl_is_partitioned.h
index 1492ce212742d47..39cf6369339db69 100644
--- a/libcxx/include/__algorithm/pstl_is_partitioned.h
+++ b/libcxx/include/__algorithm/pstl_is_partitioned.h
@@ -18,6 +18,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -35,8 +36,8 @@ template <class _ExecutionPolicy,
           class _Predicate,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
-is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool> __is_partitioned(
+    _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
@@ -51,6 +52,19 @@ is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIt
       std::move(__pred));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Predicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
+is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+  auto __res = std::__is_partitioned(__policy, std::move(__first), std::move(__last), std::move(__pred));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_merge.h b/libcxx/include/__algorithm/pstl_merge.h
index f10ac7674282874..ed8014510863266 100644
--- a/libcxx/include/__algorithm/pstl_merge.h
+++ b/libcxx/include/__algorithm/pstl_merge.h
@@ -16,6 +16,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -25,6 +26,32 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _ForwardOutIterator,
+          class _Comp                                         = std::less<>,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+__merge(_ExecutionPolicy&&,
+        _ForwardIterator1 __first1,
+        _ForwardIterator1 __last1,
+        _ForwardIterator2 __first2,
+        _ForwardIterator2 __last2,
+        _ForwardOutIterator __result,
+        _Comp __comp = {}) noexcept {
+  using _Backend = typename __select_backend<_RawPolicy>::type;
+  return std::__pstl_merge<_RawPolicy>(
+      _Backend{},
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      std::move(__last2),
+      std::move(__result),
+      std::move(__comp));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,
@@ -33,22 +60,24 @@ template <class _ExecutionPolicy,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
-merge(_ExecutionPolicy&&,
+merge(_ExecutionPolicy&& __policy,
       _ForwardIterator1 __first1,
       _ForwardIterator1 __last1,
       _ForwardIterator2 __first2,
       _ForwardIterator2 __last2,
       _ForwardOutIterator __result,
       _Comp __comp = {}) {
-  using _Backend = typename __select_backend<_RawPolicy>::type;
-  return std::__pstl_merge<_RawPolicy>(
-      _Backend{},
+  auto __res = std::__merge(
+      __policy,
       std::move(__first1),
       std::move(__last1),
       std::move(__first2),
       std::move(__last2),
       std::move(__result),
       std::move(__comp));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/pstl_replace.h b/libcxx/include/__algorithm/pstl_replace.h
index 08f59ce2deab85d..05dee3f6a4f30c6 100644
--- a/libcxx/include/__algorithm/pstl_replace.h
+++ b/libcxx/include/__algorithm/pstl_replace.h
@@ -18,6 +18,7 @@
 #include <__type_traits/enable_if.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -36,19 +37,21 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-replace_if(_ExecutionPolicy&& __policy,
-           _ForwardIterator __first,
-           _ForwardIterator __last,
-           _Pred __pred,
-           const _Tp& __new_value) {
-  std::__pstl_frontend_dispatch(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__replace_if(_ExecutionPolicy&& __policy,
+             _ForwardIterator&& __first,
+             _ForwardIterator&& __last,
+             _Pred&& __pred,
+             const _Tp& __new_value) noexcept {
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_if, _RawPolicy),
-      [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred, const _Tp& __g_new_value) {
+      [&__policy](
+          _ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Pred&& __g_pred, const _Tp& __g_new_value) {
         std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) {
           if (__g_pred(__element))
             __element = __g_new_value;
         });
+        return optional<__empty>{__empty{}};
       },
       std::move(__first),
       std::move(__last),
@@ -56,6 +59,23 @@ replace_if(_ExecutionPolicy&& __policy,
       __new_value);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Pred,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+replace_if(_ExecutionPolicy&& __policy,
+           _ForwardIterator __first,
+           _ForwardIterator __last,
+           _Pred __pred,
+           const _Tp& __new_value) {
+  auto __res = std::__replace_if(__policy, std::move(__first), std::move(__last), std::move(__pred), __new_value);
+  if (!__res)
+    std::__throw_bad_alloc();
+}
+
 template <class>
 void __pstl_replace();
 
@@ -64,17 +84,17 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-replace(_ExecutionPolicy&& __policy,
-        _ForwardIterator __first,
-        _ForwardIterator __last,
-        const _Tp& __old_value,
-        const _Tp& __new_value) {
-  std::__pstl_frontend_dispatch(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
+__replace(_ExecutionPolicy&& __policy,
+          _ForwardIterator __first,
+          _ForwardIterator __last,
+          const _Tp& __old_value,
+          const _Tp& __new_value) noexcept {
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace, _RawPolicy),
       [&__policy](
           _ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_old_value, const _Tp& __g_new_value) {
-        std::replace_if(
+        return std::__replace_if(
             __policy,
             std::move(__g_first),
             std::move(__g_last),
@@ -87,6 +107,21 @@ replace(_ExecutionPolicy&& __policy,
       __new_value);
 }
 
+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
+replace(_ExecutionPolicy&& __policy,
+        _ForwardIterator __first,
+        _ForwardIterator __last,
+        const _Tp& __old_value,
+        const _Tp& __new_value) {
+  if (!std::__replace(__policy, std::move(__first), std::move(__last), __old_value, __new_value))
+    std::__throw_bad_alloc();
+}
+
 template <class>
 void __pstl_replace_copy_if();
 
@@ -97,23 +132,26 @@ template <class _ExecutionPolicy,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void replace_copy_if(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy_if(
     _ExecutionPolicy&& __policy,
-    _ForwardIterator __first,
-    _ForwardIterator __last,
-    _ForwardOutIterator __result,
-    _Pred __pred,
+    _ForwardIterator&& __first,
+    _ForwardIterator&& __last,
+    _ForwardOutIterator&& __result,
+    _Pred&& __pred,
     const _Tp& __new_value) {
-  std::__pstl_frontend_dispatch(
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy_if, _RawPolicy),
       [&__policy](_ForwardIterator __g_first,
                   _ForwardIterator __g_last,
                   _ForwardOutIterator __g_result,
                   _Pred __g_pred,
-                  const _Tp& __g_new_value) {
-        std::transform(__policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) {
-          return __g_pred(__element) ? __g_new_value : __element;
-        });
+                  const _Tp& __g_new_value) -> optional<__empty> {
+        if (!std::__transform(
+                __policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) {
+                  return __g_pred(__element) ? __g_new_value : __element;
+                }))
+          return nullopt;
+        return __empty{};
       },
       std::move(__first),
       std::move(__last),
@@ -122,30 +160,49 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy_if(
       __new_value);
 }
 
-template <class>
-void __pstl_replace_copy();
-
 template <class _ExecutionPolicy,
           class _ForwardIterator,
           class _ForwardOutIterator,
+          class _Pred,
           class _Tp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void replace_copy(
+_LIBCPP_HIDE_FROM_ABI void replace_copy_if(
     _ExecutionPolicy&& __policy,
     _ForwardIterator __first,
     _ForwardIterator __last,
     _ForwardOutIterator __result,
-    const _Tp& __old_value,
+    _Pred __pred,
     const _Tp& __new_value) {
-  std::__pstl_frontend_dispatch(
+  if (!std::__replace_copy_if(
+          __policy, std::move(__first), std::move(__last), std::move(__result), std::move(__pred), __new_value))
+    std::__throw_bad_alloc();
+}
+
+template <class>
+void __pstl_replace_copy();
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _ForwardOutIterator,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator&& __first,
+    _ForwardIterator&& __last,
+    _ForwardOutIterator&& __result,
+    const _Tp& __old_value,
+    const _Tp& __new_value) noexcept {
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy, _RawPolicy),
       [&__policy](_ForwardIterator __g_first,
                   _ForwardIterator __g_last,
                   _ForwardOutIterator __g_result,
                   const _Tp& __g_old_value,
                   const _Tp& __g_new_value) {
-        return std::replace_copy_if(
+        return std::__replace_copy_if(
             __policy,
             std::move(__g_first),
             std::move(__g_last),
@@ -160,6 +217,24 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy(
       __new_value);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _ForwardOutIterator,
+          class _Tp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void replace_copy(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator __first,
+    _ForwardIterator __last,
+    _ForwardOutIterator __result,
+    const _Tp& __old_value,
+    const _Tp& __new_value) {
+  if (!std::__replace_copy(
+          __policy, std::move(__first), std::move(__last), std::move(__result), __old_value, __new_value))
+    std::__throw_bad_alloc();
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__algorithm/pstl_sort.h b/libcxx/include/__algorithm/pstl_sort.h
index 85239df0abebe3f..3e71e0aa5ae0a1c 100644
--- a/libcxx/include/__algorithm/pstl_sort.h
+++ b/libcxx/include/__algorithm/pstl_sort.h
@@ -16,8 +16,10 @@
 #include <__functional/operations.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.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
@@ -35,18 +37,30 @@ template <class _ExecutionPolicy,
           class _Comp,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
-  std::__pstl_frontend_dispatch(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __sort(
+    _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) noexcept {
+  return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_sort, _RawPolicy),
       [&__policy](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
         std::stable_sort(__policy, std::move(__g_first), std::move(__g_last), std::move(__g_comp));
+        return optional<__empty>{__empty{}};
       },
       std::move(__first),
       std::move(__last),
       std::move(__comp));
 }
 
+template <class _ExecutionPolicy,
+          class _RandomAccessIterator,
+          class _Comp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void
+sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
+  if (!std::__sort(__policy, std::move(__first), std::move(__last), std::move(__comp)))
+    std::__throw_bad_alloc();
+}
+
 template <class _ExecutionPolicy,
           class _RandomAccessIterator,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,

diff  --git a/libcxx/include/__algorithm/pstl_stable_sort.h b/libcxx/include/__algorithm/pstl_stable_sort.h
index 510ffd862980dcd..c9d375535fc4505 100644
--- a/libcxx/include/__algorithm/pstl_stable_sort.h
+++ b/libcxx/include/__algorithm/pstl_stable_sort.h
@@ -15,7 +15,9 @@
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
+#include <__utility/empty.h>
 #include <__utility/move.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -30,10 +32,21 @@ template <class _ExecutionPolicy,
           class _Comp                                         = less<>,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void
-stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __stable_sort(
+    _ExecutionPolicy&&, _RandomAccessIterator&& __first, _RandomAccessIterator&& __last, _Comp&& __comp = {}) noexcept {
   using _Backend = typename __select_backend<_RawPolicy>::type;
-  std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp));
+  return std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp));
+}
+
+template <class _ExecutionPolicy,
+          class _RandomAccessIterator,
+          class _Comp                                         = less<>,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void stable_sort(
+    _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) {
+  if (!std::__stable_sort(__policy, std::move(__first), std::move(__last), std::move(__comp)))
+    std::__throw_bad_alloc();
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/pstl_transform.h b/libcxx/include/__algorithm/pstl_transform.h
index a34439304a8fdd0..aad59d1f30e6b93 100644
--- a/libcxx/include/__algorithm/pstl_transform.h
+++ b/libcxx/include/__algorithm/pstl_transform.h
@@ -16,7 +16,7 @@
 #include <__type_traits/is_execution_policy.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -26,6 +26,23 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _ForwardOutIterator,
+          class _UnaryOperation,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>>
+__transform(_ExecutionPolicy&&,
+            _ForwardIterator&& __first,
+            _ForwardIterator&& __last,
+            _ForwardOutIterator&& __result,
+            _UnaryOperation&& __op) noexcept {
+  using _Backend = typename __select_backend<_RawPolicy>::type;
+  return std::__pstl_transform<_RawPolicy>(
+      _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator,
           class _ForwardOutIterator,
@@ -33,7 +50,7 @@ template <class _ExecutionPolicy,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
-    _ExecutionPolicy&&,
+    _ExecutionPolicy&& __policy,
     _ForwardIterator __first,
     _ForwardIterator __last,
     _ForwardOutIterator __result,
@@ -41,9 +58,29 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator);
   _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first)));
+  auto __res = std::__transform(__policy, std::move(__first), std::move(__last), std::move(__result), std::move(__op));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _ForwardOutIterator,
+          class _BinaryOperation,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>>
+__transform(_ExecutionPolicy&&,
+            _ForwardIterator1&& __first1,
+            _ForwardIterator1&& __last1,
+            _ForwardIterator2&& __first2,
+            _ForwardOutIterator&& __result,
+            _BinaryOperation&& __op) noexcept {
   using _Backend = typename __select_backend<_RawPolicy>::type;
   return std::__pstl_transform<_RawPolicy>(
-      _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op));
+      _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op));
 }
 
 template <class _ExecutionPolicy,
@@ -54,7 +91,7 @@ template <class _ExecutionPolicy,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
-    _ExecutionPolicy&&,
+    _ExecutionPolicy&& __policy,
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
     _ForwardIterator2 __first2,
@@ -64,9 +101,11 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2);
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator);
   _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first1, *__first2)));
-  using _Backend = typename __select_backend<_RawPolicy>::type;
-  return std::__pstl_transform<_RawPolicy>(
-      _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op));
+  auto __res = std::__transform(
+      __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__numeric/pstl_reduce.h b/libcxx/include/__numeric/pstl_reduce.h
index 22ef2707d7d3eea..b19972a46db7fac 100644
--- a/libcxx/include/__numeric/pstl_reduce.h
+++ b/libcxx/include/__numeric/pstl_reduce.h
@@ -33,16 +33,16 @@ template <class _ExecutionPolicy,
           class _BinaryOperation                              = plus<>,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _Tp
-reduce(_ExecutionPolicy&& __policy,
-       _ForwardIterator __first,
-       _ForwardIterator __last,
-       _Tp __init,
-       _BinaryOperation __op = {}) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_Tp>
+__reduce(_ExecutionPolicy&& __policy,
+         _ForwardIterator&& __first,
+         _ForwardIterator&& __last,
+         _Tp&& __init,
+         _BinaryOperation&& __op = {}) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Tp __g_init, _BinaryOperation __g_op) {
-        return std::transform_reduce(
+        return std::__transform_reduce(
             __policy, std::move(__g_first), std::move(__g_last), std::move(__g_init), std::move(__g_op), __identity{});
       },
       std::move(__first),
@@ -53,19 +53,50 @@ reduce(_ExecutionPolicy&& __policy,
 
 template <class _ExecutionPolicy,
           class _ForwardIterator,
+          class _Tp,
+          class _BinaryOperation                              = plus<>,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator>
-reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+_LIBCPP_HIDE_FROM_ABI _Tp
+reduce(_ExecutionPolicy&& __policy,
+       _ForwardIterator __first,
+       _ForwardIterator __last,
+       _Tp __init,
+       _BinaryOperation __op = {}) {
+  auto __res = std::__reduce(__policy, std::move(__first), std::move(__last), std::move(__init), std::move(__op));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_value_type<_ForwardIterator>>
+__reduce(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last) noexcept {
   return std::__pstl_frontend_dispatch(
       _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce, _RawPolicy),
       [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last) {
-        return std::reduce(__policy, __g_first, __g_last, __iter_value_type<_ForwardIterator>());
+        return std::__reduce(
+            __policy, std::move(__g_first), std::move(__g_last), __iter_value_type<_ForwardIterator>());
       },
       std::move(__first),
       std::move(__last));
 }
 
+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 __iter_value_type<_ForwardIterator>
+reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+  auto __res = std::__reduce(__policy, std::move(__first), std::move(__last));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__numeric/pstl_transform_reduce.h b/libcxx/include/__numeric/pstl_transform_reduce.h
index b7c9d8d288f99c2..4127ee21e3045c8 100644
--- a/libcxx/include/__numeric/pstl_transform_reduce.h
+++ b/libcxx/include/__numeric/pstl_transform_reduce.h
@@ -16,7 +16,7 @@
 #include <__numeric/transform_reduce.h>
 #include <__type_traits/is_execution_policy.h>
 #include <__utility/move.h>
-#include <__utility/terminate_on_exception.h>
+#include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -34,23 +34,53 @@ template <class _ExecutionPolicy,
           class _BinaryOperation2,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
+_LIBCPP_HIDE_FROM_ABI optional<_Tp> __transform_reduce(
     _ExecutionPolicy&&,
+    _ForwardIterator1&& __first1,
+    _ForwardIterator1&& __last1,
+    _ForwardIterator2&& __first2,
+    _Tp&& __init,
+    _BinaryOperation1&& __reduce,
+    _BinaryOperation2&& __transform) noexcept {
+  using _Backend = typename __select_backend<_RawPolicy>::type;
+  return std::__pstl_transform_reduce<_RawPolicy>(
+      _Backend{},
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      std::move(__init),
+      std::move(__reduce),
+      std::move(__transform));
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _Tp,
+          class _BinaryOperation1,
+          class _BinaryOperation2,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
+    _ExecutionPolicy&& __policy,
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
     _ForwardIterator2 __first2,
     _Tp __init,
     _BinaryOperation1 __reduce,
     _BinaryOperation2 __transform) {
-  using _Backend = typename __select_backend<_RawPolicy>::type;
-  return std::__pstl_transform_reduce<_RawPolicy>(
-      _Backend{},
+  auto __res = std::__transform_reduce(
+      __policy,
       std::move(__first1),
       std::move(__last1),
       std::move(__first2),
       std::move(__init),
       std::move(__reduce),
       std::move(__transform));
+
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
 }
 
 // This overload doesn't get a customization point because it's trivial to detect (through e.g.
@@ -76,13 +106,13 @@ template <class _ExecutionPolicy,
           class _UnaryOperation,
           class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
           enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_Tp>> __transform_reduce(
     _ExecutionPolicy&&,
-    _ForwardIterator __first,
-    _ForwardIterator __last,
-    _Tp __init,
-    _BinaryOperation __reduce,
-    _UnaryOperation __transform) {
+    _ForwardIterator&& __first,
+    _ForwardIterator&& __last,
+    _Tp&& __init,
+    _BinaryOperation&& __reduce,
+    _UnaryOperation&& __transform) noexcept {
   using _Backend = typename __select_backend<_RawPolicy>::type;
   return std::__pstl_transform_reduce<_RawPolicy>(
       _Backend{},
@@ -93,6 +123,27 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
       std::move(__transform));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _Tp,
+          class _BinaryOperation,
+          class _UnaryOperation,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator __first,
+    _ForwardIterator __last,
+    _Tp __init,
+    _BinaryOperation __reduce,
+    _UnaryOperation __transform) {
+  auto __res = std::__transform_reduce(
+      __policy, std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform));
+  if (!__res)
+    std::__throw_bad_alloc();
+  return *std::move(__res);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__utility/empty.h b/libcxx/include/__utility/empty.h
new file mode 100644
index 000000000000000..8cca197145c7235
--- /dev/null
+++ b/libcxx/include/__utility/empty.h
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___UTILITY_EMPTY_H
+#define _LIBCPP___UTILITY_EMPTY_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+struct __empty {};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_EMPTY_H

diff  --git a/libcxx/include/__utility/terminate_on_exception.h b/libcxx/include/__utility/terminate_on_exception.h
deleted file mode 100644
index e035ec3409ae529..000000000000000
--- a/libcxx/include/__utility/terminate_on_exception.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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___UTILITY_TERMINATE_ON_EXCEPTION_H
-#define _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H
-
-#include <__config>
-#include <__exception/terminate.h>
-#include <new>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-#if _LIBCPP_STD_VER >= 17
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-#  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
-
-template <class _Func>
-_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) {
-  try {
-    return __func();
-  } catch (...) {
-    std::terminate();
-  }
-}
-
-#  else // _LIBCPP_HAS_NO_EXCEPTIONS
-
-template <class _Func>
-_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) {
-  return __func();
-}
-
-#  endif // _LIBCPP_HAS_NO_EXCEPTIONS
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_STD_VER >= 17
-
-#endif // _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6d9bb8653fcb5e9..26657b78b8440c6 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2053,6 +2053,7 @@ module std_private_utility_cmp                    [system] {
 }
 module std_private_utility_convert_to_integral    [system] { header "__utility/convert_to_integral.h" }
 module std_private_utility_declval                [system] { header "__utility/declval.h" }
+module std_private_utility_empty                  [system] { header "__utility/empty.h" }
 module std_private_utility_exception_guard        [system] { header "__utility/exception_guard.h" }
 module std_private_utility_exchange               [system] { header "__utility/exchange.h" }
 module std_private_utility_forward                [system] { header "__utility/forward.h" }
@@ -2088,7 +2089,6 @@ module std_private_utility_swap                   [system] {
   header "__utility/swap.h"
   export std_private_type_traits_is_swappable
 }
-module std_private_utility_terminate_on_exception [system] { header "__utility/terminate_on_exception.h" }
 module std_private_utility_to_underlying          [system] { header "__utility/to_underlying.h" }
 module std_private_utility_unreachable            [system] { header "__utility/unreachable.h" }
 

diff  --git a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp
index 89349d1610d0d0e..e3733bf468da4d4 100644
--- a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp
@@ -17,7 +17,9 @@
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/readable_traits.h>
+#include <__utility/empty.h>
 #include <cassert>
+#include <optional>
 
 struct TestPolicy {};
 struct TestBackend {};
@@ -27,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 bool pstl_any_of_called = false;
 
 template <class, class ForwardIterator, class Pred>
-bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
   assert(!pstl_any_of_called);
   pstl_any_of_called = true;
   return true;
@@ -36,7 +38,7 @@ bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
 bool pstl_all_of_called = false;
 
 template <class, class ForwardIterator, class Pred>
-bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
   assert(!pstl_all_of_called);
   pstl_all_of_called = true;
   return true;
@@ -45,25 +47,25 @@ bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
 bool pstl_copy_called = false;
 
 template <class, class ForwardIterator, class ForwardOutIterator>
-ForwardIterator __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator) {
+optional<ForwardOutIterator> __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res) {
   assert(!pstl_copy_called);
   pstl_copy_called = true;
-  return 0;
+  return res;
 }
 
 bool pstl_copy_n_called = false;
 
 template <class, class ForwardIterator, class Size, class ForwardOutIterator>
-ForwardIterator __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator) {
+optional<ForwardOutIterator> __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator res) {
   assert(!pstl_copy_n_called);
   pstl_copy_n_called = true;
-  return 0;
+  return res;
 }
 
 bool pstl_count_called = false;
 
 template <class, class ForwardIterator, class T>
-typename std::iterator_traits<ForwardIterator>::
diff erence_type
+optional<typename std::iterator_traits<ForwardIterator>::
diff erence_type>
 __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) {
   assert(!pstl_count_called);
   pstl_count_called = true;
@@ -73,7 +75,7 @@ __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) {
 bool pstl_count_if_called = false;
 
 template <class, class ForwardIterator, class Pred>
-typename std::iterator_traits<ForwardIterator>::
diff erence_type
+optional<typename std::iterator_traits<ForwardIterator>::
diff erence_type>
 __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
   assert(!pstl_count_if_called);
   pstl_count_if_called = true;
@@ -83,23 +85,25 @@ __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
 bool pstl_generate_called = false;
 
 template <class, class ForwardIterator, class Gen>
-void __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) {
+optional<__empty> __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) {
   assert(!pstl_generate_called);
   pstl_generate_called = true;
+  return __empty{};
 }
 
 bool pstl_generate_n_called = false;
 
 template <class, class ForwardIterator, class Size, class Gen>
-void __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) {
+optional<__empty> __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) {
   assert(!pstl_generate_n_called);
   pstl_generate_n_called = true;
+  return __empty{};
 }
 
 bool pstl_none_of_called = false;
 
 template <class, class ForwardIterator, class Pred>
-bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
   assert(!pstl_none_of_called);
   pstl_none_of_called = true;
   return true;
@@ -108,164 +112,177 @@ bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
 bool pstl_find_called = false;
 
 template <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __pstl_find(TestBackend, ForwardIterator first, ForwardIterator, Pred) {
   assert(!pstl_find_called);
   pstl_find_called = true;
-  return {};
+  return first;
 }
 
 bool pstl_find_if_called = false;
 
 template <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __pstl_find_if(TestBackend, ForwardIterator first, ForwardIterator, Pred) {
   assert(!pstl_find_if_called);
   pstl_find_if_called = true;
-  return {};
+  return first;
 }
 
 bool pstl_find_if_not_called = false;
 
 template <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find_if_not(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __pstl_find_if_not(TestBackend, ForwardIterator first, ForwardIterator, Pred) {
   assert(!pstl_find_if_not_called);
   pstl_find_if_not_called = true;
-  return {};
+  return first;
 }
 
 bool pstl_for_each_called = false;
 
 template <class, class ForwardIterator, class Size, class Func>
-void __pstl_for_each(TestBackend, ForwardIterator, Size, Func) {
+optional<__empty> __pstl_for_each(TestBackend, ForwardIterator, Size, Func) {
   assert(!pstl_for_each_called);
   pstl_for_each_called = true;
+  return __empty{};
 }
 
 bool pstl_for_each_n_called = false;
 
 template <class, class ForwardIterator, class Size, class Func>
-void __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) {
+optional<__empty> __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) {
   assert(!pstl_for_each_n_called);
   pstl_for_each_n_called = true;
+  return __empty{};
 }
 
 bool pstl_fill_called = false;
 
 template <class, class ForwardIterator, class Size, class Func>
-void __pstl_fill(TestBackend, ForwardIterator, Size, Func) {
+optional<__empty> __pstl_fill(TestBackend, ForwardIterator, Size, Func) {
   assert(!pstl_fill_called);
   pstl_fill_called = true;
+  return __empty{};
 }
 
 bool pstl_fill_n_called = false;
 
 template <class, class ForwardIterator, class Size, class Func>
-void __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) {
+optional<__empty> __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) {
   assert(!pstl_fill_n_called);
   pstl_fill_n_called = true;
+  return __empty{};
 }
 
 bool pstl_is_partitioned_called = false;
 
 template <class, class ForwardIterator, class Func>
-bool __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) {
+optional<bool> __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) {
   assert(!pstl_is_partitioned_called);
   pstl_is_partitioned_called = true;
-  return {};
+  return true;
 }
 
 bool pstl_replace_called = false;
 
 template <class, class ForwardIterator, class T>
-void __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) {
+optional<__empty> __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) {
   assert(!pstl_replace_called);
   pstl_replace_called = true;
+  return __empty{};
 }
 
 bool pstl_replace_if_called = false;
 
 template <class, class ForwardIterator, class T, class Func>
-void __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) {
+optional<__empty> __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) {
   assert(!pstl_replace_if_called);
   pstl_replace_if_called = true;
+  return __empty{};
 }
 
 bool pstl_replace_copy_called = false;
 
 template <class, class ForwardIterator, class ForwardOutIterator, class T>
-void __pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) {
+optional<__empty>
+__pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) {
   assert(!pstl_replace_copy_called);
   pstl_replace_copy_called = true;
+  return __empty{};
 }
 
 bool pstl_replace_copy_if_called = false;
 
 template <class, class ForwardIterator, class ForwardOutIterator, class T, class Func>
-void __pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) {
+optional<__empty>
+__pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) {
   assert(!pstl_replace_copy_if_called);
   pstl_replace_copy_if_called = true;
+  return __empty{};
 }
 
 bool pstl_unary_transform_called = false;
 
 template <class, class ForwardIterator, class ForwardOutIterator, class UnaryOperation>
-ForwardOutIterator __pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, UnaryOperation) {
+optional<ForwardOutIterator>
+__pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res, UnaryOperation) {
   assert(!pstl_unary_transform_called);
   pstl_unary_transform_called = true;
-  return {};
+  return res;
 }
 
 bool pstl_binary_transform_called = false;
 
 template <class, class ForwardIterator1, class ForwardIterator2, class ForwardOutIterator, class BinaryOperation>
-ForwardOutIterator __pstl_transform(
-    TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator, BinaryOperation) {
+optional<ForwardOutIterator> __pstl_transform(
+    TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator res, BinaryOperation) {
   assert(!pstl_binary_transform_called);
   pstl_binary_transform_called = true;
-  return {};
+  return res;
 }
 
 bool pstl_reduce_with_init_called = false;
 
 template <class, class ForwardIterator, class T, class BinaryOperation>
-T __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T, BinaryOperation) {
+optional<T> __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, BinaryOperation) {
   assert(!pstl_reduce_with_init_called);
   pstl_reduce_with_init_called = true;
-  return {};
+  return v;
 }
 
 bool pstl_reduce_without_init_called = false;
 
 template <class, class ForwardIterator>
-typename std::iterator_traits<ForwardIterator>::value_type
-__pstl_reduce(TestBackend, ForwardIterator, ForwardIterator) {
+optional<typename std::iterator_traits<ForwardIterator>::value_type>
+__pstl_reduce(TestBackend, ForwardIterator first, ForwardIterator) {
   assert(!pstl_reduce_without_init_called);
   pstl_reduce_without_init_called = true;
-  return {};
+  return *first;
 }
 
 bool pstl_sort_called = false;
 
 template <class, class RandomAccessIterator, class Comp>
-void __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) {
+optional<__empty> __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) {
   assert(!pstl_sort_called);
   pstl_sort_called = true;
+  return __empty{};
 }
 
 bool pstl_stable_sort_called = false;
 
 template <class, class RandomAccessIterator, class Comp>
-void __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) {
+optional<__empty> __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) {
   assert(!pstl_stable_sort_called);
   pstl_stable_sort_called = true;
+  return __empty{};
 }
 
 bool pstl_unary_transform_reduce_called = false;
 
 template <class, class ForwardIterator, class T, class UnaryOperation, class BinaryOperation>
-T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T, UnaryOperation, BinaryOperation) {
+T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, UnaryOperation, BinaryOperation) {
   assert(!pstl_unary_transform_reduce_called);
   pstl_unary_transform_reduce_called = true;
-  return {};
+  return v;
 }
 
 bool pstl_binary_transform_reduce_called = false;
@@ -277,10 +294,10 @@ template <class,
           class BinaryOperation1,
           class BinaryOperation2>
 typename std::iterator_traits<ForwardIterator1>::value_type __pstl_transform_reduce(
-    TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T, BinaryOperation1, BinaryOperation2) {
+    TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T v, BinaryOperation1, BinaryOperation2) {
   assert(!pstl_binary_transform_reduce_called);
   pstl_binary_transform_reduce_called = true;
-  return {};
+  return v;
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 70dbad21780a1c7..f6aeb837a7292f6 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -6,7 +6,6 @@ algorithm cstddef
 algorithm cstdint
 algorithm cstdlib
 algorithm cstring
-algorithm ctime
 algorithm cwchar
 algorithm execution
 algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
 algorithm limits
 algorithm memory
 algorithm new
-algorithm ratio
+algorithm optional
 algorithm stdexcept
 algorithm type_traits
 algorithm utility
@@ -585,15 +584,12 @@ numeric cmath
 numeric concepts
 numeric cstddef
 numeric cstdint
-numeric cstring
-numeric ctime
 numeric execution
 numeric functional
-numeric initializer_list
 numeric iterator
 numeric limits
 numeric new
-numeric ratio
+numeric optional
 numeric type_traits
 numeric version
 optional atomic

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 1ee950f9fc30ea2..08fd94393f47320 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -6,7 +6,6 @@ algorithm cstddef
 algorithm cstdint
 algorithm cstdlib
 algorithm cstring
-algorithm ctime
 algorithm cwchar
 algorithm execution
 algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
 algorithm limits
 algorithm memory
 algorithm new
-algorithm ratio
+algorithm optional
 algorithm stdexcept
 algorithm type_traits
 algorithm utility
@@ -590,15 +589,12 @@ numeric cmath
 numeric concepts
 numeric cstddef
 numeric cstdint
-numeric cstring
-numeric ctime
 numeric execution
 numeric functional
-numeric initializer_list
 numeric iterator
 numeric limits
 numeric new
-numeric ratio
+numeric optional
 numeric type_traits
 numeric version
 optional atomic

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 22e1d30f7fd67b2..33384a628e65c01 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -6,7 +6,6 @@ algorithm cstddef
 algorithm cstdint
 algorithm cstdlib
 algorithm cstring
-algorithm ctime
 algorithm cwchar
 algorithm execution
 algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
 algorithm limits
 algorithm memory
 algorithm new
-algorithm ratio
+algorithm optional
 algorithm stdexcept
 algorithm type_traits
 algorithm utility
@@ -592,15 +591,12 @@ numeric cmath
 numeric concepts
 numeric cstddef
 numeric cstdint
-numeric cstring
-numeric ctime
 numeric execution
 numeric functional
-numeric initializer_list
 numeric iterator
 numeric limits
 numeric new
-numeric ratio
+numeric optional
 numeric type_traits
 numeric version
 optional atomic

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 22e1d30f7fd67b2..33384a628e65c01 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -6,7 +6,6 @@ algorithm cstddef
 algorithm cstdint
 algorithm cstdlib
 algorithm cstring
-algorithm ctime
 algorithm cwchar
 algorithm execution
 algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
 algorithm limits
 algorithm memory
 algorithm new
-algorithm ratio
+algorithm optional
 algorithm stdexcept
 algorithm type_traits
 algorithm utility
@@ -592,15 +591,12 @@ numeric cmath
 numeric concepts
 numeric cstddef
 numeric cstdint
-numeric cstring
-numeric ctime
 numeric execution
 numeric functional
-numeric initializer_list
 numeric iterator
 numeric limits
 numeric new
-numeric ratio
+numeric optional
 numeric type_traits
 numeric version
 optional atomic

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 0cbd4c52c6e4c9b..8f6e8dd646df583 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -6,7 +6,6 @@ algorithm cstddef
 algorithm cstdint
 algorithm cstdlib
 algorithm cstring
-algorithm ctime
 algorithm cwchar
 algorithm execution
 algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
 algorithm limits
 algorithm memory
 algorithm new
-algorithm ratio
+algorithm optional
 algorithm stdexcept
 algorithm type_traits
 algorithm utility
@@ -597,15 +596,12 @@ numeric cmath
 numeric concepts
 numeric cstddef
 numeric cstdint
-numeric cstring
-numeric ctime
 numeric execution
 numeric functional
-numeric initializer_list
 numeric iterator
 numeric limits
 numeric new
-numeric ratio
+numeric optional
 numeric type_traits
 numeric version
 optional atomic

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 8b32cad73fb5ada..d0d858056b1b00d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -9,6 +9,7 @@ algorithm initializer_list
 algorithm iosfwd
 algorithm limits
 algorithm new
+algorithm optional
 algorithm ratio
 algorithm version
 any cstddef
@@ -432,6 +433,7 @@ numeric execution
 numeric initializer_list
 numeric limits
 numeric new
+numeric optional
 numeric ratio
 numeric version
 optional compare

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 8b32cad73fb5ada..d0d858056b1b00d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -9,6 +9,7 @@ algorithm initializer_list
 algorithm iosfwd
 algorithm limits
 algorithm new
+algorithm optional
 algorithm ratio
 algorithm version
 any cstddef
@@ -432,6 +433,7 @@ numeric execution
 numeric initializer_list
 numeric limits
 numeric new
+numeric optional
 numeric ratio
 numeric version
 optional compare

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..f7279655cb129f9
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::fill(ExecutionPolicy) and std::fill_n(ExecutionPolicy) terminate on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+struct ThrowOnCopy {
+  ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; }
+};
+#endif
+
+int main(int, char**) {
+  ThrowOnCopy a[2]{};
+  int b[2]{};
+
+  test_execution_policies([&](auto&& policy) {
+    // std::fill
+    EXPECT_STD_TERMINATE([&] { (void)std::fill(policy, std::begin(a), std::end(a), ThrowOnCopy{}); });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        (void)std::fill(
+            policy, util::throw_on_move_iterator(std::begin(b), 1), util::throw_on_move_iterator(std::end(b), 1), 0);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::fill_n
+    EXPECT_STD_TERMINATE([&] { (void)std::fill_n(policy, std::begin(a), std::size(a), ThrowOnCopy{}); });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        (void)std::fill_n(policy, util::throw_on_move_iterator(std::begin(b), 1), std::size(b), 0);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp
index a341816b10b6ee7..556326fb0894cab 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp
@@ -61,24 +61,8 @@ struct Test {
   }
 };
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-struct ThrowOnCopy {
-  ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; }
-};
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCopy a[2];
-  try {
-    (void)std::fill(std::execution::par, std::begin(a), std::end(a), ThrowOnCopy{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
index 594ac6a44bef448..4abbd6f7a17c3d4 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
@@ -61,24 +61,8 @@ struct Test {
   }
 };
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-struct ThrowOnCopy {
-  ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; }
-};
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCopy a[2];
-  try {
-    (void)std::fill_n(std::execution::par, std::begin(a), std::size(a), ThrowOnCopy{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..98fde95fb0e441f
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::replace(ExecutionPolicy), std::replace_if(ExecutionPolicy), std::replace_copy(ExecutionPolicy)
+// and std::replace_copy_if(ExecutionPolicy) terminate on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+struct ThrowOnCompare {};
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
+#endif
+
+int main(int, char**) {
+  test_execution_policies([&](auto&& policy) {
+    // std::replace
+    EXPECT_STD_TERMINATE([&] {
+      ThrowOnCompare a[2]{};
+      (void)std::replace(policy, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{});
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::replace(
+            policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1, 2);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::replace_if
+    EXPECT_STD_TERMINATE([&] {
+      ThrowOnCompare a[2]{};
+      (void)std::replace_if(
+          policy, std::begin(a), std::end(a), [](ThrowOnCompare&) -> bool { throw int{}; }, ThrowOnCompare{});
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::replace_if(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; },
+            2);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::replace_copy
+    EXPECT_STD_TERMINATE([&] {
+      ThrowOnCompare a[2]{};
+      (void)std::replace_copy(policy, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{});
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::replace_copy(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            1,
+            2);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::replace_copy_if
+    EXPECT_STD_TERMINATE([&] {
+      ThrowOnCompare a[2]{};
+      (void)std::replace_copy_if(
+          policy,
+          std::begin(a),
+          std::end(a),
+          std::begin(a),
+          [](ThrowOnCompare& i) { return i == i; },
+          ThrowOnCompare{});
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::replace_copy_if(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            [](int) { return true; },
+            2);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
index 0b51d35cdeb99f9..751d6b74b0128a3 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
@@ -73,24 +73,8 @@ struct Test {
   }
 };
 
-struct ThrowOnCompare {};
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCompare a[2];
-  try {
-    (void)std::replace(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
index 29c9692e0307aed..f24bedabebccdf9 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
@@ -82,25 +82,8 @@ struct Test {
   }
 };
 
-struct ThrowOnCompare {};
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCompare a[2];
-  try {
-    (void)std::replace_copy(
-        std::execution::par, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
index 965cedb91c4e1db..f7c746f382d117f 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
@@ -95,30 +95,8 @@ struct Test {
   }
 };
 
-struct ThrowOnCompare {};
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCompare a[2];
-  try {
-    (void)std::replace_copy_if(
-        std::execution::par,
-        std::begin(a),
-        std::end(a),
-        std::begin(a),
-        [](ThrowOnCompare& i) { return i == i; },
-        ThrowOnCompare{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
index 2f81955a029d64f..3ffc1c021bb9ce9 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
@@ -78,25 +78,8 @@ struct Test {
   }
 };
 
-struct ThrowOnCompare {};
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCompare a[2];
-  try {
-    (void)std::replace_if(
-        std::execution::par, std::begin(a), std::end(a), [](ThrowOnCompare&) { return false; }, ThrowOnCompare{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..6c7149f4048ade8
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::transform(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([&](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[2]{};
+      int b[2]{};
+      int c[2]{};
+      (void)std::transform(
+          policy, std::begin(a), std::end(a), std::begin(b), std::begin(c), [](auto v, auto) -> decltype(v) {
+            throw int{};
+          });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::transform(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            [](int i) { return i; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    EXPECT_STD_TERMINATE([&] {
+      int a[2]{};
+      int b[2]{};
+      (void)std::transform(policy, std::begin(a), std::end(a), std::begin(b), [](auto v) -> decltype(v) {
+        throw int{};
+      });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::transform(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            std::plus{});
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp
index 82ba4338886d696..a3af9b949bfd2e4 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp
@@ -69,15 +69,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    (void)std::all_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp
new file mode 100644
index 000000000000000..cc62979835361b6
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::all_of(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      (void)std::all_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::all_of(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp
index c21ce8afe556bc2..229bf576dd80136 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp
@@ -63,15 +63,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    (void)std::any_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..167c4ac4df95e3f
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::any_of(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      (void)std::any_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::any_of(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..06b0810c257b3f6
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::find(ExecutionPolicy), std::find_if(ExecutionPolicy) and std::find_if_not(ExecutionPolicy) terminate
+// on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+struct ThrowOnCompare {};
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
+#endif
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    // std::find
+    EXPECT_STD_TERMINATE([&] {
+      ThrowOnCompare a[2] = {};
+      (void)std::find(policy, std::begin(a), std::end(a), ThrowOnCompare{});
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::find(
+            policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 0);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::find_if
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      (void)std::find_if(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::find_if(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::find_if_not
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      (void)std::find_if_not(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::find_if_not(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
index 9822ffbff8b03f8..8a9eee81d95c06f 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
@@ -61,24 +61,8 @@ struct Test {
   }
 };
 
-struct ThrowOnCompare {};
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
-#endif
-
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  ThrowOnCompare a[2];
-  try {
-    (void)std::find(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{});
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
index c67868ccc8881bd..49eef2a7bc55f71 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
@@ -70,15 +70,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    (void)std::find_if(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
index d536249f6f1e20a..e5a242c57a2c4a0 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
@@ -71,15 +71,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    (void)std::find_if_not(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..ab15bdf5d8b99be
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::for_each(ExecutionPolicy) and std::for_each_n(ExecutionPolicy) terminate on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    int a[] = {1, 2};
+    // std::for_each
+    EXPECT_STD_TERMINATE([&] { std::for_each(policy, std::begin(a), std::end(a), [](int) { throw int{}; }); });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        (void)std::for_each(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) {});
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    // std::for_each_n
+    EXPECT_STD_TERMINATE([&] { std::for_each_n(policy, std::data(a), std::size(a), [](int) { throw int{}; }); });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        (void)std::for_each_n(policy, util::throw_on_move_iterator(std::begin(a), 1), std::size(a), [](int) {});
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp
index 4f70c1be3074576..b0e77094f0a4242 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp
@@ -51,15 +51,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    std::for_each(std::execution::par, std::begin(a), std::end(a), [](int) { throw int{}; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp
index 4efe19944183ef8..d5b42966b00007c 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp
@@ -50,15 +50,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    std::for_each_n(std::execution::par, std::data(a), std::size(a), [](int) { throw int{}; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..9a6d8d636200cf8
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::none_of(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      (void)std::none_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::none_of(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            [](int) { return true; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp
index f6dfe0cbf7b3dea..fb3e34a2bdec3d2 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp
@@ -63,15 +63,5 @@ struct Test {
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    (void)std::none_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..b56959809829b87
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::merge(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      std::merge(policy, std::begin(a), std::end(a), std::begin(a), std::end(a), std::begin(a), [](int, int) -> bool {
+        throw int{};
+      });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::merge(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            std::less{});
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+
+  return 0;
+}

diff  --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..43ee937a8a185e5
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::stable_sort(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <algorithm>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      int a[] = {1, 2};
+      std::stable_sort(policy, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::stable_sort(
+            policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1));
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp
index 0c4dda5b03ca5cb..e1a64f5185b5d4e 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp
@@ -146,15 +146,5 @@ int main(int, char**) {
                                        types::random_access_iterator_list<NotDefaultConstructible*>>{},
                   TestIteratorWithPolicies<Test>{});
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  std::set_terminate(terminate_successful);
-  int a[] = {1, 2};
-  try {
-    std::stable_sort(std::execution::par, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; });
-  } catch (int) {
-    assert(false);
-  }
-#endif
-
   return 0;
 }

diff  --git a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..65a112774ff7627
--- /dev/null
+++ b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <numeric>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([&](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::reduce(
+            policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1));
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    EXPECT_STD_TERMINATE([&] {
+      int a[2]{};
+      (void)std::reduce(policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::reduce(
+            policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp
new file mode 100644
index 000000000000000..d2df251d5c8ad59
--- /dev/null
+++ b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-exceptions
+// REQUIRES: has-unix-headers
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions
+
+#include <numeric>
+
+#include "check_assertion.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+int main(int, char**) {
+  test_execution_policies([&](auto&& policy) {
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::transform_reduce(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            util::throw_on_move_iterator(std::begin(a), 1),
+            1);
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+
+    EXPECT_STD_TERMINATE([&] {
+      int a[2]{};
+      (void)std::transform_reduce(
+          policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; }, [](int) -> int { return 0; });
+    });
+    EXPECT_STD_TERMINATE([&] {
+      try {
+        int a[] = {1, 2};
+        (void)std::transform_reduce(
+            policy,
+            util::throw_on_move_iterator(std::begin(a), 1),
+            util::throw_on_move_iterator(std::end(a), 1),
+            1,
+            std::plus{},
+            [](int) -> int { return 0; });
+      } catch (const util::iterator_error&) {
+        assert(false);
+      }
+      std::terminate(); // make the test pass in case the algorithm didn't move the iterator
+    });
+  });
+}

diff  --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 741dc4a78828a6f..98dd95b11556e6c 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -14,6 +14,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <cstdlib>
+#include <exception>
 #include <string>
 #include <string_view>
 #include <utility>
@@ -24,10 +25,6 @@
 #include "test_macros.h"
 #include "test_allocator.h"
 
-#ifndef _LIBCPP_VERSION
-# error "This header may only be used for libc++ tests"
-#endif
-
 #if TEST_STD_VER < 11
 # error "C++11 or greater is required to use this header"
 #endif
@@ -111,7 +108,7 @@ inline AssertionInfoMatcher& GlobalMatcher() {
 
 struct DeathTest {
   enum ResultKind {
-    RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown
+    RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_Terminate, RK_SetupFailure, RK_Unknown
   };
 
   static const char* ResultKindToString(ResultKind RK) {
@@ -122,6 +119,7 @@ struct DeathTest {
     CASE(RK_SetupFailure);
     CASE(RK_MatchFound);
     CASE(RK_Unknown);
+    CASE(RK_Terminate);
     }
     return "not a result kind";
   }
@@ -236,6 +234,7 @@ struct DeathTest {
   std::string stderr_from_child_;
 };
 
+#ifdef _LIBCPP_VERSION
 void std::__libcpp_verbose_abort(char const* format, ...) {
   // Extract information from the error message. This has to stay synchronized with
   // how we format assertions in the library.
@@ -252,9 +251,15 @@ void std::__libcpp_verbose_abort(char const* format, ...) {
   }
   std::exit(DeathTest::RK_MatchFailure);
 }
+#endif // _LIBCPP_VERSION
+
+[[noreturn]] inline void terminate_handler() {
+  std::exit(DeathTest::RK_Terminate);
+}
 
 template <class Func>
 inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) {
+  std::set_terminate(terminate_handler);
   DeathTest DT(Matcher);
   DeathTest::ResultKind RK = DT.Run(func);
   auto OnFailure = [&](const char* msg) {
@@ -272,6 +277,7 @@ inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matc
   };
   switch (RK) {
   case DeathTest::RK_MatchFound:
+  case DeathTest::RK_Terminate:
     return true;
   case DeathTest::RK_SetupFailure:
     return OnFailure("child failed to setup test environment");
@@ -293,6 +299,8 @@ inline bool ExpectDeath(const char* stmt, Func&& func) {
 /// Assert that the specified expression throws a libc++ debug exception.
 #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
 
+#define EXPECT_STD_TERMINATE(...) assert(ExpectDeath(#__VA_ARGS__, __VA_ARGS__))
+
 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
 
 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message))))

diff  --git a/libcxx/test/support/test_execution_policies.h b/libcxx/test/support/test_execution_policies.h
index df2ce94c7cc912f..65569bbec0836bf 100644
--- a/libcxx/test/support/test_execution_policies.h
+++ b/libcxx/test/support/test_execution_policies.h
@@ -58,8 +58,4 @@ struct Bool {
   }
 };
 
-#ifndef TEST_HAS_NO_EXCEPTIONS
-[[noreturn]] inline void terminate_successful() { std::exit(0); }
-#endif
-
 #endif // TEST_SUPPORT_TEST_EXECUTION_POLICIES

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index f0e19fc3d5e628d..1133b9597d09cfb 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -1420,6 +1420,125 @@ ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
 
 #endif // TEST_STD_VER > 17
 
+#if TEST_STD_VER >= 17
+
+namespace util {
+template <class Derived, class Iter>
+class iterator_wrapper {
+  Iter iter_;
+
+  using iter_traits = std::iterator_traits<Iter>;
+
+public:
+  using iterator_cateory = typename iter_traits::iterator_category;
+  using value_type       = typename iter_traits::value_type;
+  using 
diff erence_type  = typename iter_traits::
diff erence_type;
+  using pointer          = typename iter_traits::pointer;
+  using reference        = typename iter_traits::reference;
+
+  constexpr iterator_wrapper() : iter_() {}
+  constexpr explicit iterator_wrapper(Iter iter) : iter_(iter) {}
+
+  decltype(*iter_) operator*() { return *iter_; }
+  decltype(*iter_) operator*() const { return *iter_; }
+
+  decltype(iter_[0]) operator[](
diff erence_type v) const {
+    return iter_[v];
+  }
+
+  Derived& operator++() {
+    ++iter_;
+    return static_cast<Derived&>(*this);
+  }
+
+  Derived operator++(int) {
+    auto tmp = static_cast<Derived&>(*this);
+    ++(*this);
+    return tmp;
+  }
+
+  Derived& operator--() {
+    --iter_;
+    return static_cast<Derived&>(*this);
+  }
+
+  Derived operator--(int) {
+    auto tmp = static_cast<Derived&>(*this);
+    --(*this);
+    return tmp;
+  }
+
+  iterator_wrapper& operator+=(
diff erence_type i) {
+    iter_ += i;
+    return *this;
+  }
+
+  friend decltype(iter_ - iter_) operator-(const iterator_wrapper& lhs, const iterator_wrapper& rhs) {
+    return lhs.iter_ - rhs.iter_;
+  }
+
+  friend Derived operator-(Derived iter, 
diff erence_type i) {
+    iter.iter_ -= i;
+    return iter;
+  }
+
+  friend Derived operator+(Derived iter, 
diff erence_type i) {
+    iter.iter_ += i;
+    return iter;
+  }
+
+  friend bool operator==(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ == rhs.iter_; }
+  friend bool operator!=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ != rhs.iter_; }
+};
+
+class iterator_error : std::runtime_error {
+public:
+  iterator_error(const char* what) : std::runtime_error(what) {}
+};
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+template <class Iter>
+class throw_on_move_iterator : public iterator_wrapper<throw_on_move_iterator<Iter>, Iter> {
+  using base = iterator_wrapper<throw_on_move_iterator<Iter>, Iter>;
+
+  int moves_until_throw_ = 0;
+
+public:
+  using 
diff erence_type   = typename base::
diff erence_type;
+  using value_type        = typename base::value_type;
+  using iterator_category = typename base::iterator_cateory;
+
+  throw_on_move_iterator() = default;
+  throw_on_move_iterator(Iter iter, int moves_until_throw)
+      : base(std::move(iter)), moves_until_throw_(moves_until_throw) {}
+
+  throw_on_move_iterator(const throw_on_move_iterator& other) : base(other) {}
+  throw_on_move_iterator& operator=(const throw_on_move_iterator& other) {
+    static_cast<base&>(*this) = other;
+    return *this;
+  }
+
+  throw_on_move_iterator(throw_on_move_iterator&& other)
+      : base(std::move(other)), moves_until_throw_(other.moves_until_throw_ - 1) {
+    if (moves_until_throw_ == -1)
+      throw iterator_error("throw_on_move_iterator");
+  }
+
+  throw_on_move_iterator& operator=(throw_on_move_iterator&& other) {
+    moves_until_throw_ = other.moves_until_throw_ - 1;
+    if (moves_until_throw_ == -1)
+      throw iterator_error("throw_on_move_iterator");
+    return *this;
+  }
+};
+
+template <class Iter>
+throw_on_move_iterator(Iter) -> throw_on_move_iterator<Iter>;
+#endif // TEST_HAS_NO_EXCEPTIONS
+} // namespace util
+
+#endif // TEST_STD_VER >= 17
+
 namespace types {
 template <class Ptr>
 using random_access_iterator_list =


        


More information about the libcxx-commits mailing list