Date: Fri, 20 Dec 2024 17:44:29 +0800 (CST)
Hi,
As the title explains, when coroutine state should destruct is not clear. And there have been some disagreements between main stream compilers.
FYI: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118074
Consider the following code:
```
#include <cstdio>
#include <utility>
#include <coroutine>
template<class T>
struct CRCoro { // Curiously Recurring Coroutine
struct RValueWrapper {
T* p;
operator T&&() const noexcept { return std::move(*p); }
};
using promise_type = T;
T& getDerived() noexcept { return *static_cast<T*>(this); }
auto get_return_object() noexcept { return RValueWrapper(&getDerived()); }
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(T&& x) noexcept { getDerived() = std::move(x); }
void unhandled_exception() {}
};
struct A : public CRCoro<A> {
int a;
};
A func() {
A aa{};
aa.a = 5;
co_return std::move(aa);
}
int main() {
printf("%d\n", func().a);
return 0;
}
```
9.5.4 [dcl.fct.def.coroutine] paragraph 11 reads:
> The coroutine state is destroyed when control flows off the end of the coroutine
> or the destroy member function ([coroutine.handle.resumption]) of a coroutine handle ([coroutine.handle]) that refers to the coroutine is invoked.
If I am not misunderstanding, 'flows off the end of the coroutine' occurs before 'returning to the caller'. It is unclear whether return value initialization happens before or after destruction. And the wording 'flows off the end of the coroutine' seems too strict. I suggest the following change:
> The coroutine state is destroyed when returns from the await_resume() of final_suspend
> or the destroy member function ([coroutine.handle.resumption]) of a coroutine handle ([coroutine.handle]) that refers to the coroutine is invoked.
Note that initialization will be done before destruction of coroutine state.
Best,
Weibo
As the title explains, when coroutine state should destruct is not clear. And there have been some disagreements between main stream compilers.
FYI: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118074
Consider the following code:
```
#include <cstdio>
#include <utility>
#include <coroutine>
template<class T>
struct CRCoro { // Curiously Recurring Coroutine
struct RValueWrapper {
T* p;
operator T&&() const noexcept { return std::move(*p); }
};
using promise_type = T;
T& getDerived() noexcept { return *static_cast<T*>(this); }
auto get_return_object() noexcept { return RValueWrapper(&getDerived()); }
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(T&& x) noexcept { getDerived() = std::move(x); }
void unhandled_exception() {}
};
struct A : public CRCoro<A> {
int a;
};
A func() {
A aa{};
aa.a = 5;
co_return std::move(aa);
}
int main() {
printf("%d\n", func().a);
return 0;
}
```
9.5.4 [dcl.fct.def.coroutine] paragraph 11 reads:
> The coroutine state is destroyed when control flows off the end of the coroutine
> or the destroy member function ([coroutine.handle.resumption]) of a coroutine handle ([coroutine.handle]) that refers to the coroutine is invoked.
If I am not misunderstanding, 'flows off the end of the coroutine' occurs before 'returning to the caller'. It is unclear whether return value initialization happens before or after destruction. And the wording 'flows off the end of the coroutine' seems too strict. I suggest the following change:
> The coroutine state is destroyed when returns from the await_resume() of final_suspend
> or the destroy member function ([coroutine.handle.resumption]) of a coroutine handle ([coroutine.handle]) that refers to the coroutine is invoked.
Note that initialization will be done before destruction of coroutine state.
Best,
Received on 2024-12-20 09:44:36