diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -85,6 +85,7 @@ __algorithm/pstl_backends/cpu_backends/thread.h __algorithm/pstl_backends/cpu_backends/transform.h __algorithm/pstl_backends/cpu_backends/transform_reduce.h + __algorithm/pstl_backends/pstl_expected.h __algorithm/pstl_copy.h __algorithm/pstl_count.h __algorithm/pstl_fill.h diff --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h --- a/libcxx/include/__algorithm/pstl_backend.h +++ b/libcxx/include/__algorithm/pstl_backend.h @@ -155,6 +155,12 @@ // TODO: Complete this list +Exception handling +================== + +The backend is expected to terminate on any user-thrown exceptions. This includes exceptions which are thrown by a +parallel algorithm which is invoked inside another algorithm. If any allocation fails, the backend shall return a +__pstl_unexpected, which will be turned into a bad_alloc at the frontend level. */ template diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h @@ -44,6 +44,13 @@ _LeafSort __leaf_sort); TODO: Document the parallel backend + +Exception handling +================== + +The backend is expected to terminate on any user-thrown exceptions. This includes exceptions which are thrown by a +parallel algorithm which is invoked inside another algorithm. If any allocation fails, the backend shall return a +__pstl_unexpected, which will be turned into a bad_alloc at the frontend level. */ #include <__algorithm/pstl_backends/cpu_backends/any_of.h> diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h @@ -11,6 +11,7 @@ #include <__algorithm/lower_bound.h> #include <__algorithm/max.h> +#include <__algorithm/pstl_backends/pstl_expected.h> #include <__algorithm/upper_bound.h> #include <__atomic/atomic.h> #include <__config> @@ -90,7 +91,7 @@ typename _RandomAccessIterator3, typename _Compare, typename _LeafMerge> -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI __pstl_expected __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -102,11 +103,11 @@ __libdispatch::__partition_chunks(std::max(__last1 - __first1, __last2 - __first2)); if (__partitions.__chunk_count_ == 0) - return; + return __pstl_expected{}; if (__partitions.__chunk_count_ == 1) { __leaf_merge(__first1, __last1, __first2, __last2, __result, __comp); - return; + return __pstl_expected{}; } using __merge_range_t = __merge_range<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3>; @@ -117,8 +118,23 @@ 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 __pstl_unexpected; // 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([&] { @@ -168,6 +184,8 @@ __comp); }); }); + + return __pstl_expected{}; } template diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h @@ -30,7 +30,7 @@ class _ForwardIterator2, class _ForwardOutIterator, class _Comp> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge( +_LIBCPP_HIDE_FROM_ABI __pstl_expected<_ForwardOutIterator> __pstl_merge( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -42,31 +42,31 @@ __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) { + (void)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)); + }); + if (!__res.__has_value()) + return __pstl_unexpected; + return __result + (__last1 - __first1) + (__last2 - __first2); } else { return std::merge(__first1, __last1, __first2, __last2, __result, __comp); } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H #define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H +#include <__algorithm/pstl_backends/pstl_expected.h> #include <__config> #include <__utility/move.h> #include @@ -26,38 +27,42 @@ inline namespace __serial_cpu_backend { template -_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { +_LIBCPP_HIDE_FROM_ABI __pstl_expected +__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) noexcept { __f(__first, __last); + return __pstl_expected{}; } template -_LIBCPP_HIDE_FROM_ABI _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)); +_LIBCPP_HIDE_FROM_ABI __pstl_expected<_Tp> +__parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) noexcept { + return {in_place, __reduce(std::move(__first), std::move(__last), std::move(__init))}; } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( - _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) { +_LIBCPP_HIDE_FROM_ABI __pstl_expected __parallel_stable_sort( + _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) noexcept { __leaf_sort(__first, __last, __comp); + return __pstl_expected{}; } -_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} +_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() noexcept {} template -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI __pstl_expected __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _RandomAccessIterator3 __outit, _Compare __comp, - _LeafMerge __leaf_merge) { + _LeafMerge __leaf_merge) noexcept { __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp); + return __pstl_expected{}; } // TODO: Complete this list diff --git a/libcxx/include/__algorithm/pstl_backends/pstl_expected.h b/libcxx/include/__algorithm/pstl_backends/pstl_expected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/pstl_expected.h @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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___ALGORITH_PSTL_BACKENDS_PSTL_EXPECTED_H +#define _LIBCPP___ALGORITH_PSTL_BACKENDS_PSTL_EXPECTED_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_void.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline constexpr struct __pstl_unexpected_t { +} __pstl_unexpected; + +template +class [[nodiscard]] __pstl_expected { + struct __empty {}; + + union { + conditional_t, __empty, _Tp> __val_; + }; + bool __has_value_; + +public: + __pstl_expected(const __pstl_expected&) = delete; + __pstl_expected& operator=(const __pstl_expected&) = delete; + __pstl_expected& operator=(__pstl_expected&&) = delete; + + template , int> = 0> + explicit __pstl_expected() : __has_value_(true) {} + + __pstl_expected(__pstl_expected&& __other) : __has_value_(__other.__has_value_) { + if (__other.__has_value_) { + std::construct_at(&__val_, std::move(__other.__val_)); + } + } + + ~__pstl_expected() { + if (__has_value_) + std::destroy_at(&__val_); + } + + __pstl_expected(__pstl_unexpected_t) : __has_value_(false) {} + + template , int> = 0 > + __pstl_expected(_Up&& __val) : __val_(std::forward<_Up>(__val)), __has_value_(true) {} + + template + __pstl_expected(in_place_t, _Args&&... __args) : __val_(std::forward<_Args>(__args)...) {} + + [[nodiscard]] _Tp __get_value_or_throw() && { + if (!__has_value_) + std::__throw_bad_alloc(); + if constexpr (!is_void_v<_Tp>) + return __val_; + } + + [[nodiscard]] bool __has_value() const { return __has_value_; } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITH_PSTL_BACKENDS_PSTL_EXPECTED_H diff --git a/libcxx/include/__algorithm/pstl_merge.h b/libcxx/include/__algorithm/pstl_merge.h --- a/libcxx/include/__algorithm/pstl_merge.h +++ b/libcxx/include/__algorithm/pstl_merge.h @@ -41,14 +41,17 @@ _ForwardOutIterator __result, _Comp __comp = {}) { 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)); + return std::__terminate_on_exception([&] { + return std::__pstl_merge<_RawPolicy>( + _Backend{}, + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::move(__comp)); + }) + .__get_value_or_throw(); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__numeric/pstl_transform_reduce.h b/libcxx/include/__numeric/pstl_transform_reduce.h --- a/libcxx/include/__numeric/pstl_transform_reduce.h +++ b/libcxx/include/__numeric/pstl_transform_reduce.h @@ -43,14 +43,17 @@ _BinaryOperation1 __reduce, _BinaryOperation2 __transform) { 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)); + return std::__terminate_on_exception([&] { + 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)); + }) + .__get_value_or_throw(); } // This overload doesn't get a customization point because it's trivial to detect (through e.g. @@ -84,13 +87,16 @@ _BinaryOperation __reduce, _UnaryOperation __transform) { using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_transform_reduce<_RawPolicy>( - _Backend{}, - std::move(__first), - std::move(__last), - std::move(__init), - std::move(__reduce), - std::move(__transform)); + return std::__terminate_on_exception([&] { + return std::__pstl_transform_reduce<_RawPolicy>( + _Backend{}, + std::move(__first), + std::move(__last), + std::move(__init), + std::move(__reduce), + std::move(__transform)); + }) + .__get_value_or_throw(); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/terminate_on_exception.h b/libcxx/include/__utility/terminate_on_exception.h --- a/libcxx/include/__utility/terminate_on_exception.h +++ b/libcxx/include/__utility/terminate_on_exception.h @@ -21,26 +21,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS - template -_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) { - try { +_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) noexcept { return __func(); - } catch (...) { - std::terminate(); - } -} - -# else // _LIBCPP_HAS_NO_EXCEPTIONS - -template -_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 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 --- 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 @@ -24,6 +24,8 @@ #include "test_execution_policies.h" #include "test_iterators.h" +#include "check_assertion.h" + EXECUTION_POLICY_SFINAE_TEST(fill); static_assert(sfinae_test_fill); @@ -61,24 +63,8 @@ } }; -#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{}, TestIteratorWithPolicies{}); -#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.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.terminate.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +// check that std::fill(ExecutionPolicy) terminates properly + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +#include + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct ThrowOnCopy { + ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } +}; +#endif + +TEST_TERMINATIONS([] { + ThrowOnCopy a[2]{}; + + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { (void)std::fill(policy, std::begin(a), std::end(a), ThrowOnCopy{}); }); + EXPECT_STD_TERMINATE([&] { (void)std::fill_n(policy, std::begin(a), std::size(a), ThrowOnCopy{}); }); + }); +}); 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 --- 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 @@ } }; -#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{}, TestIteratorWithPolicies{}); -#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.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp --- 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 ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.terminate.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +#include + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +TEST_TERMINATIONS([] { + ThrowOnCompare a[2]{}; + + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + (void)std::replace(policy, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + (void)std::replace_if( + policy, std::begin(a), std::end(a), [](ThrowOnCompare&) -> bool { throw int{}; }, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + (void)std::replace_copy(policy, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + (void)std::replace_copy_if( + policy, + std::begin(a), + std::end(a), + std::begin(a), + [](ThrowOnCompare& i) { return i == i; }, + ThrowOnCompare{}); + }); + }); +}); 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 --- 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 ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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 --- 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 ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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 --- 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 ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.transform.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.transform.terminate.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +#include + +TEST_TERMINATIONS([] { + int a[2]{}; + int b[2]{}; + int c[2]{}; + + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + (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([&] { + (void)std::transform(policy, std::begin(a), std::end(a), std::begin(b), [](auto v) -> decltype(v) { + throw int{}; + }); + }); + }); +}); 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 --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.all_of.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.terminate.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include "terminating_test_helper.h" + +#include + +TEST_TERMINATIONS([] { + int a[] = {1, 2}; + + EXPECT_STD_TERMINATE([&] { + (void)std::all_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); +}); 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 --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.any_of.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.terminate.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +TEST_TERMINATIONS([] { + 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; }); + }); + }); +}); 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 --- 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 ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.terminate.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include + +#include "test_execution_policies.h" +#include "terminating_test_helper.h" + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +TEST_TERMINATIONS([] { + test_execution_policies([](auto&& policy) { + 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([&] { + ThrowOnCompare a[2] = {}; + (void)std::find(policy, std::begin(a), std::end(a), ThrowOnCompare{}); + }); + + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::find_if_not(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); + }); + }); +}); 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 --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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 --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.for_each.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.terminate.pass.cpp @@ -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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +#include + +#include "test_execution_policies.h" +#include "terminating_test_helper.h" + +TEST_TERMINATIONS([] { + test_execution_policies([](auto&& policy) { + int a[] = {1, 2}; + EXPECT_STD_TERMINATE([&] { std::for_each(policy, std::begin(a), std::end(a), [](int) { throw int{}; }); }); + EXPECT_STD_TERMINATE([&] { std::for_each_n(policy, std::data(a), std::size(a), [](int) { throw int{}; }); }); + }); +}); 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 --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp --- 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 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#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.nonmodifying/alg.none_of/pstl.none_of.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.terminate.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +TEST_TERMINATIONS([] { + 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; }); + }); + }); +}); diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.terminate.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include + +#include "check_assertion.h" +#include "test_execution_policies.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{}; + }); + }); + }); + + return 0; +} 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 --- 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 @@ -129,15 +129,5 @@ int main(int, char**) { types::for_each(types::random_access_iterator_list{}, TestIteratorWithPolicies{}); -#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/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.terminate.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.terminate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.terminate.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-pstl + +#include + +#include "terminating_test_helper.h" +#include "test_execution_policies.h" + +TEST_TERMINATIONS([] { + 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{}; }); + }); + }); +}); diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h --- a/libcxx/test/support/check_assertion.h +++ b/libcxx/test/support/check_assertion.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -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 @@ 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 @@ CASE(RK_SetupFailure); CASE(RK_MatchFound); CASE(RK_Unknown); + CASE(RK_Terminate); } return "not a result kind"; } @@ -236,6 +234,7 @@ 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 @@ } std::exit(DeathTest::RK_MatchFailure); } +#endif // _LIBCPP_VERSION + +[[noreturn]] inline void terminate_handler() { + std::exit(DeathTest::RK_Terminate); +} template 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 @@ }; 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 @@ /// 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 --- a/libcxx/test/support/test_execution_policies.h +++ b/libcxx/test/support/test_execution_policies.h @@ -58,8 +58,4 @@ } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -[[noreturn]] inline void terminate_successful() { std::exit(0); } -#endif - #endif // TEST_SUPPORT_TEST_EXECUTION_POLICIES