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
This commit is contained in:
Richard Guenther 2007-07-26 10:27:50 +00:00 committed by Richard Biener
parent 0ee0208ecc
commit 7e98624c5e
9 changed files with 758 additions and 110 deletions

View File

@ -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

4
configure vendored
View File

@ -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;

View 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)

View File

@ -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

22
gcc/configure vendored
View File

@ -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

View 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,

View 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)
}
}
#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);

View 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. */

View 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,