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;