From f332498f9880d276890562fb861a375a13bfd9d9 Mon Sep 17 00:00:00 2001 From: Deniz Evrenci Date: Tue, 28 Feb 2023 11:36:46 +0100 Subject: [PATCH] [Clang] Do not emit exception diagnostics from coroutines and coroutine lambdas 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. Fixes #48797. Differential Revision: https://reviews.llvm.org/D144352 --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- .../test/SemaCXX/warn-throw-out-noexcept-coro.cpp | 63 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 07e17f9..4367435 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2509,7 +2509,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // 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(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. diff --git a/clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp b/clang/test/SemaCXX/warn-throw-out-noexcept-coro.cpp new file mode 100644 index 0000000..4d52bdc --- /dev/null +++ b/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 +struct promise; + +template +struct task { + using promise_type = promise; + + explicit task(promise_type& p) { throw 1; p.return_val = this; } + + task(const task&) = delete; + + T value; +}; + +template +struct promise { + task get_return_object() { return task{*this}; } + + std::suspend_never initial_suspend() const noexcept { return {}; } + + std::suspend_never final_suspend() const noexcept { return {}; } + + template + void return_value(U&& val) { return_val->value = static_cast(val); } + + void unhandled_exception() { throw 1; } + + task* return_val; +}; + +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; +} + +const auto c_ShouldNotDiag = [](const int a, const int b) -> task { + if (b == 0) + throw b; + + co_return a / b; +}; + +const auto d_ShouldNotDiag = [](const int a, const int b) noexcept -> task { + if (b == 0) + throw b; + + co_return a / b; +}; -- 2.7.4