https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63226

--- Comment #4 from Jan Hubicka <hubicka at ucw dot cz> ---
Hi,
this is patch I am testing.  It fixes few issues in the ODR comparsions code
and seems to handle this testcase sanely.

Honza

Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c    (revision 215196)
+++ ipa-devirt.c    (working copy)
@@ -136,8 +136,44 @@ along with GCC; see the file COPYING3.
 #include "intl.h"
 #include "hash-map.h"

+/* Hash based set of pairs of types.  */
+typedef struct
+{
+  tree first;
+  tree second;
+} type_pair;
+
+struct pair_traits : default_hashset_traits
+{
+  static hashval_t
+  hash (type_pair p)
+  {
+    return TYPE_UID (p.first) ^ TYPE_UID (p.second);
+  }
+  static bool
+  is_empty (type_pair p)
+  {
+    return p.first == NULL;
+  }
+  static bool
+  is_deleted (type_pair p ATTRIBUTE_UNUSED)
+    {
+      return false;
+    }
+  static bool
+  equal (const type_pair &a, const type_pair &b)
+    {
+      return a.first==b.first && a.second == b.second;
+    }
+  static void
+  mark_empty (type_pair &e)
+    {
+      e.first = NULL;
+    }
+};
+
 static bool odr_types_equivalent_p (tree, tree, bool, bool *,
-                    hash_set<tree> *);
+                    hash_set<type_pair,pair_traits> *);

 static bool odr_violation_reported = false;

@@ -471,7 +507,7 @@ set_type_binfo (tree type, tree binfo)
 /* Compare T2 and T2 based on name or structure.  */

 static bool
-odr_subtypes_equivalent_p (tree t1, tree t2, hash_set<tree> *visited)
+odr_subtypes_equivalent_p (tree t1, tree t2, hash_set<type_pair,pair_traits>
*visited)
 {
   bool an1, an2;

@@ -489,29 +525,39 @@ odr_subtypes_equivalent_p (tree t1, tree
   if (an1 != an2 || an1)
     return false;

-  /* For types where we can not establish ODR equivalency (either by ODR names
-     or by virtual tables), recurse and deeply compare.  */
-  if ((!odr_type_p (t1) || !odr_type_p (t2))
-      && (TREE_CODE (t1) != RECORD_TYPE || TREE_CODE (t2) != RECORD_TYPE
-          || !TYPE_BINFO (t1) || !TYPE_BINFO (t2)
-          || !polymorphic_type_binfo_p (TYPE_BINFO (t1))
-          || !polymorphic_type_binfo_p (TYPE_BINFO (t2))))
+  /* For ODR types be sure to compare their names.  */
+  if ((odr_type_p (t1) && !odr_type_p (t2))
+      || (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE
+          && TYPE_BINFO (t1) && TYPE_BINFO (t2)
+          && polymorphic_type_binfo_p (TYPE_BINFO (t1))
+          && polymorphic_type_binfo_p (TYPE_BINFO (t2))))
     {
-      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;
-      /* 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 (visited->add (t1))
-    return true;
-      return odr_types_equivalent_p (t1, t2, false, NULL, visited);
+      if (!types_same_for_odr (t1, t2))
+        return false;
+      /* Limit recursion: If subtypes are ODR types and we know
+         that they are same, be happy.  */
+      if (!get_odr_type (t1, true)->odr_violated)
+        return true;
     }

-  return types_same_for_odr (t1, t2);
+  /* Component types, builtins and possibly vioalting ODR types
+     have to be compared structurally.  */
+  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;
+
+  type_pair pair={t1,t2};
+  if (TYPE_UID (t1) > TYPE_UID (t2))
+    {
+      pair.first = t2;
+      pair.second = t1;
+    }
+  if (visited->add (pair))
+    return true;
+  return odr_types_equivalent_p (t1, t2, false, NULL, visited);
 }

 /* Compare two virtual tables, PREVAILING and VTABLE and output ODR
@@ -646,16 +692,25 @@ warn_odr (tree t1, tree t2, tree st1, tr
            "type %qT violates one definition rule",
            t1))
     return;
-  if (!st1)
+  if (!st1 && !st2)
     ;
-  else if (TREE_CODE (st1) == FIELD_DECL)
+  /* For FIELD_DECL support also case where one of fields is
+     NULL - this is used when the structures have mismatching number of
+     elements.  */
+  else if (!st1 || TREE_CODE (st1) == FIELD_DECL)
     {
       inform (DECL_SOURCE_LOCATION (decl2),
           "a different type is defined in another translation unit");
+      if (!st1)
+    {
+      st1 = st2;
+      st2 = NULL;
+    }
       inform (DECL_SOURCE_LOCATION (st1),
           "the first difference of corresponding definitions is field %qD",
           st1);
-      decl2 = st2;
+      if (st2)
+        decl2 = st2;
     }
   else if (TREE_CODE (st1) == FUNCTION_DECL)
     {
@@ -710,7 +765,7 @@ warn_types_mismatch (tree t1, tree t2)
    gimple_canonical_types_compatible_p.  */

 static bool
-odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
hash_set<tree> *visited)
+odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
hash_set<type_pair,pair_traits> *visited)
 {
   /* Check first for the obvious case of pointer identity.  */
   if (t1 == t2)
@@ -834,7 +889,6 @@ odr_types_equivalent_p (tree t1, tree t2
         }
     }

-      /* 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))
     {
@@ -846,17 +900,9 @@ odr_types_equivalent_p (tree t1, tree t2
         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))
+  else switch (TREE_CODE (t1))
     {
     case ARRAY_TYPE:
       {
@@ -896,11 +942,8 @@ odr_types_equivalent_p (tree t1, tree t2
              "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;
+    break;

     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -1013,9 +1056,20 @@ odr_types_equivalent_p (tree t1, tree t2
            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"));
+        if (f1 && DECL_ARTIFICIAL (f1))
+          f1 = NULL;
+        if (f2 && DECL_ARTIFICIAL (f2))
+          f2 = NULL;
+        if (f1 || f2)
+          warn_odr (t1, t2, f1, f2, warn, warned,
+                G_("a type with different number of fields "
+                   "is defined in another translation unit"));
+        /* Ideally we should never get this generic message.  */
+        else
+          warn_odr (t1, t2, f1, f2, warn, warned,
+                G_("a type with different memory representation "
+                   "is defined in another translation unit"));
+        
         return false;
           }
         if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2)
@@ -1063,17 +1117,35 @@ odr_types_equivalent_p (tree t1, tree 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));
       }
-
-    return true;
+    break;
       }

     default:
       gcc_unreachable ();
     }
+
+  /* Those are better to come last as they are utterly uninformative.  */
+  if (TYPE_SIZE (t1) && TYPE_SIZE (t2)
+      && !operand_equal_p (TYPE_SIZE (t1), TYPE_SIZE (t2), 0))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+        G_("a type with different size "
+           "is defined in another translation unit"));
+      return false;
+    }
+  if (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)
+      && TYPE_ALIGN (t1) != TYPE_ALIGN (t2))
+    {
+      warn_odr (t1, t2, NULL, NULL, warn, warned,
+        G_("a type with different alignment "
+           "is defined in another translation unit"));
+      return false;
+    }
+  gcc_assert (!TYPE_SIZE_UNIT (t1) || !TYPE_SIZE_UNIT (t2)
+          || operand_equal_p (TYPE_SIZE_UNIT (t1),
+                  TYPE_SIZE_UNIT (t2), 0));
+  return true;
 }

 /* TYPE is equivalent to VAL by ODR, but its tree representation differs
@@ -1106,7 +1178,7 @@ add_type_duplicate (odr_type val, tree t
       bool base_mismatch = false;
       unsigned int i,j;
       bool warned = false;
-      hash_set<tree> visited;
+      hash_set<type_pair,pair_traits> visited;

       gcc_assert (in_lto_p);
       vec_safe_push (val->types, type);

Reply via email to