diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2020-09-11 11:14:49 +0200 |
---|---|---|
committer | Eric Botcazou <ebotcazou@adacore.com> | 2020-09-11 11:14:49 +0200 |
commit | ef4ab841d94a4f6ec975c9653c69faeeb85c78e8 (patch) | |
tree | 80865fa17b4278a87fcb9baf63c29ddc36e2b443 /gcc/ada | |
parent | b5ffd55a61df01d226f3fa4260f108bda8565c16 (diff) | |
download | gcc-ef4ab841d94a4f6ec975c9653c69faeeb85c78e8.zip gcc-ef4ab841d94a4f6ec975c9653c69faeeb85c78e8.tar.gz gcc-ef4ab841d94a4f6ec975c9653c69faeeb85c78e8.tar.bz2 |
Fix ICE on nested packed variant record type
This is a regression present on the mainline and 10 branch: the compiler
aborts on code accessing a component of a packed record type whose type
is a packed discriminated record type with variant part.
gcc/ada/ChangeLog:
* gcc-interface/utils.c (type_has_variable_size): New function.
(create_field_decl): In the packed case, also force byte alignment
when the type of the field has variable size.
gcc/testsuite/ChangeLog:
* gnat.dg/pack27.adb: New test.
* gnat.dg/pack27_pkg.ads: New helper.
Diffstat (limited to 'gcc/ada')
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index a96fde6..3065fcb 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -2905,6 +2905,31 @@ aggregate_type_contains_array_p (tree type, bool self_referential) } } +/* 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 a FIELD_DECL node. NAME is the field's name, TYPE is its type and RECORD_TYPE is the type of the enclosing record. If SIZE is nonzero, it is the specified size of the field. If POS is nonzero, it is the bit @@ -2974,13 +2999,15 @@ 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. + /* If FIELD_TYPE has BLKmode, we must ensure this is aligned to at least + a byte boundary since GCC cannot handle less aligned BLKmode bitfields. + Likewise if it has a variable size and no specified position because + variable-sized objects need to be aligned to at least a byte boundary. 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. */ + array because, in this case, slices of variable length of this array + must be handled by GCC and have variable size. */ if (packed && (TYPE_MODE (type) == BLKmode + || (!pos && type_has_variable_size (type)) || (!pos && AGGREGATE_TYPE_P (type) && aggregate_type_contains_array_p (type, false)))) |