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