aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/gcc-interface/decl.c')
-rw-r--r--gcc/ada/gcc-interface/decl.c68
1 files changed, 50 insertions, 18 deletions
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 9e1ecb0..dd912f3 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -6,7 +6,7 @@
* *
* C Implementation File *
* *
- * Copyright (C) 1992-2013, Free Software Foundation, Inc. *
+ * Copyright (C) 1992-2014, Free Software Foundation, Inc. *
* *
* GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- *
@@ -147,6 +147,7 @@ static bool array_type_has_nonaliased_component (tree, Entity_Id);
static bool compile_time_known_address_p (Node_Id);
static bool cannot_be_superflat_p (Node_Id);
static bool constructor_address_p (tree);
+static int compare_field_bitpos (const PTR, const PTR);
static bool components_to_record (tree, Node_Id, tree, int, bool, bool, bool,
bool, bool, bool, bool, bool, tree, tree *);
static Uint annotate_value (tree);
@@ -3341,9 +3342,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
{
vec<subst_pair> gnu_subst_list
= build_subst_list (gnat_entity, gnat_base_type, definition);
- tree gnu_unpad_base_type, gnu_rep_part, gnu_variant_part, t;
+ tree gnu_unpad_base_type, gnu_rep_part, gnu_variant_part;
tree gnu_pos_list, gnu_field_list = NULL_TREE;
- bool selected_variant = false;
+ bool selected_variant = false, all_constant_pos = true;
Entity_Id gnat_field;
vec<variant_desc> gnu_variant_list;
@@ -3362,7 +3363,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
else
gnu_unpad_base_type = gnu_base_type;
- /* Look for a variant part in the base type. */
+ /* Look for REP and variant parts in the base type. */
+ gnu_rep_part = get_rep_part (gnu_unpad_base_type);
gnu_variant_part = get_variant_part (gnu_unpad_base_type);
/* If there is a variant part, we must compute whether the
@@ -3414,13 +3416,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
selected_variant = false;
}
+ /* Make a list of fields and their position in the base type. */
gnu_pos_list
= build_position_list (gnu_unpad_base_type,
gnu_variant_list.exists ()
- && !selected_variant,
+ && !selected_variant,
size_zero_node, bitsize_zero_node,
BIGGEST_ALIGNMENT, NULL_TREE);
+ /* Now go down every component in the subtype and compute its
+ size and position from those of the component in the base
+ type and from the constraints of the subtype. */
for (gnat_field = First_Entity (gnat_entity);
Present (gnat_field);
gnat_field = Next_Entity (gnat_field))
@@ -3428,8 +3434,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
|| Ekind (gnat_field) == E_Discriminant)
&& !(Present (Corresponding_Discriminant (gnat_field))
&& Is_Tagged_Type (gnat_base_type))
- && Underlying_Type (Scope (Original_Record_Component
- (gnat_field)))
+ && Underlying_Type
+ (Scope (Original_Record_Component (gnat_field)))
== gnat_base_type)
{
Name_Id gnat_name = Chars (gnat_field);
@@ -3438,7 +3444,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
tree gnu_old_field
= gnat_to_gnu_field_decl (gnat_old_field);
tree gnu_context = DECL_CONTEXT (gnu_old_field);
- tree gnu_field, gnu_field_type, gnu_size;
+ tree gnu_field, gnu_field_type, gnu_size, gnu_pos;
tree gnu_cont_type, gnu_last = NULL_TREE;
/* If the type is the same, retrieve the GCC type from the
@@ -3489,24 +3495,21 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
and put the field either in the new type if there is a
selected variant or in one of the new variants. */
if (gnu_context == gnu_unpad_base_type
- || ((gnu_rep_part = get_rep_part (gnu_unpad_base_type))
+ || (gnu_rep_part
&& gnu_context == TREE_TYPE (gnu_rep_part)))
gnu_cont_type = gnu_type;
else
{
variant_desc *v;
unsigned int i;
+ tree rep_part;
- t = NULL_TREE;
FOR_EACH_VEC_ELT (gnu_variant_list, i, v)
if (gnu_context == v->type
- || ((gnu_rep_part = get_rep_part (v->type))
- && gnu_context == TREE_TYPE (gnu_rep_part)))
- {
- t = v->type;
- break;
- }
- if (t)
+ || ((rep_part = get_rep_part (v->type))
+ && gnu_context == TREE_TYPE (rep_part)))
+ break;
+ if (v)
{
if (selected_variant)
gnu_cont_type = gnu_type;
@@ -3525,6 +3528,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
= create_field_decl_from (gnu_old_field, gnu_field_type,
gnu_cont_type, gnu_size,
gnu_pos_list, gnu_subst_list);
+ gnu_pos = DECL_FIELD_OFFSET (gnu_field);
/* Put it in one of the new variants directly. */
if (gnu_cont_type != gnu_type)
@@ -3557,14 +3561,42 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_field_list = gnu_field;
if (!gnu_last)
gnu_last = gnu_field;
+ if (TREE_CODE (gnu_pos) != INTEGER_CST)
+ all_constant_pos = false;
}
save_gnu_tree (gnat_field, gnu_field, false);
}
+ /* If there is a variant list, a selected variant and the fields
+ all have a constant position, put them in order of increasing
+ position to match that of constant CONSTRUCTORs. Likewise if
+ there is no variant list but a REP part, since the latter has
+ been flattened in the process. */
+ if (((gnu_variant_list.exists () && selected_variant)
+ || (!gnu_variant_list.exists () && gnu_rep_part))
+ && all_constant_pos)
+ {
+ const int len = list_length (gnu_field_list);
+ tree *field_arr = XALLOCAVEC (tree, len), t;
+ int i;
+
+ for (t = gnu_field_list, i = 0; t; t = DECL_CHAIN (t), i++)
+ field_arr[i] = t;
+
+ qsort (field_arr, len, sizeof (tree), compare_field_bitpos);
+
+ gnu_field_list = NULL_TREE;
+ for (i = 0; i < len; i++)
+ {
+ DECL_CHAIN (field_arr[i]) = gnu_field_list;
+ gnu_field_list = field_arr[i];
+ }
+ }
+
/* If there is a variant list and no selected variant, we need
to create the nest of variant parts from the old nest. */
- if (gnu_variant_list.exists () && !selected_variant)
+ else if (gnu_variant_list.exists () && !selected_variant)
{
tree new_variant_part
= create_variant_part_from (gnu_variant_part,