return result;
}
+
+/* Return an expression tree representing an equality comparison of P1 and P2,
+ two objects of fat pointer type. The result should be of type RESULT_TYPE.
+
+ Two fat pointers are equal in one of two ways: (1) if both have a null
+ pointer to the array or (2) if they contain the same couple of pointers.
+ We perform the comparison in as efficient a manner as possible. */
+
+static tree
+compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2)
+{
+ tree p1_array, p2_array, p1_bounds, p2_bounds, same_array, same_bounds;
+ tree p1_array_is_null, p2_array_is_null;
+
+ /* If either operand has side-effects, they have to be evaluated only once
+ in spite of the multiple references to the operand in the comparison. */
+ p1 = gnat_protect_expr (p1);
+ p2 = gnat_protect_expr (p2);
+
+ /* The constant folder doesn't fold fat pointer types so we do it here. */
+ if (TREE_CODE (p1) == CONSTRUCTOR)
+ p1_array = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p1), 0)->value;
+ else
+ p1_array = build_component_ref (p1, NULL_TREE,
+ TYPE_FIELDS (TREE_TYPE (p1)), true);
+
+ p1_array_is_null
+ = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array,
+ fold_convert_loc (loc, TREE_TYPE (p1_array),
+ null_pointer_node));
+
+ if (TREE_CODE (p2) == CONSTRUCTOR)
+ p2_array = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p2), 0)->value;
+ else
+ p2_array = build_component_ref (p2, NULL_TREE,
+ TYPE_FIELDS (TREE_TYPE (p2)), true);
+
+ p2_array_is_null
+ = fold_build2_loc (loc, EQ_EXPR, result_type, p2_array,
+ fold_convert_loc (loc, TREE_TYPE (p2_array),
+ null_pointer_node));
+
+ /* If one of the pointers to the array is null, just compare the other. */
+ if (integer_zerop (p1_array))
+ return p2_array_is_null;
+ else if (integer_zerop (p2_array))
+ return p1_array_is_null;
+
+ /* Otherwise, do the fully-fledged comparison. */
+ same_array
+ = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array, p2_array);
+
+ if (TREE_CODE (p1) == CONSTRUCTOR)
+ p1_bounds = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p1), 1)->value;
+ else
+ p1_bounds
+ = build_component_ref (p1, NULL_TREE,
+ DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p1))), true);
+
+ if (TREE_CODE (p2) == CONSTRUCTOR)
+ p2_bounds = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (p2), 1)->value;
+ else
+ p2_bounds
+ = build_component_ref (p2, NULL_TREE,
+ DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p2))), true);
+
+ same_bounds
+ = fold_build2_loc (loc, EQ_EXPR, result_type, p1_bounds, p2_bounds);
+
+ /* P1_ARRAY == P2_ARRAY && (P1_ARRAY == NULL || P1_BOUNDS == P2_BOUNDS). */
+ return build_binary_op (TRUTH_ANDIF_EXPR, result_type, same_array,
+ build_binary_op (TRUTH_ORIF_EXPR, result_type,
+ p1_array_is_null, same_bounds));
+}
\f
/* Compute the result of applying OP_CODE to LHS and RHS, where both are of
type TYPE. We know that TYPE is a modular type with a nonbinary
right_operand = convert (right_base_type, right_operand);
}
- /* If we are comparing a fat pointer against zero, we just need to
- compare the data pointer. */
- if (TYPE_IS_FAT_POINTER_P (left_base_type)
- && TREE_CODE (right_operand) == CONSTRUCTOR
- && integer_zerop (VEC_index (constructor_elt,
- CONSTRUCTOR_ELTS (right_operand),
- 0)->value))
+ /* If both objects are fat pointers, compare them specially. */
+ if (TYPE_IS_FAT_POINTER_P (left_base_type))
{
- left_operand
- = build_component_ref (left_operand, NULL_TREE,
- TYPE_FIELDS (left_base_type), false);
- right_operand
- = convert (TREE_TYPE (left_operand), integer_zero_node);
+ result
+ = compare_fat_pointers (input_location,
+ result_type, left_operand, right_operand);
+ if (op_code == NE_EXPR)
+ result = invert_truthvalue_loc (EXPR_LOCATION (result), result);
+ else
+ gcc_assert (op_code == EQ_EXPR);
+
+ return result;
}
modulus = NULL_TREE;
break;
case INDIRECT_REF:
- /* If we want to refer to an unconstrained array, use the appropriate
- expression to do so. This will never survive down to the back-end.
- But if TYPE is a thin pointer, first convert to a fat pointer. */
- if (TYPE_IS_THIN_POINTER_P (type)
- && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
- {
- operand
- = convert (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
+ {
+ bool can_never_be_null;
+ tree t = operand;
+
+ while (CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ can_never_be_null = DECL_P (t) && DECL_CAN_NEVER_BE_NULL_P (t);
+
+ /* If TYPE is a thin pointer, first convert to the fat pointer. */
+ if (TYPE_IS_THIN_POINTER_P (type)
+ && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
+ {
+ operand = convert
+ (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
operand);
- type = TREE_TYPE (operand);
- }
+ type = TREE_TYPE (operand);
+ }
- if (TYPE_IS_FAT_POINTER_P (type))
- {
- result = build1 (UNCONSTRAINED_ARRAY_REF,
- TYPE_UNCONSTRAINED_ARRAY (type), operand);
- TREE_READONLY (result)
- = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
- }
+ /* If we want to refer to an unconstrained array, use the appropriate
+ expression. But this will never survive down to the back-end. */
+ if (TYPE_IS_FAT_POINTER_P (type))
+ {
+ result = build1 (UNCONSTRAINED_ARRAY_REF,
+ TYPE_UNCONSTRAINED_ARRAY (type), operand);
+ TREE_READONLY (result)
+ = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
+ }
- /* If we are dereferencing an ADDR_EXPR, return its operand. */
- else if (TREE_CODE (operand) == ADDR_EXPR)
- result = TREE_OPERAND (operand, 0);
+ /* If we are dereferencing an ADDR_EXPR, return its operand. */
+ else if (TREE_CODE (operand) == ADDR_EXPR)
+ result = TREE_OPERAND (operand, 0);
- /* Otherwise, build and fold the indirect reference. */
- else
- {
- result = build_fold_indirect_ref (operand);
- TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
- }
+ /* Otherwise, build and fold the indirect reference. */
+ else
+ {
+ result = build_fold_indirect_ref (operand);
+ TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
+ }
- if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
- {
- TREE_SIDE_EFFECTS (result) = 1;
- if (TREE_CODE (result) == INDIRECT_REF)
- TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
- }
- break;
+ if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
+ {
+ TREE_SIDE_EFFECTS (result) = 1;
+ if (TREE_CODE (result) == INDIRECT_REF)
+ TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
+ }
+
+ if ((TREE_CODE (result) == INDIRECT_REF
+ || TREE_CODE (result) == UNCONSTRAINED_ARRAY_REF)
+ && can_never_be_null)
+ TREE_THIS_NOTRAP (result) = 1;
+
+ break;
+ }
case NEGATE_EXPR:
case BIT_NOT_EXPR:
gcc_assert ((TREE_CODE (record_type) == RECORD_TYPE
|| TREE_CODE (record_type) == UNION_TYPE
|| TREE_CODE (record_type) == QUAL_UNION_TYPE)
- && TYPE_SIZE (record_type)
- && (component != 0) != (field != 0));
+ && COMPLETE_TYPE_P (record_type)
+ && (component == NULL_TREE) != (field == NULL_TREE));
- /* If no field was specified, look for a field with the specified name
- in the current record only. */
+ /* If no field was specified, look for a field with the specified name in
+ the current record only. */
if (!field)
- for (field = TYPE_FIELDS (record_type); field;
- field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (record_type);
+ field;
+ field = DECL_CHAIN (field))
if (DECL_NAME (field) == component)
break;
tree new_field;
/* First loop thru normal components. */
- for (new_field = TYPE_FIELDS (record_type); new_field;
+ for (new_field = TYPE_FIELDS (record_type);
+ new_field;
new_field = DECL_CHAIN (new_field))
if (SAME_FIELD_P (field, new_field))
break;
return ref;
}
- /* Next, loop thru DECL_INTERNAL_P components if we haven't found
- the component in the first search. Doing this search in 2 steps
- is required to avoiding hidden homonymous fields in the
- _Parent field. */
+ /* Next, loop thru DECL_INTERNAL_P components if we haven't found the
+ component in the first search. Doing this search in two steps is
+ required to avoid hidden homonymous fields in the _Parent field. */
if (!new_field)
- for (new_field = TYPE_FIELDS (record_type); new_field;
+ for (new_field = TYPE_FIELDS (record_type);
+ new_field;
new_field = DECL_CHAIN (new_field))
if (DECL_INTERNAL_P (new_field))
{
NULL_TREE, new_field, no_fold_p);
ref = build_simple_component_ref (field_ref, NULL_TREE, field,
no_fold_p);
-
if (ref)
return ref;
}
if (!field)
return NULL_TREE;
- /* If the field's offset has overflowed, do not attempt to access it
- as doing so may trigger sanity checks deeper in the back-end.
- Note that we don't need to warn since this will be done on trying
- to declare the object. */
+ /* If the field's offset has overflowed, do not try to access it, as doing
+ so may trigger sanity checks deeper in the back-end. Note that we don't
+ need to warn since this will be done on trying to declare the object. */
if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST
&& TREE_OVERFLOW (DECL_FIELD_OFFSET (field)))
return NULL_TREE;
- /* Look through conversion between type variants. Note that this
- is transparent as far as the field is concerned. */
+ /* Look through conversion between type variants. This is transparent as
+ far as the field is concerned. */
if (TREE_CODE (record_variable) == VIEW_CONVERT_EXPR
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (record_variable, 0)))
== record_type)
ref = build3 (COMPONENT_REF, TREE_TYPE (field), inner_variable, field,
NULL_TREE);
- if (TREE_READONLY (record_variable) || TREE_READONLY (field))
+ if (TREE_READONLY (record_variable)
+ || TREE_READONLY (field)
+ || TYPE_READONLY (record_type))
TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (record_variable) || TREE_THIS_VOLATILE (field)
+
+ if (TREE_THIS_VOLATILE (record_variable)
+ || TREE_THIS_VOLATILE (field)
|| TYPE_VOLATILE (record_type))
TREE_THIS_VOLATILE (ref) = 1;
/* The generic folder may punt in this case because the inner array type
can be self-referential, but folding is in fact not problematic. */
- else if (TREE_CODE (record_variable) == CONSTRUCTOR
- && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record_variable)))
+ if (TREE_CODE (record_variable) == CONSTRUCTOR
+ && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record_variable)))
{
VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (record_variable);
unsigned HOST_WIDE_INT idx;
return ref;
}
- else
- return fold (ref);
+ return fold (ref);
}
\f
/* Like build_simple_component_ref, except that we give an error if the
TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
- if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ if (code == INDIRECT_REF
+ || code == UNCONSTRAINED_ARRAY_REF
+ || code == ARRAY_REF
+ || code == ARRAY_RANGE_REF)
TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (e);
return result;
TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
- if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ if (code == INDIRECT_REF
+ || code == UNCONSTRAINED_ARRAY_REF
+ || code == ARRAY_REF
+ || code == ARRAY_RANGE_REF)
TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (ref);
return result;