150 lines · cpp
1// RUN: rm -fR %t2// RUN: split-file %s %t3// RUN: cd %t4// RUN: %clang_cc1 -std=c++20 -xc++ -emit-module -fmodules foo.cppmap -fmodule-name=foo -fmodule-name=foo -o foo.pcm5// RUN: %clang_cc1 -std=c++20 -xc++ -emit-module -fmodules bar.cppmap -fmodule-name=bar -o bar.pcm6// 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.pcm7// RUN: %clang_cc1 -verify -std=c++20 -xc++ -fmodule-file=experiment_context.pcm experiment_context_test.cc -o experiment_context_test.o8 9// https://github.com/llvm/llvm-project/issues/14158210//--- bar.cppmap11module "bar" {12 export *13 header "co.h"14}15 16//--- foo.cppmap17module "foo" {18 export *19 header "co.h"20}21 22//--- experiment_context.cppmap23module "experiment_context" {24 export *25 header "lazy.h"26 27 use "foo"28 use "bar"29}30 31//--- experiment_context_test.cc32// expected-no-diagnostics33#include "lazy.h"34 35namespace c9 {36 37template <typename T>38void WaitForCoroutine() {39 MakeCo<T>([]() -> Co<void> {40 co_return;41 });42}43 44void test() {45 c9::WaitForCoroutine<void>();46}47}48 49//--- lazy.h50#pragma once51 52#include "co.h"53 54namespace c9 {55template <typename T, typename F>56Co<T> MakeCo(F f)57{58 co_return co_await f();59}60}61 62inline c9::Co<void> DoNothing() { co_return; }63 64 65//--- co.h66#pragma once67namespace std {68 69template <class _Ret, class... _Args>70struct coroutine_traits {};71 72template <typename Ret, typename... Args>73 requires requires { typename Ret::promise_type; }74struct coroutine_traits<Ret, Args...> {75 using promise_type = typename Ret::promise_type;76};77 78template <typename Promise = void>79struct coroutine_handle;80 81template <>82struct coroutine_handle<void> {};83 84template <typename Promise = void>85struct coroutine_handle : coroutine_handle<> {86 static coroutine_handle from_address(void *addr);87};88 89struct suspend_always {90 bool await_ready() noexcept;91 void await_suspend(coroutine_handle<>) noexcept;92 void await_resume() noexcept;93};94 95} // namespace std96 97namespace c9 {98 99template <typename T>100class Co;101 102namespace internal {103 104template <typename T>105class CoroutinePromise {106 public:107 template <typename... Args>108 explicit CoroutinePromise(Args&&... args) {109 // Ensure that the 'dummy_color' VarDecl referenced by the inner DeclRefExpr110 // is the same declaration as the one outside the lambda.111 // This is guaranteed because both CoroutinePromise and the lambda's call operator112 // (CXXMethodDecl) are loaded from the same module.113 const int dummy_color = 1;114 [&]{ (void)dummy_color; }();115 }116 117 ~CoroutinePromise();118 void return_void();119 auto get_return_object() {120 return Co<T>();121 }122 void unhandled_exception();123 std::suspend_always initial_suspend();124 125 struct result_t {126 ~result_t();127 bool await_ready() const noexcept;128 void await_suspend(std::coroutine_handle<void>) noexcept;129 void await_resume() const noexcept;130 };131 132 template <typename U>133 result_t await_transform(Co<U> co);134 135 std::suspend_always final_suspend() noexcept;136};137} // namespace internal138 139template <typename T>140class Co {141 public:142 using promise_type = internal::CoroutinePromise<void>;143};144 145class CoIncomingModuleBase {146 public:147 Co<void> CoAfterFinish() { co_return; }148};149} // namespace c9150