utils.c (finish_record_type): Clear DECL_BIT_FIELD on sufficiently aligned bit-fields...
authorEric Botcazou <ebotcazou@adacore.com>
Sat, 8 Mar 2008 11:30:26 +0000 (11:30 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Sat, 8 Mar 2008 11:30:26 +0000 (11:30 +0000)
* 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.

From-SVN: r133028

gcc/ada/ChangeLog
gcc/ada/utils.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/pack4.adb [new file with mode: 0644]

index 2a10f10f1b68e648880a0de873aefd81e14143b3..77ceedae6ff5f2a6b144e3b7f802f259792852da 100644 (file)
@@ -1,3 +1,10 @@
+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
index 46ce865bdb4a6e5915e3a75fbd62e0ab9507622d..f1ffa4f7b297dc3518b0c2939a2f0c93275e543e 100644 (file)
@@ -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
index 64896b804ef5298b5147cf4877d139c07af829cc..4915a4229f2501af3915d1c3c6066dde020f54bb 100644 (file)
@@ -1,3 +1,7 @@
+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.
diff --git a/gcc/testsuite/gnat.dg/pack4.adb b/gcc/testsuite/gnat.dg/pack4.adb
new file mode 100644 (file)
index 0000000..2c73e1d
--- /dev/null
@@ -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;