* decl.c (gnat_to_gnu_entity) <E_Record_Type>: If the type has
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 25 Nov 2007 13:37:12 +0000 (13:37 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 25 Nov 2007 13:37:12 +0000 (13:37 +0000)
strict alignment, no alignment clause and a known static size, cap
the type alignment to the greatest power of 2 factor of the size.
(gnat_to_gnu_field): If the field has a component clause, is aliased
or of a type with strict alignment, require that its size be equal to
that of the type.
(validate_size): Use the type size as the minimum size for a type with
strict alignment.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@130406 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ada/ChangeLog
gcc/ada/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/specs/size_clause1.ads [new file with mode: 0644]
gcc/testsuite/gnat.dg/specs/size_clause2.ads [new file with mode: 0644]
gcc/testsuite/gnat.dg/specs/size_clause3.ads [new file with mode: 0644]

index b8f8e24..4f229ba 100644 (file)
@@ -1,3 +1,14 @@
+2007-11-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * decl.c (gnat_to_gnu_entity) <E_Record_Type>: If the type has
+       strict alignment, no alignment clause and a known static size, cap
+       the type alignment to the greatest power of 2 factor of the size.
+       (gnat_to_gnu_field): If the field has a component clause, is aliased
+       or of a type with strict alignment, require that its size be equal to
+       that of the type.
+       (validate_size): Use the type size as the minimum size for a type with
+       strict alignment.
+
 2007-11-23  Samuel Tardieu  <sam@rfc1149.net>
 
        * s-inmaop-posix.adb, s-intman-vxworks.adb, s-taprop-hpux-dce.adb,
index 20b65d2..8cac29a 100644 (file)
@@ -2405,12 +2405,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        tree gnu_field;
        tree gnu_field_list = NULL_TREE;
        tree gnu_get_parent;
+       /* Set PACKED in keeping with gnat_to_gnu_field.  */
        int packed
          = Is_Packed (gnat_entity)
            ? 1
            : Component_Alignment (gnat_entity) == Calign_Storage_Unit
              ? -1
-             : Known_Alignment (gnat_entity)
+             : (Known_Alignment (gnat_entity)
+                || (Strict_Alignment (gnat_entity)
+                    && Known_Static_Esize (gnat_entity)))
                ? -2
                : 0;
        bool has_rep = Has_Specified_Layout (gnat_entity);
@@ -2466,6 +2469,16 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        else if (Is_Atomic (gnat_entity))
          TYPE_ALIGN (gnu_type)
            = esize >= BITS_PER_WORD ? BITS_PER_WORD : ceil_alignment (esize);
+       /* If a type needs strict alignment, the minimum size will be the
+          type size instead of the RM size (see validate_size).  Cap the
+          alignment, lest it causes this type size to become too large.  */
+       else if (Strict_Alignment (gnat_entity)
+                && Known_Static_Esize (gnat_entity))
+         {
+           unsigned int raw_size = UI_To_Int (Esize (gnat_entity));
+           TYPE_ALIGN (gnu_type)
+             = MIN (BIGGEST_ALIGNMENT, raw_size & -raw_size);
+         }
        else
          TYPE_ALIGN (gnu_type) = 0;
 
@@ -5709,38 +5722,32 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed,
         consistent with the alignment.  */
       if (needs_strict_alignment)
        {
-         tree gnu_rounded_size = round_up (rm_size (gnu_field_type),
-                                           TYPE_ALIGN (gnu_field_type));
-
          TYPE_ALIGN (gnu_record_type)
            = MAX (TYPE_ALIGN (gnu_record_type), TYPE_ALIGN (gnu_field_type));
 
-         /* If Atomic, the size must match exactly that of the field.  */
-         if ((Is_Atomic (gnat_field) || Is_Atomic (Etype (gnat_field)))
+         if (gnu_size
              && !operand_equal_p (gnu_size, TYPE_SIZE (gnu_field_type), 0))
            {
-             post_error_ne_tree
-               ("atomic field& must be natural size of type{ (^)}",
-                Last_Bit (Component_Clause (gnat_field)), gnat_field,
-                TYPE_SIZE (gnu_field_type));
+             if (Is_Atomic (gnat_field) || Is_Atomic (Etype (gnat_field)))
+               post_error_ne_tree
+                 ("atomic field& must be natural size of type{ (^)}",
+                  Last_Bit (Component_Clause (gnat_field)), gnat_field,
+                  TYPE_SIZE (gnu_field_type));
+
+             else if (Is_Aliased (gnat_field))
+               post_error_ne_tree
+                 ("size of aliased field& must be ^ bits",
+                  Last_Bit (Component_Clause (gnat_field)), gnat_field,
+                  TYPE_SIZE (gnu_field_type));
 
-             gnu_size = NULL_TREE;
-           }
+             else if (Strict_Alignment (Etype (gnat_field)))
+               post_error_ne_tree
+                 ("size of & with aliased or tagged components not ^ bits",
+                  Last_Bit (Component_Clause (gnat_field)), gnat_field,
+                  TYPE_SIZE (gnu_field_type));
 
-         /* If Aliased, the size must match exactly the rounded size.  We
-            used to be more accommodating here and accept greater sizes, but
-            fully supporting this case on big-endian platforms would require
-            switching to a more involved layout for the field.  */
-         else if (Is_Aliased (gnat_field)
-                  && gnu_size
-                  && ! operand_equal_p (gnu_size, gnu_rounded_size, 0))
-           {
-             post_error_ne_tree
-               ("size of aliased field& must be ^ bits",
-                Last_Bit (Component_Clause (gnat_field)), gnat_field,
-                gnu_rounded_size);
              gnu_size = NULL_TREE;
-           }
+           }
 
          if (!integer_zerop (size_binop
                              (TRUNC_MOD_EXPR, gnu_pos,
@@ -5763,6 +5770,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed,
   ("position of & with aliased or tagged components not multiple of ^ bits",
                   First_Bit (Component_Clause (gnat_field)), gnat_field,
                   TYPE_ALIGN (gnu_field_type));
+
              else
                gcc_unreachable ();
 
@@ -6479,9 +6487,15 @@ validate_size (Uint uint_size, tree gnu_type, Entity_Id gnat_object,
               enum tree_code kind, bool component_p, bool zero_ok)
 {
   Node_Id gnat_error_node;
-  tree type_size
-    = kind == VAR_DECL ? TYPE_SIZE (gnu_type) : rm_size (gnu_type);
-  tree size;
+  tree type_size, size;
+
+  if (kind == VAR_DECL
+      /* If a type needs strict alignment, a component of this type in
+        a packed record cannot be packed and thus uses the type size.  */
+      || (kind == TYPE_DECL && Strict_Alignment (gnat_object)))
+    type_size = TYPE_SIZE (gnu_type);
+  else
+    type_size = rm_size (gnu_type);
 
   /* Find the node to use for errors.  */
   if ((Ekind (gnat_object) == E_Component
index 9ec0be0..6c4f2ac 100644 (file)
@@ -1,3 +1,9 @@
+2007-11-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gnat.dg/specs/size_clause1.ads: New test.
+       * gnat.dg/specs/size_clause2.ads: Likewise.
+       * gnat.dg/specs/size_clause3.ads: Likewise.
+
 2007-11-25  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/33499
diff --git a/gcc/testsuite/gnat.dg/specs/size_clause1.ads b/gcc/testsuite/gnat.dg/specs/size_clause1.ads
new file mode 100644 (file)
index 0000000..5b8417e
--- /dev/null
@@ -0,0 +1,48 @@
+-- { dg-do compile }
+
+package Size_Clause1 is
+
+  -- The record inherits the alignment of Integer, which is 4, so
+  -- the real size is 64 instead of 40.  That's OK, as long as the
+  -- size of a component of type R1 in a packed record is 40.
+  type R1 is record
+    I : Integer;
+    B : Boolean;
+  end record;
+  for R1'Size use 40;
+
+  type S1 is record
+    rr : R1; -- size must be 40
+  end record;
+  pragma Pack(S1);
+
+  -- The record is explicitly given alignment 1 so its real type is 40 too.
+  -- The size of a component of type R2 in a packed record is naturally 40.
+  type R2 is record
+    I : Integer;
+    B : Boolean;
+  end record;
+  for R2'Size use 40;
+  for R2'Alignment use 1;
+
+  type S2 is record
+    rr : R2; -- size must be 40
+  end record;
+  pragma Pack(S2);
+
+  -- The record is explicitly given alignment 4 so its real type is 64.
+  -- That's OK, as long as the size of a component of type R3 in a packed
+  -- record is 40.
+  type R3 is record
+    I : Integer;
+    B : Boolean;
+  end record;
+  for R3'Size use 40;
+  for R3'Alignment use 4;
+
+  type S3 is record
+    rr : R3; -- size must be 40
+  end record;
+  pragma Pack(S3);
+
+end Size_Clause1;
diff --git a/gcc/testsuite/gnat.dg/specs/size_clause2.ads b/gcc/testsuite/gnat.dg/specs/size_clause2.ads
new file mode 100644 (file)
index 0000000..957d392
--- /dev/null
@@ -0,0 +1,48 @@
+-- { dg-do compile }
+
+package Size_Clause2 is
+
+  -- The alignment of the record is capped to the greatest power of 2
+  -- factor of the size, so that the real size is 40 too and the size
+  -- of a component of type R1 in a packed record can be 40.
+  type R1 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+  for R1'Size use 40;
+
+  type S1 is record
+    rr : R1; -- size must be 40
+  end record;
+  pragma Pack(S1);
+
+  -- The record is explicitly given alignment 1 so its real type is 40 too.
+  -- The size of a component of type R2 in a packed record is naturally 40.
+  type R2 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+  for R2'Size use 40;
+  for R2'Alignment use 1;
+
+  type S2 is record
+    rr : R2; -- size must be 40
+  end record;
+  pragma Pack(S2);
+
+  -- The record is explicitly given alignment 4 so its real type is 64.
+  -- That's not OK, because the size of a component of type R3 in a packed
+  -- record cannot be 40 so the size clause is violated.
+  type R3 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+  for R3'Size use 40;  -- { dg-error "size for .R3. too small" }
+  for R3'Alignment use 4;
+
+  type S3 is record
+    rr : R3; -- size must be 40
+  end record;
+  pragma Pack(S3);
+
+end Size_Clause2;
diff --git a/gcc/testsuite/gnat.dg/specs/size_clause3.ads b/gcc/testsuite/gnat.dg/specs/size_clause3.ads
new file mode 100644 (file)
index 0000000..6a89114
--- /dev/null
@@ -0,0 +1,50 @@
+-- { dg-do compile }
+
+package Size_Clause3 is
+
+  -- The record inherits the alignment of Integer, which is 4, so
+  -- the real size is 64 instead of 40.
+  type R1 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+
+  -- That's not OK, the size of a component of type R1 cannot be 40.
+  type S1 is record
+    rr : R1; -- size must be 40
+  end record;
+  for S1 use record
+    rr at 0 range 0 .. 39;  -- { dg-error "size of .rr. with aliased or tagged component" }
+  end record;
+
+  -- The record is explicitly given alignment 1 so its real type is 40.
+  type R2 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+  for R2'Alignment use 1;
+
+  -- That's OK, the size of a component of type R2 can be 40.
+  type S2 is record
+    rr : R2; -- size must be 40
+  end record;
+  for S2 use record
+    rr at 0 range 0 .. 39;
+  end record;
+
+  -- The record is explicitly given alignment 4 so its real type is 64.
+  type R3 is record
+    I : Integer;
+    B : aliased Boolean;
+  end record;
+  for R3'Alignment use 4;
+
+  -- That's not OK, the size of a component of type R3 cannot be 40.
+  type S3 is record
+    rr : R3; -- size must be 40
+  end record;
+  for S3 use record
+    rr at 0 range 0 .. 39;  -- { dg-error "size of .rr. with aliased or tagged component" }
+  end record;
+
+end Size_Clause3;