On 6/9/25 4:06 PM, Iain Sandoe wrote:
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.

This seems to be https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68604

But only some typeid expressions are unevaluated; the
https://eel.is/c++draft/expr#typeid-4 case (polymorphic glvalue) is not.

I don't understand how we're supposed to distinguish these cases before parsing; it's weird to say that it's unevaluated or not based on the value category.

Perhaps we parse it as an unevaluated operand and if it turns out to be evaluated, either rewind the parse and start over or go through the expression and odr-use everything? Do you know what Clang does?

In any case let's not mess with it in this patch.

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;
+}

Reply via email to