https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/76729
>From c0baa45c2541bc688f377a6bd2c9281532b4d541 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Tue, 2 Jan 2024 16:49:28 +0100 Subject: [PATCH 1/2] [coroutines] Do not check coroutine wrappers for skipped function bodies --- .../clangd/unittests/DiagnosticsTests.cpp | 54 +++++++++++++++++++ clang/lib/Sema/SemaDecl.cpp | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 37643e5afa2304..a5744cdd4cbe6f 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -420,6 +420,60 @@ 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( + #include "header.hpp" + )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(), IsEmpty()); +} + 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 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ffbe317d559995..8329c00f1d16c1 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15845,7 +15845,7 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) { } void Sema::CheckCoroutineWrapper(FunctionDecl *FD) { - if (!FD) + if (!FD || FD->hasSkippedBody()) return; RecordDecl *RD = FD->getReturnType()->getAsRecordDecl(); if (!RD || !RD->getUnderlyingDecl()->hasAttr<CoroReturnTypeAttr>()) >From a2ac00f74130e0caa47072785fbd650c53a67be6 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Wed, 3 Jan 2024 11:25:33 +0100 Subject: [PATCH 2/2] addressed comments and added negative test as well --- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp | 6 ++++-- clang/lib/Sema/SemaDecl.cpp | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index a5744cdd4cbe6f..f302dcf5f09db0 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -465,13 +465,15 @@ template <typename T> struct [[clang::coro_return_type]] Gen { Gen<int> foo_coro(int b) { co_return b; } )cpp"; Annotations Main(R"cpp( - #include "header.hpp" +// 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(), IsEmpty()); + EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(hasRange(Main.range()))); } TEST(DiagnosticTest, MakeShared) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 8329c00f1d16c1..2de631941325fa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15845,8 +15845,6 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) { } void Sema::CheckCoroutineWrapper(FunctionDecl *FD) { - if (!FD || FD->hasSkippedBody()) - 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits