Hi, in PR 68851, IPA-CP decides to clone for all known contexts, even when it is not local because the code is not supposed to grow anyway. The code doing that uses collect_callers method of cgraph_edge to find all the edges which are to be redirected in such case. However, there is also an edge from a hunk to the cloned node and that gets collected and redirected too. Later on, this inconsistency (a thunk calling a wrong node) leads to an assert in comdat handling, but it can lead to all sorts of trouble.
The following patch fixes it by checking that thunks are not added into the vector in that method (which is only used by IPA-CP at this one spot and IPA-SRA so it should be fine). Bootstrapped and tested on x86_64-linux. OK for trunk? And perhaps for the gcc-5 branch too? Thanks, Martin 2015-12-14 Martin Jambor <mjam...@suse.cz> PR ipa/68851 * cgraph.c (collect_callers_of_node_1): Do not collect thunks. * cgraph.h (cgraph_node): Change comment of collect_callers. testsuite/ * g++.dg/ipa/pr68851.C: New test. --- gcc/cgraph.c | 3 ++- gcc/cgraph.h | 2 +- gcc/testsuite/g++.dg/ipa/pr68851.C | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/pr68851.C diff --git a/gcc/cgraph.c b/gcc/cgraph.c index c8c3370..5a9c2a2 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2592,7 +2592,8 @@ collect_callers_of_node_1 (cgraph_node *node, void *data) if (avail > AVAIL_INTERPOSABLE) for (cs = node->callers; cs != NULL; cs = cs->next_caller) - if (!cs->indirect_inlining_edge) + if (!cs->indirect_inlining_edge + && !cs->caller->thunk.thunk_p) redirect_callers->safe_push (cs); return false; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 0a09391..ba14215 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1070,7 +1070,7 @@ public: cgraph_edge *get_edge (gimple *call_stmt); /* Collect all callers of cgraph_node and its aliases that are known to lead - to NODE (i.e. are not overwritable). */ + to NODE (i.e. are not overwritable) and that are not thunks. */ vec<cgraph_edge *> collect_callers (void); /* Remove all callers from the node. */ diff --git a/gcc/testsuite/g++.dg/ipa/pr68851.C b/gcc/testsuite/g++.dg/ipa/pr68851.C new file mode 100644 index 0000000..659e4cd --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr68851.C @@ -0,0 +1,29 @@ +// { dg-do compile } +// { dg-options "-O3" } + +class A; +class B { +public: + operator A *() const; +}; +class A { +public: + virtual bool isFormControlElement() const {} +}; +class C { + struct D { + B element; + }; + bool checkPseudoClass(const D &, int &) const; +}; +class F { + virtual bool isFormControlElement() const; +}; +class G : A, F { + bool isFormControlElement() const {} +}; +bool C::checkPseudoClass(const D &p1, int &) const { + A &a = *p1.element; + a.isFormControlElement(); + a.isFormControlElement() || a.isFormControlElement(); +} -- 2.6.3