From 7e98624c5eefcd77b90ad1ebbbc06ab17b005a32 Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguenther@suse.de>
Date: Thu, 26 Jul 2007 10:27:50 +0000
Subject: [PATCH] configure.ac: Add types checking to stage1 checking flags.

2007-07-26  Richard Guenther  <rguenther@suse.de>

	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.

From-SVN: r126951
---
 ChangeLog        |   5 +
 configure        |   4 +-
 configure.ac     |   4 +-
 gcc/config.in    |   6 +
 gcc/configure    |  22 +-
 gcc/configure.ac |  21 +-
 gcc/gimplify.c   | 100 +------
 gcc/tree-cfg.c   | 704 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-flow.h  |   2 +
 9 files changed, 758 insertions(+), 110 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 178322090626..94ab187effc8 100644
--- 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
diff --git a/configure b/configure
index 1a43f9e69a62..df7479320e40 100755
--- 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;
 
diff --git a/configure.ac b/configure.ac
index da88113f0684..2500cc6f3511 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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)
 
diff --git a/gcc/config.in b/gcc/config.in
index 30b1c4266596..aba1bb54c5bf 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -121,6 +121,12 @@
 #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
diff --git a/gcc/configure b/gcc/configure
index 1b72cdb94423..376a3e394c45 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -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
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index c7b9bc99025b..b50bba56fb11 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -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,
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 4e0e16aad128..fdf34d18ea89 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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)
     }
 }
 
-#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);
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 17808e77e7c8..26a5ac9c06f0 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -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.  */
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index c314ed5bd730..e67bd0a50b5f 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -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,
-- 
GitLab