This is a partial fix for PR115906. Per [expr.await] 2s3, "An await-expression shall not appear in a default argument ([dcl.fct.default])". This patch introduces the diagnostic in that case, and in the case of a co_yield (as co_yield is defined in terms of co_await, so prerequisites of co_await hold).
PR c++/115906 - [coroutines] missing diagnostic and ICE when co_await used as default argument in function declaration gcc/cp/ChangeLog: PR c++/115906 * parser.cc (cp_parser_unary_expression): Reject await expressions if use of local variables is currently forbidden. (cp_parser_yield_expression): Reject yield expressions if use of local variables is currently forbidden. gcc/testsuite/ChangeLog: PR c++/115906 * g++.dg/coroutines/pr115906-yield.C: New test. * g++.dg/coroutines/pr115906.C: New test. * g++.dg/coroutines/co-await-syntax-02-outside-fn.C: Don't rely on default arguments. * g++.dg/coroutines/co-yield-syntax-01-outside-fn.C: Ditto. --- gcc/cp/parser.cc | 17 ++++++++++ .../co-await-syntax-02-outside-fn.C | 2 +- .../co-yield-syntax-01-outside-fn.C | 3 +- .../g++.dg/coroutines/pr115906-yield.C | 29 +++++++++++++++++ gcc/testsuite/g++.dg/coroutines/pr115906.C | 32 +++++++++++++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/pr115906-yield.C create mode 100644 gcc/testsuite/g++.dg/coroutines/pr115906.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index f79736c17ac6..5cba35eff1c1 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -9242,6 +9242,14 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, if (expr == error_mark_node) return error_mark_node; + /* ... but, we cannot use co_await in default arguments. */ + if (parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) + { + error_at (kw_loc, + "%<co_await%> cannot be used in default arguments"); + return error_mark_node; + } + /* Handle [expr.await]. */ return cp_expr (finish_co_await_expr (kw_loc, expr)); } @@ -29646,6 +29654,15 @@ cp_parser_yield_expression (cp_parser* parser) else expr = cp_parser_assignment_expression (parser); + /* Similar to co_await, we cannot use co_yield in default arguments (as + co_awaits underlie co_yield). */ + if (parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) + { + error_at (kw_loc, + "%<co_yield%> cannot be used in default arguments"); + return error_mark_node; + } + if (expr == error_mark_node) return expr; diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C index 4ce5c2e04a0a..132128f27192 100644 --- a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C @@ -2,4 +2,4 @@ #include "coro.h" -auto f (int x = co_await coro::suspend_always{}); // { dg-error {'co_await' cannot be used outside a function} } +auto x = co_await coro::suspend_always{}; // { dg-error {'co_await' cannot be used outside a function} } diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C index 30db0e963b09..51c304625278 100644 --- a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C @@ -2,5 +2,4 @@ #include "coro.h" -auto f (int x = co_yield 5); // { dg-error {'co_yield' cannot be used outside a function} } - +auto x = co_yield 5; // { dg-error {'co_yield' cannot be used outside a function} } diff --git a/gcc/testsuite/g++.dg/coroutines/pr115906-yield.C b/gcc/testsuite/g++.dg/coroutines/pr115906-yield.C new file mode 100644 index 000000000000..f8b6ded5001c --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr115906-yield.C @@ -0,0 +1,29 @@ +#include <coroutine> + +struct Promise; + +struct Handle : std::coroutine_handle<Promise> { + using promise_type = Promise; +}; + +struct Promise { + Handle get_return_object() noexcept { + return {Handle::from_promise(*this)}; + } + std::suspend_never initial_suspend() const noexcept { return {}; } + std::suspend_never final_suspend() const noexcept { return {}; } + void return_void() const noexcept {} + void unhandled_exception() const noexcept {} + std::suspend_never yield_value(int) { return {}; } +}; + +Handle Coro() { + [] (int x = co_yield 1){}; // { dg-error ".co_yield. cannot be used in default arguments" } + co_return; +} + +int main() { + Coro(); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr115906.C b/gcc/testsuite/g++.dg/coroutines/pr115906.C new file mode 100644 index 000000000000..28f408fbaddd --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr115906.C @@ -0,0 +1,32 @@ +#include <coroutine> + +struct Promise; + +struct Handle : std::coroutine_handle<Promise> { + using promise_type = Promise; +}; + +struct Promise { + Handle get_return_object() noexcept { + return {Handle::from_promise(*this)}; + } + std::suspend_never initial_suspend() const noexcept { return {}; } + std::suspend_never final_suspend() const noexcept { return {}; } + void return_void() const noexcept {} + void unhandled_exception() const noexcept {} +}; + +Handle Coro() { + struct Awaiter : std::suspend_never { + int await_resume() { return 0; } + }; + + [] (int x = co_await Awaiter{}){}; // { dg-error ".co_await. cannot be used in default arguments" } + co_return; +} + +int main() { + Coro(); + + return 0; +} -- 2.45.2