mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-21 22:51:06 +08:00
coroutines : Convert await_ready () expressions to bool [PR99047].
The awaiter.await_ready() should be converted per [expr.await]/3 (3.6) await-ready is the expression e.await_ready(), contextually converted to bool. gcc/cp/ChangeLog: PR c++/99047 * coroutines.cc (expand_one_await_expression): If the await_ready() expression is not a boolean then convert it as required. gcc/testsuite/ChangeLog: PR c++/99047 * g++.dg/coroutines/pr99047.C: New test.
This commit is contained in:
parent
020b286c76
commit
541840b891
@ -1586,7 +1586,13 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
|
||||
|
||||
/* Use the await_ready() call to test if we need to suspend. */
|
||||
tree ready_cond = TREE_VEC_ELT (awaiter_calls, 0); /* await_ready(). */
|
||||
ready_cond = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, ready_cond);
|
||||
/* Convert to bool, if necessary. */
|
||||
if (TREE_CODE (TREE_TYPE (ready_cond)) != BOOLEAN_TYPE)
|
||||
ready_cond = cp_convert (boolean_type_node, ready_cond,
|
||||
tf_warning_or_error);
|
||||
/* Be aggressive in folding here, since there are a significant number of
|
||||
cases where the ready condition is constant. */
|
||||
ready_cond = invert_truthvalue_loc (loc, ready_cond);
|
||||
ready_cond
|
||||
= build1_loc (loc, CLEANUP_POINT_EXPR, boolean_type_node, ready_cond);
|
||||
|
||||
|
83
gcc/testsuite/g++.dg/coroutines/pr99047.C
Normal file
83
gcc/testsuite/g++.dg/coroutines/pr99047.C
Normal file
@ -0,0 +1,83 @@
|
||||
#include <optional>
|
||||
#include <coroutine>
|
||||
|
||||
template <typename T>
|
||||
struct [[nodiscard]] task {
|
||||
struct promise_type {
|
||||
std::suspend_always initial_suspend() {
|
||||
return {};
|
||||
}
|
||||
auto final_suspend() noexcept {
|
||||
struct awaiter {
|
||||
#if 1
|
||||
std::false_type await_ready() noexcept {
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept {
|
||||
return next;
|
||||
}
|
||||
void await_resume() noexcept {
|
||||
}
|
||||
std::coroutine_handle<> next;
|
||||
};
|
||||
return awaiter{next};
|
||||
}
|
||||
|
||||
void unhandled_exception() noexcept {
|
||||
std::terminate();
|
||||
}
|
||||
auto get_return_object() {
|
||||
return task(this);
|
||||
}
|
||||
auto coro() {
|
||||
return std::coroutine_handle<promise_type>::from_promise(*this);
|
||||
}
|
||||
void return_value(T val) {
|
||||
result.emplace(std::move(val));
|
||||
}
|
||||
|
||||
std::coroutine_handle<> next;
|
||||
std::optional<T> result;
|
||||
};
|
||||
|
||||
task(task&& source) : p(std::exchange(source.p, nullptr)) {}
|
||||
explicit task(promise_type* p) : p(p) {}
|
||||
~task() {
|
||||
if (p)
|
||||
p->coro().destroy();
|
||||
}
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return p->coro().done();
|
||||
}
|
||||
std::coroutine_handle<> await_suspend(std::coroutine_handle<> next) noexcept {
|
||||
p->next = next;
|
||||
return p->coro();
|
||||
}
|
||||
const T& await_resume() const& noexcept {
|
||||
return *p->result;
|
||||
}
|
||||
|
||||
promise_type* p;
|
||||
};
|
||||
|
||||
task<int> five() {
|
||||
co_return 5;
|
||||
}
|
||||
|
||||
task<int> six() {
|
||||
co_return co_await five() + 1;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
auto task = six();
|
||||
task.p->next = std::noop_coroutine();
|
||||
task.p->coro().resume();
|
||||
return *task.p->result;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user