Tested on x86_64-darwin, powerpc64le-linux, OK for trunk? thanks Iain --- 8< --
>From [expr.await]/2 We should not accept co_await, co_yield in unevaluated contexts. It seems that we had not been marking typeid expressions as unevaluated so that is also added here. gcc/cp/ChangeLog: * coroutines.cc (finish_co_await_expr): Do not allow in an unevaluated context. (finish_co_yield_expr): Likewise. * parser.cc (cp_parser_postfix_expression): Mark typeid expressions as unevaluated. gcc/testsuite/ChangeLog: * g++.dg/coroutines/unevaluated.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> --- gcc/cp/coroutines.cc | 12 ++++++++++ gcc/cp/parser.cc | 2 ++ gcc/testsuite/g++.dg/coroutines/unevaluated.C | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 gcc/testsuite/g++.dg/coroutines/unevaluated.C diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 32fd1c65bf7..4d6ec171cd5 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1549,6 +1549,12 @@ finish_co_await_expr (location_t kw, tree expr) if (!expr || error_operand_p (expr)) return error_mark_node; + if (cp_unevaluated_operand) + { + error_at (kw, "%qs cannot be used in an unevaluated context","co_await"); + return error_mark_node; + } + if (!coro_common_keyword_context_valid_p (current_function_decl, kw, "co_await")) return error_mark_node; @@ -1629,6 +1635,12 @@ finish_co_yield_expr (location_t kw, tree expr) if (!expr || error_operand_p (expr)) return error_mark_node; + if (cp_unevaluated_operand) + { + error_at (kw, "%qs cannot be used in an unevaluated context","co_yield"); + return error_mark_node; + } + /* Check the general requirements and simple syntax errors. */ if (!coro_common_keyword_context_valid_p (current_function_decl, kw, "co_yield")) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 86337635f48..15815f9e61b 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -7957,9 +7957,11 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, tree expression; /* Look for an expression. */ + ++cp_unevaluated_operand; expression = cp_parser_expression (parser, & idk); /* Compute its typeid. */ postfix_expression = build_typeid (expression, tf_warning_or_error); + --cp_unevaluated_operand; /* Look for the `)' token. */ close_paren = parens.require_close (parser); } diff --git a/gcc/testsuite/g++.dg/coroutines/unevaluated.C b/gcc/testsuite/g++.dg/coroutines/unevaluated.C new file mode 100644 index 00000000000..f763b208cc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/unevaluated.C @@ -0,0 +1,24 @@ +// { dg-additional-options "-fsyntax-only" } +#include <typeinfo> +#include <coroutine> + +struct Task { + struct promise_type { + promise_type() = default; + Task get_return_object() { return {}; } + std::suspend_never initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() {} + void return_void () {} + std::suspend_never yield_value (int) { return {}; } + }; +}; + +// We do not permit co_await, co_yield outside a function, and so uses in +// noexcept or requirements are covered by that. +Task foo() { + const std::type_info& ti1 = typeid (co_await std::suspend_never{}); // { dg-error {'co_await' cannot be used in an unevaluated context} } + std::size_t x = sizeof (co_yield (19)); // { dg-error {'co_yield' cannot be used in an unevaluated context} } + decltype (co_await std::suspend_never{}) A; // { dg-error {'co_await' cannot be used in an unevaluated context} } + co_return; +} -- 2.39.2 (Apple Git-143)