https://gcc.gnu.org/g:77e0c0df0907657a7d72bbba9e6329d93ec65edb

commit r15-9207-g77e0c0df0907657a7d72bbba9e6329d93ec65edb
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Apr 4 20:51:50 2025 +0200

    cfgrtl: Remove REG_EH_REGION notes from tail calls [PR119613]
    
    In PR119491 r15-9154 I've allowed some useless EH regions for musttail
    calls (if there are no non-debug/clobber stmts before resx which resumes
    external throwing).
    Now, for -O1+ (but not -O0/-Og) there is a cleanup_eh pass after it
    which should optimize that way.
    The following testcase ICEs at -O0 though, the cleanup_eh in that case
    is before the musttail pass and dunno why it didn't actually optimize
    it away.
    
    The following patch catches that during expansion and just removes the note,
    which causes EH cleanups to do the rest.  A tail call, even when it throws,
    will not throw while the musttail caller's frame is still on the stack,
    will throw after that and so REG_EH_REGION for it is irrelevant (like it
    would be never set before the r15-9154 changes).
    
    2025-04-04  Jakub Jelinek  <ja...@redhat.com>
    
            PR middle-end/119613
            * cfgrtl.cc (purge_dead_edges): Remove REG_EH_REGION notes from
            tail calls.
    
            * g++.dg/opt/pr119613.C: New test.

Diff:
---
 gcc/cfgrtl.cc                       | 10 ++++++++++
 gcc/testsuite/g++.dg/opt/pr119613.C | 22 ++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/gcc/cfgrtl.cc b/gcc/cfgrtl.cc
index d206c0d53a72..310028f1719b 100644
--- a/gcc/cfgrtl.cc
+++ b/gcc/cfgrtl.cc
@@ -3213,6 +3213,16 @@ purge_dead_edges (basic_block bb)
              && ! may_trap_p (XEXP (eqnote, 0))))
        remove_note (insn, note);
     }
+  /* A tail call cannot trap either.  The tailc/musttail pass could have
+     allowed a tail call if it could throw internally, but perform no
+     actual statements and then caused the exception to be thrown externally
+     in the hope that it is cleaned up later.  If it is not, just
+     remove REG_EH_REGION note.  While the call maybe can throw, the
+     current function's frame will not be there anymore when it does.  */
+   if (CALL_P (insn)
+       && SIBLING_CALL_P (insn)
+       && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
+     remove_note (insn, note);
 
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
   for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
diff --git a/gcc/testsuite/g++.dg/opt/pr119613.C 
b/gcc/testsuite/g++.dg/opt/pr119613.C
new file mode 100644
index 000000000000..432a30cdcdb0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr119613.C
@@ -0,0 +1,22 @@
+// PR middle-end/119613
+// { dg-do compile { target { musttail && { c || c++11 } } } }
+// { dg-options "-O0" }
+
+struct S { S () {} };
+char *foo (S);
+void bar (int);
+
+[[gnu::always_inline]] inline char *
+baz (S x)
+{
+  unsigned i;
+  &i;
+  bar (i);
+  [[gnu::musttail]] return foo (x);
+}
+
+char *
+qux (S)
+{
+  [[gnu::musttail]] return baz (S {});
+}

Reply via email to