OSDN Git Service

2007-07-26 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 26 Jul 2007 10:27:50 +0000 (10:27 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 26 Jul 2007 10:27:50 +0000 (10:27 +0000)
toplev/
* configure.ac: Add types checking to stage1 checking flags.
* configure: Regenerate.

        gcc/
* tree-cfg.c (verify_gimple_unary_expr, verify_gimple_binary_expr,
verify_gimple_min_lval, verify_gimple_reference, verify_gimple_expr,
verify_gimple_modify_stmt, verify_gimple_stmt, verify_gimple_1,
verify_gimple): New functions.
* tree-flow.h (verify_gimple): Declare.
(verify_gimple_1): Declare.
* gimplify.c (cpt_same_type): Remove.
(gimplify_addr_expr): Remove checking code.
(check_pointer_types_r): Remove.
(gimplify_body): Call verify_gimple_1 instead of check_pointer_types_r.
Only verify if there were no errors.
* configure.ac: Add types checking flag.
* configure: Regenerate.
* config.in: Regenerate.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126951 138bc75d-0d04-0410-961f-82ee72b054a4

ChangeLog
configure
configure.ac
gcc/config.in
gcc/configure
gcc/configure.ac
gcc/gimplify.c
gcc/tree-cfg.c
gcc/tree-flow.h

index 1783220..94ab187 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-07-26  Richard Guenther  <rguenther@suse.de>
+
+       * configure.ac: Add types checking to stage1 checking flags.
+       * configure: Regenerate.
+
 2007-07-17  Nick Clifton  <nickc@redhat.com>
 
        * COPYING3: New file.  Contains version 3 of the GNU General
index 1a43f9e..df74793 100755 (executable)
--- a/configure
+++ b/configure
@@ -11967,9 +11967,9 @@ if test "${enable_stage1_checking+set}" = set; then
   stage1_checking=--enable-checking=${enable_stage1_checking}
 else
   if test "x$enable_checking" = xno; then
-  stage1_checking=--enable-checking
+  stage1_checking=--enable-checking=yes,types
 else
-  stage1_checking=--enable-checking${enable_checking+=}$enable_checking
+  stage1_checking=--enable-checking=types${enable_checking+,}$enable_checking
 fi
 fi;
 
index da88113..2500cc6 100644 (file)
@@ -2593,9 +2593,9 @@ AC_ARG_ENABLE(stage1-checking,
                           of the compiler],
 [stage1_checking=--enable-checking=${enable_stage1_checking}],
 [if test "x$enable_checking" = xno; then
-  stage1_checking=--enable-checking
+  stage1_checking=--enable-checking=yes,types
 else
-  stage1_checking=--enable-checking${enable_checking+=}$enable_checking
+  stage1_checking=--enable-checking=types${enable_checking+,}$enable_checking
 fi])
 AC_SUBST(stage1_checking)
 
index 30b1c42..aba1bb5 100644 (file)
 #endif
 
 
+/* Define if you want all gimple types to be verified after gimplifiation. */
+#ifndef USED_FOR_TARGET
+#undef ENABLE_TYPES_CHECKING
+#endif
+
+
 /* Define if you want to run subprograms and generated programs through
    valgrind (a memory checker). This is extremely expensive. */
 #ifndef USED_FOR_TARGET
index 1b72cdb..376a3e3 100755 (executable)
@@ -868,7 +868,7 @@ Optional Features:
                          enable only specific categories of checks.
                          Categories are: yes,no,all,none,release.
                          Flags are: assert,df,fold,gc,gcac,misc,
-                         rtlflag,rtl,runtime,tree,valgrind.
+                         rtlflag,rtl,runtime,tree,valgrind,types.
   --enable-mapped-location   location_t is fileline integer cookie
   --enable-coverage=LEVEL
                          enable compiler's code coverage collection.
@@ -6429,22 +6429,26 @@ do
                        ac_fold_checking= ; ac_gc_checking=1 ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
-                       ac_tree_checking=1 ; ac_valgrind_checking= ;;
+                       ac_tree_checking=1 ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        no|none)        ac_assert_checking= ; ac_checking= ; ac_df_checking= ;
                        ac_fold_checking= ; ac_gc_checking= ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking= ; ac_runtime_checking= ;
-                       ac_tree_checking= ; ac_valgrind_checking= ;;
+                       ac_tree_checking= ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        all)            ac_assert_checking=1 ; ac_checking=1 ; ac_df_checking=1 ;
                        ac_fold_checking=1 ; ac_gc_checking=1 ;
                        ac_gc_always_collect=1 ; ac_rtl_checking=1 ;
                        ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
-                       ac_tree_checking=1 ; ac_valgrind_checking= ;;
+                       ac_tree_checking=1 ; ac_valgrind_checking= ;
+                       ac_types_checking=1 ;;
        release)        ac_assert_checking=1 ; ac_checking= ; ac_df_checking= ;
                        ac_fold_checking= ; ac_gc_checking= ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking= ; ac_runtime_checking=1 ;
-                       ac_tree_checking= ; ac_valgrind_checking= ;;
+                       ac_tree_checking= ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        # these enable particular checks
        assert)         ac_assert_checking=1 ;;
        df)             ac_df_checking=1 ;;
@@ -6456,6 +6460,7 @@ do
        rtlflag)        ac_rtlflag_checking=1 ;;
        runtime)        ac_runtime_checking=1 ;;
        tree)           ac_tree_checking=1 ;;
+       types)          ac_types_checking=1 ;;
        valgrind)       ac_valgrind_checking=1 ;;
        *)      { { echo "$as_me:$LINENO: error: unknown check category $check" >&5
 echo "$as_me: error: unknown check category $check" >&2;}
@@ -6504,6 +6509,13 @@ _ACEOF
 
   TREEBROWSER=tree-browser.o
 fi
+if test x$ac_types_checking != x ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_TYPES_CHECKING 1
+_ACEOF
+
+fi
 
 if test x$ac_rtl_checking != x ; then
 
index c7b9bc9..b50bba5 100644 (file)
@@ -346,7 +346,7 @@ AC_ARG_ENABLE(checking,
                          enable only specific categories of checks.
                          Categories are: yes,no,all,none,release.
                          Flags are: assert,df,fold,gc,gcac,misc,
-                         rtlflag,rtl,runtime,tree,valgrind.],
+                         rtlflag,rtl,runtime,tree,valgrind,types.],
 [ac_checking_flags="${enableval}"],[
 # Determine the default checks.
 if test x$is_release = x ; then
@@ -363,22 +363,26 @@ do
                        ac_fold_checking= ; ac_gc_checking=1 ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
-                       ac_tree_checking=1 ; ac_valgrind_checking= ;;
+                       ac_tree_checking=1 ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        no|none)        ac_assert_checking= ; ac_checking= ; ac_df_checking= ;
                        ac_fold_checking= ; ac_gc_checking= ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking= ; ac_runtime_checking= ;
-                       ac_tree_checking= ; ac_valgrind_checking= ;;
+                       ac_tree_checking= ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        all)            ac_assert_checking=1 ; ac_checking=1 ; ac_df_checking=1 ;
                        ac_fold_checking=1 ; ac_gc_checking=1 ;
                        ac_gc_always_collect=1 ; ac_rtl_checking=1 ;
                        ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
-                       ac_tree_checking=1 ; ac_valgrind_checking= ;;
+                       ac_tree_checking=1 ; ac_valgrind_checking= ;
+                       ac_types_checking=1 ;;
        release)        ac_assert_checking=1 ; ac_checking= ; ac_df_checking= ;
                        ac_fold_checking= ; ac_gc_checking= ;
                        ac_gc_always_collect= ; ac_rtl_checking= ;
                        ac_rtlflag_checking= ; ac_runtime_checking=1 ;
-                       ac_tree_checking= ; ac_valgrind_checking= ;;
+                       ac_tree_checking= ; ac_valgrind_checking= ;
+                       ac_types_checking= ;;
        # these enable particular checks
        assert)         ac_assert_checking=1 ;;
        df)             ac_df_checking=1 ;;
@@ -390,6 +394,7 @@ do
        rtlflag)        ac_rtlflag_checking=1 ;;
        runtime)        ac_runtime_checking=1 ;;
        tree)           ac_tree_checking=1 ;;
+       types)          ac_types_checking=1 ;;
        valgrind)       ac_valgrind_checking=1 ;;
        *)      AC_MSG_ERROR(unknown check category $check) ;;
        esac
@@ -426,6 +431,12 @@ if test x$ac_tree_checking != x ; then
    ])
   TREEBROWSER=tree-browser.o
 fi
+if test x$ac_types_checking != x ; then
+  AC_DEFINE(ENABLE_TYPES_CHECKING, 1,
+[Define if you want all gimple types to be verified after gimplifiation.
+   This is cheap.
+   ])
+fi
 AC_SUBST(TREEBROWSER)
 if test x$ac_rtl_checking != x ; then
   AC_DEFINE(ENABLE_RTL_CHECKING, 1,
index 4e0e16a..fdf34d1 100644 (file)
@@ -112,9 +112,6 @@ typedef struct gimple_temp_hash_elt
 
 /* Forward declarations.  */
 static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
-#ifdef ENABLE_CHECKING
-static bool cpt_same_type (tree a, tree b);
-#endif
 
 /* Mark X addressable.  Unlike the langhook we expect X to be in gimple
    form and we don't do any syntax checking.  */
@@ -3985,19 +3982,7 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
        tree t_op00 = TREE_TYPE (op00);
 
         if (!useless_type_conversion_p (t_expr, t_op00))
-         {
-#ifdef ENABLE_CHECKING
-           tree t_op0 = TREE_TYPE (op0);
-           gcc_assert (POINTER_TYPE_P (t_expr)
-                       && (cpt_same_type (TREE_TYPE (t_expr), t_op0)
-                           || (TREE_CODE (t_op0) == ARRAY_TYPE
-                               && cpt_same_type (TREE_TYPE (t_expr),
-                                                 TREE_TYPE (t_op0))))
-                       && POINTER_TYPE_P (t_op00)
-                       && cpt_same_type (t_op0, TREE_TYPE (t_op00)));
-#endif
-           op00 = fold_convert (TREE_TYPE (expr), op00);
-         }
+         op00 = fold_convert (TREE_TYPE (expr), op00);
         *expr_p = op00;
         ret = GS_OK;
       }
@@ -6393,84 +6378,6 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
     }
 }
 \f
-#ifdef ENABLE_CHECKING
-/* Compare types A and B for a "close enough" match.  */
-
-static bool
-cpt_same_type (tree a, tree b)
-{
-  if (useless_type_conversion_p (a, b))
-    return true;
-
-  /* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't
-     link them together.  This routine is intended to catch type errors
-     that will affect the optimizers, and the optimizers don't add new
-     dereferences of function pointers, so ignore it.  */
-  if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE)
-      && (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE))
-    return true;
-
-  /* ??? The C FE pushes type qualifiers after the fact into the type of
-     the element from the type of the array.  See build_unary_op's handling
-     of ADDR_EXPR.  This seems wrong -- if we were going to do this, we
-     should have done it when creating the variable in the first place.
-     Alternately, why aren't the two array types made variants?  */
-  if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE)
-    return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
-  /* And because of those, we have to recurse down through pointers.  */
-  if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b))
-    return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
-  return false;
-}
-
-/* Check for some cases of the front end missing cast expressions.
-   The type of a dereference should correspond to the pointer type;
-   similarly the type of an address should match its object.  */
-
-static tree
-check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  tree t = *tp;
-  tree ptype, otype, dtype;
-
-  switch (TREE_CODE (t))
-    {
-    case INDIRECT_REF:
-    case ARRAY_REF:
-      otype = TREE_TYPE (t);
-      ptype = TREE_TYPE (TREE_OPERAND (t, 0));
-      dtype = TREE_TYPE (ptype);
-      gcc_assert (cpt_same_type (otype, dtype));
-      break;
-
-    case ADDR_EXPR:
-      ptype = TREE_TYPE (t);
-      otype = TREE_TYPE (TREE_OPERAND (t, 0));
-      dtype = TREE_TYPE (ptype);
-      if (!cpt_same_type (dtype, otype))
-       {
-         /* &array is allowed to produce a pointer to the element, rather than
-            a pointer to the array type.  We must allow this in order to
-            properly represent assigning the address of an array in C into
-            pointer to the element type.  */
-         gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
-                     && POINTER_TYPE_P (ptype)
-                     && cpt_same_type (dtype, TREE_TYPE (otype)));
-         break;
-       }
-      break;
-
-    default:
-      return NULL_TREE;
-    }
-
-
-  return NULL_TREE;
-}
-#endif
 
 /* Gimplify the body of statements pointed to by BODY_P.  FNDECL is the
    function decl containing BODY.  */
@@ -6539,8 +6446,9 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
   pop_gimplify_context (body);
   gcc_assert (gimplify_ctxp == NULL);
 
-#ifdef ENABLE_CHECKING
-  walk_tree (body_p, check_pointer_types_r, NULL, NULL);
+#ifdef ENABLE_TYPES_CHECKING
+  if (!errorcount && !sorrycount)
+    verify_gimple_1 (BIND_EXPR_BODY (*body_p));
 #endif
 
   timevar_pop (TV_TREE_GIMPLIFY);
index 17808e7..26a5ac9 100644 (file)
@@ -3345,6 +3345,710 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 #undef CHECK_OP
 }
 
+/* Verifies if EXPR is a valid GIMPLE unary expression.  Returns true
+   if there is an error, otherwise false.  */
+
+static bool
+verify_gimple_unary_expr (tree expr)
+{
+  tree op = TREE_OPERAND (expr, 0);
+  tree type = TREE_TYPE (expr);
+
+  if (!is_gimple_val (op))
+    {
+      error ("invalid operand in unary expression");
+      return true;
+    }
+
+  /* For general unary expressions we have the operations type
+     as the effective type the operation is carried out on.  So all
+     we need to require is that the operand is trivially convertible
+     to that type.  */
+  if (!useless_type_conversion_p (type, TREE_TYPE (op)))
+    {
+      error ("type mismatch in unary expression");
+      debug_generic_expr (type);
+      debug_generic_expr (TREE_TYPE (op));
+      return true;
+    }
+
+  return false;
+}
+
+/* Verifies if EXPR is a valid GIMPLE binary expression.  Returns true
+   if there is an error, otherwise false.  */
+
+static bool
+verify_gimple_binary_expr (tree expr)
+{
+  tree op0 = TREE_OPERAND (expr, 0);
+  tree op1 = TREE_OPERAND (expr, 1);
+  tree type = TREE_TYPE (expr);
+
+  if (!is_gimple_val (op0) || !is_gimple_val (op1))
+    {
+      error ("invalid operands in binary expression");
+      return true;
+    }
+
+  /* For general binary expressions we have the operations type
+     as the effective type the operation is carried out on.  So all
+     we need to require is that both operands are trivially convertible
+     to that type.  */
+  if (!useless_type_conversion_p (type, TREE_TYPE (op0))
+      || !useless_type_conversion_p (type, TREE_TYPE (op1)))
+    {
+      error ("type mismatch in binary expression");
+      debug_generic_stmt (type);
+      debug_generic_stmt (TREE_TYPE (op0));
+      debug_generic_stmt (TREE_TYPE (op1));
+      return true;
+    }
+
+  return false;
+}
+
+/* Verify if EXPR is either a GIMPLE ID or a GIMPLE indirect reference.
+   Returns true if there is an error, otherwise false.  */
+
+static bool
+verify_gimple_min_lval (tree expr)
+{
+  tree op;
+
+  if (is_gimple_id (expr))
+    return false;
+
+  if (TREE_CODE (expr) != INDIRECT_REF
+      && TREE_CODE (expr) != ALIGN_INDIRECT_REF
+      && TREE_CODE (expr) != MISALIGNED_INDIRECT_REF)
+    {
+      error ("invalid expression for min lvalue");
+      return true;
+    }
+
+  op = TREE_OPERAND (expr, 0);
+  if (!is_gimple_val (op))
+    {
+      error ("invalid operand in indirect reference");
+      debug_generic_stmt (op);
+      return true;
+    }
+  if (!useless_type_conversion_p (TREE_TYPE (expr),
+                                 TREE_TYPE (TREE_TYPE (op))))
+    {
+      error ("type mismatch in indirect reference");
+      debug_generic_stmt (TREE_TYPE (expr));
+      debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+      return true;
+    }
+
+  return false;
+}
+
+/* Verify if EXPR is a valid GIMPLE reference expression.  Returns true
+   if there is an error, otherwise false.  */
+
+static bool
+verify_gimple_reference (tree expr)
+{
+  while (handled_component_p (expr))
+    {
+      tree op = TREE_OPERAND (expr, 0);
+
+      if (TREE_CODE (expr) == ARRAY_REF
+         || TREE_CODE (expr) == ARRAY_RANGE_REF)
+       {
+         if (!is_gimple_val (TREE_OPERAND (expr, 1))
+             || (TREE_OPERAND (expr, 2)
+                 && !is_gimple_val (TREE_OPERAND (expr, 2)))
+             || (TREE_OPERAND (expr, 3)
+                 && !is_gimple_val (TREE_OPERAND (expr, 3))))
+           {
+             error ("invalid operands to array reference");
+             debug_generic_stmt (expr);
+             return true;
+           }
+       }
+
+      /* Verify if the reference array element types are compatible.  */
+      if (TREE_CODE (expr) == ARRAY_REF
+         && !useless_type_conversion_p (TREE_TYPE (expr),
+                                        TREE_TYPE (TREE_TYPE (op))))
+       {
+         error ("type mismatch in array reference");
+         debug_generic_stmt (TREE_TYPE (expr));
+         debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+         return true;
+       }
+      if (TREE_CODE (expr) == ARRAY_RANGE_REF
+         && !useless_type_conversion_p (TREE_TYPE (TREE_TYPE (expr)),
+                                        TREE_TYPE (TREE_TYPE (op))))
+       {
+         error ("type mismatch in array range reference");
+         debug_generic_stmt (TREE_TYPE (TREE_TYPE (expr)));
+         debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+         return true;
+       }
+
+      if ((TREE_CODE (expr) == REALPART_EXPR
+          || TREE_CODE (expr) == IMAGPART_EXPR)
+         && !useless_type_conversion_p (TREE_TYPE (expr),
+                                        TREE_TYPE (TREE_TYPE (op))))
+       {
+         error ("type mismatch in real/imagpart reference");
+         debug_generic_stmt (TREE_TYPE (expr));
+         debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+         return true;
+       }
+
+      if (TREE_CODE (expr) == COMPONENT_REF
+         && !useless_type_conversion_p (TREE_TYPE (expr),
+                                        TREE_TYPE (TREE_OPERAND (expr, 1))))
+       {
+         error ("type mismatch in component reference");
+         debug_generic_stmt (TREE_TYPE (expr));
+         debug_generic_stmt (TREE_TYPE (TREE_OPERAND (expr, 1)));
+         return true;
+       }
+
+      /* For VIEW_CONVERT_EXPRs which are allowed here, too, there
+        is nothing to verify.  Gross mismatches at most invoke
+        undefined behavior.  */
+
+      expr = op;
+    }
+
+  return verify_gimple_min_lval (expr);
+}
+
+/* Verify the GIMPLE expression EXPR.  Returns true if there is an
+   error, otherwise false.  */
+
+static bool
+verify_gimple_expr (tree expr)
+{
+  tree type = TREE_TYPE (expr);
+
+  if (is_gimple_val (expr))
+    return false;
+
+  /* Special codes we cannot handle via their class.  */
+  switch (TREE_CODE (expr))
+    {
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+      {
+       tree op = TREE_OPERAND (expr, 0);
+       if (!is_gimple_val (op))
+         {
+           error ("invalid operand in conversion");
+           return true;
+         }
+
+       /* Allow conversions between integral types.  */
+        if (INTEGRAL_TYPE_P (type) == INTEGRAL_TYPE_P (TREE_TYPE (op)))
+         return false;
+
+       /* Allow conversions between integral types and pointers only if
+          there is no sign or zero extension involved.  */
+       if (((POINTER_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (op)))
+            || (POINTER_TYPE_P (TREE_TYPE (op)) && INTEGRAL_TYPE_P (type)))
+           && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op)))
+         return false;
+
+       /* Allow conversion from integer to offset type and vice versa.  */
+       if ((TREE_CODE (type) == OFFSET_TYPE
+            && TREE_CODE (TREE_TYPE (op)) == INTEGER_TYPE)
+           || (TREE_CODE (type) == INTEGER_TYPE
+               && TREE_CODE (TREE_TYPE (op)) == OFFSET_TYPE))
+         return false;
+
+       /* Otherwise assert we are converting between types of the
+          same kind.  */
+       if (TREE_CODE (type) != TREE_CODE (TREE_TYPE (op)))
+         {
+           error ("invalid types in nop conversion");
+           debug_generic_expr (type);
+           debug_generic_expr (TREE_TYPE (op));
+           return true;
+         }
+
+       return false;
+      }
+
+    case FLOAT_EXPR:
+      {
+       tree op = TREE_OPERAND (expr, 0);
+       if (!is_gimple_val (op))
+         {
+           error ("invalid operand in int to float conversion");
+           return true;
+         }
+       if (!INTEGRAL_TYPE_P (TREE_TYPE (op))
+           || !SCALAR_FLOAT_TYPE_P (type))
+         {
+           error ("invalid types in conversion to floating point");
+           debug_generic_expr (type);
+           debug_generic_expr (TREE_TYPE (op));
+           return true;
+         }
+        return false;
+      }
+
+    case FIX_TRUNC_EXPR:
+      {
+       tree op = TREE_OPERAND (expr, 0);
+       if (!is_gimple_val (op))
+         {
+           error ("invalid operand in float to int conversion");
+           return true;
+         }
+       if (!INTEGRAL_TYPE_P (type)
+           || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (op)))
+         {
+           error ("invalid types in conversion to integer");
+           debug_generic_expr (type);
+           debug_generic_expr (TREE_TYPE (op));
+           return true;
+         }
+        return false;
+      }
+
+    case COMPLEX_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       if (!is_gimple_val (op0) || !is_gimple_val (op1))
+         {
+           error ("invalid operands in complex expression");
+           return true;
+         }
+       if (!TREE_CODE (type) == COMPLEX_TYPE
+           || !(TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
+                || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0)))
+           || !(TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE
+                || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op1)))
+           || !useless_type_conversion_p (TREE_TYPE (type),
+                                          TREE_TYPE (op0))
+           || !useless_type_conversion_p (TREE_TYPE (type),
+                                          TREE_TYPE (op1)))
+         {
+           error ("type mismatch in complex expression");
+           debug_generic_stmt (TREE_TYPE (expr));
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           return true;
+         }
+       return false;
+      }
+
+    case CONSTRUCTOR:
+      {
+       /* This is used like COMPLEX_EXPR but for vectors.  */
+       if (TREE_CODE (type) != VECTOR_TYPE)
+         {
+           error ("constructor not allowed for non-vector types");
+           debug_generic_stmt (type);
+           return true;
+         }
+       /* FIXME: verify constructor arguments.  */
+       return false;
+      }
+
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       if (!is_gimple_val (op0) || !is_gimple_val (op1))
+         {
+           error ("invalid operands in shift expression");
+           return true;
+         }
+       if (!TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE
+           || !useless_type_conversion_p (type, TREE_TYPE (op0)))
+         {
+           error ("type mismatch in shift expression");
+           debug_generic_stmt (TREE_TYPE (expr));
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           return true;
+         }
+       return false;
+      }
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       if (POINTER_TYPE_P (type)
+           || POINTER_TYPE_P (TREE_TYPE (op0))
+           || POINTER_TYPE_P (TREE_TYPE (op1)))
+         {
+           error ("invalid (pointer) operands to plus/minus");
+           return true;
+         }
+       /* Continue with generic binary expression handling.  */
+       break;
+      }
+
+    case POINTER_PLUS_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       if (!is_gimple_val (op0) || !is_gimple_val (op1))
+         {
+           error ("invalid operands in pointer plus expression");
+           return true;
+         }
+       if (!POINTER_TYPE_P (TREE_TYPE (op0))
+           || TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE
+           || !useless_type_conversion_p (type, TREE_TYPE (op0))
+           || !useless_type_conversion_p (sizetype, TREE_TYPE (op1)))
+         {
+           error ("type mismatch in pointer plus expression");
+           debug_generic_stmt (type);
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           return true;
+         }
+       return false;
+      }
+
+    case COND_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       tree op2 = TREE_OPERAND (expr, 2);
+       if ((!is_gimple_val (op1)
+            && TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
+           || (!is_gimple_val (op2)
+               && TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE))
+         {
+           error ("invalid operands in conditional expression");
+           return true;
+         }
+       if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+           || (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE
+               && !useless_type_conversion_p (type, TREE_TYPE (op1)))
+           || (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE
+               && !useless_type_conversion_p (type, TREE_TYPE (op2))))
+         {
+           error ("type mismatch in conditional expression");
+           debug_generic_stmt (type);
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           debug_generic_stmt (TREE_TYPE (op2));
+           return true;
+         }
+       return verify_gimple_expr (op0);
+      }
+
+    case ADDR_EXPR:
+      {
+       tree op = TREE_OPERAND (expr, 0);
+       tree ptr_type;
+       if (!is_gimple_addressable (op))
+         {
+           error ("invalid operand in unary expression");
+           return true;
+         }
+       ptr_type = build_pointer_type (TREE_TYPE (op));
+       if (!useless_type_conversion_p (type, ptr_type)
+           /* FIXME: a longstanding wart, &a == &a[0].  */
+           && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
+               || !useless_type_conversion_p (type,
+                       build_pointer_type (TREE_TYPE (TREE_TYPE (op))))))
+         {
+           error ("type mismatch in address expression");
+           debug_generic_stmt (TREE_TYPE (expr));
+           debug_generic_stmt (ptr_type);
+           return true;
+         }
+
+       return verify_gimple_reference (op);
+      }
+
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+
+       if (!is_gimple_val (op0) || !is_gimple_val (op1))
+         {
+           error ("invalid operands in truth expression");
+           return true;
+         }
+
+       /* We allow any kind of integral typed argument and result.  */
+       if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+           || !INTEGRAL_TYPE_P (TREE_TYPE (op1))
+           || !INTEGRAL_TYPE_P (type))
+         {
+           error ("type mismatch in binary truth expression");
+           debug_generic_stmt (type);
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           return true;
+         }
+
+       return false;
+      }
+
+    case TRUTH_NOT_EXPR:
+      {
+       tree op = TREE_OPERAND (expr, 0);
+
+       if (!is_gimple_val (op))
+         {
+           error ("invalid operand in unary not");
+           return true;
+         }
+
+       /* For TRUTH_NOT_EXPR we can have any kind of integral
+          typed arguments and results.  */
+       if (!INTEGRAL_TYPE_P (TREE_TYPE (op))
+           || !INTEGRAL_TYPE_P (type))
+         {
+           error ("type mismatch in not expression");
+           debug_generic_expr (TREE_TYPE (expr));
+           debug_generic_expr (TREE_TYPE (op));
+           return true;
+         }
+
+       return false;
+      }
+
+    case CALL_EXPR:
+      /* FIXME.  The C frontend passes unpromoted arguments in case it
+        didn't see a function declaration before the call.  */
+      return false;
+
+    default:;
+    }
+
+  /* Generic handling via classes.  */
+  switch (TREE_CODE_CLASS (TREE_CODE (expr)))
+    {
+    case tcc_unary:
+      return verify_gimple_unary_expr (expr);
+
+    case tcc_binary:
+      return verify_gimple_binary_expr (expr);
+
+    case tcc_reference:
+      return verify_gimple_reference (expr);
+
+    case tcc_comparison:
+      {
+       tree op0 = TREE_OPERAND (expr, 0);
+       tree op1 = TREE_OPERAND (expr, 1);
+       if (!is_gimple_val (op0) || !is_gimple_val (op1))
+         {
+           error ("invalid operands in comparison expression");
+           return true;
+         }
+       /* For comparisons we do not have the operations type as the
+          effective type the comparison is carried out in.  Instead
+          we require that either the first operand is trivially
+          convertible into the second, or the other way around.
+          The resulting type of a comparison may be any integral type.
+          Because we special-case pointers to void we allow
+          comparisons of pointers with the same mode as well.  */
+       if ((!useless_type_conversion_p (TREE_TYPE (op0), TREE_TYPE (op1))
+            && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0))
+            && (!POINTER_TYPE_P (TREE_TYPE (op0))
+                || !POINTER_TYPE_P (TREE_TYPE (op1))
+                || TYPE_MODE (TREE_TYPE (op0)) != TYPE_MODE (TREE_TYPE (op1))))
+           || !INTEGRAL_TYPE_P (type))
+         {
+           error ("type mismatch in comparison expression");
+           debug_generic_stmt (TREE_TYPE (expr));
+           debug_generic_stmt (TREE_TYPE (op0));
+           debug_generic_stmt (TREE_TYPE (op1));
+           return true;
+         }
+        break;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return false;
+}
+
+/* Verify the GIMPLE assignment statement STMT.  Returns true if there
+   is an error, otherwise false.  */
+
+static bool
+verify_gimple_modify_stmt (tree stmt)
+{
+  tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+  tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+
+  gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
+
+  if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                 TREE_TYPE (rhs)))
+    {
+      error ("non-trivial conversion at assignment");
+      debug_generic_expr (TREE_TYPE (lhs));
+      debug_generic_expr (TREE_TYPE (rhs));
+      return true;
+    }
+
+  /* Loads/stores from/to a variable are ok.  */
+  if ((is_gimple_val (lhs)
+       && is_gimple_variable (rhs))
+      || (is_gimple_val (rhs)
+         && is_gimple_variable (lhs)))
+    return false;
+
+  /* Aggregate copies are ok.  */
+  if (!is_gimple_reg_type (TREE_TYPE (lhs))
+      && !is_gimple_reg_type (TREE_TYPE (rhs)))
+    return false;
+
+  /* We might get 'loads' from a parameter which is not a gimple value.  */
+  if (TREE_CODE (rhs) == PARM_DECL)
+    return verify_gimple_expr (lhs);
+
+  if (!is_gimple_variable (lhs)
+      && verify_gimple_expr (lhs))
+    return true;
+
+  if (!is_gimple_variable (rhs)
+      && verify_gimple_expr (rhs))
+    return true;
+
+  return false;
+}
+
+/* Verify the GIMPLE statement STMT.  Returns true if there is an
+   error, otherwise false.  */
+
+static bool
+verify_gimple_stmt (tree stmt)
+{
+  if (!is_gimple_stmt (stmt))
+    {
+      error ("is not a valid GIMPLE statement");
+      return true;
+    }
+
+  if (OMP_DIRECTIVE_P (stmt))
+    {
+      /* OpenMP directives are validated by the FE and never operated
+        on by the optimizers.  Furthermore, OMP_FOR may contain
+        non-gimple expressions when the main index variable has had
+        its address taken.  This does not affect the loop itself
+        because the header of an OMP_FOR is merely used to determine
+        how to setup the parallel iteration.  */
+      return false;
+    }
+
+  switch (TREE_CODE (stmt))
+    {
+    case GIMPLE_MODIFY_STMT:
+      return verify_gimple_modify_stmt (stmt);
+
+    case GOTO_EXPR:
+    case LABEL_EXPR:
+      return false;
+
+    case SWITCH_EXPR:
+      if (!is_gimple_val (TREE_OPERAND (stmt, 0)))
+       {
+         error ("invalid operand to switch statement");
+         debug_generic_expr (TREE_OPERAND (stmt, 0));
+       }
+      return false;
+
+    case RETURN_EXPR:
+      {
+       tree op = TREE_OPERAND (stmt, 0);
+
+       if (TREE_CODE (TREE_TYPE (stmt)) != VOID_TYPE)
+         {
+           error ("type error in return expression");
+           return true;
+         }
+
+       if (op == NULL_TREE
+           || TREE_CODE (op) == RESULT_DECL)
+         return false;
+
+       return verify_gimple_modify_stmt (op);
+      }
+
+    case CALL_EXPR:
+    case COND_EXPR:
+      return verify_gimple_expr (stmt);
+
+    case NOP_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+    case ASM_EXPR:
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Verify the GIMPLE statements inside the statement list STMTS.  */
+
+void
+verify_gimple_1 (tree stmts)
+{
+  tree_stmt_iterator tsi;
+
+  for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
+    {
+      tree stmt = tsi_stmt (tsi);
+
+      switch (TREE_CODE (stmt))
+       {
+       case BIND_EXPR:
+         verify_gimple_1 (BIND_EXPR_BODY (stmt));
+         break;
+
+       case TRY_CATCH_EXPR:
+       case TRY_FINALLY_EXPR:
+         verify_gimple_1 (TREE_OPERAND (stmt, 0));
+         verify_gimple_1 (TREE_OPERAND (stmt, 1));
+         break;
+
+       case CATCH_EXPR:
+         verify_gimple_1 (CATCH_BODY (stmt));
+         break;
+
+       case EH_FILTER_EXPR:
+         verify_gimple_1 (EH_FILTER_FAILURE (stmt));
+         break;
+
+       default:
+         if (verify_gimple_stmt (stmt))
+           debug_generic_expr (stmt);
+       }
+    }
+}
+
+/* Verify the GIMPLE statements inside the current function.  */
+
+void
+verify_gimple (void)
+{
+  verify_gimple_1 (BIND_EXPR_BODY (DECL_SAVED_TREE (cfun->decl)));
+}
 
 /* Verify STMT, return true if STMT is not in GIMPLE form.
    TODO: Implement type checking.  */
index c314ed5..e67bd0a 100644 (file)
@@ -752,6 +752,8 @@ extern void bsi_commit_edge_inserts (void);
 extern void notice_special_calls (tree);
 extern void clear_special_calls (void);
 extern void verify_stmts (void);
+extern void verify_gimple (void);
+extern void verify_gimple_1 (tree);
 extern tree tree_block_label (basic_block);
 extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
 extern bool tree_duplicate_sese_region (edge, edge, basic_block *, unsigned,