// RUN: %check_clang_tidy -std=c++20 %s bugprone-exception-escape %t -- \ // RUN: -- -fexceptions namespace std { template struct coroutine_traits { using promise_type = typename Ret::promise_type; }; template struct coroutine_handle { static coroutine_handle from_address(void *) noexcept; static coroutine_handle from_promise(Promise &promise); constexpr void *address() const noexcept; }; template <> struct coroutine_handle { template coroutine_handle(coroutine_handle) noexcept; static coroutine_handle from_address(void *); constexpr void *address() const noexcept; }; struct suspend_always { bool await_ready() noexcept { return false; } void await_suspend(coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; struct suspend_never { bool await_ready() noexcept { return true; } void await_suspend(coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; } // namespace std template struct Promise; template < typename T, bool ThrowInTaskConstructor = false, bool ThrowInPromiseConstructor = false, bool ThrowInInitialSuspend = false, bool ThrowInGetReturnObject = false, bool ThrowInUnhandledException = false, bool RethrowInUnhandledException = false> struct Task { using promise_type = Promise; explicit Task(promise_type &p) { if constexpr (ThrowInTaskConstructor) { throw 1; } p.return_val = this; } bool await_ready() { return true; } void await_suspend(std::coroutine_handle<> h) {} void await_resume() {} T value; }; template struct Task { using promise_type = Promise; explicit Task(promise_type &p) { if constexpr (ThrowInTaskConstructor) { throw 1; } p.return_val = this; } bool await_ready() { return true; } void await_suspend(std::coroutine_handle<> h) {} void await_resume() {} }; template struct Promise { Promise() { if constexpr (ThrowInPromiseConstructor) { throw 1; } } Task get_return_object() { if constexpr (ThrowInGetReturnObject) { throw 1; } return Task{*this}; } std::suspend_never initial_suspend() const { if constexpr (ThrowInInitialSuspend) { throw 1; } return {}; } std::suspend_never final_suspend() const noexcept { return {}; } template void return_value(U &&val) { return_val->value = static_cast(val); } template std::suspend_never yield_value(U &&val) { return_val->value = static_cast(val); return {}; } void unhandled_exception() { if constexpr (ThrowInUnhandledException) { throw 1; } else if constexpr (RethrowInUnhandledException) { throw; } } Task *return_val; }; template struct Promise { Promise() { if constexpr (ThrowInPromiseConstructor) { throw 1; } } Task get_return_object() { if constexpr (ThrowInGetReturnObject) { throw 1; } return Task{*this}; } std::suspend_never initial_suspend() const { if constexpr (ThrowInInitialSuspend) { throw 1; } return {}; } std::suspend_never final_suspend() const noexcept { return {}; } void return_void() {} void unhandled_exception() { if constexpr (ThrowInUnhandledException) { throw 1; } else if constexpr (RethrowInUnhandledException) { throw; } } Task *return_val; }; struct Evil { ~Evil() noexcept(false) { throw 42; } }; Task returnOne() { co_return 1; } namespace function { namespace coreturn { Task a_ShouldNotDiag(const int a, const int b) { if (b == 0) throw b; co_return a / b; } Task b_ShouldNotDiag(const int a, const int b) noexcept { if (b == 0) throw b; co_return a / b; } Task c_ShouldNotDiag(const int a, const int b) { if (b == 0) throw Evil{}; co_return a / b; } Task c_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions if (b == 0) throw Evil{}; co_return a / b; } Task d_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task d_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions co_return a / b; } Task e_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task e_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions co_return a / b; } Task f_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task f_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions co_return a / b; } Task g_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task g_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions co_return a / b; } Task h_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task h_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions co_return a / b; } Task i_ShouldNotDiag(const int a, const int b) { co_return a / b; } Task i_ShouldNotDiagNoexcept(const int a, const int b) noexcept { co_return a / b; } Task j_ShouldNotDiag(const int a, const int b) { if (b == 0) throw b; co_return a / b; } Task j_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions if (b == 0) throw b; co_return a / b; } } // namespace coreturn namespace coyield { Task a_ShouldNotDiag(const int a, const int b) { if (b == 0) throw b; co_yield a / b; } Task b_ShouldNotDiag(const int a, const int b) noexcept { if (b == 0) throw b; co_yield a / b; } Task c_ShouldNotDiag(const int a, const int b) { if (b == 0) throw Evil{}; co_yield a / b; } Task c_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions if (b == 0) throw Evil{}; co_yield a / b; } Task d_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task d_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions co_yield a / b; } Task e_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task e_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions co_yield a / b; } Task f_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task f_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions co_yield a / b; } Task g_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task g_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions co_yield a / b; } Task h_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task h_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions co_yield a / b; } Task i_ShouldNotDiag(const int a, const int b) { co_yield a / b; } Task i_ShouldNotDiagNoexcept(const int a, const int b) noexcept { co_yield a / b; } Task j_ShouldNotDiag(const int a, const int b) { if (b == 0) throw b; co_yield a / b; } Task j_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions if (b == 0) throw b; co_yield a / b; } } // namespace coyield namespace coawait { Task a_ShouldNotDiag(const int a, const int b) { if (b == 0) throw b; co_await returnOne(); } Task b_ShouldNotDiag(const int a, const int b) noexcept { if (b == 0) throw b; co_await returnOne(); } Task c_ShouldNotDiag(const int a, const int b) { if (b == 0) throw Evil{}; co_await returnOne(); } Task c_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: an exception may be thrown in function 'c_ShouldDiag' which should not throw exceptions if (b == 0) throw Evil{}; co_await returnOne(); } Task d_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task d_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions co_await returnOne(); } Task e_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task e_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions co_await returnOne(); } Task f_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task f_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions co_await returnOne(); } Task g_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task g_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions co_await returnOne(); } Task h_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task h_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions co_await returnOne(); } Task i_ShouldNotDiag(const int a, const int b) { co_await returnOne(); } Task i_ShouldNotDiagNoexcept(const int a, const int b) noexcept { co_await returnOne(); } Task j_ShouldNotDiag(const int a, const int b) { co_await returnOne(); if (b == 0) throw b; } Task j_ShouldDiag(const int a, const int b) noexcept { // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'j_ShouldDiag' which should not throw exceptions co_await returnOne(); if (b == 0) throw b; } } // namespace coawait } // namespace function namespace lambda { namespace coreturn { const auto a_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw b; co_return a / b; }; const auto b_ShouldNotDiag = [](const int a, const int b) noexcept -> Task { if (b == 0) throw b; co_return a / b; }; const auto c_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw Evil{}; co_return a / b; }; const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions if (b == 0) throw Evil{}; co_return a / b; }; const auto d_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto d_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_return a / b; }; const auto e_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto e_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_return a / b; }; const auto f_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto f_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_return a / b; }; const auto g_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto g_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_return a / b; }; const auto h_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto h_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_return a / b; }; const auto i_ShouldNotDiag = [](const int a, const int b) -> Task { co_return a / b; }; const auto i_ShouldNotDiagNoexcept = [](const int a, const int b) noexcept -> Task { co_return a / b; }; const auto j_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw b; co_return a / b; }; const auto j_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions if (b == 0) throw b; co_return a / b; }; } // namespace coreturn namespace coyield { const auto a_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw b; co_yield a / b; }; const auto b_ShouldNotDiag = [](const int a, const int b) noexcept -> Task { if (b == 0) throw b; co_yield a / b; }; const auto c_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw Evil{}; co_yield a / b; }; const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions if (b == 0) throw Evil{}; co_yield a / b; }; const auto d_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto d_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_yield a / b; }; const auto e_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto e_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_yield a / b; }; const auto f_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto f_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_yield a / b; }; const auto g_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto g_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_yield a / b; }; const auto h_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto h_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_yield a / b; }; const auto i_ShouldNotDiag = [](const int a, const int b) -> Task { co_yield a / b; }; const auto i_ShouldNotDiagNoexcept = [](const int a, const int b) noexcept -> Task { co_yield a / b; }; const auto j_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw b; co_yield a / b; }; const auto j_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions if (b == 0) throw b; co_yield a / b; }; } // namespace coyield namespace coawait { const auto a_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw b; co_await returnOne(); }; const auto b_ShouldNotDiag = [](const int a, const int b) noexcept -> Task { if (b == 0) throw b; co_await returnOne(); }; const auto c_ShouldNotDiag = [](const int a, const int b) -> Task { if (b == 0) throw Evil{}; co_await returnOne(); }; const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions if (b == 0) throw Evil{}; co_await returnOne(); }; const auto d_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto d_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); }; const auto e_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto e_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); }; const auto f_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto f_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); }; const auto g_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto g_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); }; const auto h_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto h_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); }; const auto i_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); }; const auto i_ShouldNotDiagNoexcept = [](const int a, const int b) noexcept -> Task { co_await returnOne(); }; const auto j_ShouldNotDiag = [](const int a, const int b) -> Task { co_await returnOne(); if (b == 0) throw b; }; const auto j_ShouldDiag = [](const int a, const int b) noexcept -> Task { // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions co_await returnOne(); if (b == 0) throw b; }; } // namespace coawait } // namespace lambda