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
