Skip to content

[Clang] Warn about [[noreturn]] on coroutines #127623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
30 changes: 30 additions & 0 deletions clang/test/SemaCXX/coroutine-noreturn.cpp
Original file line number Diff line number Diff line change
@@ -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();