<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/61900>61900</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [coroutines] Clang generates incorrect code for throwing promise.unhandled_exception()
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          lewissbaker
      </td>
    </tr>
</table>

<pre>
    The [wording](https://eel.is/c++draft/dcl.fct.def.coroutine#14) for coroutines in `[dcl.fct.def.coroutine]` for `unhandled_exception()` says that:
> If the evaluation of the expression `promise.unhandled_exception()` exits via an exception, the coroutine is considered suspended at the final suspend-point and the exception propagates to the caller or resumer.

However, it seems that the current codegen for Clang does not set the suspend point to be at a final suspend point in this case. Instead, if a coroutine exits the call to `unhandled_exception()` with an exception, which you then catch and then destroy the coroutine, the coroutine behaves as if the coroutine was still suspended at the last suspend-point it suspended at. i.e. it does not seem to be writing a new suspend-point index to the coroutine-state if `unhandled_exception()` exits with an exception, instead it leaves the last-written suspend-point index value unchanged.

This can lead to unexpected behaviour. e.g. double-destruction of variables in-scope at the last suspend-point.

For example: Compile the following code with Clang 16.0 and the compiler args `-std=c++20 -stdlib=libc++ -O2`
```c++
#include <coroutine>
#include <cstdio>

struct generator {
    struct promise_type {
        generator get_return_object() noexcept { return generator{std::coroutine_handle<promise_type>::from_promise(*this)}; }
 void unhandled_exception() { throw; }
        void return_void() noexcept {}
        std::suspend_always yield_value(int) noexcept { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        std::suspend_always initial_suspend() noexcept { return {}; }
    };

    explicit generator(std::coroutine_handle<promise_type> h) noexcept
    : coro(h)
    {}

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

    ~generator() {
        if (coro)
 coro.destroy();
    }

    std::coroutine_handle<promise_type> coro;
};

struct RAII {
    __attribute__((noinline)) RAII() noexcept { std::puts("ctor"); }
    __attribute__((noinline)) ~RAII() { std::puts("dtor"); }
};

struct X {};

static generator example() {
    RAII raii;
    co_yield 0;
    throw X{};
}

int main() {
    generator g = example();
 g.coro.resume();
    try {
        g.coro.resume();
    } catch (X) {
        std::puts("caught X");
 }
}
```
Compiler-Explorer: https://godbolt.org/z/xqY4bbPTW

The expected output is:
```
ctor
dtor
caught X
```
The observed output under Clang 16 is:
```
ctor
dtor
caught X
dtor
```

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykV82O4zYMfhrlQsRw5PweckgmG3ROLYoFOj0FssXYahXJleQk08M-eyHJ-XHG2cF2B4NEoUTyI_mJkpi1olSISzJZk8lmwBpXabOUeBLW5uxvNINc8_fl1wqBTNYnbbhQJZlsCJ1XztWWZCtCt4RuEWUiLKHbgtA1oWtu2N4RuuWFTPaFSzjuk0Ib3TihkNBsNCZ0AXtt4Cq1IBSQaUom636tyYZM06BDpmmjKqa4RL7Dc4G1E1oROid04ddY9m7BVcx5fOmGpCuSfYHXPbgKAY9MNswrgG4l59qgtV5Cpmlt9EFYTL7rAc_CWTgKBkzB3fxLMHjFDMJCoZUVHA1ysI2tUXHkwFxYuBeKyYt4WGuhHDDFW1StVaiNrlnJHFpwOjpgUqIBbcCgbQ5okjbM8PmLPuERjUcjHFjEQ8xGVG2MQeWg0BxLVCGfL5KpErhGC0p7jbi0xQURl9OQowfOurDbaaHAVT5cZjGBV2UdMh4g7IHdZSRm7hKEt_pZNU_CVR_SfKpEUcG7brwpBQVzRXVJnQKO1hn93i3Gx-rkWLEjWmDWo-zOnZgF64SUH6smmXUPRROusywBkWDipXdJxUObw5MRTqgSGCg8PRpSHM_XMl_QDK1jDj3Iz5IV09ubMhFr4lFJDHFfghl6RA5VLxa_XRAaVVRMlcg7TPsaK668Qe5RNwrPNRYOeUyu0I1JAJMyAa6bXOIwlKYpLvvvyIxguQy7f2gLXePzLHdcb7UBPLNDLZFkK3jRh1pIjLtKS6lPPsOe5DEZkeKjaZJeN1gRVQwwU1qf2KF1nGSbtoXRFLxAipxkGynyVgzDX6nvUhHKNI3_7WQrpZlQhWw4AslebvzLvvTOW8eFvk2Gz5gjKFGhYc63vFlrHACgnW071c6919hd4P9uuiW6nUHXGLXT-V9YuEgXUDryw-tCXHDTIrN1SMeKZKtrCLvIPJK93Pv22MO6vdGHXTsTfKx8S_DMnG1Itgb_FTEeteDwlMgBkKuMPnW12r-g3Abkxz3hfNC5xtIyasfkyZ8S7wIl3wWOEzoXyj1LTGu0D88z26FN7lrhd3L-P0wLJZz4GeNRdk85L8VzLUUh7ohH6PwHaADVPYw7b9kqNDN_b_B0uINxK9VNeu_9bjwldArlpx7KJA4e3HQ3R1gDJNvcEtSu6MHz7R5Qy8-uPd-Z6bzr1_9K2pOobdDZuluBBz8_kung61rBD9VsW8Tvq9fXLtrdjjlnRN443O0CrLnSQslwQC58cF6nj1BXdHXjbFhAi5ASGkPrEuxzP9_uHD2xz_vtPw337bGal1nmRHHXES8HR081Q8YME6JTrELvQqeAtCMOPQreHp12K-uP0gMTqs_bXZMOZOwAu7mKdE3iZa-HS868P-P4cyUy27T3JkLnb7207is5a8rKwdu1LB-2zXVwORzjz_aENsMv51pqg8Zv2e4rotQ819Il2pSEbv8ldHv-589xnv_29Y_urSPc2eM1QzeubhwIe7vrd_0GjoYRv46uQfQpePM6t2iON_ON4miul4if8naTP6gO-DLji2zBBrgcTefpOBuPZ7NBtVyklBVZTifjrGA0Hc_pPMsWsyItUlbMptlALGlKs3Sc0tGIjkazhE5oNppMFpPJbLQf0wUZp3hgQiZSHg8-vQNhbYPL6WiRpgPJcpQ2PAIp9VfSMOkLPNkMzNLrDPOmtGScSmGdvVlxwsnwery94shk0-ap5Xa42hXaGCziqyM8OcLO8Ve0T59bg8bI5QNPhKuaPCn0gdCtB9N-DWuj4_1mG0LwD9IQ4n8BAAD__6NvmFg">