brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.3 KiB · baa8c27 Raw
126 lines · cpp
1// Test for PR56919. Tests the destroy function contains the call to delete function only.2//3// REQUIRES: x86-registered-target4//5// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 %s -O3 -S -o - | FileCheck %s6 7#include "Inputs/coroutine.h"8 9namespace std {10 11template <typename T> struct remove_reference { using type = T; };12template <typename T> struct remove_reference<T &> { using type = T; };13template <typename T> struct remove_reference<T &&> { using type = T; };14 15template <typename T>16constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {17  return static_cast<typename std::remove_reference<T>::type &&>(t);18}19 20}21 22template <typename T>23class Task final {24 public:25  using value_type = T;26 27  class promise_type final {28   public: 29    Task<void> get_return_object() { return Task<void>(std::coroutine_handle<promise_type>::from_promise(*this)); }30 31    void unhandled_exception() {}32 33    std::suspend_always initial_suspend() { return {}; }34 35    auto await_transform(Task<void> co) {36      return await_transform(std::move(co.handle_.promise()));37    }38 39    auto await_transform(promise_type&& awaited) {40      struct Awaitable {41        promise_type&& awaited;42 43        bool await_ready() { return false; }44 45        std::coroutine_handle<> await_suspend(46            const std::coroutine_handle<> handle) {47          // Register our handle to be resumed once the awaited promise's coroutine48          // finishes, and then resume that coroutine.49          awaited.registered_handle_ = handle;50          return std::coroutine_handle<promise_type>::from_promise(awaited);51        }52 53        void await_resume() {}54 55       private:56      };57 58      return Awaitable{std::move(awaited)};59    }60 61    void return_void() {}62 63    // At final suspend resume our registered handle.64    auto final_suspend() noexcept {65      struct FinalSuspendAwaitable final {66        bool await_ready() noexcept { return false; }67 68        std::coroutine_handle<> await_suspend(69            std::coroutine_handle<> h) noexcept {70          return to_resume;71        }72 73        void await_resume() noexcept {}74 75        std::coroutine_handle<> to_resume;76      };77 78      return FinalSuspendAwaitable{registered_handle_};79    }80 81   private:82    std::coroutine_handle<promise_type> my_handle() {83      return std::coroutine_handle<promise_type>::from_promise(*this);84    }85 86    std::coroutine_handle<> registered_handle_;87  };88 89  ~Task() {90    // Teach llvm that we are only ever destroyed when the coroutine body is done,91    // so there is no need for the jump table in the destroy function. Our coroutine92    // library doesn't expose handles to the user, so we know this constraint isn't93    // violated.94    if (!handle_.done()) {95      __builtin_unreachable();96    }97 98    handle_.destroy();99  }100 101 private:102  explicit Task(const std::coroutine_handle<promise_type> handle)103      : handle_(handle) {}104 105  const std::coroutine_handle<promise_type> handle_;106};107 108Task<void> Qux() { co_return; }109Task<void> Baz() { co_await Qux(); }110Task<void> Bar() { co_await Baz(); }111 112// CHECK: _Z3Quxv.destroy:{{.*}}113// CHECK-NEXT: #114// CHECK-NEXT: movl	$40, %esi115// CHECK-NEXT: jmp	_ZdlPvm@PLT116 117// CHECK: _Z3Bazv.destroy:{{.*}}118// CHECK-NEXT: #119// CHECK-NEXT: movl	$80, %esi120// CHECK-NEXT: jmp	_ZdlPvm121 122// CHECK: _Z3Barv.destroy:{{.*}}123// CHECK-NEXT: #124// CHECK-NEXT: movl	$120, %esi125// CHECK-NEXT: jmp	_ZdlPvm126