The Get_Integer_Type function is used by the expander when generating
code for the Enum_Rep and Pos attributes applied to an enumeration type.
The expansion generates a direct conversion from the enumeration type
to the result type, which is nominally Universal_Integer; therefore,
in order to preserve the size information, an intermediate conversion
to a smaller integer type is introduced by means of Get_Integer_Type.
The type is picked based on the RM_Size of the base type, which means
that it may not be large enough to handle invalid values of this base
type, which might seem desirable for the Enum_Rep and Pos attributes.
So this changes the function to use the Esize of the base type instead,
and also to return an unsigned type, which is more consistent with the
enumeration type source. There is also a small tweak for CCG.
Tested on x86_64-pc-linux-gnu, committed on trunk
2020-06-18 Eric Botcazou <[email protected]>
gcc/ada/
* exp_attr.adb (Get_Integer_Type): Pick an unsigned type based
on the Esize of the base type of the input type.--- gcc/ada/exp_attr.adb
+++ gcc/ada/exp_attr.adb
@@ -1750,23 +1750,25 @@ package body Exp_Attr is
----------------------
function Get_Integer_Type (Typ : Entity_Id) return Entity_Id is
- Siz : constant Uint := RM_Size (Base_Type (Typ));
+ Siz : constant Uint := Esize (Base_Type (Typ));
Int_Typ : Entity_Id;
begin
- -- We need to accommodate unsigned values
+ -- We need to accommodate invalid values of the base type since we
+ -- accept them for Enum_Rep and Pos, so we reason on the Esize. And
+ -- we use an unsigned type since the enumeration type is unsigned.
- if Siz < RM_Size (Standard_Short_Short_Integer) then
- Int_Typ := Standard_Short_Short_Integer;
+ if Siz <= Esize (Standard_Short_Short_Unsigned) then
+ Int_Typ := Standard_Short_Short_Unsigned;
- elsif Siz < RM_Size (Standard_Short_Integer) then
- Int_Typ := Standard_Short_Integer;
+ elsif Siz <= Esize (Standard_Short_Unsigned) then
+ Int_Typ := Standard_Short_Unsigned;
- elsif Siz < RM_Size (Standard_Integer) then
- Int_Typ := Standard_Integer;
+ elsif Siz <= Esize (Standard_Unsigned) then
+ Int_Typ := Standard_Unsigned;
else
- Int_Typ := Standard_Long_Long_Integer;
+ raise Program_Error;
end if;
return Int_Typ;