re PR ipa/83983 (FAIL: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_0.C line 8))
[gcc.git] / gcc / ipa-devirt.c
index d7d97ec2422fa9f0695cd140dfaf2d3bfa8fa845..fae82072a7e90eb754bc96cca3684bbfdde20dac 100644 (file)
@@ -1,6 +1,6 @@
 /* Basic IPA utilities for type inheritance graph construction and
    devirtualization.
-   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+   Copyright (C) 2013-2018 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -108,64 +108,43 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
+#include "gimple.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
 #include "fold-const.h"
 #include "print-tree.h"
 #include "calls.h"
-#include "predict.h"
-#include "basic-block.h"
-#include "is-a.h"
-#include "plugin-api.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "ipa-ref.h"
-#include "cgraph.h"
-#include "rtl.h"
-#include "flags.h"
-#include "insn-config.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "tree-pass.h"
-#include "target.h"
-#include "tree-pretty-print.h"
 #include "ipa-utils.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
 #include "gimple-fold.h"
-#include "gimple-expr.h"
-#include "gimple.h"
-#include "alloc-pool.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
 #include "ipa-prop.h"
-#include "ipa-inline.h"
-#include "diagnostic.h"
-#include "tree-dfa.h"
+#include "ipa-fnsummary.h"
 #include "demangle.h"
 #include "dbgcnt.h"
 #include "gimple-pretty-print.h"
-#include "stor-layout.h"
 #include "intl.h"
-#include "streamer-hooks.h"
-#include "lto-streamer.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Hash based set of pairs of types.  */
-typedef struct
+struct type_pair
 {
   tree first;
   tree second;
-} type_pair;
+};
 
-struct pair_traits : default_hashset_traits
+template <>
+struct default_hash_traits <type_pair>
+  : typed_noop_remove <type_pair>
 {
+  GTY((skip)) typedef type_pair value_type;
+  GTY((skip)) typedef type_pair compare_type;
   static hashval_t
   hash (type_pair p)
   {
@@ -194,7 +173,7 @@ struct pair_traits : default_hashset_traits
 };
 
 static bool odr_types_equivalent_p (tree, tree, bool, bool *,
-                                   hash_set<type_pair,pair_traits> *,
+                                   hash_set<type_pair> *,
                                    location_t, location_t);
 
 static bool odr_violation_reported = false;
@@ -234,96 +213,6 @@ struct GTY(()) odr_type_d
   bool rtti_broken;
 };
 
-/* Return true if T is a type with linkage defined.  */
-
-bool
-type_with_linkage_p (const_tree t)
-{
-  /* Builtin types do not define linkage, their TYPE_CONTEXT is NULL.  */
-  if (!TYPE_CONTEXT (t)
-      || !TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL
-      || !TYPE_STUB_DECL (t))
-    return false;
-
-  /* In LTO do not get confused by non-C++ produced types or types built
-     with -fno-lto-odr-type-merigng.  */
-  if (in_lto_p)
-    {
-      /* To support -fno-lto-odr-type-merigng recognize types with vtables
-         to have linkage.  */
-      if (RECORD_OR_UNION_TYPE_P (t)
-         && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
-        return true;
-      /* Do not accept any other types - we do not know if they were produced
-         by C++ FE.  */
-      if (!DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
-        return false;
-    }
-
-  return (RECORD_OR_UNION_TYPE_P (t)
-         || TREE_CODE (t) == ENUMERAL_TYPE);
-}
-
-/* Return true if T is in anonymous namespace.
-   This works only on those C++ types with linkage defined.  */
-
-bool
-type_in_anonymous_namespace_p (const_tree t)
-{
-  gcc_assert (type_with_linkage_p (t));
-
-  /* Keep -fno-lto-odr-type-merging working by recognizing classes with vtables
-     properly into anonymous namespaces.  */
-  if (RECORD_OR_UNION_TYPE_P (t)
-      && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
-    return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
-
-  if (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)))
-    {
-      /* C++ FE uses magic <anon> as assembler names of anonymous types.
-        verify that this match with type_in_anonymous_namespace_p.  */
-#ifdef ENABLE_CHECKING
-      if (in_lto_p)
-       gcc_assert (!strcmp ("<anon>",
-                   IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))));
-#endif
-      return true;
-    }
-  return false;
-}
-
-/* Return true of T is type with One Definition Rule info attached. 
-   It means that either it is anonymous type or it has assembler name
-   set.  */
-
-bool
-odr_type_p (const_tree t)
-{
-  /* We do not have this information when not in LTO, but we do not need
-     to care, since it is used only for type merging.  */
-  gcc_checking_assert (in_lto_p || flag_lto);
-
-  /* To support -fno-lto-odr-type-merging consider types with vtables ODR.  */
-  if (type_with_linkage_p (t) && type_in_anonymous_namespace_p (t))
-    return true;
-
-  if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
-      && (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))))
-    {
-#ifdef ENABLE_CHECKING
-      /* C++ FE uses magic <anon> as assembler names of anonymous types.
-        verify that this match with type_in_anonymous_namespace_p.  */
-      gcc_assert (!type_with_linkage_p (t)
-                 || strcmp ("<anon>",
-                            IDENTIFIER_POINTER
-                               (DECL_ASSEMBLER_NAME (TYPE_NAME (t))))
-                 || type_in_anonymous_namespace_p (t));
-#endif
-      return true;
-    }
-  return false;
-}
-
 /* Return TRUE if all derived types of T are known and thus
    we may consider the walk of derived type complete.
 
@@ -385,9 +274,8 @@ type_possibly_instantiated_p (tree t)
 /* Hash used to unify ODR types based on their mangled name and for anonymous
    namespace types.  */
 
-struct odr_name_hasher
+struct odr_name_hasher : pointer_hash <odr_type_d>
 {
-  typedef odr_type_d *value_type;
   typedef union tree_node *compare_type;
   static inline hashval_t hash (const odr_type_d *);
   static inline bool equal (const odr_type_d *, const tree_node *);
@@ -485,7 +373,7 @@ hash_odr_vtable (const_tree t)
       v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
     }
 
-  hstate.add_wide_int (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
+  hstate.add_hwi (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
   return hstate.end ();
 }
 
@@ -509,7 +397,7 @@ odr_vtable_hasher::hash (const odr_type_d *odr_type)
 
    When STRICT is true, we compare types by their names for purposes of
    ODR violation warnings.  When strict is false, we consider variants
-   equivalent, becuase it is all that matters for devirtualization machinery.
+   equivalent, because it is all that matters for devirtualization machinery.
 */
 
 bool
@@ -561,7 +449,7 @@ types_same_for_odr (const_tree type1, const_tree type2, bool strict)
        return false;
       if (TREE_CODE (type1) == RECORD_TYPE
          && (TYPE_BINFO (type1) == NULL_TREE)
-             != (TYPE_BINFO (type1) == NULL_TREE))
+             != (TYPE_BINFO (type2) == NULL_TREE))
        return false;
       if (TREE_CODE (type1) == RECORD_TYPE && TYPE_BINFO (type1)
          && (BINFO_VTABLE (TYPE_BINFO (type1)) == NULL_TREE)
@@ -772,7 +660,7 @@ set_type_binfo (tree type, tree binfo)
 
 static bool
 odr_subtypes_equivalent_p (tree t1, tree t2,
-                          hash_set<type_pair,pair_traits> *visited,
+                          hash_set<type_pair> *visited,
                           location_t loc1, location_t loc2)
 {
 
@@ -796,9 +684,14 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
     {
       if (!types_same_for_odr (t1, t2, true))
         return false;
-      /* Limit recursion: If subtypes are ODR types and we know
-         that they are same, be happy.  */
-      if (!odr_type_p (t1) || !get_odr_type (t1, true)->odr_violated)
+      /* Limit recursion: if subtypes are ODR types and we know that they are
+        same, be happy.  We need to call get_odr_type on both subtypes since
+        we don't know which among t1 and t2 defines the common ODR type and
+        therefore which call will report the ODR violation, if any.  */
+        if (!odr_type_p (t1)
+            || !odr_type_p (t2)
+            || (!get_odr_type (t1, true)->odr_violated
+                && !get_odr_type (t2, true)->odr_violated))
         return true;
     }
 
@@ -821,6 +714,29 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
   return odr_types_equivalent_p (t1, t2, false, NULL, visited, loc1, loc2);
 }
 
+/* Return true if DECL1 and DECL2 are identical methods.  Consider
+   name equivalent to name.localalias.xyz.  */
+
+static bool
+methods_equal_p (tree decl1, tree decl2)
+{
+  if (DECL_ASSEMBLER_NAME (decl1) == DECL_ASSEMBLER_NAME (decl2))
+    return true;
+  const char sep = symbol_table::symbol_suffix_separator ();
+
+  const char *name1 = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl1));
+  const char *ptr1 = strchr (name1, sep);
+  int len1 = ptr1 ? ptr1 - name1 : strlen (name1);
+
+  const char *name2 = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl2));
+  const char *ptr2 = strchr (name2, sep);
+  int len2 = ptr2 ? ptr2 - name2 : strlen (name2);
+
+  if (len1 != len2)
+    return false;
+  return !strncmp (name1, name2, len1);
+}
+
 /* Compare two virtual tables, PREVAILING and VTABLE and output ODR
    violation warnings.  */
 
@@ -874,8 +790,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
         accept the other case.  */
       while (!end2
             && (end1
-                || (DECL_ASSEMBLER_NAME (ref1->referred->decl)
-                    != DECL_ASSEMBLER_NAME (ref2->referred->decl)
+                || (methods_equal_p (ref1->referred->decl,
+                                     ref2->referred->decl)
                     && TREE_CODE (ref1->referred->decl) == FUNCTION_DECL))
             && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
        {
@@ -901,8 +817,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
        }
       while (!end1
             && (end2
-                || (DECL_ASSEMBLER_NAME (ref2->referred->decl)
-                    != DECL_ASSEMBLER_NAME (ref1->referred->decl)
+                || (methods_equal_p (ref2->referred->decl, ref1->referred->decl)
                     && TREE_CODE (ref2->referred->decl) == FUNCTION_DECL))
             && TREE_CODE (ref1->referred->decl) != FUNCTION_DECL)
        {
@@ -939,8 +854,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 
       if (!end1 && !end2)
        {
-         if (DECL_ASSEMBLER_NAME (ref1->referred->decl)
-             == DECL_ASSEMBLER_NAME (ref2->referred->decl))
+         if (methods_equal_p (ref1->referred->decl, ref2->referred->decl))
            continue;
 
          class_type->odr_violated = true;
@@ -971,9 +885,9 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
          if (TREE_CODE (ref1->referred->decl)
              != TREE_CODE (ref2->referred->decl))
            {
-             if (TREE_CODE (ref1->referred->decl) == VAR_DECL)
+             if (VAR_P (ref1->referred->decl))
                end1 = true;
-             else if (TREE_CODE (ref2->referred->decl) == VAR_DECL)
+             else if (VAR_P (ref2->referred->decl))
                end2 = true;
            }
        }
@@ -1014,7 +928,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                  inform (DECL_SOURCE_LOCATION
                           (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                          "the conflicting type defined in another translation "
-                         "unit has virtual table table with more entries");
+                         "unit has virtual table with more entries");
                }
            }
          return;
@@ -1036,17 +950,20 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                      "unit");
              gcc_assert (TREE_CODE (ref2->referred->decl)
                          == FUNCTION_DECL);
-             inform (DECL_SOURCE_LOCATION (ref1->referred->decl),
-                     "virtual method %qD", ref1->referred->decl);
-             inform (DECL_SOURCE_LOCATION (ref2->referred->decl),
+             inform (DECL_SOURCE_LOCATION
+                        (ref1->referred->ultimate_alias_target ()->decl),
+                     "virtual method %qD",
+                     ref1->referred->ultimate_alias_target ()->decl);
+             inform (DECL_SOURCE_LOCATION
+                        (ref2->referred->ultimate_alias_target ()->decl),
                      "ought to match virtual method %qD but does not",
-                     ref2->referred->decl);
+                     ref2->referred->ultimate_alias_target ()->decl);
            }
          else
            inform (DECL_SOURCE_LOCATION
                      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                    "the conflicting type defined in another translation "
-                   "unit has virtual table table with different contents");
+                   "unit has virtual table with different contents");
          return;
        }
     }
@@ -1230,7 +1147,7 @@ warn_types_mismatch (tree t1, tree t2, location_t loc1, location_t loc2)
       if (name1 && name2 && strcmp (name1, name2))
        {
          inform (loc_t1,
-                 "type name %<%s%> should match type name %<%s%>",
+                 "type name %qs should match type name %qs",
                  name1, name2);
          if (loc_t2_useful)
            inform (loc_t2,
@@ -1317,7 +1234,7 @@ warn_types_mismatch (tree t1, tree t2, location_t loc1, location_t loc2)
   if (types_odr_comparable (t1, t2, true)
       && types_same_for_odr (t1, t2, true))
     inform (loc_t1,
-           "type %qT itself violate the C++ One Definition Rule", t1);
+           "type %qT itself violates the C++ One Definition Rule", t1);
   /* Prevent pointless warnings like "struct aa" should match "struct aa".  */
   else if (TYPE_NAME (t1) == TYPE_NAME (t2)
           && TREE_CODE (t1) == TREE_CODE (t2) && !loc_t2_useful)
@@ -1338,7 +1255,7 @@ warn_types_mismatch (tree t1, tree t2, location_t loc1, location_t loc2)
 
 static bool
 odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
-                       hash_set<type_pair,pair_traits> *visited,
+                       hash_set<type_pair> *visited,
                        location_t loc1, location_t loc2)
 {
   /* Check first for the obvious case of pointer identity.  */
@@ -1664,7 +1581,7 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
                    if (DECL_ARTIFICIAL (f1))
                      break;
                    warn_odr (t1, t2, f1, f2, warn, warned,
-                             G_("fields has different layout "
+                             G_("fields have different layout "
                                 "in another translation unit"));
                    return false;
                  }
@@ -1692,62 +1609,6 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
                
                return false;
              }
-           if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2)
-               && COMPLETE_TYPE_P (TYPE_MAIN_VARIANT (t1))
-               && COMPLETE_TYPE_P (TYPE_MAIN_VARIANT (t2))
-               && odr_type_p (TYPE_MAIN_VARIANT (t1))
-               && odr_type_p (TYPE_MAIN_VARIANT (t2))
-               && (TYPE_METHODS (TYPE_MAIN_VARIANT (t1))
-                   != TYPE_METHODS (TYPE_MAIN_VARIANT (t2))))
-             {
-               /* Currently free_lang_data sets TYPE_METHODS to error_mark_node
-                  if it is non-NULL so this loop will never realy execute.  */
-               if (TYPE_METHODS (TYPE_MAIN_VARIANT (t1)) != error_mark_node
-                   && TYPE_METHODS (TYPE_MAIN_VARIANT (t2)) != error_mark_node)
-                 for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)),
-                      f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2));
-                      f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2))
-                   {
-                     if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2))
-                       {
-                         warn_odr (t1, t2, f1, f2, warn, warned,
-                                   G_("a different method of same type "
-                                      "is defined in another "
-                                      "translation unit"));
-                         return false;
-                       }
-                     if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2))
-                       {
-                         warn_odr (t1, t2, f1, f2, warn, warned,
-                                   G_("s definition that differs by virtual "
-                                      "keyword in another translation unit"));
-                         return false;
-                       }
-                     if (DECL_VINDEX (f1) != DECL_VINDEX (f2))
-                       {
-                         warn_odr (t1, t2, f1, f2, warn, warned,
-                                   G_("virtual table layout differs "
-                                      "in another translation unit"));
-                         return false;
-                       }
-                     if (odr_subtypes_equivalent_p (TREE_TYPE (f1),
-                                                    TREE_TYPE (f2), visited,
-                                                    loc1, loc2))
-                       {
-                         warn_odr (t1, t2, f1, f2, warn, warned,
-                                   G_("method with incompatible type is "
-                                      "defined in another translation unit"));
-                         return false;
-                       }
-                   }
-               if ((f1 == NULL) != (f2 == NULL))
-                 {
-                   warn_odr (t1, t2, NULL, NULL, warn, warned,
-                             G_("a type with different number of methods "
-                                "is defined in another translation unit"));
-                   return false;
-                 }
-             }
          }
        break;
       }
@@ -1788,11 +1649,10 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
 bool
 odr_types_equivalent_p (tree type1, tree type2)
 {
-  hash_set<type_pair,pair_traits> visited;
+  gcc_checking_assert (odr_or_derived_type_p (type1)
+                      && odr_or_derived_type_p (type2));
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (odr_or_derived_type_p (type1) && odr_or_derived_type_p (type2));
-#endif
+  hash_set<type_pair> visited;
   return odr_types_equivalent_p (type1, type2, false, NULL,
                                 &visited, UNKNOWN_LOCATION, UNKNOWN_LOCATION);
 }
@@ -1848,12 +1708,7 @@ add_type_duplicate (odr_type val, tree type)
     }
 
   if (prevail)
-    {
-      tree tmp = type;
-
-      type = val->type;
-      val->type = tmp;
-    }
+    std::swap (val->type, type);
 
   val->types_set->add (type);
 
@@ -1868,7 +1723,7 @@ add_type_duplicate (odr_type val, tree type)
   bool base_mismatch = false;
   unsigned int i;
   bool warned = false;
-  hash_set<type_pair,pair_traits> visited;
+  hash_set<type_pair> visited;
 
   gcc_assert (in_lto_p);
   vec_safe_push (val->types, type);
@@ -1994,7 +1849,12 @@ add_type_duplicate (odr_type val, tree type)
        }
     }
 
-  /* Next compare memory layout.  */
+  /* Next compare memory layout.
+     The DECL_SOURCE_LOCATIONs in this invocation came from LTO streaming.
+     We must apply the location cache to ensure that they are valid
+     before we can pass them to odr_types_equivalent_p (PR lto/83121).  */
+  if (lto_location_cache::current_cache)
+    lto_location_cache::current_cache->apply_location_cache ();
   if (!odr_types_equivalent_p (val->type, type,
                               !flag_ltrans && !val->odr_violated && !warned,
                               &warned, &visited,
@@ -2004,20 +1864,11 @@ add_type_duplicate (odr_type val, tree type)
       merge = false;
       odr_violation_reported = true;
       val->odr_violated = true;
-      if (symtab->dump_file)
-       {
-         fprintf (symtab->dump_file, "ODR violation\n");
-
-         print_node (symtab->dump_file, "", val->type, 0);
-         putc ('\n',symtab->dump_file);
-         print_node (symtab->dump_file, "", type, 0);
-         putc ('\n',symtab->dump_file);
-       }
     }
   gcc_assert (val->odr_violated || !odr_must_violate);
   /* Sanity check that all bases will be build same way again.  */
-#ifdef ENABLE_CHECKING
-  if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
+  if (flag_checking
+      && COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
       && TREE_CODE (val->type) == RECORD_TYPE
       && TREE_CODE (type) == RECORD_TYPE
       && TYPE_BINFO (val->type) && TYPE_BINFO (type)
@@ -2046,7 +1897,6 @@ add_type_duplicate (odr_type val, tree type)
            j++;
          }
     }
-#endif
 
 
   /* Regularize things a little.  During LTO same types may come with
@@ -2152,8 +2002,8 @@ get_odr_type (tree type, bool insert)
       if (slot && *slot)
        {
          val = *slot;
-#ifdef ENABLE_CHECKING
-         if (in_lto_p && can_be_vtable_hashed_p (type))
+         if (flag_checking
+             && in_lto_p && can_be_vtable_hashed_p (type))
            {
              hash = hash_odr_vtable (type);
              vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
@@ -2161,7 +2011,6 @@ get_odr_type (tree type, bool insert)
              gcc_assert (!vtable_slot || *vtable_slot == *slot);
              vtable_slot = NULL;
            }
-#endif
        }
       else if (*vtable_slot)
        val = *vtable_slot;
@@ -2245,8 +2094,7 @@ get_odr_type (tree type, bool insert)
       /* Be sure we did not recorded any derived types; these may need
         renumbering too.  */
       gcc_assert (val->derived_types.length() == 0);
-      if (odr_types_ptr)
-       val->id = odr_types.length ();
+      val->id = odr_types.length ();
       vec_safe_push (odr_types_ptr, val);
     }
   return val;
@@ -2368,7 +2216,7 @@ build_type_inheritance_graph (void)
 {
   struct symtab_node *n;
   FILE *inheritance_dump_file;
-  int flags;
+  dump_flags_t flags;
 
   if (odr_hash)
     return;
@@ -2379,7 +2227,7 @@ build_type_inheritance_graph (void)
     odr_vtable_hash = new odr_vtable_hash_type (23);
 
   /* We reconstruct the graph starting of types of all methods seen in the
-     the unit.  */
+     unit.  */
   FOR_EACH_SYMBOL (n)
     if (is_a <cgraph_node *> (n)
        && DECL_VIRTUAL_P (n->decl)
@@ -2451,7 +2299,7 @@ referenced_from_vtable_p (struct cgraph_node *node)
     if ((ref->use == IPA_REF_ALIAS
         && referenced_from_vtable_p (dyn_cast<cgraph_node *> (ref->referring)))
        || (ref->use == IPA_REF_ADDR
-           && TREE_CODE (ref->referring->decl) == VAR_DECL
+           && VAR_P (ref->referring->decl)
            && DECL_VIRTUAL_P (ref->referring->decl)))
       {
        found = true;
@@ -2460,6 +2308,17 @@ referenced_from_vtable_p (struct cgraph_node *node)
   return found;
 }
 
+/* Return if TARGET is cxa_pure_virtual.  */
+
+static bool
+is_cxa_pure_virtual_p (tree target)
+{
+  return target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE
+        && DECL_NAME (target)
+        && id_equal (DECL_NAME (target),
+                    "__cxa_pure_virtual");
+}
+
 /* If TARGET has associated node, record it in the NODES array.
    CAN_REFER specify if program can refer to the target directly.
    if TARGET is unknown (NULL) or it can not be inserted (for example because
@@ -2474,11 +2333,12 @@ maybe_record_node (vec <cgraph_node *> &nodes,
 {
   struct cgraph_node *target_node, *alias_target;
   enum availability avail;
+  bool pure_virtual = is_cxa_pure_virtual_p (target);
 
-  /* cxa_pure_virtual and __builtin_unreachable do not need to be added into
+  /* __builtin_unreachable do not need to be added into
      list of targets; the runtime effect of calling them is undefined.
      Only "real" virtual methods should be accounted.  */
-  if (target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE)
+  if (target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE && !pure_virtual)
     return;
 
   if (!can_refer)
@@ -2521,6 +2381,7 @@ maybe_record_node (vec <cgraph_node *> &nodes,
      ??? Maybe it would make sense to be more aggressive for LTO even
      elsewhere.  */
   if (!flag_ltrans
+      && !pure_virtual
       && type_in_anonymous_namespace_p (DECL_CONTEXT (target))
       && (!target_node
           || !referenced_from_vtable_p (target_node)))
@@ -2534,16 +2395,43 @@ maybe_record_node (vec <cgraph_node *> &nodes,
     {
       gcc_assert (!target_node->global.inlined_to);
       gcc_assert (target_node->real_symbol_p ());
+      /* When sanitizing, do not assume that __cxa_pure_virtual is not called
+        by valid program.  */
+      if (flag_sanitize & SANITIZE_UNREACHABLE)
+       ;
+      /* Only add pure virtual if it is the only possible target.  This way
+        we will preserve the diagnostics about pure virtual called in many
+        cases without disabling optimization in other.  */
+      else if (pure_virtual)
+       {
+         if (nodes.length ())
+           return;
+       }
+      /* If we found a real target, take away cxa_pure_virtual.  */
+      else if (!pure_virtual && nodes.length () == 1
+              && is_cxa_pure_virtual_p (nodes[0]->decl))
+       nodes.pop ();
+      if (pure_virtual && nodes.length ())
+       return;
       if (!inserted->add (target))
        {
          cached_polymorphic_call_targets->add (target_node);
          nodes.safe_push (target_node);
        }
     }
-  else if (completep
-          && (!type_in_anonymous_namespace_p
-                (DECL_CONTEXT (target))
-              || flag_ltrans))
+  else if (!completep)
+    ;
+  /* We have definition of __cxa_pure_virtual that is not accessible (it is
+     optimized out or partitioned to other unit) so we can not add it.  When
+     not sanitizing, there is nothing to do.
+     Otherwise declare the list incomplete.  */
+  else if (pure_virtual)
+    {
+      if (flag_sanitize & SANITIZE_UNREACHABLE)
+       *completep = false;
+    }
+  else if (flag_ltrans
+          || !type_in_anonymous_namespace_p (DECL_CONTEXT (target)))
     *completep = false;
 }
 
@@ -2731,10 +2619,9 @@ struct polymorphic_call_target_d
 
 /* Polymorphic call target cache helpers.  */
 
-struct polymorphic_call_target_hasher 
+struct polymorphic_call_target_hasher
+  : pointer_hash <polymorphic_call_target_d>
 {
-  typedef polymorphic_call_target_d *value_type;
-  typedef polymorphic_call_target_d *compare_type;
   static inline hashval_t hash (const polymorphic_call_target_d *);
   static inline bool equal (const polymorphic_call_target_d *,
                            const polymorphic_call_target_d *);
@@ -2748,14 +2635,14 @@ polymorphic_call_target_hasher::hash (const polymorphic_call_target_d *odr_query
 {
   inchash::hash hstate (odr_query->otr_token);
 
-  hstate.add_wide_int (odr_query->type->id);
+  hstate.add_hwi (odr_query->type->id);
   hstate.merge_hash (TYPE_UID (odr_query->context.outer_type));
-  hstate.add_wide_int (odr_query->context.offset);
+  hstate.add_hwi (odr_query->context.offset);
 
   if (odr_query->context.speculative_outer_type)
     {
       hstate.merge_hash (TYPE_UID (odr_query->context.speculative_outer_type));
-      hstate.add_wide_int (odr_query->context.speculative_offset);
+      hstate.add_hwi (odr_query->context.speculative_offset);
     }
   hstate.add_flag (odr_query->speculative);
   hstate.add_flag (odr_query->context.maybe_in_construction);
@@ -3008,7 +2895,7 @@ struct odr_type_warn_count
 {
   tree type;
   int count;
-  gcov_type dyn_count;
+  profile_count dyn_count;
 };
 
 /* Record about how many calls would benefit from given method to be final.  */
@@ -3017,17 +2904,34 @@ struct decl_warn_count
 {
   tree decl;
   int count;
-  gcov_type dyn_count;
+  profile_count dyn_count;
 };
 
 /* Information about type and decl warnings.  */
 
 struct final_warning_record
 {
-  gcov_type dyn_count;
-  vec<odr_type_warn_count> type_warnings;
+  /* If needed grow type_warnings vector and initialize new decl_warn_count
+     to have dyn_count set to profile_count::zero ().  */
+  void grow_type_warnings (unsigned newlen);
+
+  profile_count dyn_count;
+  auto_vec<odr_type_warn_count> type_warnings;
   hash_map<tree, decl_warn_count> decl_warnings;
 };
+
+void
+final_warning_record::grow_type_warnings (unsigned newlen)
+{
+  unsigned len = type_warnings.length ();
+  if (newlen > len)
+    {
+      type_warnings.safe_grow_cleared (newlen);
+      for (unsigned i = len; i < newlen; i++)
+       type_warnings[i].dyn_count = profile_count::zero ();
+    }
+}
+
 struct final_warning_record *final_warning_records;
 
 /* Return vector containing possible targets of polymorphic call of type
@@ -3162,15 +3066,22 @@ possible_polymorphic_call_targets (tree otr_type,
       if ((*slot)->type_warning && final_warning_records)
        {
          final_warning_records->type_warnings[(*slot)->type_warning - 1].count++;
-         final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count
-           += final_warning_records->dyn_count;
+         if (!final_warning_records->type_warnings
+               [(*slot)->type_warning - 1].dyn_count.initialized_p ())
+           final_warning_records->type_warnings
+               [(*slot)->type_warning - 1].dyn_count = profile_count::zero ();
+         if (final_warning_records->dyn_count > 0)
+           final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count
+             = final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count
+               + final_warning_records->dyn_count;
        }
       if (!speculative && (*slot)->decl_warning && final_warning_records)
        {
          struct decl_warn_count *c =
             final_warning_records->decl_warnings.get ((*slot)->decl_warning);
          c->count++;
-         c->dyn_count += final_warning_records->dyn_count;
+         if (final_warning_records->dyn_count > 0)
+           c->dyn_count += final_warning_records->dyn_count;
        }
       return (*slot)->targets;
     }
@@ -3284,17 +3195,21 @@ possible_polymorphic_call_targets (tree otr_type,
 
          if (!outer_type->all_derivations_known)
            {
-             if (!speculative && final_warning_records)
+             if (!speculative && final_warning_records
+                 && nodes.length () == 1
+                 && TREE_CODE (TREE_TYPE (nodes[0]->decl)) == METHOD_TYPE)
                {
                  if (complete
-                     && nodes.length () == 1
                      && warn_suggest_final_types
                      && !outer_type->derived_types.length ())
                    {
-                     if (outer_type->id >= (int)final_warning_records->type_warnings.length ())
-                       final_warning_records->type_warnings.safe_grow_cleared
-                         (odr_types.length ());
+                     final_warning_records->grow_type_warnings
+                       (outer_type->id);
                      final_warning_records->type_warnings[outer_type->id].count++;
+                     if (!final_warning_records->type_warnings
+                               [outer_type->id].dyn_count.initialized_p ())
+                       final_warning_records->type_warnings
+                          [outer_type->id].dyn_count = profile_count::zero ();
                      final_warning_records->type_warnings[outer_type->id].dyn_count
                        += final_warning_records->dyn_count;
                      final_warning_records->type_warnings[outer_type->id].type
@@ -3303,7 +3218,6 @@ possible_polymorphic_call_targets (tree otr_type,
                    }
                  if (complete
                      && warn_suggest_final_methods
-                     && nodes.length () == 1
                      && types_same_for_odr (DECL_CONTEXT (nodes[0]->decl),
                                             outer_type->type))
                    {
@@ -3385,7 +3299,8 @@ dump_targets (FILE *f, vec <cgraph_node *> targets)
       char *name = NULL;
       if (in_lto_p)
        name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
-      fprintf (f, " %s/%i", name ? name : targets[i]->name (), targets[i]->order);
+      fprintf (f, " %s/%i", name ? name : targets[i]->name (),
+              targets[i]->order);
       if (in_lto_p)
        free (name);
       if (!targets[i]->definition)
@@ -3437,7 +3352,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
       fprintf (f, "  Speculative targets:");
       dump_targets (f, targets);
     }
-  gcc_assert (targets.length () <= len);
+  /* Ugly: during callgraph construction the target cache may get populated
+     before all targets are found.  While this is harmless (because all local
+     types are discovered and only in those case we devirtualize fully and we
+     don't do speculative devirtualization before IPA stage) it triggers
+     assert here when dumping at that stage also populates the case with
+     speculative targets.  Quietly ignore this.  */
+  gcc_assert (symtab->state < IPA_SSA || targets.length () <= len);
   fprintf (f, "\n");
 }
 
@@ -3457,11 +3378,13 @@ possible_polymorphic_call_target_p (tree otr_type,
   bool final;
 
   if (TREE_CODE (TREE_TYPE (n->decl)) == FUNCTION_TYPE
-      && ((fcode = DECL_FUNCTION_CODE (n->decl))
-         == BUILT_IN_UNREACHABLE
+      && ((fcode = DECL_FUNCTION_CODE (n->decl)) == BUILT_IN_UNREACHABLE
           || fcode == BUILT_IN_TRAP))
     return true;
 
+  if (is_cxa_pure_virtual_p (n->decl))
+    return true;
+
   if (!odr_hash)
     return true;
   targets = possible_polymorphic_call_targets (otr_type, otr_token, ctx, &final);
@@ -3483,7 +3406,7 @@ possible_polymorphic_call_target_p (tree otr_type,
 
 bool
 possible_polymorphic_call_target_p (tree ref,
-                                   gimple stmt,
+                                   gimple *stmt,
                                    struct cgraph_node *n)
 {
   ipa_polymorphic_call_context context (current_function_decl, ref, stmt);
@@ -3510,7 +3433,7 @@ update_type_inheritance_graph (void)
   free_polymorphic_call_targets_hash ();
   timevar_push (TV_IPA_INHERITANCE);
   /* We reconstruct the graph starting from types of all methods seen in the
-     the unit.  */
+     unit.  */
   FOR_EACH_FUNCTION (n)
     if (DECL_VIRTUAL_P (n->decl)
        && !n->definition
@@ -3647,8 +3570,8 @@ ipa_devirt (void)
   if (warn_suggest_final_methods || warn_suggest_final_types)
     {
       final_warning_records = new (final_warning_record);
-      final_warning_records->type_warnings = vNULL;
-      final_warning_records->type_warnings.safe_grow_cleared (odr_types.length ());
+      final_warning_records->dyn_count = profile_count::zero ();
+      final_warning_records->grow_type_warnings (odr_types.length ());
       free_polymorphic_call_targets_hash ();
     }
 
@@ -3658,8 +3581,8 @@ ipa_devirt (void)
       if (!opt_for_fn (n->decl, flag_devirtualize))
        continue;
       if (dump_file && n->indirect_calls)
-       fprintf (dump_file, "\n\nProcesing function %s/%i\n",
-                n->name (), n->order);
+       fprintf (dump_file, "\n\nProcesing function %s\n",
+                n->dump_name ());
       for (e = n->indirect_calls; e; e = e->next_callee)
        if (e->indirect_info->polymorphic)
          {
@@ -3668,7 +3591,7 @@ ipa_devirt (void)
            bool final;
 
            if (final_warning_records)
-             final_warning_records->dyn_count = e->count;
+             final_warning_records->dyn_count = e->count.ipa ();
 
            vec <cgraph_node *>targets
               = possible_polymorphic_call_targets
@@ -3814,10 +3737,10 @@ ipa_devirt (void)
                   {
                     location_t locus = gimple_location_safe (e->call_stmt);
                     dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, locus,
-                                     "speculatively devirtualizing call in %s/%i to %s/%i\n",
-                                     n->name (), n->order,
-                                     likely_target->name (),
-                                     likely_target->order);
+                                    "speculatively devirtualizing call "
+                                    "in %s to %s\n",
+                                    n->dump_name (),
+                                    likely_target->dump_name ());
                   }
                if (!likely_target->can_be_discarded_p ())
                  {
@@ -3829,11 +3752,11 @@ ipa_devirt (void)
                nconverted++;
                update = true;
                e->make_speculative
-                 (likely_target, e->count * 8 / 10, e->frequency * 8 / 10);
+                 (likely_target, e->count.apply_scale (8, 10));
              }
          }
       if (update)
-       inline_update_overall_summary (n);
+       ipa_update_overall_fn_summary (n);
     }
   if (warn_suggest_final_methods || warn_suggest_final_types)
     {
@@ -3846,10 +3769,10 @@ ipa_devirt (void)
              {
                tree type = final_warning_records->type_warnings[i].type;
                int count = final_warning_records->type_warnings[i].count;
-               long long dyn_count
+               profile_count dyn_count
                  = final_warning_records->type_warnings[i].dyn_count;
 
-               if (!dyn_count)
+               if (!(dyn_count > 0))
                  warning_n (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
                             OPT_Wsuggest_final_types, count,
                             "Declaring type %qD final "
@@ -3869,13 +3792,13 @@ ipa_devirt (void)
                             "executed %lli times",
                             type,
                             count,
-                            dyn_count);
+                            (long long) dyn_count.to_gcov_type ());
              }
        }
 
       if (warn_suggest_final_methods)
        {
-         vec<const decl_warn_count*> decl_warnings_vec = vNULL;
+         auto_vec<const decl_warn_count*> decl_warnings_vec;
 
          final_warning_records->decl_warnings.traverse
            <vec<const decl_warn_count *> *, add_decl_warning> (&decl_warnings_vec);
@@ -3884,9 +3807,10 @@ ipa_devirt (void)
            {
              tree decl = decl_warnings_vec[i]->decl;
              int count = decl_warnings_vec[i]->count;
-             long long dyn_count = decl_warnings_vec[i]->dyn_count;
+             profile_count dyn_count
+                 = decl_warnings_vec[i]->dyn_count;
 
-             if (!dyn_count)
+             if (!(dyn_count > 0))
                if (DECL_CXX_DESTRUCTOR_P (decl))
                  warning_n (DECL_SOURCE_LOCATION (decl),
                              OPT_Wsuggest_final_methods, count,
@@ -3912,7 +3836,8 @@ ipa_devirt (void)
                              "Declaring virtual destructor of %qD final "
                              "would enable devirtualization of %i calls "
                              "executed %lli times",
-                             DECL_CONTEXT (decl), count, dyn_count);
+                             DECL_CONTEXT (decl), count,
+                             (long long)dyn_count.to_gcov_type ());
                else
                  warning_n (DECL_SOURCE_LOCATION (decl),
                              OPT_Wsuggest_final_methods, count,
@@ -3922,10 +3847,11 @@ ipa_devirt (void)
                              "Declaring method %qD final "
                              "would enable devirtualization of %i calls "
                              "executed %lli times",
-                             decl, count, dyn_count);
+                             decl, count,
+                             (long long)dyn_count.to_gcov_type ());
            }
        }
-       
+
       delete (final_warning_records);
       final_warning_records = 0;
     }