Hi, in the PR, verifier claims an edge is pointing to a wrong declaration even though it has successfully verified the edge multiple times before. The reason is that symtab_remove_unreachable_nodes decides to "remove the body" of a node and also clear any information that it is an alias of another in the process (more detailed analysis in comment #9 of the bug).
In bugzilla Honza wrote that "silencing the verifier" is the way to go. Either we can dedicate a new flag in each cgraph_node or symtab_node just for the purpose of verification or do something more hackish like the patch below which re-uses the former_clone_of field for this purpose. Since clones are always private nodes, they should always either survive removal of unreachable nodes or be completely killed by it and should never enter the in_border zombie state. Therefore their former_clone_of must always be NULL. So I added a new special value, error_mark_node, to mark this zombie state and taught the verifier to be happy with such nodes. Bootstrapped and tested on x86_64-linux. What do you think? Thanks, Martin 2014-03-19 Martin Jambor <mjam...@suse.cz> PR ipa/59176 * ipa.c (symtab_remove_unreachable_nodes): Assert nodes in border are not former clones. Set their former_clone_of to error_mark_node. * cgraphclones.c (cgraph_materialize_clone): Do not copy error_mark_node former_clone_of. * cgraph.c (verify_edge_corresponds_to_fndecl): Ignore nodes with error_mark_node former_clone_of. testsuite/ * g++.dg/torture/pr59176.C: New test. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index a15b6bc..3bf5ecd 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1935,6 +1935,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, " Clone of %s/%i\n", node->clone_of->asm_name (), node->clone_of->order); + if (node->former_clone_of == error_mark_node) + fprintf (f, " Body removed by symtab_remove_unreachable_nodes\n"); if (cgraph_function_flags_ready) fprintf (f, " Availability: %s\n", cgraph_availability_names [cgraph_function_body_availability (node)]); @@ -2602,7 +2604,10 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl) /* We do not know if a node from a different partition is an alias or what it aliases and therefore cannot do the former_clone_of check reliably. */ - if (!node || node->in_other_partition || e->callee->in_other_partition) + if (!node + || node->former_clone_of == error_mark_node + || node->in_other_partition + || e->callee->in_other_partition) return false; node = cgraph_function_or_thunk_node (node, NULL); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index ca69033..ba08281 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -914,7 +914,8 @@ cgraph_materialize_clone (struct cgraph_node *node) { bitmap_obstack_initialize (NULL); node->former_clone_of = node->clone_of->decl; - if (node->clone_of->former_clone_of) + if (node->clone_of->former_clone_of + && node->clone_of->former_clone_of != error_mark_node) node->former_clone_of = node->clone_of->former_clone_of; /* Copy the OLD_VERSION_NODE function tree to the new version. */ tree_function_versioning (node->clone_of->decl, node->decl, diff --git a/gcc/ipa.c b/gcc/ipa.c index 572dba1..85c73ef 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -484,6 +484,8 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) { if (file) fprintf (file, " %s", node->name ()); + gcc_assert (!node->former_clone_of); + node->former_clone_of = error_mark_node; node->analyzed = false; node->definition = false; node->cpp_implicit_alias = false; diff --git a/gcc/testsuite/g++.dg/ipa/pr59176.C b/gcc/testsuite/g++.dg/ipa/pr59176.C new file mode 100644 index 0000000..d576bc3 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr59176.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +template <class> class A { +protected: + void m_fn2(); + ~A() { m_fn2(); } + virtual void m_fn1(); +}; + +class D : A<int> {}; +template <class Key> void A<Key>::m_fn2() { + m_fn1(); + m_fn1(); + m_fn1(); +} + +#pragma interface +class B { + D m_cellsAlreadyProcessed; + D m_cellsNotToProcess; + +public: + virtual ~B() {} + void m_fn1(); +}; + +class C { + unsigned long m_fn1(); + B m_fn2(); + unsigned long m_fn3(); +}; +unsigned long C::m_fn1() { +CellHierarchy: + m_fn2().m_fn1(); +} + +unsigned long C::m_fn3() { +CellHierarchy: + m_fn2().m_fn1(); +}