On 8/28/24 3:18 PM, Arsen Arsenović wrote:
Regtested on x86_64-pc-linux-gnu. OK for trunk?
OK.
---------- >8 ----------
In some scenarios, it is possible for the CFG cleanup to cause one of
the labels mentioned in CO_YIELD, which coro-early-expand-ifns intends
to remove, to become part of some statement. As a result, when that
label is removed, the statement it became part of becomes invalid,
crashing the compiler.
There doesn't appear to be a reason to remove the labels (anymore, at
least), so let's not do that.
PR c++/105104
gcc/ChangeLog:
* coroutine-passes.cc (execute_early_expand_coro_ifns): Don't
remove any labels.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/torture/pr105104.C: New test.
---
gcc/coroutine-passes.cc | 26 ------------
.../g++.dg/coroutines/torture/pr105104.C | 40 +++++++++++++++++++
2 files changed, 40 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/pr105104.C
diff --git a/gcc/coroutine-passes.cc b/gcc/coroutine-passes.cc
index 9124ecae5916..0f8e24f8d551 100644
--- a/gcc/coroutine-passes.cc
+++ b/gcc/coroutine-passes.cc
@@ -294,9 +294,6 @@ execute_early_expand_coro_ifns (void)
/* Some of the possible YIELD points will hopefully have been removed by
earlier optimisations; record the ones that are still present. */
hash_map<int_hash<HOST_WIDE_INT, -1, -2>, tree> destinations;
- /* Labels we added to carry the CFG changes, we need to remove these to
- avoid confusing EH. */
- hash_set<tree> to_remove;
/* List of dispatch points to update. */
auto_vec<gimple_stmt_iterator, 16> actor_worklist;
basic_block bb;
@@ -384,8 +381,6 @@ execute_early_expand_coro_ifns (void)
}
else
dst_dest = dst_tgt;
- to_remove.add (res_tgt);
- to_remove.add (dst_tgt);
/* lose the co_yield. */
gsi_remove (&gsi, true);
stmt = gsi_stmt (gsi); /* next. */
@@ -473,27 +468,6 @@ execute_early_expand_coro_ifns (void)
}
}
- /* Remove the labels we inserted to map our hidden CFG, this
- avoids confusing block merges when there are also EH labels. */
- FOR_EACH_BB_FN (bb, cfun)
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
- {
- gimple *stmt = gsi_stmt (gsi);
- if (glabel *glab = dyn_cast<glabel *> (stmt))
- {
- tree rem = gimple_label_label (glab);
- if (to_remove.contains (rem))
- {
- gsi_remove (&gsi, true);
- to_remove.remove (rem);
- continue; /* We already moved to the next insn. */
- }
- }
- else
- break;
- gsi_next (&gsi);
- }
-
/* Changed the CFG. */
todoflags |= TODO_cleanup_cfg;
return todoflags;
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C
b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C
new file mode 100644
index 000000000000..fcc783e3066d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C
@@ -0,0 +1,40 @@
+// https://gcc.gnu.org/PR105104
+// { dg-additional-options "-O" }
+
+#include <coroutine>
+
+// ICE during GIMPLE pass: coro-early-expand-ifs. final_awaiter::await_resume
is
+// non-void, and optimizations are enabled.
+
+struct return_object
+{
+ struct promise_type
+ {
+ static constexpr std::suspend_always initial_suspend () noexcept
+ {
+ return {};
+ }
+
+ struct final_awaiter
+ {
+ static constexpr bool await_ready () noexcept { return false; }
+ static constexpr void await_suspend (std::coroutine_handle<>) noexcept {}
+ static constexpr int await_resume () noexcept { return {}; }
+ };
+ static constexpr final_awaiter final_suspend () noexcept { return {}; }
+
+ static void unhandled_exception () { throw; }
+
+ return_object get_return_object () { return {}; }
+
+ static constexpr void return_void () noexcept {}
+ };
+};
+
+return_object
+coroutine ()
+{
+ co_return;
+}
+
+return_object f = coroutine ();