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:
Iain Sandoe 2021-03-14 14:42:52 +00:00
parent 020b286c76
commit 541840b891
2 changed files with 90 additions and 1 deletions

View File

@ -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);

View 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;
}