diff options
Diffstat (limited to 'gcc/ada/utils.c')
-rw-r--r-- | gcc/ada/utils.c | 94 |
1 files changed, 59 insertions, 35 deletions
diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c index 32cbbffa2a9..58f0b68c4fc 100644 --- a/gcc/ada/utils.c +++ b/gcc/ada/utils.c @@ -750,9 +750,9 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, tree name = TYPE_NAME (record_type); tree ada_size = bitsize_zero_node; tree size = bitsize_zero_node; - bool var_size = false; bool had_size = TYPE_SIZE (record_type) != 0; bool had_size_unit = TYPE_SIZE_UNIT (record_type) != 0; + bool had_align = TYPE_ALIGN (record_type) != 0; tree field; if (name && TREE_CODE (name) == TYPE_DECL) @@ -805,33 +805,55 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, for (field = fieldlist; field; field = TREE_CHAIN (field)) { - tree pos = bit_position (field); - tree type = TREE_TYPE (field); + tree pos = bit_position (field); tree this_size = DECL_SIZE (field); - tree this_ada_size = DECL_SIZE (field); + tree this_ada_size; - /* We need to make an XVE/XVU record if any field has variable size, - whether or not the record does. For example, if we have a union, - it may be that all fields, rounded up to the alignment, have the - same size, in which case we'll use that size. But the debug - output routines (except Dwarf2) won't be able to output the fields, - so we need to make the special record. */ - if (TREE_CODE (this_size) != INTEGER_CST) - var_size = true; - - if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) + if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) && !TYPE_IS_FAT_POINTER_P (type) && !TYPE_CONTAINS_TEMPLATE_P (type) && TYPE_ADA_SIZE (type)) this_ada_size = TYPE_ADA_SIZE (type); + else + this_ada_size = this_size; /* Clear DECL_BIT_FIELD for the cases layout_decl does not handle. */ - if (DECL_BIT_FIELD (field) && !STRICT_ALIGNMENT - && value_factor_p (pos, BITS_PER_UNIT) + if (DECL_BIT_FIELD (field) && operand_equal_p (this_size, TYPE_SIZE (type), 0)) - DECL_BIT_FIELD (field) = 0; + { + unsigned int align = TYPE_ALIGN (type); + + /* In the general case, type alignment is required. */ + if (value_factor_p (pos, align)) + { + /* The enclosing record type must be sufficiently aligned. + Otherwise, if no alignment was specified for it and it + has been laid out already, bump its alignment to the + desired one if this is compatible with its size. */ + if (TYPE_ALIGN (record_type) >= align) + { + DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + DECL_BIT_FIELD (field) = 0; + } + else if (!had_align + && rep_level == 0 + && value_factor_p (TYPE_SIZE (record_type), align)) + { + TYPE_ALIGN (record_type) = align; + DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + DECL_BIT_FIELD (field) = 0; + } + } + + /* In the non-strict alignment case, only byte alignment is. */ + if (!STRICT_ALIGNMENT + && DECL_BIT_FIELD (field) + && value_factor_p (pos, BITS_PER_UNIT)) + DECL_BIT_FIELD (field) = 0; + } /* If we still have DECL_BIT_FIELD set at this point, we know the field is technically not addressable. Except that it can actually be @@ -840,7 +862,9 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, DECL_NONADDRESSABLE_P (field) |= DECL_BIT_FIELD (field) && DECL_MODE (field) != BLKmode; - if ((rep_level > 0) && !DECL_BIT_FIELD (field)) + /* A type must be as aligned as its most aligned field that is not + a bit-field. But this is already enforced by layout_type. */ + if (rep_level > 0 && !DECL_BIT_FIELD (field)) TYPE_ALIGN (record_type) = MAX (TYPE_ALIGN (record_type), DECL_ALIGN (field)); @@ -1530,7 +1554,7 @@ aggregate_type_contains_array_p (tree type) case ARRAY_TYPE: return true; - + default: gcc_unreachable (); } @@ -1810,7 +1834,7 @@ value_factor_p (tree value, HOST_WIDE_INT factor) return (value_factor_p (TREE_OPERAND (value, 0), factor) || value_factor_p (TREE_OPERAND (value, 1), factor)); - return 0; + return false; } /* Given 2 consecutive field decls PREV_FIELD and CURR_FIELD, return true @@ -1908,18 +1932,18 @@ create_subprog_decl (tree subprog_name, tree asm_name, DECL_ARTIFICIAL (DECL_RESULT (subprog_decl)) = 1; DECL_IGNORED_P (DECL_RESULT (subprog_decl)) = 1; - /* TREE_ADDRESSABLE is set on the result type to request the use of the - target by-reference return mechanism. This is not supported all the - way down to RTL expansion with GCC 4, which ICEs on temporary creation - attempts with such a type and expects DECL_BY_REFERENCE to be set on - the RESULT_DECL instead - see gnat_genericize for more details. */ - if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (subprog_decl)))) - { - tree result_decl = DECL_RESULT (subprog_decl); + /* TREE_ADDRESSABLE is set on the result type to request the use of the + target by-reference return mechanism. This is not supported all the + way down to RTL expansion with GCC 4, which ICEs on temporary creation + attempts with such a type and expects DECL_BY_REFERENCE to be set on + the RESULT_DECL instead - see gnat_genericize for more details. */ + if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (subprog_decl)))) + { + tree result_decl = DECL_RESULT (subprog_decl); - TREE_ADDRESSABLE (TREE_TYPE (result_decl)) = 0; - DECL_BY_REFERENCE (result_decl) = 1; - } + TREE_ADDRESSABLE (TREE_TYPE (result_decl)) = 0; + DECL_BY_REFERENCE (result_decl) = 1; + } if (inline_flag) DECL_DECLARED_INLINE_P (subprog_decl) = 1; @@ -2496,9 +2520,9 @@ build_template (tree template_type, tree array_type, tree expr) tree bound_list = NULL_TREE; tree field; - if (TREE_CODE (array_type) == RECORD_TYPE - && (TYPE_IS_PADDING_P (array_type) - || TYPE_JUSTIFIED_MODULAR_P (array_type))) + while (TREE_CODE (array_type) == RECORD_TYPE + && (TYPE_IS_PADDING_P (array_type) + || TYPE_JUSTIFIED_MODULAR_P (array_type))) array_type = TREE_TYPE (TYPE_FIELDS (array_type)); if (TREE_CODE (array_type) == ARRAY_TYPE |