@@ -113,6 +113,23 @@ static VEC (tree,heap) *defer_finalize_list;
static GTY ((if_marked ("tree_int_map_marked_p"),
param_is (struct tree_int_map))) htab_t annotate_value_cache;
+typedef struct GTY(()) rec_variant_d {
+ /* The type of the variant. */
+ tree type;
+
+ /* The associated field. */
+ tree field;
+
+ /* The value of the qualifier. */
+ tree qual;
+
+ /* The record associated with this variant. */
+ tree record;
+} rec_variant;
+
+DEF_VEC_O(rec_variant);
+DEF_VEC_ALLOC_O(rec_variant,heap);
+
enum alias_set_op
{
ALIAS_SET_COPY,
@@ -147,7 +164,8 @@ static Uint annotate_value (tree);
static void annotate_rep (Entity_Id, tree);
static tree build_position_list (tree, bool, tree, tree, unsigned int, tree);
static tree build_subst_list (Entity_Id, Entity_Id, bool);
-static tree build_variant_list (tree, tree, tree);
+static void build_variant_list_1 (tree, tree, VEC(rec_variant,heap) **);
+static VEC(rec_variant,heap) *build_variant_list (tree, tree);
static tree validate_size (Uint, tree, Entity_Id, enum tree_code, bool, bool);
static void set_rm_size (Uint, tree, Entity_Id);
static tree make_type_from_size (tree, tree, bool);
@@ -157,7 +175,8 @@ static void check_ok_for_atomic (tree, Entity_Id, bool);
static tree create_field_decl_from (tree, tree, tree, tree, tree, tree);
static tree get_rep_part (tree);
static tree get_variant_part (tree);
-static tree create_variant_part_from (tree, tree, tree, tree, tree);
+static tree create_variant_part_from (tree, VEC(rec_variant,heap) *,
+ tree, tree, tree);
static void copy_and_substitute_in_size (tree, tree, tree);
static void rest_of_type_decl_compilation_no_defer (tree);
@@ -3041,9 +3060,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
tree 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_variant_list, gnu_pos_list, gnu_field_list = NULL_TREE;
+ tree gnu_pos_list, gnu_field_list = NULL_TREE;
bool selected_variant = false;
Entity_Id gnat_field;
+ VEC(rec_variant,heap) *gnu_variant_list;
gnu_type = make_node (RECORD_TYPE);
TYPE_NAME (gnu_type) = gnu_entity_name;
@@ -3071,15 +3091,19 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
union for the variants that are still relevant. */
if (gnu_variant_part)
{
+ rec_variant *v;
+ unsigned ix;
+
gnu_variant_list
= build_variant_list (TREE_TYPE (gnu_variant_part),
- gnu_subst_list, NULL_TREE);
+ gnu_subst_list);
/* If all the qualifiers are unconditionally true, the
innermost variant is statically selected. */
selected_variant = true;
- for (t = gnu_variant_list; t; t = TREE_CHAIN (t))
- if (!integer_onep (TREE_VEC_ELT (TREE_VALUE (t), 1)))
+ FOR_EACH_VEC_ELT_REVERSE (rec_variant, gnu_variant_list,
+ ix, v)
+ if (!integer_onep (v->qual))
{
selected_variant = false;
break;
@@ -3087,20 +3111,21 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
/* Otherwise, create the new variants. */
if (!selected_variant)
- for (t = gnu_variant_list; t; t = TREE_CHAIN (t))
+ FOR_EACH_VEC_ELT_REVERSE (rec_variant, gnu_variant_list,
+ ix, v)
{
- tree old_variant = TREE_PURPOSE (t);
+ tree old_variant = v->type;
tree new_variant = make_node (RECORD_TYPE);
TYPE_NAME (new_variant)
= DECL_NAME (TYPE_NAME (old_variant));
copy_and_substitute_in_size (new_variant, old_variant,
gnu_subst_list);
- TREE_VEC_ELT (TREE_VALUE (t), 2) = new_variant;
+ v->record = new_variant;
}
}
else
{
- gnu_variant_list = NULL_TREE;
+ gnu_variant_list = NULL;
selected_variant = false;
}
@@ -3183,13 +3208,23 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_cont_type = gnu_type;
else
{
- t = purpose_member (gnu_context, gnu_variant_list);
+ rec_variant *v;
+ unsigned ix;
+
+ t = NULL_TREE;
+ FOR_EACH_VEC_ELT_REVERSE (rec_variant,
+ gnu_variant_list, ix, v)
+ if (v->type == gnu_context)
+ {
+ t = v->type;
+ break;
+ }
if (t)
{
if (selected_variant)
gnu_cont_type = gnu_type;
else
- gnu_cont_type = TREE_VEC_ELT (TREE_VALUE (t), 2);
+ gnu_cont_type = v->record;
}
else
/* The front-end may pass us "ghost" components if
@@ -3315,6 +3350,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnat_entity);
}
+ VEC_free (rec_variant, heap, gnu_variant_list);
+
/* Now we can finalize it. */
rest_of_record_type_compilation (gnu_type);
}
@@ -7541,15 +7578,13 @@ build_subst_list (Entity_Id gnat_subtype, Entity_Id gnat_type, bool definition)
return gnu_list;
}
-/* Scan all fields in QUAL_UNION_TYPE and return a TREE_LIST describing the
- variants of QUAL_UNION_TYPE that are still relevant after applying the
- substitutions described in SUBST_LIST. TREE_PURPOSE is the type of the
- variant and TREE_VALUE is a TREE_VEC containing the field, the new value
- of the qualifier and NULL_TREE respectively. GNU_LIST is a pre-existing
- list to be chained to the newly created entries. */
+/* Scan all fields in QUAL_UNION_TYPE and return a VEC describing the
+ variants of QUAL_UNION_TYPE that are still relevant after applying
+ the substitutions described in SUBST_LIST. */
-static tree
-build_variant_list (tree qual_union_type, tree subst_list, tree gnu_list)
+static void
+build_variant_list_1 (tree qual_union_type, tree subst_list,
+ VEC(rec_variant,heap) **variant_list)
{
tree gnu_field;
@@ -7566,18 +7601,20 @@ build_variant_list (tree qual_union_type, tree subst_list, tree gnu_list)
still be accessed. */
if (!integer_zerop (qual))
{
+ rec_variant *v;
tree variant_type = TREE_TYPE (gnu_field), variant_subpart;
- tree v = make_tree_vec (3);
- TREE_VEC_ELT (v, 0) = gnu_field;
- TREE_VEC_ELT (v, 1) = qual;
- TREE_VEC_ELT (v, 2) = NULL_TREE;
- gnu_list = tree_cons (variant_type, v, gnu_list);
+
+ v = VEC_safe_push (rec_variant, heap, *variant_list, NULL);
+ v->type = variant_type;
+ v->field = gnu_field;
+ v->qual = qual;
+ v->record = NULL_TREE;
/* Recurse on the variant subpart of the variant, if any. */
variant_subpart = get_variant_part (variant_type);
if (variant_subpart)
- gnu_list = build_variant_list (TREE_TYPE (variant_subpart),
- subst_list, gnu_list);
+ build_variant_list_1 (TREE_TYPE (variant_subpart),
+ subst_list, variant_list);
/* If the new qualifier is unconditionally true, the subsequent
variants cannot be accessed. */
@@ -7585,8 +7622,16 @@ build_variant_list (tree qual_union_type, tree subst_list, tree gnu_list)
break;
}
}
+}
- return gnu_list;
+static VEC(rec_variant,heap) *
+build_variant_list (tree qual_union_type, tree subst_list)
+{
+ VEC(rec_variant,heap) *variant_list = NULL;
+
+ build_variant_list_1 (qual_union_type, subst_list, &variant_list);
+
+ return variant_list;
}
/* UINT_SIZE is a Uint giving the specified size for an object of GNU_TYPE
@@ -8307,13 +8352,16 @@ get_variant_part (tree record_type)
layout. */
static tree
-create_variant_part_from (tree old_variant_part, tree variant_list,
+create_variant_part_from (tree old_variant_part,
+ VEC(rec_variant,heap) *variant_list,
tree record_type, tree pos_list, tree subst_list)
{
tree offset = DECL_FIELD_OFFSET (old_variant_part);
tree old_union_type = TREE_TYPE (old_variant_part);
- tree new_union_type, new_variant_part, t;
+ tree new_union_type, new_variant_part;
tree union_field_list = NULL_TREE;
+ rec_variant *v;
+ unsigned ix;
/* First create the type of the variant part from that of the old one. */
new_union_type = make_node (QUAL_UNION_TYPE);
@@ -8341,9 +8389,9 @@ create_variant_part_from (tree old_variant_part, tree variant_list,
copy_and_substitute_in_size (new_union_type, old_union_type, subst_list);
/* Now finish up the new variants and populate the union type. */
- for (t = variant_list; t; t = TREE_CHAIN (t))
+ FOR_EACH_VEC_ELT_REVERSE (rec_variant, variant_list, ix, v)
{
- tree old_field = TREE_VEC_ELT (TREE_VALUE (t), 0), new_field;
+ tree old_field = v->field, new_field;
tree old_variant, old_variant_subpart, new_variant, field_list;
/* Skip variants that don't belong to this nesting level. */
@@ -8351,12 +8399,12 @@ create_variant_part_from (tree old_variant_part, tree variant_list,
continue;
/* Retrieve the list of fields already added to the new variant. */
- new_variant = TREE_VEC_ELT (TREE_VALUE (t), 2);
+ new_variant = v->record;;
field_list = TYPE_FIELDS (new_variant);
/* If the old variant had a variant subpart, we need to create a new
variant subpart and add it to the field list. */
- old_variant = TREE_PURPOSE (t);
+ old_variant = v->type;
old_variant_subpart = get_variant_part (old_variant);
if (old_variant_subpart)
{
@@ -8378,7 +8426,7 @@ create_variant_part_from (tree old_variant_part, tree variant_list,
= create_field_decl_from (old_field, new_variant, new_union_type,
TYPE_SIZE (new_variant),
pos_list, subst_list);
- DECL_QUALIFIER (new_field) = TREE_VEC_ELT (TREE_VALUE (t), 1);
+ DECL_QUALIFIER (new_field) = v->qual;
DECL_INTERNAL_P (new_field) = 1;
DECL_CHAIN (new_field) = union_field_list;
union_field_list = new_field;