]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp/coroutines: do not rewrite parameters in unevaluated contexts
authorArsen Arsenović <arsen@aarsen.me>
Thu, 18 Jul 2024 16:16:49 +0000 (18:16 +0200)
committerThomas Koenig <tkoenig@gcc.gnu.org>
Sun, 28 Jul 2024 17:05:57 +0000 (19:05 +0200)
It is possible to use parameters of a parent function of a lambda in
unevaluated contexts without capturing them.  By not capturing them, we
work around the usual mechanism we use to prevent rewriting captured
parameters.  Prevent this by simply skipping rewrites in unevaluated
contexts.  Those won't mind the value not being present anyway.

This prevents an ICE during parameter substitution.  In the testcase
from the PR, the rewriting machinery finds a param in the body of the
coroutine, which it did not previously encounter while processing the
coroutine declaration, and that does not have a DECL_VALUE_EXPR, and
fails.

gcc/cp/ChangeLog:

PR c++/111728
* coroutines.cc (rewrite_param_uses): Skip unevaluated
subexpressions.

gcc/testsuite/ChangeLog:

PR c++/111728
* g++.dg/coroutines/pr111728.C: New test.

gcc/cp/coroutines.cc
gcc/testsuite/g++.dg/coroutines/pr111728.C [new file with mode: 0644]

index e8f028df3adb41e1371deb850c115cbb5ef7cbda..4ddd98673c8d2253427a4e31722a85b9b2d277e8 100644 (file)
@@ -3755,6 +3755,13 @@ rewrite_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d)
       return cp_walk_tree (&t, rewrite_param_uses, d, NULL);
     }
 
+  if (unevaluated_p (TREE_CODE (*stmt)))
+    {
+      /* No odr-uses in unevaluated operands.  */
+      *do_subtree = 0;
+      return NULL_TREE;
+    }
+
   if (TREE_CODE (*stmt) != PARM_DECL)
     return NULL_TREE;
 
diff --git a/gcc/testsuite/g++.dg/coroutines/pr111728.C b/gcc/testsuite/g++.dg/coroutines/pr111728.C
new file mode 100644 (file)
index 0000000..c1fee4b
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// https://gcc.gnu.org/PR111728
+#include <coroutine>
+struct promise;
+struct coroutine : std::coroutine_handle<promise>
+{
+    using promise_type = ::promise;
+    bool await_ready() { return false; }
+    void await_suspend(coroutine_handle h) {}
+    int await_resume() { return {} ;}
+};
+struct promise
+{
+    coroutine get_return_object() { return {coroutine::from_promise(*this)}; }
+    std::suspend_always initial_suspend() noexcept { return {}; }
+    std::suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception() {}
+};
+coroutine
+write_fields() {
+  int static_buffer[10];
+  co_await [](auto)
+  -> coroutine
+  {
+    if (sizeof(static_buffer));
+      co_return;
+  }(0);
+}