diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 57b0266af26bb..9ccef6a3f39eb 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -566,7 +566,7 @@ class ASTReader /// modules. It is used for the following cases: /// - Lambda inside a template function definition: The main declaration is /// the enclosing function, and the related declarations are the lambda - /// declarations. + /// call operators. /// - Friend function defined inside a template CXXRecord declaration: The /// main declaration is the enclosing record, and the related declarations /// are the friend functions. diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index f3d260e8671b2..b16026c4ba898 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1655,7 +1655,7 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { if (auto *FD = llvm::dyn_cast_or_null(D->getDeclContext()); FD && isDefinitionInDependentContext(FD)) { Writer.RelatedDeclsMap[Writer.GetDeclRef(FD)].push_back( - Writer.GetDeclRef(D)); + Writer.GetDeclRef(D->getLambdaCallOperator())); } } else { Record.push_back(CXXRecNotTemplate); diff --git a/clang/test/Headers/crash-instantiated-in-scope-cxx-modules6.cpp b/clang/test/Headers/crash-instantiated-in-scope-cxx-modules6.cpp new file mode 100644 index 0000000000000..077f69ea6598d --- /dev/null +++ b/clang/test/Headers/crash-instantiated-in-scope-cxx-modules6.cpp @@ -0,0 +1,149 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -std=c++20 -xc++ -emit-module -fmodules foo.cppmap -fmodule-name=foo -fmodule-name=foo -o foo.pcm +// RUN: %clang_cc1 -std=c++20 -xc++ -emit-module -fmodules bar.cppmap -fmodule-name=bar -o bar.pcm +// RUN: %clang_cc1 -std=c++20 -xc++ -emit-module -fmodules experiment_context.cppmap -fmodule-name=experiment_context -fmodule-file=foo.pcm -fmodule-file=bar.pcm -o experiment_context.pcm +// RUN: %clang_cc1 -verify -std=c++20 -xc++ -fmodule-file=experiment_context.pcm experiment_context_test.cc -o experiment_context_test.o + +// https://github.com/llvm/llvm-project/issues/141582 +//--- bar.cppmap +module "bar" { + export * + header "co.h" +} + +//--- foo.cppmap +module "foo" { + export * + header "co.h" +} + +//--- experiment_context.cppmap +module "experiment_context" { + export * + header "lazy.h" + + use "foo" + use "bar" +} + +//--- experiment_context_test.cc +// expected-no-diagnostics +#include "lazy.h" + +namespace c9 { + +template +void WaitForCoroutine() { + MakeCo([]() -> Co { + co_return; + }); +} + +void test() { + c9::WaitForCoroutine(); +} +} + +//--- lazy.h +#pragma once + +#include "co.h" + +namespace c9 { +template +Co MakeCo(F f) +{ + co_return co_await f(); +} +} + +inline c9::Co DoNothing() { co_return; } + + +//--- co.h +#pragma once +namespace std { + +template +struct coroutine_traits {}; + +template + requires requires { typename Ret::promise_type; } +struct coroutine_traits { + using promise_type = typename Ret::promise_type; +}; + +template +struct coroutine_handle; + +template <> +struct coroutine_handle {}; + +template +struct coroutine_handle : coroutine_handle<> { + static coroutine_handle from_address(void *addr); +}; + +struct suspend_always { + bool await_ready() noexcept; + void await_suspend(coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +} // namespace std + +namespace c9 { + +template +class Co; + +namespace internal { + +template +class CoroutinePromise { + public: + template + explicit CoroutinePromise(Args&&... args) { + // Ensure that the 'dummy_color' VarDecl referenced by the inner DeclRefExpr + // is the same declaration as the one outside the lambda. + // This is guaranteed because both CoroutinePromise and the lambda's call operator + // (CXXMethodDecl) are loaded from the same module. + const int dummy_color = 1; + [&]{ (void)dummy_color; }(); + } + + ~CoroutinePromise(); + void return_void(); + auto get_return_object() { + return Co(); + } + void unhandled_exception(); + std::suspend_always initial_suspend(); + + struct result_t { + ~result_t(); + bool await_ready() const noexcept; + void await_suspend(std::coroutine_handle) noexcept; + void await_resume() const noexcept; + }; + + template + result_t await_transform(Co co); + + std::suspend_always final_suspend() noexcept; +}; +} // namespace internal + +template +class Co { + public: + using promise_type = internal::CoroutinePromise; +}; + +class CoIncomingModuleBase { + public: + Co CoAfterFinish() { co_return; } +}; +} // namespace c9