aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ada/ChangeLog7
-rw-r--r--gcc/ada/utils.c54
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gnat.dg/pack4.adb38
4 files changed, 93 insertions, 10 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 2a10f10..77ceeda 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,5 +1,12 @@
2008-03-08 Eric Botcazou <ebotcazou@adacore.com>
+ * utils.c (finish_record_type): Clear DECL_BIT_FIELD on sufficiently
+ aligned bit-fields, bumping the alignment of the record type if deemed
+ profitable.
+ (value_factor_p): Return false instead of 0.
+
+2008-03-08 Eric Botcazou <ebotcazou@adacore.com>
+
* decl.c (gnat_to_gnu_entity) <E_Signed_Integer_Subtype>: Add support
for scalar types with small alignment.
diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c
index 46ce865..f1ffa4f 100644
--- a/gcc/ada/utils.c
+++ b/gcc/ada/utils.c
@@ -752,6 +752,7 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level,
tree size = bitsize_zero_node;
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)
@@ -804,24 +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;
- 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
@@ -830,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));
@@ -1800,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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 64896b8..4915a42 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
2008-03-08 Eric Botcazou <ebotcazou@adacore.com>
+ * gnat.dg/pack4.adb: New test.
+
+2008-03-08 Eric Botcazou <ebotcazou@adacore.com>
+
* gnat.dg/small_alignment.adb: New test.
2008-03-07 Eric Botcazou <ebotcazou@adacore.com>
diff --git a/gcc/testsuite/gnat.dg/pack4.adb b/gcc/testsuite/gnat.dg/pack4.adb
new file mode 100644
index 0000000..2c73e1d
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/pack4.adb
@@ -0,0 +1,38 @@
+-- { dg-do run }
+
+procedure Pack4 is
+
+ type Time_T is record
+ Hour : Integer;
+ end record;
+
+ type Date_And_Time_T is record
+ Date : Integer;
+ Time : Time_T;
+ end record;
+
+ pragma Pack(Date_And_Time_T);
+
+ procedure
+ Assign_Hour_Of (T : out Time_T)
+ is
+ begin
+ T.Hour := 44;
+ end;
+
+ procedure
+ Clobber_Hour_Of (DT: out Date_And_Time_T)
+ is
+ begin
+ Assign_Hour_Of (Dt.Time);
+ end;
+
+ DT : Date_And_Time_T;
+
+begin
+ DT.Time.Hour := 22;
+ Clobber_Hour_Of (DT);
+ if DT.Time.Hour /= 44 then
+ raise Program_Error;
+ end if;
+end;