[clang] [Clang] Warn about `[[noreturn]]` on coroutines (PR #127623)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 18 12:31:42 PST 2025
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/127623
>From 51d7ebdd37013c3d90d2720952c712815fb49525 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at 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 | 27 +++++++++++++++++++
5 files changed, 40 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..c5555773863c8 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 (Fn->isCoroutine())
+ 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..bb23e2adcd5c6
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-noreturn.cpp
@@ -0,0 +1,27 @@
+// 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{};
+}
More information about the cfe-commits
mailing list