// RUN: rm -rf %t // RUN: split-file %s %t // RUN: %clang_cc1 -std=c++20 %t/task.cppm -I%t -emit-reduced-module-interface -o %t/task.pcm // RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/user.cpp -verify -fsyntax-only //--- coroutine.h namespace std { template struct coroutine_traits { using promise_type = typename R::promise_type; }; template struct coroutine_handle; template <> struct coroutine_handle { static coroutine_handle from_address(void *addr) noexcept { coroutine_handle me; me.ptr = addr; return me; } void operator()() { resume(); } void *address() const noexcept { return ptr; } void resume() const { __builtin_coro_resume(ptr); } void destroy() const { __builtin_coro_destroy(ptr); } bool done() const { return __builtin_coro_done(ptr); } coroutine_handle &operator=(decltype(nullptr)) { ptr = nullptr; return *this; } coroutine_handle(decltype(nullptr)) : ptr(nullptr) {} coroutine_handle() : ptr(nullptr) {} // void reset() { ptr = nullptr; } // add to P0057? explicit operator bool() const { return ptr; } protected: void *ptr; }; template struct coroutine_handle : coroutine_handle<> { using coroutine_handle<>::operator=; static coroutine_handle from_address(void *addr) noexcept { coroutine_handle me; me.ptr = addr; return me; } Promise &promise() const { return *reinterpret_cast( __builtin_coro_promise(ptr, alignof(Promise), false)); } static coroutine_handle from_promise(Promise &promise) { coroutine_handle p; p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true); return p; } }; template bool operator==(coroutine_handle<_PromiseT> const &_Left, coroutine_handle<_PromiseT> const &_Right) noexcept { return _Left.address() == _Right.address(); } template bool operator!=(coroutine_handle<_PromiseT> const &_Left, coroutine_handle<_PromiseT> const &_Right) noexcept { return !(_Left == _Right); } struct noop_coroutine_promise {}; template <> struct coroutine_handle { operator coroutine_handle<>() const noexcept { return coroutine_handle<>::from_address(address()); } constexpr explicit operator bool() const noexcept { return true; } constexpr bool done() const noexcept { return false; } constexpr void operator()() const noexcept {} constexpr void resume() const noexcept {} constexpr void destroy() const noexcept {} noop_coroutine_promise &promise() const noexcept { return *static_cast( __builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false)); } constexpr void *address() const noexcept { return __handle_; } private: friend coroutine_handle noop_coroutine() noexcept; coroutine_handle() noexcept { this->__handle_ = __builtin_coro_noop(); } void *__handle_ = nullptr; }; using noop_coroutine_handle = coroutine_handle; inline noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); } struct suspend_always { bool await_ready() noexcept { return false; } void await_suspend(coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; struct suspend_never { bool await_ready() noexcept { return true; } void await_suspend(coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; } // namespace std //--- task.cppm module; #include "coroutine.h" export module task; export template struct [[clang::coro_await_elidable]] Task { struct promise_type { struct FinalAwaiter { bool await_ready() const noexcept { return false; } template std::coroutine_handle<> await_suspend(std::coroutine_handle

coro) noexcept { if (!coro) return std::noop_coroutine(); return coro.promise().continuation; } void await_resume() noexcept {} }; Task get_return_object() noexcept { return std::coroutine_handle::from_promise(*this); } std::suspend_always initial_suspend() noexcept { return {}; } FinalAwaiter final_suspend() noexcept { return {}; } void unhandled_exception() noexcept {} void return_value(T x) noexcept { value = x; } std::coroutine_handle<> continuation; T value; }; Task(std::coroutine_handle handle) : handle(handle) {} ~Task() { if (handle) handle.destroy(); } struct Awaiter { Awaiter(Task *t) : task(t) {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle continuation) noexcept {} T await_resume() noexcept { return task->handle.promise().value; } Task *task; }; auto operator co_await() { return Awaiter{this}; } private: std::coroutine_handle handle; }; inline Task callee() { co_return 1; } export inline Task elidable() { co_return co_await callee(); } namespace std { export using std::coroutine_traits; export using std::coroutine_handle; export using std::suspend_always; } //--- user.cpp // expected-no-diagnostics import task; Task test() { co_return co_await elidable(); }