Hi,
this patch adds bare bones of type checker.  You can call verify_type on any
type in the IL and see compiler bomb if some of invariants are broken.  So far
it only verify tests I already tested in last stage1 with my reverted variant
streaming patch https://gcc.gnu.org/ml/gcc-patches/2014-06/msg02454.html

The checks found interesting problems that was fixed. I have other tests and
fixes but would like to go incrementally.  Some of tests already broke again
with recent C++ align attribute changes (I think), see FIXME comments.
I plan to proceed with small steps becuase all the checks seems to trigger
fun issues.

The patch still fix on bug in ipa-chkp.c that is obvious enough - it is
cut&pasted from old code in cgraphunit.c that was updated same way.

I hope with early debug we are on the track of getting simplified gimple types,
but to make this without hitting too many surprises I think we first want to
document and verify our FE type representation and also verify what we need
in middle-end and drop the rest (in free lang data).

Placement of verify_type calls may seem bit random. Basic idea is to verify that
bad types do not hit LTO and are not produced by LTO type merging. In non-LTO 
path
we verify types at dwarf2out that is major consumer of the type variants.
I would be happy to place more calls/relocate existing to better places.

LTO-Boostrapped/regtested x86_64-linux without Ada. I am doing full run on
PPC64, but it fails on unrelated libgmp miscomplation I proably need to track 
down
first.

OK if testing passes?

Honza

        * tree.c: Include print-tree.h
        (verify_type_variant): New function.
        (verify_type): New function.
        * tree.h (verify_type): Declare.
        * tree-streamer-out.c (write_ts_type_common_tree_pointers): Verify type.
        * dwarf2out.c (dwarf2out_decl): Verify type.
        * ipa-chkp.c (chkp_copy_function_type_adding_bounds): Do not consider
        updated type to be variant.

        * lto.c (lto_fixup_state): Verify types.
Index: tree.c
===================================================================
--- tree.c      (revision 222391)
+++ tree.c      (working copy)
@@ -102,6 +102,7 @@ along with GCC; see the file COPYING3.
 #include "debug.h"
 #include "intl.h"
 #include "builtins.h"
+#include "print-tree.h"
 
 /* Tree code classes.  */
 
@@ -12425,4 +12437,124 @@ element_mode (const_tree t)
   return TYPE_MODE (t);
 }
 
+/* Veirfy that basic properties of T match TV and thus T can be a variant of
+   TV.  TV should be the more specified variant (i.e. the main variant).  */
+
+static bool
+verify_type_variant (const_tree t, tree tv)
+{
+  if (TREE_CODE (t) != TREE_CODE (tv))
+    {
+      error ("type variant has different TREE_CODE");
+      debug_tree (tv);
+      return false;
+    }
+  if (COMPLETE_TYPE_P (t) && TYPE_SIZE (t) != TYPE_SIZE (tv))
+    {
+      error ("type variant has different TYPE_SIZE");
+      debug_tree (tv);
+      return false;
+    }
+  if (COMPLETE_TYPE_P (t) && TYPE_SIZE_UNIT (t) != TYPE_SIZE_UNIT (tv))
+    {
+      error ("type variant has different TYPE_SIZE_UNIT");
+      debug_tree (tv);
+      return false;
+    }
+  if (RECORD_OR_UNION_TYPE_P (t) && TYPE_VFIELD (t) != TYPE_VFIELD (tv))
+    {
+      error ("type variant has different TYPE_VFIELD");
+      debug_tree (tv);
+      return false;
+    }
+  if (((TREE_CODE (t) == ENUMERAL_TYPE && COMPLETE_TYPE_P (t))
+       || TREE_CODE (t) == INTEGER_TYPE
+       || TREE_CODE (t) == BOOLEAN_TYPE
+       || TREE_CODE (t) == REAL_TYPE
+       || TREE_CODE (t) == FIXED_POINT_TYPE)
+       && (TYPE_MAX_VALUE (t) != TYPE_MAX_VALUE (tv)
+          || TYPE_MAX_VALUE (t) != TYPE_MAX_VALUE (tv)))
+    {
+      error ("type variant has different TYPE_MIN_VALUE");
+      debug_tree (tv);
+      return false;
+    }
+  if (TREE_CODE (t) == METHOD_TYPE
+      && TYPE_METHOD_BASETYPE (t) != TYPE_METHOD_BASETYPE (tv))
+    {
+      error ("type variant has different TYPE_METHOD_BASETYPE");
+      debug_tree (tv);
+      return false;
+    }
+  /* FIXME: Be lax and allow TYPE_METHODS to be NULL.  This is a bug
+     but affecting only the debug output.  */
+  if (RECORD_OR_UNION_TYPE_P (t) && COMPLETE_TYPE_P (t)
+      && TYPE_METHODS (t) && TYPE_METHODS (tv)
+      && TYPE_METHODS (t) != TYPE_METHODS (tv))
+    {
+      error ("type variant has different TYPE_METHODS");
+      debug_tree (tv);
+      return false;
+    }
+  if (TREE_CODE (t) == OFFSET_TYPE
+      && TYPE_OFFSET_BASETYPE (t) != TYPE_OFFSET_BASETYPE (tv))
+    {
+      error ("type variant has different TYPE_OFFSET_BASETYPE");
+      debug_tree (tv);
+      return false;
+    }
+  if (TREE_CODE (t) == ARRAY_TYPE
+      && TYPE_ARRAY_MAX_SIZE (t) != TYPE_ARRAY_MAX_SIZE (tv))
+    {
+      error ("type variant has different TYPE_ARRAY_MAX_SIZE");
+      debug_tree (tv);
+      return false;
+    }
+  /* FIXME: Be lax and allow TYPE_BINFO to be missing in variant types
+     or even type's main variant.  This is needed to make bootstrap pass
+     and the bug seems new in GCC 5.
+     C++ FE should be updated to make this consistent and we should check
+     that TYPE_BINFO is always NULL for !COMPLETE_TYPE_P and otherwise there
+     is a match with main variant.  */
+  if (RECORD_OR_UNION_TYPE_P (t) && TYPE_BINFO (t) && TYPE_BINFO (tv)
+      && TYPE_BINFO (t) != TYPE_BINFO (tv))
+    {
+      error ("type variant has different TYPE_BINFO");
+      debug_tree (tv);
+      error ("type variant's TYPE_BINFO");
+      debug_tree (TYPE_BINFO (tv));
+      error ("type's TYPE_BINFO");
+      debug_tree (TYPE_BINFO (tv));
+      return false;
+    }
+  return true;
+}
+
+/* Verify type T.  */
+
+void
+verify_type (const_tree t)
+{
+  bool error_found = false;
+  tree mv = TYPE_MAIN_VARIANT (t);
+  if (!mv)
+    {
+      error ("Main variant is not defined");
+      error_found = true;
+    }
+  else if (mv != TYPE_MAIN_VARIANT (mv))
+    {
+      error ("TYPE_MAIN_VARAINT has different TYPE_MAIN_VARIANT");
+      debug_tree (mv);
+      error_found = true;
+    }
+  else if (t != mv && !verify_type_variant (t, mv))
+    error_found = true;
+  if (error_found)
+    {
+      debug_tree (const_cast <tree> (t));
+      internal_error ("verify_type failed");
+    }
+}
+
 #include "gt-tree.h"
Index: tree.h
===================================================================
--- tree.h      (revision 222391)
+++ tree.h      (working copy)
@@ -4495,6 +4495,7 @@ extern tree drop_tree_overflow (tree);
 extern int tree_map_base_eq (const void *, const void *);
 extern unsigned int tree_map_base_hash (const void *);
 extern int tree_map_base_marked_p (const void *);
+extern void DEBUG_FUNCTION verify_type (const_tree t);
 
 #define tree_map_eq tree_map_base_eq
 extern unsigned int tree_map_hash (const void *);
Index: lto/lto.c
===================================================================
--- lto/lto.c   (revision 222391)
+++ lto/lto.c   (working copy)
@@ -2844,6 +2844,10 @@ lto_fixup_state (struct lto_in_decl_stat
       for (i = 0; i < vec_safe_length (trees); i++)
        {
          tree t = (*trees)[i];
+#ifdef ENABLE_CHECKING
+         if (TYPE_P (t))
+           verify_type (t);
+#endif
          if (VAR_OR_FUNCTION_DECL_P (t)
              && (TREE_PUBLIC (t) || DECL_EXTERNAL (t)))
            (*trees)[i] = lto_symtab_prevailing_decl (t);
Index: tree-streamer-out.c
===================================================================
--- tree-streamer-out.c (revision 222391)
+++ tree-streamer-out.c (working copy)
@@ -721,6 +721,9 @@ static void
 write_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
                                    bool ref_p)
 {
+#ifdef ENABLE_CHECKING
+  verify_type (expr);
+#endif
   stream_write_tree (ob, TYPE_SIZE (expr), ref_p);
   stream_write_tree (ob, TYPE_SIZE_UNIT (expr), ref_p);
   stream_write_tree (ob, TYPE_ATTRIBUTES (expr), ref_p);
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 222391)
+++ dwarf2out.c (working copy)
@@ -21264,6 +21264,11 @@ dwarf2out_decl (tree decl)
 {
   dw_die_ref context_die = comp_unit_die ();
 
+#ifdef ENABLE_CHECKING
+  if (TREE_TYPE (decl))
+     verify_type (TREE_TYPE (decl));
+#endif
+
   switch (TREE_CODE (decl))
     {
     case ERROR_MARK:
Index: ipa-chkp.c
===================================================================
--- ipa-chkp.c  (revision 222391)
+++ ipa-chkp.c  (working copy)
@@ -244,7 +244,7 @@ tree
 chkp_copy_function_type_adding_bounds (tree orig_type)
 {
   tree type;
-  tree arg_type, attrs, t;
+  tree arg_type, attrs;
   unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
   unsigned *indexes = XALLOCAVEC (unsigned, len);
   unsigned idx = 0, new_idx = 0;
@@ -327,20 +327,6 @@ chkp_copy_function_type_adding_bounds (t
       TYPE_ATTRIBUTES (type) = attrs;
     }
 
-  t = TYPE_MAIN_VARIANT (orig_type);
-  if (orig_type != t)
-    {
-      TYPE_MAIN_VARIANT (type) = t;
-      TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
-      TYPE_NEXT_VARIANT (t) = type;
-    }
-  else
-    {
-      TYPE_MAIN_VARIANT (type) = type;
-      TYPE_NEXT_VARIANT (type) = NULL;
-    }
-
-
   return type;
 }
 

Reply via email to