This repairs the ABI breakage for record types with Long_Float components
introduced on 32-bit x86/Linux by the previous change.  The Long_Float type
is awkward on this platform because it has got a dual alignment setting:
it's 8 for standalone object and array component and 4 for record component.
Since Ada defines a single 'Alignment value, it is set to 4 and there is a
special circuitry in Set_Elem_Alignment to implement it.

The previous change short-circuited Set_Elem_Alignment in Build_Float_Type,
which resulted in a Long_Float'Alignment value of 8.

The following package:

package P is

  type Rec is record
    I : Integer;
    F : Long_Float;
  end record;

end P;

must yield the following output when compiled with -gnatR2 on 32-bit Linux:

Representation information for unit P (spec)

for Rec'Size use 96;
for Rec'Alignment use 4;
for Rec use record
   I at 0 range  0 .. 31;
   F at 4 range  0 .. 63;
end record;

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

2017-10-14  Eric Botcazou  <ebotca...@adacore.com>

        * layout.ads (Set_Elem_Alignment): Add Align parameter defaulted to 0.
        * layout.adb (Set_Elem_Alignment): Likewise.  Use M name as maximum
        alignment for consistency.  If Align is non-zero, use the minimum of
        Align and M for the alignment.
        * cstand.adb (Build_Float_Type): Use Set_Elem_Alignment instead of
        setting the alignment directly.

Index: cstand.adb
===================================================================
--- cstand.adb  (revision 253756)
+++ cstand.adb  (working copy)
@@ -212,7 +212,7 @@
       Init_Digits_Value              (E, Digs);
       Set_Float_Rep                  (E, Rep);
       Init_Size                      (E, Siz);
-      Set_Alignment                  (E, UI_From_Int (Align));
+      Set_Elem_Alignment             (E, Align);
       Set_Float_Bounds               (E);
       Set_Is_Frozen                  (E);
       Set_Is_Public                  (E);
Index: layout.adb
===================================================================
--- layout.adb  (revision 253753)
+++ layout.adb  (working copy)
@@ -843,7 +843,7 @@
    -- Set_Elem_Alignment --
    ------------------------
 
-   procedure Set_Elem_Alignment (E : Entity_Id) is
+   procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0) is
    begin
       --  Do not set alignment for packed array types, this is handled in the
       --  backend.
@@ -869,16 +869,13 @@
          return;
       end if;
 
-      --  Here we calculate the alignment as the largest power of two multiple
-      --  of System.Storage_Unit that does not exceed either the object size of
-      --  the type, or the maximum allowed alignment.
+      --  We attempt to set the alignment in all the other cases
 
       declare
          S : Int;
          A : Nat;
+         M : Nat;
 
-         Max_Alignment : Nat;
-
       begin
          --  The given Esize may be larger that int'last because of a previous
          --  error, and the call to UI_To_Int will fail, so use default.
@@ -908,7 +905,7 @@
            and then S = 8
            and then Is_Floating_Point_Type (E)
          then
-            Max_Alignment := Ttypes.Target_Double_Float_Alignment;
+            M := Ttypes.Target_Double_Float_Alignment;
 
          --  If the default alignment of "double" or larger scalar types is
          --  specifically capped, enforce the cap.
@@ -917,19 +914,28 @@
            and then S >= 8
            and then Is_Scalar_Type (E)
          then
-            Max_Alignment := Ttypes.Target_Double_Scalar_Alignment;
+            M := Ttypes.Target_Double_Scalar_Alignment;
 
          --  Otherwise enforce the overall alignment cap
 
          else
-            Max_Alignment := Ttypes.Maximum_Alignment;
+            M := Ttypes.Maximum_Alignment;
          end if;
 
-         A := 1;
-         while 2 * A <= Max_Alignment and then 2 * A <= S loop
-            A := 2 * A;
-         end loop;
+         --  We calculate the alignment as the largest power-of-two multiple
+         --  of System.Storage_Unit that does not exceed the object size of
+         --  the type and the maximum allowed alignment, if none was specified.
+         --  Otherwise we only cap it to the maximum allowed alignment.
 
+         if Align = 0 then
+            A := 1;
+            while 2 * A <= S and then 2 * A <= M loop
+               A := 2 * A;
+            end loop;
+         else
+            A := Nat'Min (Align, M);
+         end if;
+
          --  If alignment is currently not set, then we can safely set it to
          --  this new calculated value.
 
Index: layout.ads
===================================================================
--- layout.ads  (revision 253753)
+++ layout.ads  (working copy)
@@ -74,10 +74,11 @@
    --  types, the RM_Size is simply set to zero. This routine also sets
    --  the Is_Constrained flag in Def_Id.
 
-   procedure Set_Elem_Alignment (E : Entity_Id);
+   procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0);
    --  The front end always sets alignments for elementary types by calling
    --  this procedure. Note that we have to do this for discrete types (since
    --  the Alignment attribute is static), so we might as well do it for all
-   --  elementary types, since the processing is the same.
+   --  elementary types, as the processing is the same. If Align is nonzero,
+   --  it is an external alignment setting that we must respect.
 
 end Layout;

Reply via email to