[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:
Utkarsh Saxena 2024-01-03 12:41:10 +01:00 committed by GitHub
parent 43a5c4a10d
commit aba40fb34a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 3 deletions

View File

@ -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

View File

@ -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