Regtested on x86_64-pc-linux-gnu. OK for trunk? ---------- >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 (); -- 2.46.0