https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/127623
>From 3014c72978494df2a77f4b660fcea5fd20802221 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@outlook.de> Date: Tue, 18 Feb 2025 12:56:05 +0100 Subject: [PATCH] [Clang] Warn about `[[noreturn]]` on coroutines --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Sema/AnalysisBasedWarnings.cpp | 8 +++-- clang/lib/Sema/SemaCoroutine.cpp | 4 +++ clang/lib/Sema/SemaStmt.cpp | 2 +- clang/test/SemaCXX/coroutine-noreturn.cpp | 30 +++++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaCXX/coroutine-noreturn.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f10af8f5bd6b2..ee1ad214d81df 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10606,6 +10606,9 @@ def warn_noreturn_function_has_return_expr : Warning< def warn_falloff_noreturn_function : Warning< "function declared 'noreturn' should not return">, InGroup<InvalidNoreturn>; +def warn_noreturn_coroutine : Warning< + "coroutine %0 cannot be declared 'noreturn' as it always returns a coroutine handle">, + InGroup<InvalidNoreturn>; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; def err_carries_dependency_missing_on_first_decl : Error< diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 589869d018657..ce7d9be8d2faa 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -697,10 +697,12 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, return; SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc(); auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { - if (IsCoroutine) - S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); - else + if (IsCoroutine) { + if (DiagID != 0) + S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); + } else { S.Diag(Loc, DiagID); + } }; // cpu_dispatch functions permit empty function bodies for ICC compatibility. diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 3a22097152df5..0e4f3b20c78cd 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -1176,6 +1176,10 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { for (AddrLabelExpr *ALE : Fn->AddrLabels) Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label); + // Coroutines always return a handle, so they can't be [[noreturn]]. + if (FD->isNoReturn()) + Diag(FD->getLocation(), diag::warn_noreturn_coroutine) << FD; + CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body); if (Builder.isInvalid() || !Builder.buildStatements()) return FD->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index ec38674a2c3e7..0394edb7889ba 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3910,7 +3910,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, FnRetType = FD->getReturnType(); if (FD->hasAttrs()) Attrs = &FD->getAttrs(); - if (FD->isNoReturn()) + if (FD->isNoReturn() && !getCurFunction()->isCoroutine()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD; if (FD->isMain() && RetValExp) if (isa<CXXBoolLiteralExpr>(RetValExp)) diff --git a/clang/test/SemaCXX/coroutine-noreturn.cpp b/clang/test/SemaCXX/coroutine-noreturn.cpp new file mode 100644 index 0000000000000..4516b4e720ec0 --- /dev/null +++ b/clang/test/SemaCXX/coroutine-noreturn.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -Winvalid-noreturn -verify + +#include "Inputs/std-coroutine.h" + +struct Promise; + +struct Awaitable { + bool await_ready(); + void await_suspend(std::coroutine_handle<>); + void await_resume(); +}; + +struct Coro : std::coroutine_handle<> { + using promise_type = Promise; +}; + +struct Promise { + Coro get_return_object(); + std::suspend_always initial_suspend() noexcept; + std::suspend_always final_suspend() noexcept; + void return_void(); + void unhandled_exception(); +}; + +[[noreturn]] Coro test() { // expected-warning {{coroutine 'test' cannot be declared 'noreturn' as it always returns a coroutine handle}} + co_await Awaitable{}; +} + +// NO warning here. This could be a regular function returning a `Coro` object. +[[noreturn]] Coro test2(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits