denizevrenci created this revision. denizevrenci added reviewers: NoQ, gribozavr. Herald added a subscriber: ChuanqiXu. Herald added a project: All. denizevrenci requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Fixes #48797 All exceptions thrown in coroutine bodies are caught and `unhandled_exception` member of the coroutine promise type is called. In accordance with the existing rules of diagnostics related to exceptions thrown in functions marked `noexcept`, even if the promise type's constructor, `get_return_object`, or `unhandled_exception` throws, diagnostics should not be emitted. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D144352 Files: clang/lib/Sema/AnalysisBasedWarnings.cpp clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp Index: clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -std=c++20 %s -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec + +#include "Inputs/std-coroutine.h" + +// expected-no-diagnostics + +template <typename T> +struct promise; + +template <typename T> +struct task { + using promise_type = promise<T>; + + explicit task(promise_type& p) noexcept { p.return_val = this; } + + task(const task&) = delete; + + T value; +}; + +template <typename T> +struct promise { + task<T> get_return_object() noexcept { return task{*this}; } + + std::suspend_never initial_suspend() const noexcept { return {}; } + + std::suspend_never final_suspend() const noexcept { return {}; } + + template <typename U> + void return_value(U&& val) { return_val->value = static_cast<U&&>(val); } + + void unhandled_exception() {} + + task<T>* return_val; +}; + +task<int> a_ShouldNotDiag(const int a, const int b) { + if (b == 0) + throw b; + + co_return a / b; +} + +task<int> b_ShouldNotDiag(const int a, const int b) noexcept { + if (b == 0) + throw b; + + co_return a / b; +} + +const auto c_ShouldNotDiag = [](const int a, const int b) -> task<int> { + if (b == 0) + throw b; + + co_return a / b; +}; + +const auto d_ShouldNotDiag = [](const int a, const int b) noexcept -> task<int> { + if (b == 0) + throw b; + + co_return a / b; +}; Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2509,7 +2509,7 @@ // Check for throw out of non-throwing function. if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc())) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) + if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); // Emit unsafe buffer usage warnings and fixits.
Index: clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -std=c++20 %s -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec + +#include "Inputs/std-coroutine.h" + +// expected-no-diagnostics + +template <typename T> +struct promise; + +template <typename T> +struct task { + using promise_type = promise<T>; + + explicit task(promise_type& p) noexcept { p.return_val = this; } + + task(const task&) = delete; + + T value; +}; + +template <typename T> +struct promise { + task<T> get_return_object() noexcept { return task{*this}; } + + std::suspend_never initial_suspend() const noexcept { return {}; } + + std::suspend_never final_suspend() const noexcept { return {}; } + + template <typename U> + void return_value(U&& val) { return_val->value = static_cast<U&&>(val); } + + void unhandled_exception() {} + + task<T>* return_val; +}; + +task<int> a_ShouldNotDiag(const int a, const int b) { + if (b == 0) + throw b; + + co_return a / b; +} + +task<int> b_ShouldNotDiag(const int a, const int b) noexcept { + if (b == 0) + throw b; + + co_return a / b; +} + +const auto c_ShouldNotDiag = [](const int a, const int b) -> task<int> { + if (b == 0) + throw b; + + co_return a / b; +}; + +const auto d_ShouldNotDiag = [](const int a, const int b) noexcept -> task<int> { + if (b == 0) + throw b; + + co_return a / b; +}; Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2509,7 +2509,7 @@ // Check for throw out of non-throwing function. if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc())) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) + if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); // Emit unsafe buffer usage warnings and fixits.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits