]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree.c (type_in_anonymous_namespace_p): Ignore TREE_PUBLIC on builtin types.
authorJan Hubicka <hubicka@ucw.cz>
Sat, 12 Jul 2014 15:34:45 +0000 (17:34 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 12 Jul 2014 15:34:45 +0000 (15:34 +0000)
* tree.c (type_in_anonymous_namespace_p): Ignore TREE_PUBLIC
on builtin types.
* ipa-devirt.c: Include stor-layout.h and intl.h
(odr_subtypes_equivalent_p): New function.
(warn_odr): New function.
(warn_type_mismatch): New function.
(odr_types_equivalent_p): New function.
(add_type_duplicate): Use it.
* common.opt (Wodr): New flag.
* doc/invoke.texi (Wodr): Document new warning.

From-SVN: r212481

gcc/ChangeLog
gcc/common.opt
gcc/doc/invoke.texi
gcc/ipa-devirt.c
gcc/tree.c

index 4545ca26173b47e4dd8613664a8efba04da041d0..1f32bf02ff59c7a0f96b5a589613c9a33868e1f5 100644 (file)
@@ -1,3 +1,16 @@
+2014-07-12  Jan Hubicka  <hubicka@ucw.cz>
+
+       * tree.c (type_in_anonymous_namespace_p): Ignore TREE_PUBLIC
+       on builtin types.
+       * ipa-devirt.c: Include stor-layout.h and intl.h
+       (odr_subtypes_equivalent_p): New function.
+       (warn_odr): New function.
+       (warn_type_mismatch): New function.
+       (odr_types_equivalent_p): New function.
+       (add_type_duplicate): Use it.
+       * common.opt (Wodr): New flag.
+       * doc/invoke.texi (Wodr): Document new warning.
+
 2014-07-12  Jan Hubicka  <hubicka@ucw.cz>
 
        * timevar.def (TV_IPA_LTO_DECL_INIT_IO): Remove.
index e9ceab165513704fbdd6b1ba929f46c63253d04a..a385ee03010ff7ed7135a799374becfe3ea5aed7 100644 (file)
@@ -587,6 +587,10 @@ Warn if the loop cannot be optimized due to nontrivial assumptions.
 Wmissing-noreturn
 Common Alias(Wsuggest-attribute=noreturn)
 
+Wodr
+Common Warning
+Warn about some C++ One Definition Rule violations during link time optimization
+
 Woverflow
 Common Var(warn_overflow) Init(1) Warning
 Warn about overflow in arithmetic expressions
index 029ee854af180690a64ca82eaf198d98ff5a6c68..4807ffc4f09d94871a8594d398293c222c56d637 100644 (file)
@@ -260,7 +260,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
 -Wmain -Wmaybe-uninitialized -Wmissing-braces  -Wmissing-field-initializers @gol
 -Wmissing-include-dirs @gol
--Wno-multichar  -Wnonnull  -Wno-overflow -Wopenmp-simd @gol
+-Wno-multichar  -Wnonnull  -Wodr  -Wno-overflow  -Wopenmp-simd @gol
 -Woverlength-strings  -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
 -Wparentheses  -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
 -Wpointer-arith  -Wno-pointer-to-int-cast @gol
@@ -4915,6 +4915,12 @@ attribute.
 @opindex Woverflow
 Do not warn about compile-time overflow in constant expressions.
 
+@opindex Wodr
+@opindex Wno-odr
+@opindex Wodr
+Warn about One Definition Rule violations during link time optimization.
+Require @option{-flto-odr-type-merging} to be enabled. Enabled by default
+
 @item -Wopenmp-simd
 @opindex Wopenm-simd
 Warn if the vectorizer cost model overrides the OpenMP or the Cilk Plus
index 82b064bbe6d00dbf53db7ed9bcf66af8cc3eb83e..1a0837b1a60aafe67157515d46cfeb9499453ac1 100644 (file)
@@ -130,6 +130,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "demangle.h"
 #include "dbgcnt.h"
+#include "stor-layout.h"
+#include "intl.h"
+
+static bool odr_types_equivalent_p (tree, tree, bool, bool *, pointer_set_t *);
 
 static bool odr_violation_reported = false;
 
@@ -431,6 +435,498 @@ set_type_binfo (tree type, tree binfo)
       gcc_assert (!TYPE_BINFO (type));
 }
 
+/* Compare T2 and T2 based on name or structure.  */
+
+static bool
+odr_subtypes_equivalent_p (tree t1, tree t2, pointer_set_t *visited)
+{
+  bool an1, an2;
+
+  /* This can happen in incomplete types that should be handled earlier.  */
+  gcc_assert (t1 && t2);
+
+  t1 = main_odr_variant (t1);
+  t2 = main_odr_variant (t2);
+  if (t1 == t2)
+    return true;
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    return false;
+  if ((TYPE_NAME (t1) == NULL_TREE) != (TYPE_NAME (t2) == NULL_TREE))
+    return false;
+  if (TYPE_NAME (t1) && DECL_NAME (TYPE_NAME (t1)) != DECL_NAME (TYPE_NAME (t2)))
+    return false;
+
+  /* Anonymous namespace types must match exactly.  */
+  an1 = type_in_anonymous_namespace_p (t1);
+  an2 = type_in_anonymous_namespace_p (t2);
+  if (an1 != an2 || an1)
+    return false;
+
+  /* For types where we can not establish ODR equivalency, recurse and deeply
+     compare.  */
+  if (TREE_CODE (t1) != RECORD_TYPE
+      || !TYPE_BINFO (t1) || !TYPE_BINFO (t2)
+      || !polymorphic_type_binfo_p (TYPE_BINFO (t1))
+      || !polymorphic_type_binfo_p (TYPE_BINFO (t2)))
+    {
+      /* This should really be a pair hash, but for the moment we do not need
+        100% reliability and it would be better to compare all ODR types so
+        recursion here is needed only for component types.  */
+      if (pointer_set_insert (visited, t1))
+       return true;
+      return odr_types_equivalent_p (t1, t2, true, NULL, visited);
+    }
+  return types_same_for_odr (t1, t2);
+}
+
+/* Output ODR violation warning about T1 and T2 with REASON.
+   Display location of ST1 and ST2 if REASON speaks about field or
+   method of the type.
+   If WARN is false, do nothing. Set WARNED if warning was indeed
+   output.  */
+
+void
+warn_odr (tree t1, tree t2, tree st1, tree st2,
+         bool warn, bool *warned, const char *reason)
+{
+  tree decl2 = TYPE_NAME (t2);
+
+  if (!warn)
+    return;
+  if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
+                  "type %qT violates one definition rule",
+                  t1))
+    return;
+  if (!st1)
+    ;
+  else if (TREE_CODE (st1) == FIELD_DECL)
+    {
+      inform (DECL_SOURCE_LOCATION (decl2),
+             "a different type is defined in another translation unit");
+      inform (DECL_SOURCE_LOCATION (st1),
+             "the first difference of corresponding definitions is field %qD",
+             st1);
+      decl2 = st2;
+    }
+  else if (TREE_CODE (st1) == FUNCTION_DECL)
+    {
+      inform (DECL_SOURCE_LOCATION (decl2),
+             "a different type is defined in another translation unit");
+      inform (DECL_SOURCE_LOCATION (st1),
+             "the first difference of corresponding definitions is method %qD",
+             st1);
+      decl2 = st2;
+    }
+  else
+    return;
+  inform (DECL_SOURCE_LOCATION (decl2), reason);
+
+  if (warned)
+    *warned = true;
+}
+
+/* We already warned about ODR mismatch.  T1 and T2 ought to be equivalent
+   because they are used on same place in ODR matching types.
+   They are not; inform the user.  */
+
+void
+warn_types_mismatch (tree t1, tree t2)
+{
+  if (!TYPE_NAME (t1) || !TYPE_NAME (t2))
+    return;
+  /* In Firefox it is a common bug to have same types but in
+     different namespaces.  Be a bit more informative on
+     this.  */
+  if (TYPE_CONTEXT (t1) && TYPE_CONTEXT (t2)
+      && (((TREE_CODE (TYPE_CONTEXT (t1)) == NAMESPACE_DECL)
+           != (TREE_CODE (TYPE_CONTEXT (t2)) == NAMESPACE_DECL))
+          || (TREE_CODE (TYPE_CONTEXT (t1)) == NAMESPACE_DECL
+              && (DECL_NAME (TYPE_CONTEXT (t1)) !=
+                  DECL_NAME (TYPE_CONTEXT (t2))))))
+    inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)),
+           "type %qT should match type %qT but is defined "
+           "in different namespace  ",
+           t1, t2);
+  else
+    inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)),
+           "type %qT should match type %qT",
+           t1, t2);
+  inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)),
+         "the incompatible type is defined here");
+}
+
+/* Compare T1 and T2, report ODR violations if WARN is true and set
+   WARNED to true if anything is reported.  Return true if types match.
+   If true is returned, the types are also compatible in the sense of
+   gimple_canonical_types_compatible_p.  */
+
+static bool
+odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, pointer_set_t *visited)
+{
+  /* Check first for the obvious case of pointer identity.  */
+  if (t1 == t2)
+    return true;
+  gcc_assert (!type_in_anonymous_namespace_p (t1));
+  gcc_assert (!type_in_anonymous_namespace_p (t2));
+
+  /* Can't be the same type if the types don't have the same code.  */
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+               G_("a different type is defined in another translation unit"));
+      return false;
+    }
+
+  if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+               G_("a type with different qualifiers is defined in another "
+                  "translation unit"));
+      return false;
+    }
+
+  if (comp_type_attributes (t1, t2) != 1)
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+               G_("a type with attributes "
+                  "is defined in another translation unit"));
+      return false;
+    }
+
+  if (TREE_CODE (t1) == ENUMERAL_TYPE)
+    {
+      tree v1, v2;
+      for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2);
+          v1 && v2 ; v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2))
+       {
+         if (TREE_PURPOSE (v1) != TREE_PURPOSE (v2))
+           {
+             warn_odr (t1, t2, NULL, NULL, warn, warned,
+                       G_("an enum with different value name"
+                          " is defined in another translation unit"));
+             return false;
+           }
+         if (TREE_VALUE (v1) != TREE_VALUE (v2)
+             && !operand_equal_p (DECL_INITIAL (TREE_VALUE (v1)),
+                                  DECL_INITIAL (TREE_VALUE (v2)), 0))
+           {
+             warn_odr (t1, t2, NULL, NULL, warn, warned,
+                       G_("an enum with different values is defined"
+                          " in another translation unit"));
+             return false;
+           }
+       }
+      if (v1 || v2)
+       {
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("an enum with mismatching number of values "
+                      "is defined in another translation unit"));
+         return false;
+       }
+    }
+
+  /* Non-aggregate types can be handled cheaply.  */
+  if (INTEGRAL_TYPE_P (t1)
+      || SCALAR_FLOAT_TYPE_P (t1)
+      || FIXED_POINT_TYPE_P (t1)
+      || TREE_CODE (t1) == VECTOR_TYPE
+      || TREE_CODE (t1) == COMPLEX_TYPE
+      || TREE_CODE (t1) == OFFSET_TYPE
+      || POINTER_TYPE_P (t1))
+    {
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
+       {
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("a type with different precision is defined "
+                      "in another translation unit"));
+         return false;
+       }
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+       {
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("a type with different signedness is defined "
+                      "in another translation unit"));
+         return false;
+       }
+
+      if (TREE_CODE (t1) == INTEGER_TYPE
+         && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
+       {
+         /* char WRT uint_8?  */
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("a different type is defined in another "
+                      "translation unit"));
+         return false;
+       }
+
+      /* For canonical type comparisons we do not want to build SCCs
+        so we cannot compare pointed-to types.  But we can, for now,
+        require the same pointed-to type kind and match what
+        useless_type_conversion_p would do.  */
+      if (POINTER_TYPE_P (t1))
+       {
+         if (TYPE_ADDR_SPACE (TREE_TYPE (t1))
+             != TYPE_ADDR_SPACE (TREE_TYPE (t2)))
+           {
+             warn_odr (t1, t2, NULL, NULL, warn, warned,
+                       G_("it is defined as a pointer in different address "
+                          "space in another translation unit"));
+             return false;
+           }
+
+         if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+           {
+             warn_odr (t1, t2, NULL, NULL, warn, warned,
+                       G_("it is defined as a pointer to different type "
+                          "in another translation unit"));
+             if (warn && warned)
+               warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+             return false;
+           }
+       }
+
+      /* Tail-recurse to components.  */
+      if ((TREE_CODE (t1) == VECTOR_TYPE || TREE_CODE (t1) == COMPLEX_TYPE)
+         && !odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+       {
+         /* Probably specific enough.  */
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("a different type is defined "
+                      "in another translation unit"));
+         if (warn && warned)
+           warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+         return false;
+       }
+
+      gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+      gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+                                  TYPE_SIZE_UNIT (t2), 0));
+      gcc_assert (TYPE_MODE (t1) == TYPE_MODE (t2));
+
+      return true;
+    }
+
+  /* Do type-specific comparisons.  */
+  switch (TREE_CODE (t1))
+    {
+    case ARRAY_TYPE:
+      {
+       /* Array types are the same if the element types are the same and
+          the number of elements are the same.  */
+       if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+         {
+           warn_odr (t1, t2, NULL, NULL, warn, warned,
+                     G_("a different type is defined in another "
+                        "translation unit"));
+           if (warn && warned)
+             warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+         }
+       gcc_assert (TYPE_STRING_FLAG (t1) == TYPE_STRING_FLAG (t2));
+       gcc_assert (TYPE_NONALIASED_COMPONENT (t1)
+                   == TYPE_NONALIASED_COMPONENT (t2));
+
+       tree i1 = TYPE_DOMAIN (t1);
+       tree i2 = TYPE_DOMAIN (t2);
+
+       /* For an incomplete external array, the type domain can be
+          NULL_TREE.  Check this condition also.  */
+       if (i1 == NULL_TREE || i2 == NULL_TREE)
+         return true;
+
+       tree min1 = TYPE_MIN_VALUE (i1);
+       tree min2 = TYPE_MIN_VALUE (i2);
+       tree max1 = TYPE_MAX_VALUE (i1);
+       tree max2 = TYPE_MAX_VALUE (i2);
+
+       /* In C++, minimums should be always 0.  */
+       gcc_assert (min1 == min2);
+       if (!operand_equal_p (max1, max2, 0))
+         {
+           warn_odr (t1, t2, NULL, NULL, warn, warned,
+                     G_("an array of different size is defined "
+                        "in another translation unit"));
+           return false;
+         }
+       gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+       gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+                                    TYPE_SIZE_UNIT (t2), 0));
+      }
+      return true;
+
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+      /* Function types are the same if the return type and arguments types
+        are the same.  */
+      if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), visited))
+       {
+         warn_odr (t1, t2, NULL, NULL, warn, warned,
+                   G_("has different return value "
+                      "in another translation unit"));
+         if (warn && warned)
+           warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2));
+         return false;
+       }
+
+      if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2))
+       return true;
+      else
+       {
+         tree parms1, parms2;
+
+         for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2);
+              parms1 && parms2;
+              parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2))
+           {
+             if (!odr_subtypes_equivalent_p
+                    (TREE_VALUE (parms1), TREE_VALUE (parms2), visited))
+               {
+                 warn_odr (t1, t2, NULL, NULL, warn, warned,
+                           G_("has different parameters in another "
+                              "translation unit"));
+                 if (warn && warned)
+                   warn_types_mismatch (TREE_VALUE (parms1),
+                                        TREE_VALUE (parms2));
+                 return false;
+               }
+           }
+
+         if (parms1 || parms2)
+           {
+             warn_odr (t1, t2, NULL, NULL, warn, warned,
+                       G_("has different parameters "
+                          "in another translation unit"));
+             return false;
+           }
+
+         return true;
+       }
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       tree f1, f2;
+
+       /* For aggregate types, all the fields must be the same.  */
+       if (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2))
+         {
+           for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2);
+                f1 || f2;
+                f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
+             {
+               /* Skip non-fields.  */
+               while (f1 && TREE_CODE (f1) != FIELD_DECL)
+                 f1 = TREE_CHAIN (f1);
+               while (f2 && TREE_CODE (f2) != FIELD_DECL)
+                 f2 = TREE_CHAIN (f2);
+               if (!f1 || !f2)
+                 break;
+               if (DECL_ARTIFICIAL (f1) != DECL_ARTIFICIAL (f2))
+                 break;
+               if (DECL_NAME (f1) != DECL_NAME (f2)
+                   && !DECL_ARTIFICIAL (f1))
+                 {
+                   warn_odr (t1, t2, f1, f2, warn, warned,
+                             G_("a field with different name is defined "
+                                "in another translation unit"));
+                   return false;
+                 }
+               if (!odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited))
+                 {
+                   /* Do not warn about artificial fields and just go into generic
+                      field mismatch warning.  */
+                   if (DECL_ARTIFICIAL (f1))
+                     break;
+
+                   warn_odr (t1, t2, f1, f2, warn, warned,
+                             G_("a field of same name but different type "
+                                "is defined in another translation unit"));
+                   if (warn && warned)
+                     warn_types_mismatch (TREE_TYPE (f1), TREE_TYPE (f2));
+                   return false;
+                 }
+               if (!gimple_compare_field_offset (f1, f2))
+                 {
+                   /* Do not warn about artificial fields and just go into generic
+                      field mismatch warning.  */
+                   if (DECL_ARTIFICIAL (f1))
+                     break;
+                   warn_odr (t1, t2, t1, t2, warn, warned,
+                             G_("fields has different layout "
+                                "in another translation unit"));
+                   return false;
+                 }
+               gcc_assert (DECL_NONADDRESSABLE_P (f1)
+                           == DECL_NONADDRESSABLE_P (f2));
+             }
+
+           /* If one aggregate has more fields than the other, they
+              are not the same.  */
+           if (f1 || f2)
+             {
+               warn_odr (t1, t2, NULL, NULL, warn, warned,
+                         G_("a type with different number of fields "
+                            "is defined in another translation unit"));
+               return false;
+             }
+           if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2)
+               && (TYPE_METHODS (TYPE_MAIN_VARIANT (t1))
+                   != TYPE_METHODS (TYPE_MAIN_VARIANT (t2))))
+             {
+               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))
+                     {
+                       warn_odr (t1, t2, f1, f2, warn, warned,
+                                 G_("method with incompatible type is defined "
+                                    "in another translation unit"));
+                       return false;
+                     }
+                 }
+               if (f1 || f2)
+                 {
+                   warn_odr (t1, t2, NULL, NULL, warn, warned,
+                             G_("a type with different number of methods "
+                                "is defined in another translation unit"));
+                   return false;
+                 }
+             }
+           gcc_assert (operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0));
+           gcc_assert (operand_equal_p (TYPE_SIZE_UNIT (t1),
+                                        TYPE_SIZE_UNIT (t2), 0));
+         }
+
+       return true;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* TYPE is equivalent to VAL by ODR, but its tree representation differs
    from VAL->type.  This may happen in LTO where tree merging did not merge
    all variants of the same type.  It may or may not mean the ODR violation.
@@ -459,31 +955,23 @@ add_type_duplicate (odr_type val, tree type)
     {
       bool merge = true;
       bool base_mismatch = false;
-      bool warned = 0;
       unsigned int i,j;
+      bool warned = false;
+      pointer_set_t *visited = pointer_set_create ();
 
       gcc_assert (in_lto_p);
       vec_safe_push (val->types, type);
 
       /* First we compare memory layout.  */
-      if (!types_compatible_p (val->type, type))
+      if (!odr_types_equivalent_p (val->type, type, !flag_ltrans && !val->odr_violated,
+                                  &warned, visited))
        {
          merge = false;
          odr_violation_reported = true;
-         if (BINFO_VTABLE (TYPE_BINFO (val->type))
-             && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
-                            "type %qD violates one definition rule  ",
-                            type))
-           {
-             inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
-                     "a type with the same name but different layout is "
-                     "defined in another translation unit");
-             warned = true;
-           }
          val->odr_violated = true;
          if (cgraph_dump_file)
            {
-             fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n");
+             fprintf (cgraph_dump_file, "ODR violation\n");
            
              print_node (cgraph_dump_file, "", val->type, 0);
              putc ('\n',cgraph_dump_file);
@@ -491,6 +979,7 @@ add_type_duplicate (odr_type val, tree type)
              putc ('\n',cgraph_dump_file);
            }
        }
+      pointer_set_destroy (visited);
 
       /* Next sanity check that bases are the same.  If not, we will end
         up producing wrong answers.  */
@@ -516,13 +1005,10 @@ add_type_duplicate (odr_type val, tree type)
              merge = false;
              odr_violation_reported = true;
 
-             if (!warned
-                 && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
-                                "type %qD violates one definition rule  ",
-                                type))
-               inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
-                       "a type with the same name but different bases is "
-                       "defined in another translation unit");
+             if (!warned && !val->odr_violated)
+               warn_odr (type, val->type, NULL, NULL, !warned, &warned,
+                         "a type with the same name but different bases is "
+                         "defined in another translation unit");
              val->odr_violated = true;
              if (cgraph_dump_file)
                {
@@ -625,7 +1111,6 @@ get_odr_type (tree type, bool insert)
     }
   else
     {
-
       val = ggc_cleared_alloc<odr_type_d> ();
       val->type = type;
       val->bases = vNULL;
index a8b2fd53f8932c15d7839061a4fdc1a9ff6a4ca8..46f896362318048adee2098b3fdf4a4431db33dc 100644 (file)
@@ -11864,6 +11864,10 @@ obj_type_ref_class (tree ref)
 bool
 type_in_anonymous_namespace_p (const_tree t)
 {
+  /* TREE_PUBLIC of TYPE_STUB_DECL may not be properly set for
+     bulitin types; those have CONTEXT NULL.  */
+  if (!TYPE_CONTEXT (t))
+    return false;
   return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
 }