// Test for PR56919. Tests the destroy function contains the call to delete function only.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 %s -O3 -S -o - | FileCheck %s

#include "Inputs/coroutine.h"

namespace std {

template <typename T> struct remove_reference { using type = T; };
template <typename T> struct remove_reference<T &> { using type = T; };
template <typename T> struct remove_reference<T &&> { using type = T; };

template <typename T>
constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
  return static_cast<typename std::remove_reference<T>::type &&>(t);
}

}

template <typename T>
class Task final {
 public:
  using value_type = T;

  class promise_type final {
   public: 
    Task<void> get_return_object() { return Task<void>(std::coroutine_handle<promise_type>::from_promise(*this)); }

    void unhandled_exception();

    std::suspend_always initial_suspend() { return {}; }

    auto await_transform(Task<void> co) {
      return await_transform(std::move(co.handle_.promise()));
    }

    auto await_transform(promise_type&& awaited) {
      struct Awaitable {
        promise_type&& awaited;

        bool await_ready() { return false; }

        std::coroutine_handle<> await_suspend(
            const std::coroutine_handle<> handle) {
          // Register our handle to be resumed once the awaited promise's coroutine
          // finishes, and then resume that coroutine.
          awaited.registered_handle_ = handle;
          return std::coroutine_handle<promise_type>::from_promise(awaited);
        }

        void await_resume() {}

       private:
      };

      return Awaitable{std::move(awaited)};
    }

    void return_void() {}

    // At final suspend resume our registered handle.
    auto final_suspend() noexcept {
      struct FinalSuspendAwaitable final {
        bool await_ready() noexcept { return false; }

        std::coroutine_handle<> await_suspend(
            std::coroutine_handle<> h) noexcept {
          return to_resume;
        }

        void await_resume() noexcept {}

        std::coroutine_handle<> to_resume;
      };

      return FinalSuspendAwaitable{registered_handle_};
    }

   private:
    std::coroutine_handle<promise_type> my_handle() {
      return std::coroutine_handle<promise_type>::from_promise(*this);
    }

    std::coroutine_handle<> registered_handle_;
  };

  ~Task() {
    // Teach llvm that we are only ever destroyed when the coroutine body is done,
    // so there is no need for the jump table in the destroy function. Our coroutine
    // library doesn't expose handles to the user, so we know this constraint isn't
    // violated.
    if (!handle_.done()) {
      __builtin_unreachable();
    }

    handle_.destroy();
  }

 private:
  explicit Task(const std::coroutine_handle<promise_type> handle)
      : handle_(handle) {}

  const std::coroutine_handle<promise_type> handle_;
};

Task<void> Qux() { co_return; }
Task<void> Baz() { co_await Qux(); }
Task<void> Bar() { co_await Baz(); }

// CHECK: _Z3Quxv.destroy:{{.*}}
// CHECK-NEXT: #
// CHECK-NEXT: jmp	_ZdlPv

// CHECK: _Z3Bazv.destroy:{{.*}}
// CHECK-NEXT: #
// CHECK-NEXT: jmp	_ZdlPv

// CHECK: _Z3Barv.destroy:{{.*}}
// CHECK-NEXT: #
// CHECK-NEXT: jmp	_ZdlPv
