From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1698) id 0F0163858412; Fri, 17 Dec 2021 16:58:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0F0163858412 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Iain D Sandoe To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-6046] coroutines: Handle initial awaiters with non-void returns [PR 100127]. X-Act-Checkin: gcc X-Git-Author: Iain Sandoe X-Git-Refname: refs/heads/master X-Git-Oldrev: 921942a8a106cb53994c21162922e4934eb3a3e0 X-Git-Newrev: 2466a8d0dd40d05cb4a239d7d4a21bbd9ffab698 Message-Id: <20211217165809.0F0163858412@sourceware.org> Date: Fri, 17 Dec 2021 16:58:09 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Dec 2021 16:58:09 -0000 https://gcc.gnu.org/g:2466a8d0dd40d05cb4a239d7d4a21bbd9ffab698 commit r12-6046-g2466a8d0dd40d05cb4a239d7d4a21bbd9ffab698 Author: Iain Sandoe Date: Sat Oct 2 17:20:08 2021 +0100 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 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. Diff: --- gcc/cp/coroutines.cc | 8 +++- gcc/testsuite/g++.dg/coroutines/pr100127.C | 65 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index bcc91739702..25931c92801 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -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); diff --git a/gcc/testsuite/g++.dg/coroutines/pr100127.C b/gcc/testsuite/g++.dg/coroutines/pr100127.C new file mode 100644 index 00000000000..374cd710077 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr100127.C @@ -0,0 +1,65 @@ +#ifdef __clang__ +#include +namespace std { + using namespace std::experimental; +} +#else +#include +#endif +#include + +struct future +{ + using value_type = int; + struct promise_type; + using handle_type = std::coroutine_handle; + + 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 = std::nullopt; + + future get_return_object() { + return future{handle_type::from_promise(*this)}; + } + void return_value(value_type val) { + _value = static_cast(val); + } + auto initial_suspend() noexcept { + class awaiter { + std::optional & value; + public: + explicit awaiter(std::optional & 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(); }