coroutines: Handle initial awaiters with non-void returns [PR 100127].
The way in which a C++20 coroutine is specified discards any value that might be returned from the initial or final await expressions. This ICE was caused by an initial await expression with an await_resume () returning a reference, the function rewrite code was not set up to expect this. Fixed by looking through any indirection present and by explicitly discarding the value, if any, returned by await_resume(). It does not seem useful to make a diagnostic for this, since the user could define a generic awaiter that usefully returns values when used in a different position from the initial (or final) await expressions. Signed-off-by: Iain Sandoe <iain@sandoe.co.uk> PR c++/100127 gcc/cp/ChangeLog: * coroutines.cc (coro_rewrite_function_body): Handle initial await expressions that try to produce a reference value. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr100127.C: New test.
This commit is contained in:
parent
921942a8a1
commit
2466a8d0dd
2 changed files with 72 additions and 1 deletions
|
@ -4211,9 +4211,15 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig,
|
|||
{
|
||||
/* Build a compound expression that sets the
|
||||
initial-await-resume-called variable true and then calls the
|
||||
initial suspend expression await resume. */
|
||||
initial suspend expression await resume.
|
||||
In the case that the user decides to make the initial await
|
||||
await_resume() return a value, we need to discard it and, it is
|
||||
a reference type, look past the indirection. */
|
||||
if (INDIRECT_REF_P (initial_await))
|
||||
initial_await = TREE_OPERAND (initial_await, 0);
|
||||
tree vec = TREE_OPERAND (initial_await, 3);
|
||||
tree aw_r = TREE_VEC_ELT (vec, 2);
|
||||
aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error);
|
||||
tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c,
|
||||
boolean_true_node);
|
||||
aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error);
|
||||
|
|
65
gcc/testsuite/g++.dg/coroutines/pr100127.C
Normal file
65
gcc/testsuite/g++.dg/coroutines/pr100127.C
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifdef __clang__
|
||||
#include <experimental/coroutine>
|
||||
namespace std {
|
||||
using namespace std::experimental;
|
||||
}
|
||||
#else
|
||||
#include <coroutine>
|
||||
#endif
|
||||
#include <optional>
|
||||
|
||||
struct future
|
||||
{
|
||||
using value_type = int;
|
||||
struct promise_type;
|
||||
using handle_type = std::coroutine_handle<promise_type>;
|
||||
|
||||
handle_type _coroutine;
|
||||
|
||||
future(handle_type h) : _coroutine{h} {}
|
||||
|
||||
~future() noexcept{
|
||||
if (_coroutine) {
|
||||
_coroutine.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
value_type get() {
|
||||
auto ptr = _coroutine.promise()._value;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
struct promise_type {
|
||||
std::optional<value_type> _value = std::nullopt;
|
||||
|
||||
future get_return_object() {
|
||||
return future{handle_type::from_promise(*this)};
|
||||
}
|
||||
void return_value(value_type val) {
|
||||
_value = static_cast<value_type &&>(val);
|
||||
}
|
||||
auto initial_suspend() noexcept {
|
||||
class awaiter {
|
||||
std::optional<value_type> & value;
|
||||
public:
|
||||
explicit awaiter(std::optional<value_type> & val) noexcept : value{val} {}
|
||||
bool await_ready() noexcept { return value.has_value(); }
|
||||
void await_suspend(handle_type) noexcept { }
|
||||
value_type & await_resume() noexcept { return *value; }
|
||||
};
|
||||
|
||||
return awaiter{_value};
|
||||
}
|
||||
std::suspend_always final_suspend() noexcept {
|
||||
return {};
|
||||
}
|
||||
//void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
};
|
||||
|
||||
future create_future()
|
||||
{ co_return 2021; }
|
||||
|
||||
int main()
|
||||
{ auto f = create_future(); }
|
Loading…
Add table
Reference in a new issue