https://gcc.gnu.org/g:5a275b5bebdf7746af590fa57378cd48cb8e679a
commit r14-11731-g5a275b5bebdf7746af590fa57378cd48cb8e679a Author: Arsen Arsenović <ar...@aarsen.me> Date: Fri Aug 16 19:07:01 2024 +0200 c++: don't remove labels during coro-early-expand-ifns [PR105104] 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. (cherry picked from commit d9c54e9a036189e8961ec17e118fccf794d7bfab) Diff: --- gcc/coroutine-passes.cc | 26 -------------- gcc/testsuite/g++.dg/coroutines/torture/pr105104.C | 40 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/gcc/coroutine-passes.cc b/gcc/coroutine-passes.cc index c0d6eca7c070..b962d7598c43 100644 --- a/gcc/coroutine-passes.cc +++ b/gcc/coroutine-passes.cc @@ -293,9 +293,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; @@ -374,8 +371,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. */ @@ -463,27 +458,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 ();