The compiler may report errors on enumeration types with non-standard
representation (i.e. at least one literal has a representation value
different from its 'Pos value) processing attribute 'Enum_Rep.
It may also generate wrong code for the evaluation of 'Enum_Rep raising
Constraint_Error at runtime.
Tested on x86_64-pc-linux-gnu, committed on trunk
2018-08-21 Javier Miranda <mira...@adacore.com>
gcc/ada/
* checks.ads (Determine_Range): Adding documentation.
* checks.adb (Determine_Range): Don't deal with enumerated types
with non-standard representation.
(Convert_And_Check_Range): For conversion of enumeration types
with non standard representation to an integer type perform a
direct conversion to the target integer type.
gcc/testsuite/
* gnat.dg/enum4.adb: New testcase.
--- gcc/ada/checks.adb
+++ gcc/ada/checks.adb
@@ -4490,6 +4490,11 @@ package body Checks is
or else not Is_Discrete_Type (Typ)
+ -- Don't deal with enumerated types with non-standard representation
+
+ or else (Is_Enumeration_Type (Typ)
+ and then Present (Enum_Pos_To_Rep (Base_Type (Typ))))
+
-- Ignore type for which an error has been posted, since range in
-- this case may well be a bogosity deriving from the error. Also
-- ignore if error posted on the reference node.
@@ -6758,9 +6763,36 @@ package body Checks is
-----------------------------
procedure Convert_And_Check_Range is
- Tnn : constant Entity_Id := Make_Temporary (Loc, 'T', N);
+ Tnn : constant Entity_Id := Make_Temporary (Loc, 'T', N);
+ Conv_Node : Node_Id;
begin
+ -- For enumeration types with non-standard representation this is a
+ -- direct conversion from the enumeration type to the target integer
+ -- type, which is treated by the back end as a normal integer type
+ -- conversion, treating the enumeration type as an integer, which is
+ -- exactly what we want. We set Conversion_OK to make sure that the
+ -- analyzer does not complain about what otherwise might be an
+ -- illegal conversion.
+
+ if Is_Enumeration_Type (Source_Base_Type)
+ and then Present (Enum_Pos_To_Rep (Source_Base_Type))
+ and then Is_Integer_Type (Target_Base_Type)
+ then
+ Conv_Node :=
+ OK_Convert_To (
+ Typ => Target_Base_Type,
+ Expr => Duplicate_Subexpr (N));
+
+ -- Common case
+
+ else
+ Conv_Node :=
+ Make_Type_Conversion (Loc,
+ Subtype_Mark => New_Occurrence_Of (Target_Base_Type, Loc),
+ Expression => Duplicate_Subexpr (N));
+ end if;
+
-- We make a temporary to hold the value of the converted value
-- (converted to the base type), and then do the test against this
-- temporary. The conversion itself is replaced by an occurrence of
@@ -6776,10 +6808,7 @@ package body Checks is
Defining_Identifier => Tnn,
Object_Definition => New_Occurrence_Of (Target_Base_Type, Loc),
Constant_Present => True,
- Expression =>
- Make_Type_Conversion (Loc,
- Subtype_Mark => New_Occurrence_Of (Target_Base_Type, Loc),
- Expression => Duplicate_Subexpr (N))),
+ Expression => Conv_Node),
Make_Raise_Constraint_Error (Loc,
Condition =>
--- gcc/ada/checks.ads
+++ gcc/ada/checks.ads
@@ -310,14 +310,16 @@ package Checks is
-- then OK is True on return, and Lo and Hi are set to a conservative
-- estimate of the possible range of values of N. Thus if OK is True on
-- return, the value of the subexpression N is known to lie in the range
- -- Lo .. Hi (inclusive). If the expression is not of a discrete type, or
- -- some kind of error condition is detected, then OK is False on exit, and
- -- Lo/Hi are set to No_Uint. Thus the significance of OK being False on
- -- return is that no useful information is available on the range of the
- -- expression. Assume_Valid determines whether the processing is allowed to
- -- assume that values are in range of their subtypes. If it is set to True,
- -- then this assumption is valid, if False, then processing is done using
- -- base types to allow invalid values.
+ -- Lo .. Hi (inclusive). For enumeration and character literals the values
+ -- returned are the Pos value in the relevant enumeration type. If the
+ -- expression is not of a discrete type, or some kind of error condition
+ -- is detected, then OK is False on exit, and Lo/Hi are set to No_Uint.
+ -- Thus the significance of OK being False on return is that no useful
+ -- information is available on the range of the expression. Assume_Valid
+ -- determines whether the processing is allowed to assume that values are
+ -- in range of their subtypes. If it is set to True, then this assumption
+ -- is valid, if False, then processing is done using base types to allow
+ -- invalid values.
procedure Determine_Range_R
(N : Node_Id;
--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/enum4.adb
@@ -0,0 +1,59 @@
+-- { dg-do run }
+
+procedure Enum4 is
+
+ procedure Assert (Expected, Actual : String) is
+ begin
+ if Expected /= Actual then
+ raise Program_Error;
+ end if;
+ end Assert;
+
+ procedure Test_1 is
+ type Test_Enum is (Enum_1, Enum_2);
+ for Test_Enum use (Enum_1=> 8, Enum_2=> 12);
+
+ Enum_Values : constant array (Test_Enum) of Natural := (8, 12);
+
+ type Test_Enum_Rep is range 1..12;
+ Tmp_Test_Enum_Rep : Test_Enum_Rep;
+ begin
+ Tmp_Test_Enum_Rep := Test_Enum'Enum_Rep (Test_Enum'First);
+ Assert (" 8", Tmp_Test_Enum_Rep'Img);
+
+ for Enum in Test_Enum loop
+ Tmp_Test_Enum_Rep := Test_Enum'Enum_Rep (Enum);
+ Assert (Enum_Values (Enum)'Img, Tmp_Test_Enum_Rep'Img);
+ end loop;
+ end Test_1;
+
+ procedure Test_2 is
+ type Test_Enum is (Enum_1);
+ for Test_Enum use (Enum_1=> 2);
+
+ type Test_Enum_Rep_Full is range 0..2;
+ subtype Test_Enum_Rep_Short is
+ Test_Enum_Rep_Full range 2..Test_Enum_Rep_Full'Last;
+
+ Tmp_Test_Enum_Rep_Full : Test_Enum_Rep_Full;
+ Tmp_Test_Enum_Rep_Short : Test_Enum_Rep_Short;
+
+ begin
+ Tmp_Test_Enum_Rep_Short := Test_Enum'Enum_Rep (Test_Enum'First);
+ Assert (" 2", Tmp_Test_Enum_Rep_Short'Img);
+
+ for Enum in Test_Enum loop
+ Tmp_Test_Enum_Rep_Full := Test_Enum'Enum_Rep (Enum);
+ Assert (" 2", Tmp_Test_Enum_Rep_Short'Img);
+ end loop;
+
+ for Enum in Test_Enum range Test_Enum'First .. Test_Enum'Last loop
+ Tmp_Test_Enum_Rep_Short := Test_Enum'Enum_Rep(Enum); -- Test #2
+ Assert (" 2", Tmp_Test_Enum_Rep_Short'Img);
+ end loop;
+ end Test_2;
+
+begin
+ Test_1;
+ Test_2;
+end;