llvm/clang/test/CodeGenCoroutines/coro-destructor-of-final_suspend.cpp

// This addresses https://github.com/llvm/llvm-project/issues/57339
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fcxx-exceptions \
// RUN:     -fexceptions -emit-llvm -o - %s -O1 | FileCheck %s

#include "Inputs/coroutine.h"

struct gen {
  struct promise_type {
    gen get_return_object() noexcept {
      return gen{std::coroutine_handle<promise_type>::from_promise(*this)};
    }
    std::suspend_always initial_suspend() noexcept { return {}; }

    struct final_awaiter {
      ~final_awaiter() noexcept;
      bool await_ready() noexcept {
        return false;
      }
      void await_suspend(std::coroutine_handle<>) noexcept {}
      void await_resume() noexcept {}
    };

    final_awaiter final_suspend() noexcept {
      return {};
    }

    void unhandled_exception() {
      throw;
    }
    void return_void() {}
  };

  gen(std::coroutine_handle<promise_type> coro) noexcept
  : coro(coro)
  {
  }

  ~gen() noexcept {
    if (coro) {
      coro.destroy();
    }
  }

  gen(gen&& g) noexcept
  : coro(g.coro)
  {
    g.coro = {};
  }

  std::coroutine_handle<promise_type> coro;
};

struct X {};

gen maybe_throwing(bool x) {
  if (x) {
    throw X{};
  }
  co_return;
}

// CHECK: define{{.*}}@_Z14maybe_throwingb.destroy
// CHECK: %[[INDEX:.+]] = load i1, ptr %index.addr, align 1
// CHECK: br i1 %[[INDEX]], label %[[AFTERSUSPEND:.+]], label %[[CORO_FREE:.+]]
// CHECK: [[AFTERSUSPEND]]:
// CHECK: call{{.*}}_ZN3gen12promise_type13final_awaiterD1Ev(
// CHECK: [[CORO_FREE]]:
// CHECK: call{{.*}}_ZdlPv

void noexcept_call() noexcept;

gen no_throwing() {
  noexcept_call();
  co_return;
}

// CHECK: define{{.*}}@_Z11no_throwingv.resume({{.*}}%[[ARG:.+]])
// CHECK: resume:
// CHECK:   call{{.*}}@_Z13noexcept_callv()
// CHECK:   store ptr null, ptr %[[ARG]]
// CHECK:   ret void

// CHECK: define{{.*}}@_Z11no_throwingv.destroy({{.*}}%[[ARG:.+]])
// CHECK: %[[RESUME_FN_ADDR:.+]] = load ptr, ptr %[[ARG]]
// CHECK: %[[IF_NULL:.+]] = icmp eq ptr %[[RESUME_FN_ADDR]], null
// CHECK: br i1 %[[IF_NULL]], label %[[AFTERSUSPEND:.+]], label %[[CORO_FREE:.+]]
// CHECK: [[AFTERSUSPEND]]:
// CHECK: call{{.*}}_ZN3gen12promise_type13final_awaiterD1Ev(
// CHECK: [[CORO_FREE]]:
// CHECK: call{{.*}}_ZdlPv