diff options
author | Richard Guenther <rguenther@suse.de> | 2007-07-26 10:27:50 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2007-07-26 10:27:50 +0000 |
commit | 7e98624c5eefcd77b90ad1ebbbc06ab17b005a32 (patch) | |
tree | d94c1fef3d48e52ac95d22884ff2b915e9ee622d /gcc/tree-cfg.c | |
parent | 0ee0208eccd3d707d8accf2626cbe934faa7cecd (diff) | |
download | gcc-7e98624c5eefcd77b90ad1ebbbc06ab17b005a32.zip gcc-7e98624c5eefcd77b90ad1ebbbc06ab17b005a32.tar.gz gcc-7e98624c5eefcd77b90ad1ebbbc06ab17b005a32.tar.bz2 |
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
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r-- | gcc/tree-cfg.c | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 17808e7..26a5ac9 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. */ |