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();
+}

Reply via email to