Skip to content

Commit a7924a0

Browse files
committed
[Clang] Warn about [[noreturn]] on coroutines
1 parent 6273877 commit a7924a0

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10606,6 +10606,9 @@ def warn_noreturn_function_has_return_expr : Warning<
1060610606
def warn_falloff_noreturn_function : Warning<
1060710607
"function declared 'noreturn' should not return">,
1060810608
InGroup<InvalidNoreturn>;
10609+
def warn_noreturn_coroutine : Warning<
10610+
"coroutine %0 cannot be declared 'noreturn' as it always returns a coroutine handle">,
10611+
InGroup<InvalidNoreturn>;
1060910612
def err_noreturn_block_has_return_expr : Error<
1061010613
"block declared 'noreturn' should not return">;
1061110614
def err_carries_dependency_missing_on_first_decl : Error<

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -697,10 +697,12 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
697697
return;
698698
SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();
699699
auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
700-
if (IsCoroutine)
701-
S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType();
702-
else
700+
if (IsCoroutine) {
701+
if (DiagID != 0)
702+
S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType();
703+
} else {
703704
S.Diag(Loc, DiagID);
705+
}
704706
};
705707

706708
// cpu_dispatch functions permit empty function bodies for ICC compatibility.

clang/lib/Sema/SemaStmt.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3910,8 +3910,13 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
39103910
FnRetType = FD->getReturnType();
39113911
if (FD->hasAttrs())
39123912
Attrs = &FD->getAttrs();
3913-
if (FD->isNoReturn())
3914-
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD;
3913+
if (FD->isNoReturn()) {
3914+
const FunctionScopeInfo *Scope = getEnclosingFunction();
3915+
if (Scope && Scope->isCoroutine())
3916+
Diag(ReturnLoc, diag::warn_noreturn_coroutine) << FD;
3917+
else
3918+
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD;
3919+
}
39153920
if (FD->isMain() && RetValExp)
39163921
if (isa<CXXBoolLiteralExpr>(RetValExp))
39173922
Diag(ReturnLoc, diag::warn_main_returns_bool_literal)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -Winvalid-noreturn -verify
2+
3+
#include "Inputs/std-coroutine.h"
4+
5+
struct Promise;
6+
7+
struct Awaitable {
8+
bool await_ready();
9+
void await_suspend(std::coroutine_handle<>);
10+
void await_resume();
11+
};
12+
13+
struct Coro : std::coroutine_handle<> {
14+
using promise_type = Promise;
15+
};
16+
17+
struct Promise {
18+
Coro get_return_object();
19+
std::suspend_always initial_suspend() noexcept;
20+
std::suspend_always final_suspend() noexcept;
21+
void return_void();
22+
void unhandled_exception();
23+
};
24+
25+
[[noreturn]] Coro test() { // expected-warning {{coroutine 'test' cannot be declared 'noreturn' as it always returns a coroutine handle}}
26+
co_await Awaitable{};
27+
}

0 commit comments

Comments
 (0)