Hi,

PR 122856 shows that when looking at self recursive calls with
self-feeding jump functions, we did consider pass-through functions
but not ancestor functions with zero offsets.  This then leads to the
fact that constants which were collected from IPA-CP lattices were not
among those collected from available edges, triggering a verification
assert.

This patch fixes that by also detecting self-feeding ancestor jump
functions.

Bootstrapped and tested on x86_64-linux.  OK for master and affected
release branches?

Thanks,

Martin


gcc/ChangeLog:

2026-02-06  Martin Jambor  <[email protected]>

        PR ipa/122856
        * ipa-cp.cc (self_recursive_pass_through_p): Test jump function type 
first.
        (self_recursive_ancestor_p): New function.
        (find_scalar_values_for_callers_subset): Test also for self-recursive
        ancestor jump functions.
        (push_agg_values_for_index_from_edge): Likewise.

gcc/testsuite/ChangeLog:

2026-02-06  Martin Jambor  <[email protected]>

        PR ipa/122856
        * g++.dg/ipa/pr122856.C: New test.
---
 gcc/ipa-cp.cc                       | 28 +++++++++++++++++++++++++---
 gcc/testsuite/g++.dg/ipa/pr122856.C | 26 ++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ipa/pr122856.C

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 339d306251c..5b7cb3cdb43 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -5259,9 +5259,9 @@ self_recursive_pass_through_p (cgraph_edge *cs, 
ipa_jump_func *jfunc, int i,
                               bool simple = true)
 {
   enum availability availability;
-  if (cs->caller == cs->callee->function_symbol (&availability)
+  if (jfunc->type == IPA_JF_PASS_THROUGH
+      && cs->caller == cs->callee->function_symbol (&availability)
       && availability > AVAIL_INTERPOSABLE
-      && jfunc->type == IPA_JF_PASS_THROUGH
       && (!simple || ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
       && ipa_get_jf_pass_through_formal_id (jfunc) == i
       && ipa_node_params_sum->get (cs->caller)
@@ -5270,6 +5270,25 @@ self_recursive_pass_through_p (cgraph_edge *cs, 
ipa_jump_func *jfunc, int i,
   return false;
 }
 
+/* Return true if JFUNC, which describes the i-th parameter of call CS, is an
+   ancestor function with zero offset to itself when the cgraph_node involved
+   is not an IPA-CP clone.  */
+
+static bool
+self_recursive_ancestor_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i)
+{
+  enum availability availability;
+  if (jfunc->type == IPA_JF_ANCESTOR
+      && cs->caller == cs->callee->function_symbol (&availability)
+      && availability > AVAIL_INTERPOSABLE
+      && ipa_get_jf_ancestor_offset (jfunc) == 0
+      && ipa_get_jf_ancestor_formal_id (jfunc) == i
+      && ipa_node_params_sum->get (cs->caller)
+      && !ipa_node_params_sum->get (cs->caller)->ipcp_orig_node)
+    return true;
+  return false;
+}
+
 /* Return true if JFUNC, which describes a part of an aggregate represented or
    pointed to by the i-th parameter of call CS, is a pass-through function to
    itself when the cgraph_node involved is not an IPA-CP clone..  When
@@ -5361,6 +5380,8 @@ find_scalar_values_for_callers_subset (vec<tree> 
&known_csts,
                                op_type);
              t = ipacp_value_safe_for_type (type, t);
            }
+         else if (self_recursive_ancestor_p (cs, jump_func, i))
+           continue;
          else
            t = ipa_value_from_jfunc (ipa_node_params_sum->get (cs->caller),
                                      jump_func, type);
@@ -5515,7 +5536,8 @@ push_agg_values_for_index_from_edge (struct cgraph_edge 
*cs, int index,
              && !src_plats->aggs_bottom
              && (agg_jf_preserved || !src_plats->aggs_by_ref))
            {
-             if (interim && self_recursive_pass_through_p (cs, jfunc, index))
+             if (interim && (self_recursive_pass_through_p (cs, jfunc, index)
+                             || self_recursive_ancestor_p (cs, jfunc, index)))
                {
                  interim->push_adjusted_values (src_idx, index, unit_delta,
                                                 res);
diff --git a/gcc/testsuite/g++.dg/ipa/pr122856.C 
b/gcc/testsuite/g++.dg/ipa/pr122856.C
new file mode 100644
index 00000000000..b634e628009
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr122856.C
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=gnu++11" } */
+
+template <typename T>
+class Base {
+public:
+    virtual int get();
+    virtual ~Base() = default;
+};
+
+template <typename T>
+class Derived : public Base<T> {
+public:
+    int get() override { return Base<T>::get(); }
+};
+
+template <typename T>
+int Base<T>::get() {
+
+    return static_cast<Derived<int>*>(this)->get();
+}
+
+int main() {
+    Derived<int> d;
+    return d.get();
+}
-- 
2.52.0

Reply via email to