}
-/* Verify properties of the address expression T with base object BASE. */
+/* Verify properties of the address expression T whose base should be
+ TREE_ADDRESSABLE if VERIFY_ADDRESSABLE is true. */
-static tree
-verify_address (tree t, tree base)
+static bool
+verify_address (tree t, bool verify_addressable)
{
bool old_constant;
bool old_side_effects;
if (old_constant != new_constant)
{
error ("constant not recomputed when ADDR_EXPR changed");
- return t;
+ return true;
}
if (old_side_effects != new_side_effects)
{
error ("side effects not recomputed when ADDR_EXPR changed");
- return t;
+ return true;
}
+ tree base = TREE_OPERAND (t, 0);
+ while (handled_component_p (base))
+ base = TREE_OPERAND (base, 0);
+
if (!(VAR_P (base)
|| TREE_CODE (base) == PARM_DECL
|| TREE_CODE (base) == RESULT_DECL))
- return NULL_TREE;
+ return false;
if (DECL_GIMPLE_REG_P (base))
{
error ("DECL_GIMPLE_REG_P set on a variable with address taken");
- return base;
+ return true;
}
- return NULL_TREE;
-}
-
-/* Callback for walk_tree, check that all elements with address taken are
- properly noticed as such. The DATA is an int* that is 1 if TP was seen
- inside a PHI node. */
-
-static tree
-verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
-{
- tree t = *tp, x;
-
- if (TYPE_P (t))
- *walk_subtrees = 0;
-
- /* Check operand N for being valid GIMPLE and give error MSG if not. */
-#define CHECK_OP(N, MSG) \
- do { if (!is_gimple_val (TREE_OPERAND (t, N))) \
- { error (MSG); return TREE_OPERAND (t, N); }} while (0)
-
- switch (TREE_CODE (t))
+ if (verify_addressable && !TREE_ADDRESSABLE (base))
{
- case SSA_NAME:
- if (SSA_NAME_IN_FREE_LIST (t))
- {
- error ("SSA name in freelist but still referenced");
- return *tp;
- }
- break;
-
- case PARM_DECL:
- case VAR_DECL:
- case RESULT_DECL:
- {
- tree context = decl_function_context (t);
- if (context != cfun->decl
- && !SCOPE_FILE_SCOPE_P (context)
- && !TREE_STATIC (t)
- && !DECL_EXTERNAL (t))
- {
- error ("Local declaration from a different function");
- return t;
- }
- }
- break;
-
- case INDIRECT_REF:
- error ("INDIRECT_REF in gimple IL");
- return t;
-
- case MEM_REF:
- x = TREE_OPERAND (t, 0);
- if (!POINTER_TYPE_P (TREE_TYPE (x))
- || !is_gimple_mem_ref_addr (x))
- {
- error ("invalid first operand of MEM_REF");
- return x;
- }
- if (!poly_int_tree_p (TREE_OPERAND (t, 1))
- || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1))))
- {
- error ("invalid offset operand of MEM_REF");
- return TREE_OPERAND (t, 1);
- }
- if (TREE_CODE (x) == ADDR_EXPR)
- {
- tree va = verify_address (x, TREE_OPERAND (x, 0));
- if (va)
- return va;
- x = TREE_OPERAND (x, 0);
- }
- walk_tree (&x, verify_expr, data, NULL);
- *walk_subtrees = 0;
- break;
-
- case ASSERT_EXPR:
- x = fold (ASSERT_EXPR_COND (t));
- if (x == boolean_false_node)
- {
- error ("ASSERT_EXPR with an always-false condition");
- return *tp;
- }
- break;
-
- case MODIFY_EXPR:
- error ("MODIFY_EXPR not expected while having tuples");
- return *tp;
-
- case ADDR_EXPR:
- {
- tree tem;
-
- gcc_assert (is_gimple_address (t));
-
- /* Skip any references (they will be checked when we recurse down the
- tree) and ensure that any variable used as a prefix is marked
- addressable. */
- for (x = TREE_OPERAND (t, 0);
- handled_component_p (x);
- x = TREE_OPERAND (x, 0))
- ;
-
- if ((tem = verify_address (t, x)))
- return tem;
-
- if (!(VAR_P (x)
- || TREE_CODE (x) == PARM_DECL
- || TREE_CODE (x) == RESULT_DECL))
- return NULL;
-
- if (!TREE_ADDRESSABLE (x))
- {
- error ("address taken, but ADDRESSABLE bit not set");
- return x;
- }
-
- break;
- }
-
- case COND_EXPR:
- gcc_unreachable ();
-
- case NON_LVALUE_EXPR:
- case TRUTH_NOT_EXPR:
- gcc_unreachable ();
-
- CASE_CONVERT:
- case FIX_TRUNC_EXPR:
- case FLOAT_EXPR:
- case NEGATE_EXPR:
- case ABS_EXPR:
- case BIT_NOT_EXPR:
- gcc_unreachable ();
-
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case BIT_FIELD_REF:
- if (!is_gimple_reg_type (TREE_TYPE (t)))
- {
- error ("non-scalar BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR");
- return t;
- }
-
- if (TREE_CODE (t) == BIT_FIELD_REF)
- {
- tree t0 = TREE_OPERAND (t, 0);
- tree t1 = TREE_OPERAND (t, 1);
- tree t2 = TREE_OPERAND (t, 2);
- poly_uint64 size, bitpos;
- if (!poly_int_tree_p (t1, &size)
- || !poly_int_tree_p (t2, &bitpos)
- || !types_compatible_p (bitsizetype, TREE_TYPE (t1))
- || !types_compatible_p (bitsizetype, TREE_TYPE (t2)))
- {
- error ("invalid position or size operand to BIT_FIELD_REF");
- return t;
- }
- if (INTEGRAL_TYPE_P (TREE_TYPE (t))
- && maybe_ne (TYPE_PRECISION (TREE_TYPE (t)), size))
- {
- error ("integral result type precision does not match "
- "field size of BIT_FIELD_REF");
- return t;
- }
- else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
- && TYPE_MODE (TREE_TYPE (t)) != BLKmode
- && maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (t))),
- size))
- {
- error ("mode size of non-integral result does not "
- "match field size of BIT_FIELD_REF");
- return t;
- }
- if (!AGGREGATE_TYPE_P (TREE_TYPE (t0))
- && maybe_gt (size + bitpos,
- tree_to_poly_uint64 (TYPE_SIZE (TREE_TYPE (t0)))))
- {
- error ("position plus size exceeds size of referenced object in "
- "BIT_FIELD_REF");
- return t;
- }
- }
- t = TREE_OPERAND (t, 0);
-
- /* Fall-through. */
- case COMPONENT_REF:
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- case VIEW_CONVERT_EXPR:
- /* We have a nest of references. Verify that each of the operands
- that determine where to reference is either a constant or a variable,
- verify that the base is valid, and then show we've already checked
- the subtrees. */
- while (handled_component_p (t))
- {
- if (TREE_CODE (t) == COMPONENT_REF && TREE_OPERAND (t, 2))
- CHECK_OP (2, "invalid COMPONENT_REF offset operator");
- else if (TREE_CODE (t) == ARRAY_REF
- || TREE_CODE (t) == ARRAY_RANGE_REF)
- {
- CHECK_OP (1, "invalid array index");
- if (TREE_OPERAND (t, 2))
- CHECK_OP (2, "invalid array lower bound");
- if (TREE_OPERAND (t, 3))
- CHECK_OP (3, "invalid array stride");
- }
- else if (TREE_CODE (t) == BIT_FIELD_REF
- || TREE_CODE (t) == REALPART_EXPR
- || TREE_CODE (t) == IMAGPART_EXPR)
- {
- error ("non-top-level BIT_FIELD_REF, IMAGPART_EXPR or "
- "REALPART_EXPR");
- return t;
- }
-
- t = TREE_OPERAND (t, 0);
- }
-
- if (!is_gimple_min_invariant (t) && !is_gimple_lvalue (t))
- {
- error ("invalid reference prefix");
- return t;
- }
- walk_tree (&t, verify_expr, data, NULL);
- *walk_subtrees = 0;
- break;
- case PLUS_EXPR:
- case MINUS_EXPR:
- gcc_unreachable ();
-
- case POINTER_DIFF_EXPR:
- gcc_unreachable ();
-
- case POINTER_PLUS_EXPR:
- case MULT_EXPR:
- case TRUNC_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case TRUNC_MOD_EXPR:
- case CEIL_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case ROUND_MOD_EXPR:
- case RDIV_EXPR:
- case EXACT_DIV_EXPR:
- case MIN_EXPR:
- case MAX_EXPR:
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- case BIT_IOR_EXPR:
- case BIT_XOR_EXPR:
- case BIT_AND_EXPR:
- gcc_unreachable ();
-
- case LT_EXPR:
- case LE_EXPR:
- case GT_EXPR:
- case GE_EXPR:
- case EQ_EXPR:
- case NE_EXPR:
- case UNORDERED_EXPR:
- case ORDERED_EXPR:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case UNEQ_EXPR:
- case LTGT_EXPR:
- /* Reachable via COND_EXPR condition which is GENERIC. */
- CHECK_OP (0, "invalid operand to binary operator");
- CHECK_OP (1, "invalid operand to binary operator");
- break;
-
- case CONSTRUCTOR:
- if (TREE_CONSTANT (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
- *walk_subtrees = 0;
- break;
-
- case CASE_LABEL_EXPR:
- if (CASE_CHAIN (t))
- {
- error ("invalid CASE_CHAIN");
- return t;
- }
- break;
-
- default:
- break;
+ error ("address taken, but ADDRESSABLE bit not set");
+ return true;
}
- return NULL;
-#undef CHECK_OP
+ return false;
}
static bool
verify_types_in_gimple_reference (tree expr, bool require_lvalue)
{
+ if (TREE_CODE (expr) == REALPART_EXPR
+ || TREE_CODE (expr) == IMAGPART_EXPR
+ || TREE_CODE (expr) == BIT_FIELD_REF)
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_reg_type (TREE_TYPE (expr)))
+ {
+ error ("non-scalar BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR");
+ return true;
+ }
+
+ if (TREE_CODE (expr) == BIT_FIELD_REF)
+ {
+ tree t1 = TREE_OPERAND (expr, 1);
+ tree t2 = TREE_OPERAND (expr, 2);
+ poly_uint64 size, bitpos;
+ if (!poly_int_tree_p (t1, &size)
+ || !poly_int_tree_p (t2, &bitpos)
+ || !types_compatible_p (bitsizetype, TREE_TYPE (t1))
+ || !types_compatible_p (bitsizetype, TREE_TYPE (t2)))
+ {
+ error ("invalid position or size operand to BIT_FIELD_REF");
+ return true;
+ }
+ if (INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ && maybe_ne (TYPE_PRECISION (TREE_TYPE (expr)), size))
+ {
+ error ("integral result type precision does not match "
+ "field size of BIT_FIELD_REF");
+ return true;
+ }
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ && TYPE_MODE (TREE_TYPE (expr)) != BLKmode
+ && maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr))),
+ size))
+ {
+ error ("mode size of non-integral result does not "
+ "match field size of BIT_FIELD_REF");
+ return true;
+ }
+ if (!AGGREGATE_TYPE_P (TREE_TYPE (op))
+ && maybe_gt (size + bitpos,
+ tree_to_poly_uint64 (TYPE_SIZE (TREE_TYPE (op)))))
+ {
+ error ("position plus size exceeds size of referenced object in "
+ "BIT_FIELD_REF");
+ 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;
+ }
+ expr = op;
+ }
+
while (handled_component_p (expr))
{
+ if (TREE_CODE (expr) == REALPART_EXPR
+ || TREE_CODE (expr) == IMAGPART_EXPR
+ || TREE_CODE (expr) == BIT_FIELD_REF)
+ {
+ error ("non-top-level BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR");
+ return true;
+ }
+
tree op = TREE_OPERAND (expr, 0);
if (TREE_CODE (expr) == ARRAY_REF
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))))
+ if (TREE_CODE (expr) == COMPONENT_REF)
{
- error ("type mismatch in component reference");
- debug_generic_stmt (TREE_TYPE (expr));
- debug_generic_stmt (TREE_TYPE (TREE_OPERAND (expr, 1)));
- return true;
+ if (TREE_OPERAND (expr, 2)
+ && !is_gimple_val (TREE_OPERAND (expr, 2)))
+ {
+ error ("invalid COMPONENT_REF offset operator");
+ return true;
+ }
+ if (!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;
+ }
}
if (TREE_CODE (expr) == VIEW_CONVERT_EXPR)
if (TREE_CODE (expr) == MEM_REF)
{
- if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0)))
+ if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0))
+ || (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
+ && verify_address (TREE_OPERAND (expr, 0), false)))
{
error ("invalid address operand in MEM_REF");
debug_generic_stmt (expr);
else if (TREE_CODE (expr) == TARGET_MEM_REF)
{
if (!TMR_BASE (expr)
- || !is_gimple_mem_ref_addr (TMR_BASE (expr)))
+ || !is_gimple_mem_ref_addr (TMR_BASE (expr))
+ || (TREE_CODE (TMR_BASE (expr)) == ADDR_EXPR
+ && verify_address (TMR_BASE (expr), false)))
{
error ("invalid address operand in TARGET_MEM_REF");
return true;
return true;
}
}
+ else if (TREE_CODE (expr) == INDIRECT_REF)
+ {
+ error ("INDIRECT_REF in gimple IL");
+ debug_generic_stmt (expr);
+ return true;
+ }
return ((require_lvalue || !is_gimple_min_invariant (expr))
&& verify_types_in_gimple_min_lval (expr));
return true;
}
- return verify_types_in_gimple_reference (op, true);
+ return (verify_address (rhs1, true)
+ || verify_types_in_gimple_reference (op, true));
}
/* tcc_reference */
return true;
}
return res;
- case OBJ_TYPE_REF:
+
case ASSERT_EXPR:
+ /* FIXME. */
+ rhs1 = fold (ASSERT_EXPR_COND (rhs1));
+ if (rhs1 == boolean_false_node)
+ {
+ error ("ASSERT_EXPR with an always-false condition");
+ debug_generic_stmt (rhs1);
+ return true;
+ }
+ break;
+
+ case OBJ_TYPE_REF:
case WITH_SIZE_EXPR:
/* FIXME. */
return res;
}
elt = gimple_switch_label (stmt, 0);
- if (CASE_LOW (elt) != NULL_TREE || CASE_HIGH (elt) != NULL_TREE)
+ if (CASE_LOW (elt) != NULL_TREE
+ || CASE_HIGH (elt) != NULL_TREE
+ || CASE_CHAIN (elt) != NULL_TREE)
{
error ("invalid default case label in switch statement");
debug_generic_expr (elt);
{
elt = gimple_switch_label (stmt, i);
+ if (CASE_CHAIN (elt))
+ {
+ error ("invalid CASE_CHAIN");
+ debug_generic_expr (elt);
+ return true;
+ }
if (! CASE_LOW (elt))
{
error ("invalid case label in switch statement");
verify_expr_location_1 (tree *tp, int *walk_subtrees, void *data)
{
hash_set<tree> *blocks = (hash_set<tree> *) data;
+ tree t = *tp;
- if (VAR_P (*tp) && DECL_HAS_DEBUG_EXPR_P (*tp))
+ /* ??? This doesn't really belong here but there's no good place to
+ stick this remainder of old verify_expr. */
+ /* ??? This barfs on debug stmts which contain binds to vars with
+ different function context. */
+#if 0
+ if (VAR_P (t)
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL)
+ {
+ tree context = decl_function_context (t);
+ if (context != cfun->decl
+ && !SCOPE_FILE_SCOPE_P (context)
+ && !TREE_STATIC (t)
+ && !DECL_EXTERNAL (t))
+ {
+ error ("local declaration from a different function");
+ return t;
+ }
+ }
+#endif
+
+ if (VAR_P (t) && DECL_HAS_DEBUG_EXPR_P (t))
{
- tree t = DECL_DEBUG_EXPR (*tp);
- tree addr = walk_tree (&t, verify_expr_no_block, NULL, NULL);
+ tree x = DECL_DEBUG_EXPR (t);
+ tree addr = walk_tree (&x, verify_expr_no_block, NULL, NULL);
if (addr)
return addr;
}
- if ((VAR_P (*tp)
- || TREE_CODE (*tp) == PARM_DECL
- || TREE_CODE (*tp) == RESULT_DECL)
- && DECL_HAS_VALUE_EXPR_P (*tp))
+ if ((VAR_P (t)
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL)
+ && DECL_HAS_VALUE_EXPR_P (t))
{
- tree t = DECL_VALUE_EXPR (*tp);
- tree addr = walk_tree (&t, verify_expr_no_block, NULL, NULL);
+ tree x = DECL_VALUE_EXPR (t);
+ tree addr = walk_tree (&x, verify_expr_no_block, NULL, NULL);
if (addr)
return addr;
}
- if (!EXPR_P (*tp))
+ if (!EXPR_P (t))
{
*walk_subtrees = false;
return NULL;
}
- location_t loc = EXPR_LOCATION (*tp);
+ location_t loc = EXPR_LOCATION (t);
if (verify_location (blocks, loc))
- return *tp;
+ return t;
return NULL;
}
err2 |= true;
}
- /* ??? Instead of not checking these stmts at all the walker
- should know its context via wi. */
- if (!is_gimple_debug (stmt)
- && !is_gimple_omp (stmt))
- {
- memset (&wi, 0, sizeof (wi));
- addr = walk_gimple_op (stmt, verify_expr, &wi);
- if (addr)
- {
- debug_generic_expr (addr);
- inform (gimple_location (stmt), "in statement");
- err2 |= true;
- }
- }
-
/* If the statement is marked as part of an EH region, then it is
expected that the statement could throw. Verify that when we
have optimizations that simplify statements such that we prove