]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++, coroutines: Handle unevaluated contexts.
authorIain Sandoe <iain@sandoe.co.uk>
Sun, 8 Jun 2025 13:28:01 +0000 (14:28 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Tue, 17 Jun 2025 05:11:40 +0000 (08:11 +0300)
From [expr.await]/2
We should not accept co_await, co_yield in unevaluated contexts.

Currently (see PR68604) we do not mark typeid expressions as unevaluated
since the standard rules mean that this depends on the value type.

gcc/cp/ChangeLog:

* coroutines.cc (finish_co_await_expr): Do not allow in an
unevaluated context.
(finish_co_yield_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/unevaluated.C: New test.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
gcc/cp/coroutines.cc
gcc/testsuite/g++.dg/coroutines/unevaluated.C [new file with mode: 0644]

index 17d0ee997903b3a003c6b2ac7c07c843cb0aac28..276c6c40c78555e0306b1fee01b5ab9e70a6b9d4 100644 (file)
@@ -1467,6 +1467,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;
@@ -1547,6 +1553,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/testsuite/g++.dg/coroutines/unevaluated.C b/gcc/testsuite/g++.dg/coroutines/unevaluated.C
new file mode 100644 (file)
index 0000000..63dae38
--- /dev/null
@@ -0,0 +1,25 @@
+// { 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()  {
+    /* This one will currently fail - see PR68604.  */
+    const std::type_info& ti1 = typeid (co_await std::suspend_never{}); // { dg-error {'co_await' cannot be used in an unevaluated context} "" { xfail *-*-* } }
+    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;
+}