From: Iain Sandoe Date: Wed, 3 Jun 2020 08:03:22 +0000 (+0100) Subject: coroutines: Allow parameter packs in co_await/yield expressions [PR95345] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cf7eac5805e714c7e71b699329e2c4f4a88addc1;p=gcc.git coroutines: Allow parameter packs in co_await/yield expressions [PR95345] This corrects a pasto, where I copied the constraint on bare parameter packs from the co_return to co_yield/await without properly reviewing it. gcc/cp/ChangeLog: PR c++/95345 * coroutines.cc (finish_co_await_expr): Revise to allow for parameter packs. (finish_co_yield_expr): Likewise. gcc/testsuite/ChangeLog: PR c++/95345 * g++.dg/coroutines/pr95345.C: New test. --- diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index e6896257932..58102f51797 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -851,19 +851,18 @@ finish_co_await_expr (location_t kw, tree expr) /* The current function has now become a coroutine, if it wasn't already. */ DECL_COROUTINE_P (current_function_decl) = 1; - if (processing_template_decl) - { - current_function_returns_value = 1; - - if (check_for_bare_parameter_packs (expr)) - return error_mark_node; + /* This function will appear to have no return statement, even if it + is declared to return non-void (most likely). This is correct - we + synthesize the return for the ramp in the compiler. So suppress any + extraneous warnings during substitution. */ + TREE_NO_WARNING (current_function_decl) = true; - /* If we don't know the promise type, we can't proceed. */ - tree functype = TREE_TYPE (current_function_decl); - if (dependent_type_p (functype) || type_dependent_expression_p (expr)) - return build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr, - NULL_TREE, NULL_TREE, NULL_TREE, integer_zero_node); - } + /* If we don't know the promise type, we can't proceed, build the + co_await with the expression unchanged. */ + tree functype = TREE_TYPE (current_function_decl); + if (dependent_type_p (functype) || type_dependent_expression_p (expr)) + return build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr, + NULL_TREE, NULL_TREE, NULL_TREE, integer_zero_node); /* We must be able to look up the "await_transform" method in the scope of the promise type, and obtain its return type. */ @@ -928,19 +927,17 @@ finish_co_yield_expr (location_t kw, tree expr) /* The current function has now become a coroutine, if it wasn't already. */ DECL_COROUTINE_P (current_function_decl) = 1; - if (processing_template_decl) - { - current_function_returns_value = 1; - - if (check_for_bare_parameter_packs (expr)) - return error_mark_node; + /* This function will appear to have no return statement, even if it + is declared to return non-void (most likely). This is correct - we + synthesize the return for the ramp in the compiler. So suppress any + extraneous warnings during substitution. */ + TREE_NO_WARNING (current_function_decl) = true; - tree functype = TREE_TYPE (current_function_decl); - /* If we don't know the promise type, we can't proceed. */ - if (dependent_type_p (functype) || type_dependent_expression_p (expr)) - return build2_loc (kw, CO_YIELD_EXPR, unknown_type_node, expr, - NULL_TREE); - } + /* If we don't know the promise type, we can't proceed, build the + co_await with the expression unchanged. */ + tree functype = TREE_TYPE (current_function_decl); + if (dependent_type_p (functype) || type_dependent_expression_p (expr)) + return build2_loc (kw, CO_YIELD_EXPR, unknown_type_node, expr, NULL_TREE); if (!coro_promise_type_found_p (current_function_decl, kw)) /* We must be able to look up the "yield_value" method in the scope of diff --git a/gcc/testsuite/g++.dg/coroutines/pr95345.C b/gcc/testsuite/g++.dg/coroutines/pr95345.C new file mode 100644 index 00000000000..90e946d91c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr95345.C @@ -0,0 +1,32 @@ +#if __has_include () +#include +using namespace std; +#elif defined (__clang__) && __has_include () +#include +using namespace std::experimental; +#endif + +struct dummy_coro +{ + using promise_type = dummy_coro; + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<>) { } + void await_resume() { } + dummy_coro get_return_object() { return {}; } + dummy_coro initial_suspend() { return {}; } + dummy_coro final_suspend() { return {}; } + void return_void() { } + void unhandled_exception() { } +}; + +template +dummy_coro +foo() +{ + ((co_await [](int){ return std::suspend_never{}; }(I)), ...); + co_return; +} + +void bar() { + foo<1>(); +}