diff options
Diffstat (limited to 'gcc/ada/gcc-interface/decl.c')
-rw-r--r-- | gcc/ada/gcc-interface/decl.c | 97 |
1 files changed, 74 insertions, 23 deletions
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 5ea1b16..aea191c 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -2197,14 +2197,16 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) } else { + /* We make the fields addressable for the sake of compatibility + with languages for which the regular fields are addressable. */ tem = create_field_decl (get_identifier ("P_ARRAY"), ptr_type_node, gnu_fat_type, - NULL_TREE, NULL_TREE, 0, 0); + NULL_TREE, NULL_TREE, 0, 1); DECL_CHAIN (tem) = create_field_decl (get_identifier ("P_BOUNDS"), gnu_ptr_template, gnu_fat_type, - NULL_TREE, NULL_TREE, 0, 0); + NULL_TREE, NULL_TREE, 0, 1); finish_fat_pointer_type (gnu_fat_type, tem); SET_TYPE_UNCONSTRAINED_ARRAY (gnu_fat_type, gnu_type); } @@ -2327,7 +2329,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) finish_record_type (gnu_template_type, gnu_template_fields, 0, debug_info_p); TYPE_CONTEXT (gnu_template_type) = current_function_decl; - TYPE_READONLY (gnu_template_type) = 1; /* If Component_Size is not already specified, annotate it with the size of the component. */ @@ -3054,15 +3055,24 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) || type_annotate_only); } - /* Make a node for the record. If we are not defining the record, - suppress expanding incomplete types. */ + /* Make a node for the record type. */ gnu_type = make_node (tree_code_for_record_type (gnat_entity)); TYPE_NAME (gnu_type) = gnu_entity_name; TYPE_PACKED (gnu_type) = (packed != 0) || has_align || has_rep; TYPE_REVERSE_STORAGE_ORDER (gnu_type) = Reverse_Storage_Order (gnat_entity); + + /* If the record type has discriminants, pointers to it may also point + to constrained subtypes of it, so mark it as may_alias for LTO. */ + if (has_discr) + prepend_one_attribute + (&attr_list, ATTR_MACHINE_ATTRIBUTE, + get_identifier ("may_alias"), NULL_TREE, + gnat_entity); + process_attributes (&gnu_type, &attr_list, true, gnat_entity); + /* If we are not defining it, suppress expanding incomplete types. */ if (!definition) { defer_incomplete_level++; @@ -8320,12 +8330,12 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, if (p_gnu_rep_list && gnu_rep_list) *p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_rep_list); - /* Deal with the annoying case of an extension of a record with variable size - and partial rep clause, for which the _Parent field is forced at offset 0 - and has variable size, which we do not support below. Note that we cannot - do it if the field has fixed size because we rely on the presence of the - REP part built below to trigger the reordering of the fields in a derived - record type when all the fields have a fixed position. */ + /* Deal with the case of an extension of a record type with variable size and + partial rep clause, for which the _Parent field is forced at offset 0 and + has variable size. Note that we cannot do it if the field has fixed size + because we rely on the presence of the REP part built below to trigger the + reordering of the fields in a derived record type when all the fields have + a fixed position. */ else if (gnu_rep_list && !DECL_CHAIN (gnu_rep_list) && TREE_CODE (DECL_SIZE (gnu_rep_list)) != INTEGER_CST @@ -8343,33 +8353,52 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, record, before the others, if we also have fields without rep clause. */ else if (gnu_rep_list) { - tree gnu_rep_type, gnu_rep_part; - int i, len = list_length (gnu_rep_list); - tree *gnu_arr = XALLOCAVEC (tree, len); + tree gnu_parent, gnu_rep_type; /* If all the fields have a rep clause, we can do a flat layout. */ layout_with_rep = !gnu_field_list && (!gnu_variant_part || variants_have_rep); + + /* Same as above but the extension itself has a rep clause, in which case + we need to set aside the _Parent field to lay out the REP part. */ + if (TREE_CODE (DECL_SIZE (gnu_rep_list)) != INTEGER_CST + && !layout_with_rep + && !variants_have_rep + && first_free_pos + && integer_zerop (first_free_pos) + && integer_zerop (bit_position (gnu_rep_list))) + { + gnu_parent = gnu_rep_list; + gnu_rep_list = DECL_CHAIN (gnu_rep_list); + } + else + gnu_parent = NULL_TREE; + gnu_rep_type = layout_with_rep ? gnu_record_type : make_node (RECORD_TYPE); - for (gnu_field = gnu_rep_list, i = 0; - gnu_field; - gnu_field = DECL_CHAIN (gnu_field), i++) - gnu_arr[i] = gnu_field; + /* Sort the fields in order of increasing bit position. */ + const int len = list_length (gnu_rep_list); + tree *gnu_arr = XALLOCAVEC (tree, len); + + gnu_field = gnu_rep_list; + for (int i = 0; i < len; i++) + { + gnu_arr[i] = gnu_field; + gnu_field = DECL_CHAIN (gnu_field); + } qsort (gnu_arr, len, sizeof (tree), compare_field_bitpos); - /* Put the fields in the list in order of increasing position, which - means we start from the end. */ gnu_rep_list = NULL_TREE; - for (i = len - 1; i >= 0; i--) + for (int i = len - 1; i >= 0; i--) { DECL_CHAIN (gnu_arr[i]) = gnu_rep_list; gnu_rep_list = gnu_arr[i]; DECL_CONTEXT (gnu_arr[i]) = gnu_rep_type; } + /* Do the layout of the REP part, if any. */ if (layout_with_rep) gnu_field_list = gnu_rep_list; else @@ -8378,14 +8407,36 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, = create_concat_name (gnat_record_type, "REP"); TYPE_REVERSE_STORAGE_ORDER (gnu_rep_type) = TYPE_REVERSE_STORAGE_ORDER (gnu_record_type); - finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info); + finish_record_type (gnu_rep_type, gnu_rep_list, 1, false); /* If FIRST_FREE_POS is nonzero, we need to ensure that the fields without rep clause are laid out starting from this position. Therefore, we force it as a minimal size on the REP part. */ - gnu_rep_part + tree gnu_rep_part = create_rep_part (gnu_rep_type, gnu_record_type, first_free_pos); + /* If this is an extension, put back the _Parent field as the first + field of the REP part at offset 0 and update its layout. */ + if (gnu_parent) + { + const unsigned int align = DECL_ALIGN (gnu_parent); + DECL_CHAIN (gnu_parent) = TYPE_FIELDS (gnu_rep_type); + TYPE_FIELDS (gnu_rep_type) = gnu_parent; + DECL_CONTEXT (gnu_parent) = gnu_rep_type; + if (align > TYPE_ALIGN (gnu_rep_type)) + { + SET_TYPE_ALIGN (gnu_rep_type, align); + TYPE_SIZE (gnu_rep_type) + = round_up (TYPE_SIZE (gnu_rep_type), align); + TYPE_SIZE_UNIT (gnu_rep_type) + = round_up (TYPE_SIZE_UNIT (gnu_rep_type), align); + SET_DECL_ALIGN (gnu_rep_part, align); + } + } + + if (debug_info) + rest_of_record_type_compilation (gnu_rep_type); + /* Chain the REP part at the beginning of the field list. */ DECL_CHAIN (gnu_rep_part) = gnu_field_list; gnu_field_list = gnu_rep_part; |