<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/59638>59638</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
No thread switched in coroutine example from cppreference.com
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
IGR2014
</td>
</tr>
</table>
<pre>
Consider the following code example from cppreference.com ([link](https://en.cppreference.com/w/cpp/language/coroutines#Example)) with small modification (assert added):
```C++
#include <cassert>
#include <coroutine>
#include <iostream>
#include <stdexcept>
#include <thread>
auto switch_to_new_thread(std::jthread& out)
{
struct awaitable
{
std::jthread* p_out;
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
std::jthread& out = *p_out;
if (out.joinable())
throw std::runtime_error("Output jthread parameter not empty");
out = std::jthread([h] { h.resume(); });
// Potential undefined behavior: accessing potentially destroyed *this
// std::cout << "New thread ID: " << p_out->get_id() << '\n';
std::cout << "New thread ID: " << out.get_id() << '\n'; // this is OK
}
void await_resume() {}
};
return awaitable{&out};
}
struct task
{
struct promise_type
{
task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
task resuming_on_new_thread(std::jthread& out)
{
const auto thread0 = std::this_thread::get_id();
std::cout << "Coroutine started on thread: " << thread0 << '\n';
co_await switch_to_new_thread(out);
// awaiter destroyed here
const auto thread1 = std::this_thread::get_id();
std::cout << "Coroutine resumed on thread: " << thread1 << '\n';
// Oops Clang
assert(thread0 != thread1);
}
int main()
{
std::jthread out;
resuming_on_new_thread(out);
}
```
The results among Clang 15.0, GCC 12.2 and MSVC 19.33 are following ([link](https://godbolt.org/z/sj8zeKeMo)):
![image](https://user-images.githubusercontent.com/10415461/208910337-324e8de9-84dd-4a73-bffc-32131b9497d7.png)
So it looks like Clang is not resuming coroutine on other thread but on the previous. The description of this example on cppreference.com states the following:
> Note that because the coroutine is fully suspended before entering awaiter.await_suspend(), that function is free to transfer the coroutine handle across threads, with no additional synchronization. For example, it can put it inside a callback, scheduled to run on a threadpool when async I/O operation completes. In that case, since the current coroutine may have been resumed and thus executed the awaiter object's destructor, all concurrently as await_suspend() continues its execution on the current thread, await_suspend() should treat *this as destroyed and not access it after the handle was published to other threads.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0V1uP4jgW_jXm5QhEHK4PPFRRxag1mu7VzmpfkWOfEHc5duRLMfSvX9lJIFBQPdrWIESq4uPv3I8_M-fkQSNuyPyZzF9GLPjK2M2X3_5Np9lsVBhx2myNdlKgBV8hlEYpc5T6ANwIBPyL1Y1CKK2pgTeNxRItao4TbmogdEXmz0rqNzJ_IXRVed84kj8RuiN0h3pyu4PQ3ZHQHW8aQneK6UNgB4wvjDXBS42O0Py11UnomtA1HKWvwNVMKaiNkKXkzEujo27mHFoPTAgUUTp_ItMXMu1_F9P2uyX0OX7btzSXmqsgEEi-5S0EyV_vrvZWPViXxnmLrH6w7LzAvzg2j-B9ZZGJ8yK0Dxa8AXeUnld7b_Yaj_tOkK6cF9HJ_Ol7_2oBJvjoe4u_7LwEAHDeBu6BHZn0rFDYaxnKtHK3oE_Q7CNsfiNZGKNavH0UPMX003VEBIs-WA0lUw5J_gxk-XK9991I0e11wTWor_w5R3pfMS0UknxL8leozp59NPu-6SkeQPIXIPTpvhfxI8tYPyb4yXcjdYpO8uWi7-bjK2uOF302aC9r3KO1xqat9FvwTfDQWQINs6xGjxa08YB140-E0lSld-zpjf7oUGywisxfUpSriUUX6t7YLs4PMNsmhH8Zj9pLpiBogaXUKKDAir1LY0n-BIxzdC42fNNLqhMIdN6aE4oYR19J9xB_kMPkxJbkWyCUfsUjdLH48hIVEUr75ZSYMclfD-j3UvR11O9dkvlWx8c9t_4ffTHRP1XVOxS9Beng2-_Xyj8r6WFaUqkOZeM_Q0-6Xrk05vKZ0EUs1YHgBaF9dN3smXt73OuNNbV0uPenBof6b8IYQSDGo7Vkb4rvyP3Hbu4cudfO5yx0zbzX-I4WpJaxgAYt_suQpdQfALVpB-vfRE6J6nyNf9_LU5IJuh0_Yt_iS6P_Rk6v8ts-UoRTUUh92Bv9C2OcG-08pFOhlZ5eT4pYrj10ejEs9Ku6e9Q52374gvPMehRgNJwRh310MeCzTuVmn2r70SnWuTrc0rVe2oZ2MH0qtPhJLLJ_LhZtS_8sFtlPYtE59s00DraR8FyWOupBV-eo0ix60wEPLb4dBlJ7qJnsivPuPLiuMLg6CB8W5k1mzmrPVGrIr_5TtUFS3gGrjT60DkI2n0wJ3cJv2y1kdEKBaQF__PnfLWTrSZ4Ds0OW-TmFPBhRGOUnxh4I3f0gdOe-r37g7_iH6U7rM-ejGZk_yzryyTtAwaEdp1U3OUhfhSK-4UbHI69jptl0ls1ni4zQHZ2u1tk0z5fjnM5wJXA9Xs2EGM_YMh8XZcnHOc3yrFjP1kuxnDT6cMlD-v3TgPSgjHlzoOQbdrGRLtGBPgFw5j2xzIyvEglPCSuCb0sPobH4Lk1wE4ghF-i4lWk2gSnb06pn6UZ_5OjOM4_umtvfMuX8Fb4aj-Ar5qFAzoLDtONin3RQhsgMukmcWERpLAJqjzY603Xv5JblpUxtW_AyaJ5Mj3gWEWIrW6Zd2d0_LhrbUQyMW-NcFxYXgdKNQJvI-2XEYgrcSfPKGi1_pMvBBHbG9lGJW6QHzjREgiY9yHTfAQacKVUw_hZFHK9QBIUimmSDjsFkndomEt9jhRpY1ARfCN19A9Ogbe8i3ERFHt0EvujWUc5c0uyk5l0sg7Wo_cDDmp2gYu8IBaI-D5zYLr4KMavIQxzHcXc_GvuzeunaKRm4jwx0C_GCxI3utKgTMPeBb8eTLNa81AEdSN_rSLWkr6zsZ8L2LoirTFAC4u3H9wwxKrwM7uhFLPWWXsaos9J3Oe4ye2QOmlAo6ao26sMGcJOR2ORina_ZCDfZYpkt6HKRL0bVplis2LpYlVkxpWtasOWKzXi2pHPGaFHmfCQ3dEppRmmW5dNpvphwOpviquDz-VKIWVGQ2RRrJtVEqfc6DpeRdC7gZr5e5KuRYgUql27MlGo8QlqM7H3-MrKbuGdchIMjs6mSzrsLipde4eZrfzp1ByAKkHqQ9k_v1KNg1eZmCKZ51Q2pqKt7jBtr2mLYJQsdobvkwf8CAAD__7wJ3BY">