mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 19:26:05 +00:00
[coroutines] Do not check coroutine wrappers for skipped function bodies (#76729)
Without function bodies, we cannot tell whether a function is a coroutine or not. The analysis of coroutine wrappers is not useful when this information is not available. We therefore now skip this analysis for skipped function bodies.
This commit is contained in:
parent
43a5c4a10d
commit
aba40fb34a
@ -420,6 +420,62 @@ TEST(DiagnosticTest, MakeUnique) {
|
||||
"no matching constructor for initialization of 'S'")));
|
||||
}
|
||||
|
||||
TEST(DiagnosticTest, CoroutineInHeader) {
|
||||
StringRef CoroutineH = R"cpp(
|
||||
namespace std {
|
||||
template <class Ret, typename... T>
|
||||
struct coroutine_traits { using promise_type = typename Ret::promise_type; };
|
||||
|
||||
template <class Promise = void>
|
||||
struct coroutine_handle {
|
||||
static coroutine_handle from_address(void *) noexcept;
|
||||
static coroutine_handle from_promise(Promise &promise);
|
||||
constexpr void* address() const noexcept;
|
||||
};
|
||||
template <>
|
||||
struct coroutine_handle<void> {
|
||||
template <class PromiseType>
|
||||
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
|
||||
static coroutine_handle from_address(void *);
|
||||
constexpr void* address() const noexcept;
|
||||
};
|
||||
|
||||
struct awaitable {
|
||||
bool await_ready() noexcept { return false; }
|
||||
void await_suspend(coroutine_handle<>) noexcept {}
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
} // namespace std
|
||||
)cpp";
|
||||
|
||||
StringRef Header = R"cpp(
|
||||
#include "coroutine.h"
|
||||
template <typename T> struct [[clang::coro_return_type]] Gen {
|
||||
struct promise_type {
|
||||
Gen<T> get_return_object() {
|
||||
return {};
|
||||
}
|
||||
std::awaitable initial_suspend();
|
||||
std::awaitable final_suspend() noexcept;
|
||||
void unhandled_exception();
|
||||
void return_value(T t);
|
||||
};
|
||||
};
|
||||
|
||||
Gen<int> foo_coro(int b) { co_return b; }
|
||||
)cpp";
|
||||
Annotations Main(R"cpp(
|
||||
// error-ok
|
||||
#include "header.hpp"
|
||||
Gen<int> $[[bar_coro]](int b) { return foo_coro(b); }
|
||||
)cpp");
|
||||
TestTU TU = TestTU::withCode(Main.code());
|
||||
TU.AdditionalFiles["coroutine.h"] = std::string(CoroutineH);
|
||||
TU.AdditionalFiles["header.hpp"] = std::string(Header);
|
||||
TU.ExtraArgs.push_back("--std=c++20");
|
||||
EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(hasRange(Main.range())));
|
||||
}
|
||||
|
||||
TEST(DiagnosticTest, MakeShared) {
|
||||
// We usually miss diagnostics from header functions as we don't parse them.
|
||||
// std::make_shared is only parsed when --parse-forwarding-functions is set
|
||||
|
@ -15845,8 +15845,6 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) {
|
||||
}
|
||||
|
||||
void Sema::CheckCoroutineWrapper(FunctionDecl *FD) {
|
||||
if (!FD)
|
||||
return;
|
||||
RecordDecl *RD = FD->getReturnType()->getAsRecordDecl();
|
||||
if (!RD || !RD->getUnderlyingDecl()->hasAttr<CoroReturnTypeAttr>())
|
||||
return;
|
||||
@ -15869,7 +15867,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
|
||||
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
|
||||
|
||||
if (getLangOpts().Coroutines) {
|
||||
// If we skip function body, we can't tell if a function is a coroutine.
|
||||
if (getLangOpts().Coroutines && FD && !FD->hasSkippedBody()) {
|
||||
if (FSI->isCoroutine())
|
||||
CheckCompletedCoroutineBody(FD, Body);
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user