From 8b394f71182a33a8133032f53394c3663dc70fb6 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 5 Apr 2024 14:44:56 -0400 Subject: [PATCH] [libc++][pstl] Improve exception handling There were various places where we incorrectly handled exceptions in the PSTL. Typical issues were missing `noexcept` and taking iterators by value instead of by reference. This patch fixes those inconsistent and incorrect instances, and adds proper tests for all of those. Note that the previous tests were often incorrectly turned into no-ops by the compiler due to copy ellision, which doesn't happen with these new tests. --- libcxx/include/__algorithm/pstl_copy.h | 6 +- libcxx/include/__algorithm/pstl_count.h | 8 +- libcxx/include/__algorithm/pstl_equal.h | 10 +- libcxx/include/__algorithm/pstl_fill.h | 8 +- libcxx/include/__algorithm/pstl_find.h | 18 +- libcxx/include/__algorithm/pstl_generate.h | 6 +- .../include/__algorithm/pstl_is_partitioned.h | 2 +- libcxx/include/__algorithm/pstl_merge.h | 27 +- libcxx/include/__algorithm/pstl_replace.h | 10 +- libcxx/include/__algorithm/pstl_sort.h | 16 +- .../alg.fill/pstl.exception_handling.pass.cpp | 58 --- .../alg.move/pstl.exception_handling.pass.cpp | 40 --- .../pstl.exception_handling.pass.cpp | 118 ------ .../pstl.exception_handling.pass.cpp | 43 --- .../pstl.exception_handling.pass.cpp | 73 ---- .../pstl.exception_handling.pass.cpp | 44 --- .../pstl.exception_handling.pass.cpp | 44 --- .../pstl.exception_handling.pass.cpp | 53 --- .../alg.find/pstl.exception_handling.pass.cpp | 87 ----- .../pstl.exception_handling.pass.cpp | 53 --- .../pstl.exception_handling.pass.cpp | 44 --- .../pstl.exception_handling.pass.cpp | 51 --- .../pstl.exception_handling.pass.cpp | 41 --- .../reduce/pstl.exception_handling.pass.cpp | 52 --- .../pstl.exception_handling.pass.cpp | 62 ---- .../pstl.exception_handling.pass.cpp | 339 ++++++++++++++++++ .../numeric.ops/reduce/pstl.reduce.pass.cpp | 2 +- .../pstl.transform_reduce.binary.pass.cpp | 2 +- .../pstl.transform_reduce.unary.pass.cpp | 2 +- 29 files changed, 404 insertions(+), 915 deletions(-) delete mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp delete mode 100644 libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp create mode 100644 libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp rename libcxx/test/std/{algorithms => numerics}/numeric.ops/reduce/pstl.reduce.pass.cpp (99%) rename libcxx/test/std/{algorithms => numerics}/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp (99%) rename libcxx/test/std/{algorithms => numerics}/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp (99%) diff --git a/libcxx/include/__algorithm/pstl_copy.h b/libcxx/include/__algorithm/pstl_copy.h index f35bb9713ef14..5f071bd69229b 100644 --- a/libcxx/include/__algorithm/pstl_copy.h +++ b/libcxx/include/__algorithm/pstl_copy.h @@ -95,10 +95,12 @@ template optional<_ForwardIterator> { - if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) + if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { return std::__copy(__policy, std::move(__g_first), std::move(__g_first + __g_n), std::move(__g_result)); - else + } else { + (void)__policy; return std::copy_n(__g_first, __g_n, __g_result); + } }, std::move(__first), std::move(__n), diff --git a/libcxx/include/__algorithm/pstl_count.h b/libcxx/include/__algorithm/pstl_count.h index 6ff57cac334eb..cc00d2a5a2194 100644 --- a/libcxx/include/__algorithm/pstl_count.h +++ b/libcxx/include/__algorithm/pstl_count.h @@ -87,8 +87,8 @@ template , enable_if_t, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__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) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count, _RawPolicy), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) @@ -97,8 +97,8 @@ __count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator return __v == __g_value; }); }, - std::move(__first), - std::move(__last), + std::forward<_ForwardIterator>(__first), + std::forward<_ForwardIterator>(__last), __value); } diff --git a/libcxx/include/__algorithm/pstl_equal.h b/libcxx/include/__algorithm/pstl_equal.h index 0b38197d7f63d..47333daaac88e 100644 --- a/libcxx/include/__algorithm/pstl_equal.h +++ b/libcxx/include/__algorithm/pstl_equal.h @@ -91,7 +91,10 @@ _LIBCPP_HIDE_FROM_ABI bool equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); - return std::equal(__policy, std::move(__first1), std::move(__last1), std::move(__first2), std::equal_to{}); + auto __res = std::__equal(__policy, std::move(__first1), std::move(__last1), std::move(__first2), std::equal_to{}); + if (!__res) + std::__throw_bad_alloc(); + return *__res; } template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI optional<__empty> -__fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { +_LIBCPP_HIDE_FROM_ABI optional<__empty> __fill( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, const _Tp& __value) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill, _RawPolicy), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { @@ -50,8 +50,8 @@ __fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator _ __element = __g_value; }); }, - std::move(__first), - std::move(__last), + std::forward<_ForwardIterator>(__first), + std::forward<_ForwardIterator>(__last), __value); } diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h index 3b30a7bc9b456..af106a455bd1f 100644 --- a/libcxx/include/__algorithm/pstl_find.h +++ b/libcxx/include/__algorithm/pstl_find.h @@ -65,8 +65,8 @@ template , enable_if_t, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> -__find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> __find_if_not( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not, _RawPolicy), [&](_ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Predicate&& __g_pred) @@ -76,9 +76,9 @@ __find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardI return !__g_pred(__value); }); }, - std::move(__first), - std::move(__last), - std::move(__pred)); + std::forward<_ForwardIterator>(__first), + std::forward<_ForwardIterator>(__last), + std::forward<_Predicate>(__pred)); } template , enable_if_t, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> -__find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { +[[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) -> optional<_ForwardIterator> { @@ -113,8 +113,8 @@ __find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator _ return __element == __g_value; }); }, - std::move(__first), - std::move(__last), + std::forward<_ForwardIterator>(__first), + std::forward<_ForwardIterator>(__last), __value); } diff --git a/libcxx/include/__algorithm/pstl_generate.h b/libcxx/include/__algorithm/pstl_generate.h index 886af290d7f25..869985e517df0 100644 --- a/libcxx/include/__algorithm/pstl_generate.h +++ b/libcxx/include/__algorithm/pstl_generate.h @@ -40,8 +40,8 @@ template , enable_if_t, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> -__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) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Generator __g_gen) { @@ -77,7 +77,7 @@ template , enable_if_t, int> = 0> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> -__generate_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _Generator&& __gen) { +__generate_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _Generator&& __gen) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate_n, _RawPolicy), [&__policy](_ForwardIterator __g_first, _Size __g_n, _Generator __g_gen) { diff --git a/libcxx/include/__algorithm/pstl_is_partitioned.h b/libcxx/include/__algorithm/pstl_is_partitioned.h index 108bb1e432526..60a2ea568f293 100644 --- a/libcxx/include/__algorithm/pstl_is_partitioned.h +++ b/libcxx/include/__algorithm/pstl_is_partitioned.h @@ -41,7 +41,7 @@ template , enable_if_t, int> = 0> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional __is_partitioned( - _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned, _RawPolicy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { diff --git a/libcxx/include/__algorithm/pstl_merge.h b/libcxx/include/__algorithm/pstl_merge.h index d03cd8c7fbd58..46af80eb36660 100644 --- a/libcxx/include/__algorithm/pstl_merge.h +++ b/libcxx/include/__algorithm/pstl_merge.h @@ -16,6 +16,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> #include <__utility/move.h> #include @@ -34,26 +35,26 @@ template , + class _Comp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __merge(_ExecutionPolicy&&, - _ForwardIterator1 __first1, - _ForwardIterator1 __last1, - _ForwardIterator2 __first2, - _ForwardIterator2 __last2, - _ForwardOutIterator __result, - _Comp __comp = {}) noexcept { + _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)); + std::forward<_ForwardIterator1>(__first1), + std::forward<_ForwardIterator1>(__last1), + std::forward<_ForwardIterator2>(__first2), + std::forward<_ForwardIterator2>(__last2), + std::forward<_ForwardOutIterator>(__result), + std::forward<_Comp>(__comp)); } template , int> = 0> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, + _ForwardIterator&& __first, + _ForwardIterator&& __last, const _Tp& __old_value, const _Tp& __new_value) noexcept { return std::__pstl_frontend_dispatch( @@ -106,8 +106,8 @@ __replace(_ExecutionPolicy&& __policy, [&](__iter_reference<_ForwardIterator> __element) { return __element == __g_old_value; }, __g_new_value); }, - std::move(__first), - std::move(__last), + std::forward<_ForwardIterator>(__first), + std::forward<_ForwardIterator>(__last), __old_value, __new_value); } @@ -144,7 +144,7 @@ template , enable_if_t, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __sort( - _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) noexcept { +[[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)); + std::forward<_RandomAccessIterator>(__first), + std::forward<_RandomAccessIterator>(__last), + std::forward<_Comp>(__comp)); } template (__policy), std::move(__first), std::move(__last), less{}); + if (!std::__sort(__policy, std::move(__first), std::move(__last), less{})) + std::__throw_bad_alloc(); } _LIBCPP_END_NAMESPACE_STD 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 deleted file mode 100644 index dda642be85bc0..0000000000000 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,58 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::fill(ExecutionPolicy) and std::fill_n(ExecutionPolicy) terminate on user-thrown exceptions - -#include - -#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.move/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp deleted file mode 100644 index bb8ab42172226..0000000000000 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,40 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::move(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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}; - int b[] = {1, 2}; - (void)std::move(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(b), 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.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp deleted file mode 100644 index c02496bef4212..0000000000000 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,118 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// 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 - -#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.rotate/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp deleted file mode 100644 index 88d177a6e39f4..0000000000000 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,43 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// 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 - -#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}; - int b[] = {1, 2}; - (void)std::rotate_copy( - policy, - util::throw_on_move_iterator(std::begin(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(b), 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.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp deleted file mode 100644 index 439204060e189..0000000000000 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,73 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::transform(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp deleted file mode 100644 index d1c031bdd97a2..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,44 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::all_of(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp deleted file mode 100644 index 58fe79b34c008..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,44 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::any_of(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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.equal/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp deleted file mode 100644 index 1bcd858f3c02d..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,53 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::equal(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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}; - int b[] = {1, 2}; - (void)std::equal(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(b), 1)); - } catch (const util::iterator_error&) { - assert(false); - } - }); - EXPECT_STD_TERMINATE([&] { - try { - int a[] = {1, 2}; - int b[] = {1, 2}; - (void)std::equal( - 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(b), 1), - util::throw_on_move_iterator(std::end(b), 1)); - } catch (const util::iterator_error&) { - assert(false); - } - }); - }); -} 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 deleted file mode 100644 index b0ee4f8d062ef..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,87 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// 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 - -#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.foreach/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp deleted file mode 100644 index a63276f1e025d..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,53 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::for_each(ExecutionPolicy) and std::for_each_n(ExecutionPolicy) terminate on user-thrown exceptions - -#include - -#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.none_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp deleted file mode 100644 index 26e6fea5904fe..0000000000000 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,44 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::none_of(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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.sorting/alg.merge/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp deleted file mode 100644 index b48a5a9fa2b7d..0000000000000 --- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,51 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::merge(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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 deleted file mode 100644 index 1dc603cfaa554..0000000000000 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,41 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::stable_sort(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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/numeric.ops/reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp deleted file mode 100644 index d52889b1be147..0000000000000 --- a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,52 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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 deleted file mode 100644 index 5ac04334f0005..0000000000000 --- a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp +++ /dev/null @@ -1,62 +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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14 -// UNSUPPORTED: no-exceptions -// `check_assertion.h` requires Unix headers and regex support. -// UNSUPPORTED: !has-unix-headers, no-localization - -// UNSUPPORTED: libcpp-has-no-incomplete-pstl - -// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions - -#include - -#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/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp new file mode 100644 index 0000000000000..bedb2258d1fd5 --- /dev/null +++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp @@ -0,0 +1,339 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// `check_assertion.h` requires Unix headers and regex support. +// UNSUPPORTED: !has-unix-headers, no-localization + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// +// +// +// Check that PSTL algorithms terminate on user-thrown exceptions. + +#include +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +template +void assert_non_throwing(F f) { + // We wrap this whole test in EXPECT_STD_TERMINATE because if f() terminates, we want the test to pass, + // since this signals proper handling of user exceptions in the PSTL. + EXPECT_STD_TERMINATE([&] { + bool threw = false; + try { + f(); + } catch (...) { + threw = true; + } + // If nothing was thrown, call std::terminate() to pass the EXPECT_STD_TERMINATE assertion. + // Otherwise, don't call std::terminate() to fail the assertion. + if (!threw) + std::terminate(); + }); +} + +struct ThrowToken { + void activate() { active_ = true; } + void deactivate() { active_ = false; } + bool active() const { return active_; } + +private: + bool active_{false}; +}; + +template +struct on_scope_exit { + explicit on_scope_exit(Func func) : func_(func) {} + ~on_scope_exit() { func_(); } + +private: + Func func_; +}; +template +on_scope_exit(Func) -> on_scope_exit; + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3}; + int n = 2; + int storage[999]; + int val = 99; + int init = 1; + + // We generate a certain number of "tokens" and we activate exactly one on each iteration. We then + // throw in a given operation only when that token is active. That way we check that each argument + // of the algorithm is handled properly. + ThrowToken tokens[7]; + for (ThrowToken& t : tokens) { + t.activate(); + on_scope_exit _([&] { t.deactivate(); }); + + auto first1 = util::throw_on_move_iterator(std::begin(a), tokens[0].active() ? 1 : -1); + auto last1 = util::throw_on_move_iterator(std::end(a), tokens[1].active() ? 1 : -1); + auto first2 = util::throw_on_move_iterator(std::begin(b), tokens[2].active() ? 1 : -1); + auto last2 = util::throw_on_move_iterator(std::end(b), tokens[3].active() ? 1 : -1); + auto dest = util::throw_on_move_iterator(std::end(storage), tokens[4].active() ? 1 : -1); + auto maybe_throw = [](ThrowToken const& token, auto f) { + return [&token, f](auto... args) { + if (token.active()) + throw 1; + return f(args...); + }; + }; + + { + auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; }); + + // all_of(first, last, pred) + assert_non_throwing([=, &policy] { (void)std::all_of(policy, std::move(first1), std::move(last1), pred); }); + + // any_of(first, last, pred) + assert_non_throwing([=, &policy] { (void)std::any_of(policy, std::move(first1), std::move(last1), pred); }); + + // none_of(first, last, pred) + assert_non_throwing([=, &policy] { (void)std::none_of(policy, std::move(first1), std::move(last1), pred); }); + } + + { + // copy(first, last, dest) + assert_non_throwing([=, &policy] { + (void)std::copy(policy, std::move(first1), std::move(last1), std::move(dest)); + }); + + // copy_n(first, n, dest) + assert_non_throwing([=, &policy] { (void)std::copy_n(policy, std::move(first1), n, std::move(dest)); }); + } + + { + auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; }); + + // count(first, last, val) + assert_non_throwing([=, &policy] { (void)std::count(policy, std::move(first1), std::move(last1), val); }); + + // count_if(first, last, pred) + assert_non_throwing([=, &policy] { (void)std::count_if(policy, std::move(first1), std::move(last1), pred); }); + } + + { + auto binary_pred = maybe_throw(tokens[5], [](int x, int y) -> bool { return x == y; }); + + // equal(first1, last1, first2) + assert_non_throwing([=, &policy] { + (void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2)); + }); + + // equal(first1, last1, first2, binary_pred) + assert_non_throwing([=, &policy] { + (void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2), binary_pred); + }); + + // equal(first1, last1, first2, last2) + assert_non_throwing([=, &policy] { + (void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2)); + }); + + // equal(first1, last1, first2, last2, binary_pred) + assert_non_throwing([=, &policy] { + (void)std::equal( + policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), binary_pred); + }); + } + + { + // fill(first, last, val) + assert_non_throwing([=, &policy] { (void)std::fill(policy, std::move(first1), std::move(last1), val); }); + + // fill_n(first, n, val) + assert_non_throwing([=, &policy] { (void)std::fill_n(policy, std::move(first1), n, val); }); + } + + { + auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; }); + + // find(first, last, val) + assert_non_throwing([=, &policy] { (void)std::find(policy, std::move(first1), std::move(last1), val); }); + + // find_if(first, last, pred) + assert_non_throwing([=, &policy] { (void)std::find_if(policy, std::move(first1), std::move(last1), pred); }); + + // find_if_not(first, last, pred) + assert_non_throwing([=, &policy] { + (void)std::find_if_not(policy, std::move(first1), std::move(last1), pred); + }); + } + + { + auto func = maybe_throw(tokens[5], [](int) {}); + + // for_each(first, last, func) + assert_non_throwing([=, &policy] { (void)std::for_each(policy, std::move(first1), std::move(last1), func); }); + + // for_each_n(first, n, func) + assert_non_throwing([=, &policy] { (void)std::for_each_n(policy, std::move(first1), n, func); }); + } + + { + auto gen = maybe_throw(tokens[5], []() -> int { return 42; }); + + // generate(first, last, func) + assert_non_throwing([=, &policy] { (void)std::generate(policy, std::move(first1), std::move(last1), gen); }); + + // generate_n(first, n, func) + assert_non_throwing([=, &policy] { (void)std::generate_n(policy, std::move(first1), n, gen); }); + } + + { + auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; }); + + // is_partitioned(first, last, pred) + assert_non_throwing([=, &policy] { + (void)std::is_partitioned(policy, std::move(first1), std::move(last1), pred); + }); + } + + { + auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; }); + + // merge(first1, last1, first2, last2, dest) + assert_non_throwing([=, &policy] { + (void)std::merge( + policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), std::move(dest)); + }); + + // merge(first1, last1, first2, last2, dest, comp) + assert_non_throwing([=, &policy] { + (void)std::merge( + policy, + std::move(first1), + std::move(last1), + std::move(first2), + std::move(last2), + std::move(dest), + compare); + }); + } + + { + // move(first, last, dest) + assert_non_throwing([=, &policy] { + (void)std::move(policy, std::move(first1), std::move(last1), std::move(dest)); + }); + } + + { + auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; }); + + // replace_if(first, last, pred, val) + assert_non_throwing([=, &policy] { + (void)std::replace_if(policy, std::move(first1), std::move(last1), pred, val); + }); + + // replace(first, last, val1, val2) + assert_non_throwing([=, &policy] { + (void)std::replace(policy, std::move(first1), std::move(last1), val, val); + }); + + // replace_copy_if(first, last, dest, pred, val) + assert_non_throwing([=, &policy] { + (void)std::replace_copy_if(policy, std::move(first1), std::move(last1), std::move(dest), pred, val); + }); + + // replace_copy(first, last, dest, val1, val2) + assert_non_throwing([=, &policy] { + (void)std::replace_copy(policy, std::move(first1), std::move(last1), std::move(dest), val, val); + }); + } + + { + auto mid1 = util::throw_on_move_iterator(std::begin(a) + 2, tokens[5].active() ? 1 : -1); + + // rotate_copy(first, mid, last, dest) + assert_non_throwing([=, &policy] { + (void)std::rotate_copy(policy, std::move(first1), std::move(mid1), std::move(last1), std::move(dest)); + }); + } + + { + auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; }); + + // sort(first, last) + assert_non_throwing([=, &policy] { (void)std::sort(policy, std::move(first1), std::move(last1)); }); + + // sort(first, last, comp) + assert_non_throwing([=, &policy] { (void)std::sort(policy, std::move(first1), std::move(last1), compare); }); + + // stable_sort(first, last) + assert_non_throwing([=, &policy] { (void)std::stable_sort(policy, std::move(first1), std::move(last1)); }); + + // stable_sort(first, last, comp) + assert_non_throwing([=, &policy] { + (void)std::stable_sort(policy, std::move(first1), std::move(last1), compare); + }); + } + + { + auto unary = maybe_throw(tokens[5], [](int x) -> int { return x * 2; }); + auto binary = maybe_throw(tokens[5], [](int x, int y) -> int { return x * y; }); + + // transform(first, last, dest, func) + assert_non_throwing([=, &policy] { + (void)std::transform(policy, std::move(first1), std::move(last1), std::move(dest), unary); + }); + + // transform(first1, last1, first2, dest, func) + assert_non_throwing([=, &policy] { + (void)std::transform(policy, std::move(first1), std::move(last1), std::move(first2), std::move(dest), binary); + }); + } + + { + auto reduction = maybe_throw(tokens[5], [](int x, int y) -> int { return x + y; }); + auto transform_unary = maybe_throw(tokens[6], [](int x) -> int { return x * 2; }); + auto transform_binary = maybe_throw(tokens[6], [](int x, int y) -> int { return x * y; }); + + // transform_reduce(first1, last1, first2, init) + assert_non_throwing([=, &policy] { + (void)std::transform_reduce(policy, std::move(first1), std::move(last1), std::move(first2), init); + }); + + // transform_reduce(first1, last1, init, reduce, transform) + assert_non_throwing([=, &policy] { + (void)std::transform_reduce(policy, std::move(first1), std::move(last1), init, reduction, transform_unary); + }); + + // transform_reduce(first1, last1, first2, init, reduce, transform) + assert_non_throwing([=, &policy] { + (void)std::transform_reduce( + policy, std::move(first1), std::move(last1), std::move(first2), init, reduction, transform_binary); + }); + } + + { + auto reduction = maybe_throw(tokens[5], [](int x, int y) -> int { return x + y; }); + + // reduce(first, last) + assert_non_throwing([=, &policy] { (void)std::reduce(policy, std::move(first1), std::move(last1)); }); + + // reduce(first, last, init) + assert_non_throwing([=, &policy] { (void)std::reduce(policy, std::move(first1), std::move(last1), init); }); + + // reduce(first, last, init, binop) + assert_non_throwing([=, &policy] { + (void)std::reduce(policy, std::move(first1), std::move(last1), init, reduction); + }); + } + } + }); +} diff --git a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.reduce.pass.cpp b/libcxx/test/std/numerics/numeric.ops/reduce/pstl.reduce.pass.cpp similarity index 99% rename from libcxx/test/std/algorithms/numeric.ops/reduce/pstl.reduce.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/reduce/pstl.reduce.pass.cpp index b083c4f80e0b1..f5748d7c823b7 100644 --- a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.reduce.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/reduce/pstl.reduce.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: libcpp-has-no-incomplete-pstl -// +// // template // typename iterator_traits::value_type diff --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp similarity index 99% rename from libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp index 18b56f237c3e6..6d8bb47ac7dc1 100644 --- a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.binary.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: libcpp-has-no-incomplete-pstl -// +// // template diff --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp similarity index 99% rename from libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp index a32a4f85f6334..4cea3d405aa02 100644 --- a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/transform.reduce/pstl.transform_reduce.unary.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: libcpp-has-no-incomplete-pstl -// +// // template