The problem is that Expand_Image_Attribute incorrectly fetches the root type 
for enumeration types, thus bypassing a clause present on the derived type.

The fix is to change the two fields Lit_Indexes and Lit_Strings defined for 
enumeration types and subtypes to be formally present on root types only, as 
well as to make Expand_Image_Attribute stick to base types.

Tested on x86-64/Linux, applied on the mainline, 16 and 15 branches.


2026-05-10  Eric Botcazou  <[email protected]>

        PR ada/125240
        * gen_il-gen-gen_entities.adb (Enumeration_Kind): Make
        Lit_Indexes and Lit_Strings be defined for root types only.
        * einfo.ads (Lit_Hash): Adjust description.
        (Lit_Indexes): Likewise.
        (Lit_Strings): Likewise.
        (E_Enumeration_Type): Likewise.
        * exp_imgv.adb (Expand_Image_Attribute): Do not fetch the root type
        for enumeration types, except for character types, and adjust.


2026-05-10  Eric Botcazou  <[email protected]>

        * gnat.dg/enum6.adb: New test.

-- 
Eric Botcazou
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index 9e716c427ab..c908542e3e7 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -3647,22 +3647,19 @@ package Einfo is
 --       type of the object.
 
 --    Lit_Hash [root type only]
---       Defined in enumeration types and subtypes. Non-empty only for the
---       case of an enumeration root type, where it contains the entity for
+--       Defined in enumeration types and subtypes. Contains the entity for
 --       the generated hash function. See unit Exp_Imgv for full details of
 --       the nature and use of this entity for implementing the Value
 --       attribute for the enumeration type in question.
 
---    Lit_Indexes
---       Defined in enumeration types and subtypes. Non-empty only for the
---       case of an enumeration root type, where it contains the entity for
+--    Lit_Indexes [root type only]
+--       Defined in enumeration types and subtypes. Contains the entity for
 --       the generated indexes entity. See unit Exp_Imgv for full details of
 --       the nature and use of this entity for implementing the Image and
 --       Value attributes for the enumeration type in question.
 
---    Lit_Strings
---       Defined in enumeration types and subtypes. Non-empty only for the
---       case of an enumeration root type, where it contains the entity for
+--    Lit_Strings [root type only]
+--       Defined in enumeration types and subtypes. Contains the entity for
 --       the literals string entity. See unit Exp_Imgv for full details of
 --       the nature and use of this entity for implementing the Image and
 --       Value attributes for the enumeration type in question.
@@ -5530,12 +5527,12 @@ package Einfo is
    --  E_Enumeration_Subtype
    --    First_Entity $$$ type
    --    Renamed_Object $$$
-   --    Lit_Strings                          (root type only)
    --    First_Literal
+   --    Lit_Hash                             (root type only)
    --    Lit_Indexes                          (root type only)
+   --    Lit_Strings                          (root type only)
    --    Default_Aspect_Value                 (base type only)
    --    Scalar_Range
-   --    Lit_Hash                             (root type only)
    --    Enum_Pos_To_Rep                      (type only)
    --    Static_Discrete_Predicate
    --    Has_Biased_Representation
diff --git a/gcc/ada/exp_imgv.adb b/gcc/ada/exp_imgv.adb
index 469c7c065da..082acbe4d88 100644
--- a/gcc/ada/exp_imgv.adb
+++ b/gcc/ada/exp_imgv.adb
@@ -1061,11 +1061,10 @@ package body Exp_Imgv is
 
       --  Ada 2022 allows 'Image on private types, so fetch the underlying
       --  type to obtain the structure of the type. We use the base type,
-      --  not the root type for discrete types, to handle properly derived
-      --  types, but we use the root type for enumeration types, because the
-      --  literal map is attached to the root. Should be inherited ???
+      --  not the root type, for discrete types in order to handle derived
+      --  types, except for character types for which this is not needed.
 
-      if Is_Real_Type (Ptyp) or else Is_Enumeration_Type (Ptyp) then
+      if Is_Real_Type (Ptyp) or else Is_Character_Type (Ptyp) then
          Rtyp := Underlying_Type (Root_Type (Ptyp));
       else
          Rtyp := Underlying_Type (Base_Type (Ptyp));
@@ -1076,7 +1075,7 @@ package body Exp_Imgv is
 
       Enum_Case := False;
 
-      if Rtyp = Standard_Boolean then
+      if Is_Boolean_Type (Rtyp) then
          --  Use inline expansion if the -gnatd_x switch is not passed to the
          --  compiler. Otherwise expand into a call to the runtime.
 
diff --git a/gcc/ada/gen_il-gen-gen_entities.adb b/gcc/ada/gen_il-gen-gen_entities.adb
index 94a1f04a613..bb1dd7a9441 100644
--- a/gcc/ada/gen_il-gen-gen_entities.adb
+++ b/gcc/ada/gen_il-gen-gen_entities.adb
@@ -551,11 +551,11 @@ begin -- Gen_IL.Gen.Gen_Entities
        (Sm (First_Literal, Node_Id),
         Sm (Has_Enumeration_Rep_Clause, Flag),
         Sm (Has_Pragma_Ordered, Flag, Impl_Base_Type_Only),
-        Sm (Lit_Indexes, Node_Id),
-        Sm (Lit_Strings, Node_Id),
+        Sm (Lit_Hash, Node_Id, Root_Type_Only),
+        Sm (Lit_Indexes, Node_Id, Root_Type_Only),
+        Sm (Lit_Strings, Node_Id, Root_Type_Only),
         Sm (Nonzero_Is_True, Flag, Base_Type_Only,
-            Pre => "Root_Type (N) = Standard_Boolean"),
-        Sm (Lit_Hash, Node_Id, Root_Type_Only)));
+            Pre => "Root_Type (N) = Standard_Boolean")));
 
    Cc (E_Enumeration_Type, Enumeration_Kind,
        --  Enumeration types, created by an enumeration type declaration
--  { dg-do run }

procedure Enum6 is

  type Base_Enum is (Ten, Twenty);

  type Derived_Enum is new Base_Enum;
  for Derived_Enum use (Ten => 10, Twenty => 20);

  type Rep_Enum is (Ten, Twenty);
  for Rep_Enum use (Ten => 10, Twenty => 20);

  OK : Boolean := True;

begin
  for E in Base_Enum loop
    if (E = Ten and then Base_Enum'Image(E) /= "TEN")
      or else (E = Twenty and then Base_Enum'Image(E) /= "TWENTY")
    then
      OK := False;
    end if;
  end loop;

  for E in Derived_Enum loop
    if (E = Ten and then Derived_Enum'Image(E) /= "TEN")
       or else (E = Twenty and then Derived_Enum'Image(E) /= "TWENTY")
    then
      OK := False;
    end if;
  end loop;

  for E in Rep_Enum loop
    if (E = Ten and then Rep_Enum'Image(E) /= "TEN")
      or else (E = Twenty and then Rep_Enum'Image(E) /= "TWENTY")
    then
      OK := False;
    end if;
  end loop;

  if not OK then
    raise Program_Error;
  end if;
end;

Reply via email to