mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:06:44 +00:00
[Clang] Warn about [[noreturn]]
on coroutines (#127623)
Declaring a coroutine `[[noreturn]]` doesn't make sense, because it will always return its handle. Clang previously crashed when trying to warn about this (diagnostic ID was 0). Fixes #127327.
This commit is contained in:
parent
8529bd7b96
commit
db5bc8e9d0
@ -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<
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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))
|
||||
|
30
clang/test/SemaCXX/coroutine-noreturn.cpp
Normal file
30
clang/test/SemaCXX/coroutine-noreturn.cpp
Normal file
@ -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();
|
Loading…
x
Reference in New Issue
Block a user