[Ada] Compiler abort on use of Invalid_Value on numeric positive subtype
authorEd Schonberg <schonberg@adacore.com>
Mon, 1 Jul 2019 13:34:30 +0000 (13:34 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Mon, 1 Jul 2019 13:34:30 +0000 (13:34 +0000)
commit6a04c943908a9302683dd16b59fc72419ebd54b0
treea8e5109cf9548d8f8cea3131bb86941501720799
parent867edb0b613898bec9128e1ecb055c3277e34dbc
[Ada] Compiler abort on use of Invalid_Value on numeric positive subtype

Invalid_Value in most cases uses a predefined numeric value from a
built-in table, but if the type does not include zero in its range, the
literal 0 is used instead. In that case the value (produced by a call to
Get_Simple_Init_Val) must be resolved for proper type information.

The following must compile quietly:

   gnatmake -q main

----
with Problems; use Problems;
with Text_IO; use Text_IO;

procedure Main is
begin

   Put_Line ("P1: " & P1'Image);
   Put_Line ("P2: " & P2'Image);
   Put_Line ("P3: " & P3'Image);
   Put_Line ("P4: " & P4'Image);

end Main;
--
package Problems is

   function P1 return Integer;
   function P2 return Long_Integer;

   -- Max. number of prime factors a number can have is log_2 N
   -- For N = 600851475143, this is ~ 40
   -- type P3_Factors is array (1 .. 40) of Long_Integer;
   function P3 return Long_Integer;

   type P4_Palindrome is range 100*100 .. 999*999;
   function P4 return P4_Palindrome;

end Problems;
----
package body Problems is

   function P1 return Integer is separate;
   function P2 return Long_Integer is separate;
   function P3 return Long_Integer is separate;
   function P4 return P4_Palindrome is separate;

end Problems;
----
separate(Problems)

function P1 return Integer is

   Sum : Integer range 0 .. 500_500 := 0;

begin

   for I in Integer range 1 .. 1000 - 1 loop
      if I mod 3 = 0 or I mod 5 = 0 then
         Sum := Sum + I;
      end if;
   end loop;

   return Sum;

end P1;
--
separate(Problems)

function P2 return Long_Integer is

   subtype Total is Long_Integer range 0 .. 8_000002e6 ;
   subtype Elem  is Total        range 0 .. 4e7 ;

   Sum : Total := 0;
   a, b, c : Elem;

begin
   a := 1;
   b := 2;

   loop
      if b mod 2 = 0 then
         Sum := Sum + b;
      end if;

      c := b;
      b := a + b;
      a := c;

      exit when b >= 4e6;
   end loop;

   return Sum;

end P2;
--
with Text_IO; use Text_IO;
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;

separate(Problems)
function P3 return Long_Integer is

   -- Greatest prime factor
   GPF      : Long_Integer       := 1;

   Dividend : Long_Integer  := 600851475143;
   Factor   : Long_Integer  := 2;
   Quotient : Long_Integer;

begin

   while Dividend > 1 loop
      Quotient := Dividend / Factor;
      if Dividend mod Factor = 0 then
         GPF := Factor;
         Dividend := Quotient;
      else
         if Factor >= Quotient then
            GPF := Dividend;
            exit;
         end if;
         Factor := Factor + 1;
      end if;
   end loop;

   return GPF;

end P3;
----
with Text_IO; use Text_IO;
separate(Problems)
function P4 return P4_Palindrome is

   type TripleDigit is range 100 .. 999;
   a, b: TripleDigit := TripleDigit'First;

   c : P4_Palindrome;

   Max_Palindrome : P4_Palindrome := P4_Palindrome'Invalid_Value;

   function Is_Palindrome (X : in P4_Palindrome) return Boolean is

      type Int_Digit is range 0 .. 9;
      type Int_Digits is array (1 .. 6) of Int_Digit;

      type Digit_Extractor is range 0 .. P4_Palindrome'Last;
      Y : Digit_Extractor := Digit_Extractor (X);
      X_Digits : Int_Digits;

   begin

      for I in reverse X_Digits'Range loop
         X_Digits (I) := Int_Digit (Y mod 10);
         Y := Y / 10;
      end loop;

      return
        (X_Digits (1) = X_Digits (6) and X_Digits (2) = X_Digits (5) and
             X_Digits (3) = X_Digits (4)) or
        (X_Digits (2) = X_Digits (6) and X_Digits (3) = X_Digits (5) and
             X_Digits(1) = 0);

   end Is_Palindrome;

begin

   for a in TripleDigit'Range loop
      for b in TripleDigit'Range loop
         c := P4_Palindrome (a * b);
         if Is_Palindrome (c) then
            if Max_Palindrome'Valid or else c > Max_Palindrome then
               Max_Palindrome := c;
            end if;
         end if;
      end loop;
   end loop;

   return Max_Palindrome;
end;

2019-07-01  Ed Schonberg  <schonberg@adacore.com>

gcc/ada/

* exp_attr.adb (Expand_Attribute_Reference, case Invalid_Value):
Resolve result of call to Get_Simple_Init_Val, which may be a
conversion of a literal.

From-SVN: r272855
gcc/ada/ChangeLog
gcc/ada/exp_attr.adb