From 0c2837b5c408f8fd2b023a7bf00be9abd1e28a28 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 30 Aug 2019 15:12:20 +0000 Subject: [PATCH] gigi.h (aggregate_type_contains_array_p): Declare. * gcc-interface/gigi.h (aggregate_type_contains_array_p): Declare. * gcc-interface/decl.c (gnat_to_gnu_entity) : For an extension, test Has_Record_Rep_Clause instead of Has_Specified_Layout. (adjust_packed): Return 0 if the type of the field is an aggregate type that contains (or is) a self-referential array. (type_has_variable_size): Delete. * gcc-interface/utils.c (inish_record_type): Constify a variable. (aggregate_type_contains_array_p): Add parameter SELF_REFERENTIAL. : Pass it in the recursive call. : If it is true, return true only if the array type is self-referential. (create_field_decl): Streamline the setting of the alignment on the field. Pass false to aggregate_type_contains_array_p. From-SVN: r275196 --- gcc/ada/ChangeLog | 16 ++++++++ gcc/ada/gcc-interface/decl.c | 43 +++++--------------- gcc/ada/gcc-interface/gigi.h | 5 +++ gcc/ada/gcc-interface/utils.c | 69 ++++++++++++++++++-------------- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gnat.dg/pack24.adb | 38 ++++++++++++++++++ 6 files changed, 112 insertions(+), 63 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/pack24.adb diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 71681b69258..636eb7c9dcd 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,19 @@ +2019-08-30 Eric Botcazou + + * gcc-interface/gigi.h (aggregate_type_contains_array_p): Declare. + * gcc-interface/decl.c (gnat_to_gnu_entity) : For an + extension, test Has_Record_Rep_Clause instead of Has_Specified_Layout. + (adjust_packed): Return 0 if the type of the field is an aggregate + type that contains (or is) a self-referential array. + (type_has_variable_size): Delete. + * gcc-interface/utils.c (inish_record_type): Constify a variable. + (aggregate_type_contains_array_p): Add parameter SELF_REFERENTIAL. + : Pass it in the recursive call. + : If it is true, return true only if the array type is + self-referential. + (create_field_decl): Streamline the setting of the alignment on the + field. Pass false to aggregate_type_contains_array_p. + 2019-08-30 Eric Botcazou * gcc-interface/trans.c (lvalue_required_p) : Adjust GNU_TYPE diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 0695c2f00e8..5fce2ad772d 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -202,7 +202,6 @@ static void prepend_one_attribute_pragma (struct attrib **, Node_Id); static void prepend_attributes (struct attrib **, Entity_Id); static tree elaborate_expression (Node_Id, Entity_Id, const char *, bool, bool, bool); -static bool type_has_variable_size (tree); static tree elaborate_expression_1 (tree, Entity_Id, const char *, bool, bool); static tree elaborate_expression_2 (tree, Entity_Id, const char *, bool, bool, unsigned int); @@ -2953,10 +2952,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) : 0; const bool has_align = Known_Alignment (gnat_entity); const bool has_discr = Has_Discriminants (gnat_entity); - const bool has_rep = Has_Specified_Layout (gnat_entity); const bool is_extension = (Is_Tagged_Type (gnat_entity) && Nkind (record_definition) == N_Derived_Type_Definition); + const bool has_rep + = is_extension + ? Has_Record_Rep_Clause (gnat_entity) + : Has_Specified_Layout (gnat_entity); const bool is_unchecked_union = Is_Unchecked_Union (gnat_entity); bool all_rep = has_rep; @@ -6865,11 +6867,13 @@ choices_to_gnu (tree gnu_operand, Node_Id gnat_choices) static int adjust_packed (tree field_type, tree record_type, int packed) { - /* If the field contains an item of variable size, we cannot pack it - because we cannot create temporaries of non-fixed size in case - we need to take the address of the field. See addressable_p and - the notes on the addressability issues for further details. */ - if (type_has_variable_size (field_type)) + /* If the field contains an array with self-referential size, we'd better + not pack it because this would misalign it and, therefore, cause large + temporaries to be created in case we need to take the address of the + field. See addressable_p and the notes on the addressability issues + for further details. */ + if (AGGREGATE_TYPE_P (field_type) + && aggregate_type_contains_array_p (field_type, true)) return 0; /* In the other cases, we can honor the packing. */ @@ -7274,31 +7278,6 @@ components_need_strict_alignment (Node_Id component_list) return false; } -/* Return true if TYPE is a type with variable size or a padding type with a - field of variable size or a record that has a field with such a type. */ - -static bool -type_has_variable_size (tree type) -{ - tree field; - - if (!TREE_CONSTANT (TYPE_SIZE (type))) - return true; - - if (TYPE_IS_PADDING_P (type) - && !TREE_CONSTANT (DECL_SIZE (TYPE_FIELDS (type)))) - return true; - - if (!RECORD_OR_UNION_TYPE_P (type)) - return false; - - for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - if (type_has_variable_size (TREE_TYPE (field))) - return true; - - return false; -} - /* Return true if FIELD is an artificial field. */ static bool diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 21af83ee7f8..edfcbd5a782 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -835,6 +835,11 @@ extern tree get_base_type (tree type); in bits. If we don't know anything about the alignment, return 0. */ extern unsigned int known_alignment (tree exp); +/* Return true if TYPE, an aggregate type, contains (or is) an array. + If SELF_REFERENTIAL is true, then an additional requirement on the + array is that it be self-referential. */ +extern bool aggregate_type_contains_array_p (tree type, bool self_referential); + /* Return true if VALUE is a multiple of FACTOR. FACTOR must be a power of 2. */ extern bool value_factor_p (tree value, unsigned HOST_WIDE_INT factor); diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 020257668e0..8a38b3474b3 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -1948,7 +1948,7 @@ finish_record_type (tree record_type, tree field_list, int rep_level, if (DECL_BIT_FIELD (field) && operand_equal_p (this_size, TYPE_SIZE (type), 0)) { - unsigned int align = TYPE_ALIGN (type); + const unsigned int align = TYPE_ALIGN (type); /* In the general case, type alignment is required. */ if (value_factor_p (pos, align)) @@ -2764,10 +2764,12 @@ create_var_decl (tree name, tree asm_name, tree type, tree init, return var_decl; } -/* Return true if TYPE, an aggregate type, contains (or is) an array. */ +/* Return true if TYPE, an aggregate type, contains (or is) an array. + If SELF_REFERENTIAL is true, then an additional requirement on the + array is that it be self-referential. */ -static bool -aggregate_type_contains_array_p (tree type) +bool +aggregate_type_contains_array_p (tree type, bool self_referential) { switch (TREE_CODE (type)) { @@ -2778,13 +2780,14 @@ aggregate_type_contains_array_p (tree type) tree field; for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (AGGREGATE_TYPE_P (TREE_TYPE (field)) - && aggregate_type_contains_array_p (TREE_TYPE (field))) + && aggregate_type_contains_array_p (TREE_TYPE (field), + self_referential)) return true; return false; } case ARRAY_TYPE: - return true; + return self_referential ? type_contains_placeholder_p (type) : true; default: gcc_unreachable (); @@ -2808,18 +2811,6 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, DECL_CONTEXT (field_decl) = record_type; TREE_READONLY (field_decl) = TYPE_READONLY (type); - /* If FIELD_TYPE is BLKmode, we must ensure this is aligned to at least a - byte boundary since GCC cannot handle less-aligned BLKmode bitfields. - Likewise for an aggregate without specified position that contains an - array, because in this case slices of variable length of this array - must be handled by GCC and variable-sized objects need to be aligned - to at least a byte boundary. */ - if (packed && (TYPE_MODE (type) == BLKmode - || (!pos - && AGGREGATE_TYPE_P (type) - && aggregate_type_contains_array_p (type)))) - SET_DECL_ALIGN (field_decl, BITS_PER_UNIT); - /* If a size is specified, use it. Otherwise, if the record type is packed compute a size to use, which may differ from the object's natural size. We always set a size in this case to trigger the checks for bitfield @@ -2872,23 +2863,39 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, DECL_PACKED (field_decl) = pos ? DECL_BIT_FIELD (field_decl) : packed; + /* If FIELD_TYPE is BLKmode, we must ensure this is aligned to at least a + byte boundary since GCC cannot handle less-aligned BLKmode bitfields. + Likewise for an aggregate without specified position that contains an + array, because in this case slices of variable length of this array + must be handled by GCC and variable-sized objects need to be aligned + to at least a byte boundary. */ + if (packed && (TYPE_MODE (type) == BLKmode + || (!pos + && AGGREGATE_TYPE_P (type) + && aggregate_type_contains_array_p (type, false)))) + SET_DECL_ALIGN (field_decl, BITS_PER_UNIT); + /* Bump the alignment if need be, either for bitfield/packing purposes or - to satisfy the type requirements if no such consideration applies. When + to satisfy the type requirements if no such considerations apply. When we get the alignment from the type, indicate if this is from an explicit user request, which prevents stor-layout from lowering it later on. */ - { - unsigned int bit_align - = (DECL_BIT_FIELD (field_decl) ? 1 - : packed && TYPE_MODE (type) != BLKmode ? BITS_PER_UNIT : 0); + else + { + const unsigned int field_align + = DECL_BIT_FIELD (field_decl) + ? 1 + : packed + ? BITS_PER_UNIT + : 0; - if (bit_align > DECL_ALIGN (field_decl)) - SET_DECL_ALIGN (field_decl, bit_align); - else if (!bit_align && TYPE_ALIGN (type) > DECL_ALIGN (field_decl)) - { - SET_DECL_ALIGN (field_decl, TYPE_ALIGN (type)); - DECL_USER_ALIGN (field_decl) = TYPE_USER_ALIGN (type); - } - } + if (field_align > DECL_ALIGN (field_decl)) + SET_DECL_ALIGN (field_decl, field_align); + else if (!field_align && TYPE_ALIGN (type) > DECL_ALIGN (field_decl)) + { + SET_DECL_ALIGN (field_decl, TYPE_ALIGN (type)); + DECL_USER_ALIGN (field_decl) = TYPE_USER_ALIGN (type); + } + } if (pos) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5044002c09c..715c4173ce5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-08-30 Eric Botcazou + + * gnat.dg/pack24.adb: New test. + 2019-08-30 Jeff Law * gcc.target/mips/r10k-cache-barrier-9.c: Suppress warnings. diff --git a/gcc/testsuite/gnat.dg/pack24.adb b/gcc/testsuite/gnat.dg/pack24.adb new file mode 100644 index 00000000000..90d6134c7ab --- /dev/null +++ b/gcc/testsuite/gnat.dg/pack24.adb @@ -0,0 +1,38 @@ +-- { dg-do run } + +with Interfaces; + +procedure Pack24 is + + type Enum_1 is (Lit_1); + for Enum_1'SIZE use 16; + + type Rec1(D1 : Enum_1 := Lit_1) is + record + case D1 is + when Lit_1 => + F1 : Interfaces.Unsigned_16; + when others => + Null; + end case; + end record; + pragma Pack(Rec1); + + type Rec2 is + record + F1 : Interfaces.Unsigned_16; + F2 : Rec1; + end record; + pragma Pack(Rec2); + + type Rec3 is record + F1 : Interfaces.Unsigned_8; + F2 : Rec2; + end record; + pragma Pack(Rec3); + +begin + if Rec3'Size /= 56 then + raise Program_Error; + end if; +end; -- 2.30.2