summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rwxr-xr-xconfigure4
-rw-r--r--configure.ac4
-rw-r--r--gcc/config.in6
-rwxr-xr-xgcc/configure22
-rw-r--r--gcc/configure.ac21
-rw-r--r--gcc/gimplify.c100
-rw-r--r--gcc/tree-cfg.c704
-rw-r--r--gcc/tree-flow.h2
9 files changed, 758 insertions, 110 deletions
diff --git a/ChangeLog b/ChangeLog
index 17832209062..94ab187effc 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 1a43f9e69a6..df7479320e4 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 da88113f068..2500cc6f351 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 30b1c426659..aba1bb54c5b 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 1b72cdb9442..376a3e394c4 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 c7b9bc99025..b50bba56fb1 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 4e0e16aad12..fdf34d18ea8 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 17808e77e7c..26a5ac9c06f 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 c314ed5bd73..e67bd0a50b5 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,