re PR ipa/69589 (ICE in initialize_node_lattices, at ipa-cp.c:971)
authorJan Hubicka <hubicka@ucw.cz>
Thu, 10 Mar 2016 16:11:14 +0000 (17:11 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 10 Mar 2016 16:11:14 +0000 (16:11 +0000)
PR lto/69589
* cgraph.c (cgraph_node::dump): Dump split_part and indirect_call_target.
* cgraph.h (cgraph_node): Add indirect_call_target flag.
* ipa.c (has_addr_references_p): Cleanup.
(is_indirect_call_target_p): New.
(walk_polymorphic_call_targets): Do not mark virtuals that may be
called indirectly as local.
(symbol_table::remove_unreachable_nodes): Compute indirect_call_target.

* g++.dg/lto/pr69589_0.C: New testcase
* g++.dg/lto/pr69589_1.C: New testcase

From-SVN: r234115

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lto/pr69589_0.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/pr69589_1.C [new file with mode: 0644]

index f65902b..ba9f5b5 100644 (file)
@@ -1,5 +1,16 @@
 2016-03-10  Jan Hubicka  <hubicka@ucw.cz>
 
+       PR lto/69589
+       * cgraph.c (cgraph_node::dump): Dump split_part and indirect_call_target.
+       * cgraph.h (cgraph_node): Add indirect_call_target flag.
+       * ipa.c (has_addr_references_p): Cleanup.
+       (is_indirect_call_target_p): New.
+       (walk_polymorphic_call_targets): Do not mark virtuals that may be
+       called indirectly as local.
+       (symbol_table::remove_unreachable_nodes): Compute indirect_call_target.
+
+2016-03-10  Jan Hubicka  <hubicka@ucw.cz>
+
        PR ipa/69630
        * ipa-devirt.c (possible_polymorphic_call_targets): Do not ICE
        on cxa_pure_virtual.
index ee6a209..871ed62 100644 (file)
@@ -2061,6 +2061,10 @@ cgraph_node::dump (FILE *f)
     fprintf (f, " icf_merged");
   if (merged_comdat)
     fprintf (f, " merged_comdat");
+  if (split_part)
+    fprintf (f, " split_part");
+  if (indirect_call_target)
+    fprintf (f, " indirect_call_target");
   if (nonfreeing_fn)
     fprintf (f, " nonfreeing_fn");
   if (DECL_STATIC_CONSTRUCTOR (decl))
index fc7bb22..d0345c6 100644 (file)
@@ -1366,6 +1366,8 @@ public:
   unsigned parallelized_function : 1;
   /* True if function is part split out by ipa-split.  */
   unsigned split_part : 1;
+  /* True if the function appears as possible target of indirect call.  */
+  unsigned indirect_call_target : 1;
 
 private:
   /* Worker for call_for_symbol_and_aliases.  */
index 3c8fc00..6722d3b 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -41,7 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static bool
 has_addr_references_p (struct cgraph_node *node,
-                      void *data ATTRIBUTE_UNUSED)
+                      void *)
 {
   int i;
   struct ipa_ref *ref = NULL;
@@ -52,6 +52,14 @@ has_addr_references_p (struct cgraph_node *node,
   return false;
 }
 
+/* Return true when NODE can be target of an indirect call.  */
+
+static bool
+is_indirect_call_target_p (struct cgraph_node *node, void *)
+{
+  return node->indirect_call_target;
+}
+
 /* Look for all functions inlined to NODE and update their inlined_to pointers
    to INLINED_TO.  */
 
@@ -172,23 +180,24 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
                    (TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl))))
            continue;
 
-          symtab_node *body = n->function_symbol ();
+         n->indirect_call_target = true;
+         symtab_node *body = n->function_symbol ();
 
          /* Prior inlining, keep alive bodies of possible targets for
             devirtualization.  */
-          if (n->definition
-              && (before_inlining_p
-                  && opt_for_fn (body->decl, optimize)
-                  && opt_for_fn (body->decl, flag_devirtualize)))
-             {
-                /* Be sure that we will not optimize out alias target
-                   body.  */
-                if (DECL_EXTERNAL (n->decl)
-                    && n->alias
-                    && before_inlining_p)
-                  reachable->add (body);
-               reachable->add (n);
-             }
+         if (n->definition
+             && (before_inlining_p
+                 && opt_for_fn (body->decl, optimize)
+                 && opt_for_fn (body->decl, flag_devirtualize)))
+            {
+               /* Be sure that we will not optimize out alias target
+                  body.  */
+               if (DECL_EXTERNAL (n->decl)
+                   && n->alias
+                   && before_inlining_p)
+                 reachable->add (body);
+              reachable->add (n);
+            }
          /* Even after inlining we want to keep the possible targets in the
             boundary, so late passes can still produce direct call even if
             the chance for inlining is lost.  */
@@ -323,6 +332,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
   FOR_EACH_FUNCTION (node)
     {
       node->used_as_abstract_origin = false;
+      node->indirect_call_target = false;
       if (node->definition
          && !node->global.inlined_to
          && !node->in_other_partition
@@ -659,7 +669,14 @@ symbol_table::remove_unreachable_nodes (FILE *file)
              fprintf (file, " %s", node->name ());
            node->address_taken = false;
            changed = true;
-           if (node->local_p ())
+           if (node->local_p ()
+               /* Virtual functions may be kept in cgraph just because
+                  of possible later devirtualization.  Do not mark them as
+                  local too early so we won't optimize them out before
+                  we are done with polymorphic call analysis.  */
+               && (!before_inlining_p
+                   || !node->call_for_symbol_and_aliases
+                      (is_indirect_call_target_p, NULL, true)))
              {
                node->local.local = true;
                if (file)
index 093ef57..c6ffcf3 100644 (file)
@@ -1,3 +1,9 @@
+2016-03-10  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR lto/69589
+       * g++.dg/lto/pr69589_0.C: New testcase
+       * g++.dg/lto/pr69589_1.C: New testcase
+
 2016-03-10  Marek Polacek  <polacek@redhat.com>
 
        PR c++/70153
diff --git a/gcc/testsuite/g++.dg/lto/pr69589_0.C b/gcc/testsuite/g++.dg/lto/pr69589_0.C
new file mode 100644 (file)
index 0000000..bbdcb73
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-lto-do link }
+// { dg-lto-options "-O2 -rdynamic" } 
+// { dg-extra-ld-options "-r -nostdlib" }
+#pragma GCC visibility push(hidden)
+struct A { int &operator[] (long); };
+template <typename> struct B;
+template <typename T, typename = B<T> >
+using Z = int;
+template <typename> struct C;
+struct S {
+  int e;
+  virtual ~S () {}
+};
+struct D : S {
+  A a;
+  long i;
+  D() { { e ? &a[i] : nullptr; } }
+};
+template <>
+struct C<int> { Z<S> m8 () const; };
+Z<S>
+C<int>::m8 () const
+{
+  D ();
+}
+
diff --git a/gcc/testsuite/g++.dg/lto/pr69589_1.C b/gcc/testsuite/g++.dg/lto/pr69589_1.C
new file mode 100644 (file)
index 0000000..01c1620
--- /dev/null
@@ -0,0 +1,61 @@
+struct A;
+template <class T>
+struct Q { Q (T); };
+template<typename T, class D>
+struct U {
+  ~U () { m1 (nullptr); }
+  D m2 ();
+  T *u;
+  void m1 (T *) { m2 () (u); }
+};
+struct F { F (int *); };
+template <class, class T = F>
+using W = Q<T>;
+int a, b;
+void fn1 (void *);
+template <class T>
+void
+fn2 (T *x)
+{
+  if (x)
+    x->~T();
+  fn1 (x);
+}
+template <typename T>
+struct C {
+  void operator() (T *x) { fn2 (x); }
+};
+struct D;
+template <typename T, typename D = C<T> >
+using V = U<T, D>;
+struct A {
+  A (int *);
+};
+struct S;
+struct G {
+  V<S> m3 ();
+};
+struct S {
+  int e;
+  virtual ~S () {}
+};
+template<typename T>
+struct H {
+  H (int, T x, int) : h(x) {}
+  G g;
+  void m4 () { g.m3 (); }
+  T h;
+};
+struct I {
+  I(A, W<D>);
+};
+void
+test ()
+{
+  A c (&b);
+  W<D> d (&b);
+  I e (c, d);
+  H<I> f (0, e, a);
+  f.m4 ();
+}
+