]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: coroutines and range for [PR118491]
authorJason Merrill <jason@redhat.com>
Fri, 31 Jan 2025 17:31:43 +0000 (12:31 -0500)
committerJason Merrill <jason@redhat.com>
Mon, 3 Feb 2025 21:55:03 +0000 (16:55 -0500)
The implementation of extended range-for temporaries in r15-3840 confused
coroutines, because await_statement_walker and the like get confused by the
EXPR_STMT into thinking that the whole for-loop is a single expression
statement and try to process it accordingly.  Fixing this seems to be a
simple matter of dropping the EXPR_STMT.

PR c++/116914
PR c++/117231
PR c++/118470
PR c++/118491

gcc/cp/ChangeLog:

* semantics.cc (finish_for_stmt): Don't wrap the result of
pop_stmt_list in EXPR_STMT.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/coro-range-for1.C: New test.

gcc/cp/semantics.cc
gcc/testsuite/g++.dg/coroutines/coro-range-for1.C [new file with mode: 0644]

index ad9864c3a91a1b9527412d518aaf78ad1118cf75..73b49174de43331c25de690634eb55db6d41a0c4 100644 (file)
@@ -1709,7 +1709,6 @@ finish_for_stmt (tree for_stmt)
     {
       tree stmt = pop_stmt_list (FOR_INIT_STMT (for_stmt));
       FOR_INIT_STMT (for_stmt) = NULL_TREE;
-      stmt = build_stmt (EXPR_LOCATION (for_stmt), EXPR_STMT, stmt);
       stmt = maybe_cleanup_point_expr_void (stmt);
       add_stmt (stmt);
     }
diff --git a/gcc/testsuite/g++.dg/coroutines/coro-range-for1.C b/gcc/testsuite/g++.dg/coroutines/coro-range-for1.C
new file mode 100644 (file)
index 0000000..eaf4d19
--- /dev/null
@@ -0,0 +1,38 @@
+// PR c++/118491
+// { dg-do compile { target c++20 } }
+
+#include <coroutine>
+
+struct task {
+  struct promise_type {
+    task get_return_object() { return {}; }
+    std::suspend_always initial_suspend() { return {}; }
+    std::suspend_always final_suspend() noexcept { return {}; }
+    std::suspend_always yield_value(double value) { return {}; }
+    void unhandled_exception() { throw; }
+  };
+};
+
+task do_task() {
+  const int arr[]{1, 2, 3};
+
+  // No ICE if classic loop and not range-based one.
+  // for (auto i = 0; i < 10; ++i) {
+
+  // No ICE if these are moved out of the loop.
+  // auto x = std::suspend_always{};
+  // co_await x;
+
+  for (auto _ : arr) {
+    auto bar = std::suspend_always{};
+    co_await bar;
+
+    // Alternatively:
+    // auto bar = 42.;
+    // co_yield bar;
+
+    // No ICE if r-values:
+    // co_await std::suspend_always{};
+    // co_yield 42.;
+  }
+}