<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">