diff mbox

[Ada] Improve support of size and alignment clauses

Message ID 20110804091011.GA32216@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Aug. 4, 2011, 9:10 a.m. UTC
This changes the way size and alignment clauses interact with each other.
Size clauses used to set the 'Size of a type in stone, although an alignment
clause could force the back-end to set different values for 'Object_Size
and 'Value_Size of the type, leading to an inconsistency when an object of
this type is declared with this same size clause and rejected.

'Object_Size and 'Value_Size are now decoupled and a size clause on a type
will only set the latter in stone; the former can now be increased by the
back-end to support a given alignment.

The following package must be rejected with the error:

badsize.ads:10:21: size for "RR1" too small, minimum allowed is 64

and the layout given by -gnatR1:

for r1'Object_Size use 64;
for r1'Value_Size use 40;
for r1'Alignment use 4;
for r1 use record
   i at 0 range  0 .. 31;
   b at 4 range  0 ..  7;
end record;

----
package badsize is
   type R1 is record
      I : Integer;
      B : Boolean;
   end record;
   for R1'Alignment use 4;
   for R1'Size use 40;

   RR1 : R1;
   for RR1'Size use 40;
end;
----

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-08-04  Eric Botcazou  <ebotcazou@adacore.com>

	* layout.adb (Layout_Type): For composite types, do not set Esize.
	* freeze.adb (Set_Small_Size): Remove test on alignment and do not
	set Esize.
	(Size_Known): Look at the RM size of components instead of the Esize.
	(Freeze_Record_Type): Look at the RM size instead of the Esize to
	issue warning and activate Implicit_Packing.
	(Freeze_Entity): Likewise.  Do not issue a warning for alias/atomic
	if the Esize is not known.
	* sem_ch13.adb (Analyze_Attribute_Definition_Clause) <Size>: Set Esize
	for elementary types only.
	(Analyze_Record_Representation_Clause): Look at the RM size instead
	of the Esize to issue errors.
	* gcc-interface/decl.c (gnat_to_gnu_entity): Do not set Esize if it
	is not known.
	<E_Record_Type>: Look at the RM size instead of the Esize.  Remove
	obsolete block.  
	Look at the RM size instead of the Esize for types if the latter is
	not known.
	(gnat_to_gnu_field): Use Known_Esize instead of Known_Static_Esize.
diff mbox

Patch

Index: layout.adb
===================================================================
--- layout.adb	(revision 177334)
+++ layout.adb	(working copy)
@@ -2574,27 +2574,11 @@ 
             end;
          end if;
 
-         --  If RM_Size is known, set Esize if not known
-
-         if Known_RM_Size (E) and then Unknown_Esize (E) then
-
-            --  If the alignment is known, we bump the Esize up to the next
-            --  alignment boundary if it is not already on one.
-
-            if Known_Alignment (E) then
-               declare
-                  A : constant Uint   := Alignment_In_Bits (E);
-                  S : constant SO_Ref := RM_Size (E);
-               begin
-                  Set_Esize (E, (S + A - 1) / A * A);
-               end;
-            end if;
-
          --  If Esize is set, and RM_Size is not, RM_Size is copied from Esize.
          --  At least for now this seems reasonable, and is in any case needed
          --  for compatibility with old versions of gigi.
 
-         elsif Known_Esize (E) and then Unknown_RM_Size (E) then
+         if Known_Esize (E) and then Unknown_RM_Size (E) then
             Set_RM_Size (E, Esize (E));
          end if;
 
Index: freeze.adb
===================================================================
--- freeze.adb	(revision 177320)
+++ freeze.adb	(working copy)
@@ -623,13 +623,6 @@ 
          if S > 32 then
             return;
 
-         --  Don't bother if alignment clause with a value other than 1 is
-         --  present, because size may be padded up to meet back end alignment
-         --  requirements, and only the back end knows the rules!
-
-         elsif Known_Alignment (T) and then Alignment (T) /= 1 then
-            return;
-
          --  Check for bad size clause given
 
          elsif Has_Size_Clause (T) then
@@ -638,21 +631,12 @@ 
                Error_Msg_NE
                  ("size for& too small, minimum allowed is ^",
                   Size_Clause (T), T);
-
-            elsif Unknown_Esize (T) then
-               Set_Esize (T, S);
             end if;
 
-         --  Set sizes if not set already
+         --  Set size if not set already
 
-         else
-            if Unknown_Esize (T) then
-               Set_Esize (T, S);
-            end if;
-
-            if Unknown_RM_Size (T) then
-               Set_RM_Size (T, S);
-            end if;
+         elsif Unknown_RM_Size (T) then
+            Set_RM_Size (T, S);
          end if;
       end Set_Small_Size;
 
@@ -836,7 +820,7 @@ 
                   if not Is_Constrained (T)
                     and then
                       No (Discriminant_Default_Value (First_Discriminant (T)))
-                    and then Unknown_Esize (T)
+                    and then Unknown_RM_Size (T)
                   then
                      return False;
                   end if;
@@ -2251,12 +2235,12 @@ 
            --  less than the sum of the object sizes (no point in packing if
            --  this is not the case).
 
-           and then Esize (Rec) < Scalar_Component_Total_Esize
+           and then RM_Size (Rec) < Scalar_Component_Total_Esize
 
            --  And the total RM size cannot be greater than the specified size
            --  since otherwise packing will not get us where we have to be!
 
-           and then Esize (Rec) >= Scalar_Component_Total_RM_Size
+           and then RM_Size (Rec) >= Scalar_Component_Total_RM_Size
 
            --  Never do implicit packing in CodePeer mode since we don't do
            --  any packing in this mode, since this generates over-complex
@@ -3034,12 +3018,12 @@ 
                   --  action that causes stuff to be inherited).
 
                   if Present (Size_Clause (E))
-                    and then Known_Static_Esize (E)
+                    and then Known_Static_RM_Size (E)
                     and then not Is_Packed (E)
                     and then not Has_Pragma_Pack (E)
                     and then Number_Dimensions (E) = 1
                     and then not Has_Component_Size_Clause (E)
-                    and then Known_Static_Esize (Ctyp)
+                    and then Known_Static_RM_Size (Ctyp)
                     and then not Is_Limited_Composite (E)
                     and then not Is_Packed (Root_Type (E))
                     and then not Has_Component_Size_Clause (Root_Type (E))
@@ -3412,12 +3396,18 @@ 
                      --  Start of processing for Alias_Atomic_Check
 
                      begin
+
+                        --  If object size of component type isn't known, we
+                        --  cannot be sure so we defer to the back end.
+
+                        if not Known_Static_Esize (Ctyp) then
+                           null;
+
                         --  Case where component size has no effect. First
-                        --  check for object size of component type known
-                        --  and a multiple of the storage unit size.
+                        --  check for object size of component type multiple
+                        --  of the storage unit size.
 
-                        if Known_Static_Esize (Ctyp)
-                          and then Esize (Ctyp) mod System_Storage_Unit = 0
+                        elsif Esize (Ctyp) mod System_Storage_Unit = 0
 
                           --  OK in both packing case and component size case
                           --  if RM size is known and static and the same as
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 177335)
+++ sem_ch13.adb	(working copy)
@@ -2348,11 +2348,15 @@ 
                if Is_Type (U_Ent) then
                   Set_RM_Size (U_Ent, Size);
 
-                  --  For scalar types, increase Object_Size to power of 2, but
-                  --  not less than a storage unit in any case (i.e., normally
+                  --  For elementary types, increase Object_Size to power of 2,
+                  --  but not less than a storage unit in any case (normally
                   --  this means it will be byte addressable).
 
-                  if Is_Scalar_Type (U_Ent) then
+                  --  For all other types, nothing else to do, we leave Esize
+                  --  (object size) unset, the back end will set it from the
+                  --  size and alignment in an appropriate manner.
+
+                  if Is_Elementary_Type (U_Ent) then
                      if Size <= System_Storage_Unit then
                         Init_Esize (U_Ent, System_Storage_Unit);
                      elsif Size <= 16 then
@@ -2363,15 +2367,9 @@ 
                         Set_Esize  (U_Ent, (Size + 63) / 64 * 64);
                      end if;
 
-                  --  For all other types, object size = value size. The
-                  --  backend will adjust as needed.
-
-                  else
-                     Set_Esize (U_Ent, Size);
+                     Alignment_Check_For_Esize_Change (U_Ent);
                   end if;
 
-                  Alignment_Check_For_Esize_Change (U_Ent);
-
                --  For objects, set Esize only
 
                else
@@ -3591,7 +3589,7 @@ 
                      Lbit := Lbit + UI_From_Int (SSU) * Posit;
 
                      if Has_Size_Clause (Rectype)
-                       and then Esize (Rectype) <= Lbit
+                       and then RM_Size (Rectype) <= Lbit
                      then
                         Error_Msg_N
                           ("bit number out of range of specified size",
@@ -6008,7 +6006,7 @@ 
             --  Check bit position out of range of specified size
 
             if Has_Size_Clause (Rectype)
-              and then Esize (Rectype) <= Lbit
+              and then RM_Size (Rectype) <= Lbit
             then
                Error_Msg_N
                  ("bit number out of range of specified size",
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 177274)
+++ gcc-interface/decl.c	(working copy)
@@ -406,8 +406,6 @@ 
 	  if (esize > max_esize)
 	   esize = max_esize;
 	}
-      else
-	esize = LONG_LONG_TYPE_SIZE;
     }
 
   switch (kind)
@@ -2773,7 +2771,7 @@ 
 	      ? -1
 	      : (Known_Alignment (gnat_entity)
 		 || (Strict_Alignment (gnat_entity)
-		     && Known_Static_Esize (gnat_entity)))
+		     && Known_RM_Size (gnat_entity)))
 		? -2
 		: 0;
 	bool has_discr = Has_Discriminants (gnat_entity);
@@ -2824,8 +2822,9 @@ 
 
 	/* If both a size and rep clause was specified, put the size in
 	   the record type now so that it can get the proper mode.  */
-	if (has_rep && Known_Esize (gnat_entity))
-	  TYPE_SIZE (gnu_type) = UI_To_gnu (Esize (gnat_entity), sizetype);
+	if (has_rep && Known_RM_Size (gnat_entity))
+	  TYPE_SIZE (gnu_type)
+	    = UI_To_gnu (RM_Size (gnat_entity), bitsizetype);
 
 	/* Always set the alignment here so that it can be used to
 	   set the mode, if it is making the alignment stricter.  If
@@ -2842,9 +2841,9 @@ 
 	   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))
+		 && Known_RM_Size (gnat_entity))
 	  {
-	    unsigned int raw_size = UI_To_Int (Esize (gnat_entity));
+	    unsigned int raw_size = UI_To_Int (RM_Size (gnat_entity));
 	    unsigned int raw_align = raw_size & -raw_size;
 	    if (raw_align < BIGGEST_ALIGNMENT)
 	      TYPE_ALIGN (gnu_type) = raw_align;
@@ -4583,9 +4582,13 @@ 
 	 confirming or we don't handle it properly (if the low bound is
 	 non-constant).  */
       if (!gnu_size && kind != E_String_Literal_Subtype)
-	gnu_size = validate_size (Esize (gnat_entity), gnu_type, gnat_entity,
-				  TYPE_DECL, false,
-				  Has_Size_Clause (gnat_entity));
+	{
+	  Uint gnat_size = Known_Esize (gnat_entity)
+			   ? Esize (gnat_entity) : RM_Size (gnat_entity);
+	  gnu_size
+	    = validate_size (gnat_size, gnu_type, gnat_entity, TYPE_DECL,
+			     false, Has_Size_Clause (gnat_entity));
+	}
 
       /* If a size was specified, see if we can make a new type of that size
 	 by rearranging the type, for example from a fat to a thin pointer.  */
@@ -6771,7 +6774,7 @@ 
   /* If a size is specified, use it.  Otherwise, if the record type is packed,
      use the official RM size.  See "Handling of Type'Size Values" in Einfo
      for further details.  */
-  if (Known_Static_Esize (gnat_field))
+  if (Known_Esize (gnat_field))
     gnu_size = validate_size (Esize (gnat_field), gnu_field_type,
 			      gnat_field, FIELD_DECL, false, true);
   else if (packed == 1)