> > 2015-03-01 Martin Liska <mli...@suse.cz> > Jan Hubicka <hubi...@ucw.cz> > > PR ipa/65263 > * cgraph.c (cgraph_node::has_thunk_p): New function. > * cgraph.h (cgraph_node::has_thunk_p: Likewise. > * ipa-icf.c (redirect_all_callers): Do not redirect thunks. > (sem_function::merge): Assert is changed.
OK, thanks! (assuming it fixes the original ICE reported) Honza > > gcc/testsuite/ChangeLog: > > 2015-03-01 Martin Liska <mli...@suse.cz> > Jan Hubicka <hubi...@ucw.cz> > > * g++.dg/ipa/pr65263.C: New test. > --- > gcc/cgraph.c | 12 ++++++++++ > gcc/cgraph.h | 3 +++ > gcc/ipa-icf.c | 27 +++++++++++++++++---- > gcc/testsuite/g++.dg/ipa/pr65263.C | 49 > ++++++++++++++++++++++++++++++++++++++ > 4 files changed, 86 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/ipa/pr65263.C > > diff --git a/gcc/cgraph.c b/gcc/cgraph.c > index 5555439..9bae35e 100644 > --- a/gcc/cgraph.c > +++ b/gcc/cgraph.c > @@ -3325,4 +3325,16 @@ cgraph_node::call_for_symbol_and_aliases_1 (bool > (*callback) (cgraph_node *, > } > return false; > } > + > +/* Return true if NODE has thunk. */ > + > +bool > +cgraph_node::has_thunk_p (cgraph_node *node, void *) > +{ > + for (cgraph_edge *e = node->callers; e; e = e->next_caller) > + if (e->caller->thunk.thunk_p) > + return true; > + return false; > +} > + > #include "gt-cgraph.h" > diff --git a/gcc/cgraph.h b/gcc/cgraph.h > index ff437cf..82519fa 100644 > --- a/gcc/cgraph.h > +++ b/gcc/cgraph.h > @@ -1204,6 +1204,9 @@ public: > with (not necessarily cgraph_node (DECL). */ > static cgraph_node *create_alias (tree alias, tree target); > > + /* Return true if NODE has thunk. */ > + static bool has_thunk_p (cgraph_node *node, void *); > + > cgraph_edge *callees; > cgraph_edge *callers; > /* List of edges representing indirect calls with a yet undetermined > diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c > index 31fcbec..155b96b 100644 > --- a/gcc/ipa-icf.c > +++ b/gcc/ipa-icf.c > @@ -697,12 +697,22 @@ redirect_all_callers (cgraph_node *n, cgraph_node *to) > { > int nredirected = 0; > ipa_ref *ref; > + cgraph_edge *e = n->callers; > > - while (n->callers) > + while (e) > { > - cgraph_edge *e = n->callers; > - e->redirect_callee (to); > - nredirected++; > + /* Redirecting thunks to interposable symbols or symbols in other > sections > + may not be supported by target output code. Play safe for now and > + punt on redirection. */ > + if (!e->caller->thunk.thunk_p) > + { > + struct cgraph_edge *nexte = e->next_caller; > + e->redirect_callee (to); > + e = nexte; > + nredirected++; > + } > + else > + e = e->next_callee; > } > for (unsigned i = 0; n->iterate_direct_aliases (i, ref);) > { > @@ -717,6 +727,8 @@ redirect_all_callers (cgraph_node *n, cgraph_node *to) > { > nredirected += redirect_all_callers (n_alias, to); > if (n_alias->can_remove_if_no_direct_calls_p () > + && !n_alias->call_for_symbol_and_aliases > (cgraph_node::has_thunk_p, > + NULL, true) > && !n_alias->has_aliases_p ()) > n_alias->remove (); > } > @@ -907,6 +919,8 @@ sem_function::merge (sem_item *alias_item) > return false; > } > if (!create_wrapper > + && !alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p, > + NULL, true) > && !alias->can_remove_if_no_direct_calls_p ()) > { > if (dump_file) > @@ -975,7 +989,10 @@ sem_function::merge (sem_item *alias_item) > if (dump_file) > fprintf (dump_file, "Unified; Wrapper has been created.\n\n"); > } > - gcc_assert (alias->icf_merged || remove); > + > + /* It's possible that redirection can hit thunks that block > + redirection opportunities. */ > + gcc_assert (alias->icf_merged || remove || redirect_callers); > original->icf_merged = true; > > /* Inform the inliner about cross-module merging. */ > diff --git a/gcc/testsuite/g++.dg/ipa/pr65263.C > b/gcc/testsuite/g++.dg/ipa/pr65263.C > new file mode 100644 > index 0000000..34459a2 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ipa/pr65263.C > @@ -0,0 +1,49 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O3 -c -w" } */ > + > +template <class> class A; > +template <class R> struct VirtualMatrice { > + virtual bool m_fn1(int) const { return true; } > + struct B { > + A<R> x; > + B(VirtualMatrice *p1, A<R> p2) : x(p2) { p1->m_fn1(0) ?: throw; } > + }; > + void operator*(A<R> p1) { B(this, p1); } > + ~VirtualMatrice(); > +} > +; > +template <class> class A { > +public: > + operator int *(); > + A(int *, long); > +}; > + > +class G : public A<int> { > +public: > + G(long); > +}; > +int typedef Complex; > +template <class> class H : VirtualMatrice<int> {}; > +template <class> class C; > +template <> class C<int> : H<Complex>, VirtualMatrice<Complex> { > + bool m_fn1(int) const { return true; } > +}; > +template <class K, class Mat> > +void DoIdoAction(int, int, A<K> p3, A<K>, A<K>, A<K>, Mat, Mat &p8) { > + p8 *p3; > +} > + > +class D { > + typedef int K; > + class F { > + int operator()() const; > + }; > +}; > +int D::F::operator()() const { > + VirtualMatrice<K> *a; > + VirtualMatrice<K> b, &B = *a; > + G c(0), g(1); > + int d, e, f; > + A<K> h(&g[f], 0), i(&g[e], 0), j(&g[d], 0); > + DoIdoAction(0, 3, h, i, j, c, b, B); > +} > -- > 2.1.2 >