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 <[email protected]>
---
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)