brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · 2d635c6 Raw
201 lines · plain
1// RUN: rm -rf %t2// RUN: split-file %s %t3 4// RUN: %clang_cc1 -std=c++20 %t/task.cppm -I%t -emit-reduced-module-interface -o %t/task.pcm5// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/user.cpp -verify -fsyntax-only6 7//--- coroutine.h8 9namespace std {10 11template <typename R, typename...> struct coroutine_traits {12    using promise_type = typename R::promise_type;13};14 15template <typename Promise = void> struct coroutine_handle;16 17template <> struct coroutine_handle<void> {18    static coroutine_handle from_address(void *addr) noexcept {19    coroutine_handle me;20    me.ptr = addr;21    return me;22    }23    void operator()() { resume(); }24    void *address() const noexcept { return ptr; }25    void resume() const { __builtin_coro_resume(ptr); }26    void destroy() const { __builtin_coro_destroy(ptr); }27    bool done() const { return __builtin_coro_done(ptr); }28    coroutine_handle &operator=(decltype(nullptr)) {29    ptr = nullptr;30    return *this;31    }32    coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}33    coroutine_handle() : ptr(nullptr) {}34//  void reset() { ptr = nullptr; } // add to P0057?35    explicit operator bool() const { return ptr; }36 37protected:38    void *ptr;39};40 41template <typename Promise> struct coroutine_handle : coroutine_handle<> {42    using coroutine_handle<>::operator=;43 44    static coroutine_handle from_address(void *addr) noexcept {45    coroutine_handle me;46    me.ptr = addr;47    return me;48    }49 50    Promise &promise() const {51    return *reinterpret_cast<Promise *>(52        __builtin_coro_promise(ptr, alignof(Promise), false));53    }54    static coroutine_handle from_promise(Promise &promise) {55    coroutine_handle p;56    p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);57    return p;58    }59};60 61template <typename _PromiseT>62bool operator==(coroutine_handle<_PromiseT> const &_Left,63                coroutine_handle<_PromiseT> const &_Right) noexcept {64    return _Left.address() == _Right.address();65}66 67template <typename _PromiseT>68bool operator!=(coroutine_handle<_PromiseT> const &_Left,69                coroutine_handle<_PromiseT> const &_Right) noexcept {70    return !(_Left == _Right);71}72 73struct noop_coroutine_promise {};74 75template <>76struct coroutine_handle<noop_coroutine_promise> {77    operator coroutine_handle<>() const noexcept {78    return coroutine_handle<>::from_address(address());79    }80 81    constexpr explicit operator bool() const noexcept { return true; }82    constexpr bool done() const noexcept { return false; }83 84    constexpr void operator()() const noexcept {}85    constexpr void resume() const noexcept {}86    constexpr void destroy() const noexcept {}87 88    noop_coroutine_promise &promise() const noexcept {89    return *static_cast<noop_coroutine_promise *>(90        __builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false));91    }92 93    constexpr void *address() const noexcept { return __handle_; }94 95private:96    friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;97 98    coroutine_handle() noexcept {99    this->__handle_ = __builtin_coro_noop();100    }101 102    void *__handle_ = nullptr;103};104 105using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;106 107inline noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); }108 109struct suspend_always {110    bool await_ready() noexcept { return false; }111    void await_suspend(coroutine_handle<>) noexcept {}112    void await_resume() noexcept {}113};114struct suspend_never {115    bool await_ready() noexcept { return true; }116    void await_suspend(coroutine_handle<>) noexcept {}117    void await_resume() noexcept {}118};119 120} // namespace std121 122//--- task.cppm123module;124#include "coroutine.h"125export module task;126export template <typename T>127struct [[clang::coro_await_elidable]] Task {128  struct promise_type {129    struct FinalAwaiter {130      bool await_ready() const noexcept { return false; }131 132      template <typename P>133      std::coroutine_handle<> await_suspend(std::coroutine_handle<P> coro) noexcept {134        if (!coro)135          return std::noop_coroutine();136        return coro.promise().continuation;137      }138      void await_resume() noexcept {}139    };140 141    Task get_return_object() noexcept {142      return std::coroutine_handle<promise_type>::from_promise(*this);143    }144 145    std::suspend_always initial_suspend() noexcept { return {}; }146    FinalAwaiter final_suspend() noexcept { return {}; }147    void unhandled_exception() noexcept {}148    void return_value(T x) noexcept {149      value = x;150    }151 152    std::coroutine_handle<> continuation;153    T value;154  };155 156  Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}157  ~Task() {158    if (handle)159      handle.destroy();160  }161 162  struct Awaiter {163    Awaiter(Task *t) : task(t) {}164    bool await_ready() const noexcept { return false; }165    void await_suspend(std::coroutine_handle<void> continuation) noexcept {}166    T await_resume() noexcept {167      return task->handle.promise().value;168    }169 170    Task *task;171  };172 173  auto operator co_await() {174    return Awaiter{this};175  }176 177private:178  std::coroutine_handle<promise_type> handle;179};180 181inline Task<int> callee() {182    co_return 1;183}184 185export inline Task<int> elidable() {186    co_return co_await callee();187}188 189namespace std {190    export using std::coroutine_traits;191    export using std::coroutine_handle;192    export using std::suspend_always;193}194 195//--- user.cpp196// expected-no-diagnostics197import task;198Task<int> test() {199    co_return co_await elidable();200}201