GNAT compiler is confused

I have a procedure that is supposed to be printing out limit for compiler unsigned integer. However when I use GNAT Studio semantic check, it throws error message like this:

data_types.adb:23:72: unexpected argument for “Image” attribute
data_types.adb:25:58: prefix of “First” attribute must be a type
data_types.adb:25:99: prefix of “Last” attribute must be a type

This is the procedure I have written

procedure Signed is
      
      Word_1 : String (1 .. 20) := (others => ' ');
      type Kinds is (Integer, Short_Integer, Short_Short_Integer, Long_Long_Integer);
      package Kinds_IO is new Enumeration_IO (Kinds);

   begin
      
      New_Line;
      Put_Line ("Signed Integer data types limits are:");
      Outer :
      for I in Kinds'Range loop
         Kinds_IO.Put (To   => Word_1,
                       Item => Kinds (I),
                       Set  => Upper_Case);
         case I is
            when Integer =>
               Put_Line (Word_1 & " Size  is " & Integer'Image (Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Integer'Image (Integer'First) & " .. " & Integer'Image (Integer'Last));
            when Short_Integer =>
               Put_Line (Word_1 & " Size  is " & Short_Integer'Image (Short_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Short_Integer'Image (Short_Integer'First) & " .. " &
                  Short_Integer'Image (Short_Integer'Last));
            when Short_Short_Integer =>
               Put_Line (Word_1 & " Size  is " & Short_Short_Integer'Image (Short_Short_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Short_Short_Integer'Image (Short_Short_Integer'First) & " .. " &
                  Short_Short_Integer'Image (Short_Short_Integer'Last));
            when Long_Long_Integer =>
               Put_Line (Word_1 & " Size  is " & Long_Long_Integer'Image (Long_Long_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Long_Long_Integer'Image (Long_Long_Integer'First) & " .. " &
                  Long_Long_Integer'Image (Long_Long_Integer'Last));
         end case;
      end loop Outer;
      New_Line;
   end Signed;

As far as I can tell, the compiler is confused between type Kinds enumeration (Integer etc) with the Standard Integer types since previously when I use enumeration from 1 to 4 it compiles and output correctly. How do I work around that?

Just rename your Kinds, like Integer_Kind or Is_Integer.

Ah. thanks. That works.

Or say Standard.Integer when you mean the Integer defined in Standard.

Nope, it still was confused when I tried that before asking here.

Out of curiosity, what version / target of GNAT are you using? I just tossed your code into godbolt and ran GNAT 13.x - 15.x and in all of them, prefixing the Integer calls with Standard. removed the errors. I had to do it for most of the attributes (Image, First, and Last ).

EDIT: This was the code I used:

procedure Signed is
      
      Word_1 : String (1 .. 20) := (others => ' ');
      type Kinds is (Integer, Short_Integer, Short_Short_Integer, Long_Long_Integer);
      package Kinds_IO is new Enumeration_IO (Kinds);

   begin
      
      New_Line;
      Put_Line ("Signed Integer data types limits are:");
      Outer :
      for I in Kinds'Range loop
         Kinds_IO.Put (To   => Word_1,
                       Item => Kinds (I),
                       Set  => Upper_Case);
         case I is
            when Integer =>
               Put_Line (Word_1 & " Size  is " & Standard.Integer'Image (Standard.Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Standard.Integer'Image (Standard.Integer'First) & " .. " & Standard.Integer'Image (Standard.Integer'Last));
            when Short_Integer =>
               Put_Line (Word_1 & " Size  is " & Standard.Short_Integer'Image (Standard.Short_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Standard.Short_Integer'Image (Standard.Short_Integer'First) & " .. " &
                  Standard.Short_Integer'Image (Standard.Short_Integer'Last));
            when Short_Short_Integer =>
               Put_Line (Word_1 & " Size  is " & Standard.Short_Short_Integer'Image (Standard.Short_Short_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Standard.Short_Short_Integer'Image (Standard.Short_Short_Integer'First) & " .. " &
                  Standard.Short_Short_Integer'Image (Standard.Short_Short_Integer'Last));
            when Long_Long_Integer =>
               Put_Line (Word_1 & " Size  is " & Standard.Long_Long_Integer'Image (Standard.Long_Long_Integer'Size));
               Put_Line
                 (Word_1 & " range is " & Standard.Long_Long_Integer'Image (Standard.Long_Long_Integer'First) & " .. " &
                  Standard.Long_Long_Integer'Image (Standard.Long_Long_Integer'Last));
         end case;
      end loop Outer;
      New_Line;
   end Signed;
1 Like

I probably don’t do the all the edit correctly. And using old GNAT CE 2020, since it’s just for fun there is no need for me to use the latest version.

Anyway, thank you all for the pointers.

No problem. I was just checking since GNAT has a lot of parsing bugs in various versions.

The compiler is correct. You are confused.

You have used the identifier Integer as an enumeration literal in procedure Signed. From that point on, the enumeration literal hides the identifier Integer declared in package Standard. The short name Integer is always the enumeration literal; it cannot be used to refer to the predefined type.

However, everything has a full name that begins with Standard. Your enumeration literal has the full name Standard.Signed.Integer. The predefined type has the full name Standard.Integer. You can always use the full name to refer to anything.

This also applies to your other enumeration literals that may be the same as declarations in Standard, such as Short_Integer. To correct your program, everywhere you want to refer to a predefined type hidden by your enumeration literals, you have to prefix the type name with Standard.

Note that the only thing your enumeration type gives you is unnecessary complexity. Your program would be clearer and simpler without it.

2 Likes