diff mbox

[Ada] Extra precision in the evaluation of non-static expressions

Message ID 20160706133959.GA80164@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet July 6, 2016, 1:39 p.m. UTC
This patch prevents the use of arbitrary-precision computations when an
expression consists of known numeric literals but one of them is not static
by the rules of the language but happens to be known to the compiler through
data-flow. The patch introduces a conversion to a machine number for the
evaluation of the non-static subexpression.

Executing:
   gnatmake -q maintest
   maintest

must yield:

 3541631232 3541631232 3541631232 3541631232
 3541631107 3541631107 3541631107 3541631107

---
with Text_IO;

procedure maintest
is

   type A_TYPE is mod 2 ** 32;
   for A_TYPE'SIZE use 32;

   A_VALUE : A_TYPE := 170000000;

   FLOAT_MAX_CONST : constant := ((2.0**21 - 1.0) / 2.0**21) * 2.0**84;
   type FLOAT_TYPE is digits 6 range - 2.0** 84 .. FLOAT_MAX_CONST;
   for FLOAT_TYPE'SIZE use 32;

   type B_TYPE is mod 2**32;
   for B_TYPE'SIZE use 32;

   A_CONST : aliased constant FLOAT_TYPE := 83.3325 / 4.0;

   package mod_io is new text_io.modular_io (B_TYPE);
begin
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (A_VALUE)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (A_VALUE)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (A_VALUE)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (A_VALUE)));
   Text_IO.New_Line;

   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (170000000)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (170000000)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (170000000)));
   mod_io.Put(B_TYPE (A_CONST * FLOAT_TYPE (170000000)));
end maintest;

Tested on x86_64-pc-linux-gnu, committed on trunk

2016-07-06  Ed Schonberg  <schonberg@adacore.com>

	* sem_eval.adb (Check_Non_Static_Context): If the expression
	is a real literal of a floating point type that is part of a
	larger expression and is not a static expression, transform it
	into a machine number now so that the rest of the computation,
	even if other components are static, is not evaluated with
	extra precision.
diff mbox

Patch

Index: sem_eval.adb
===================================================================
--- sem_eval.adb	(revision 238040)
+++ sem_eval.adb	(working copy)
@@ -445,11 +445,24 @@ 
       --  that an infinity will result.
 
       if not Is_Static_Expression (N) then
-         if Is_Floating_Point_Type (T)
-           and then Is_Out_Of_Range (N, Base_Type (T), Assume_Valid => True)
-         then
-            Error_Msg_N
-              ("??float value out of range, infinity will be generated", N);
+         if Is_Floating_Point_Type (T) then
+            if Is_Out_Of_Range (N, Base_Type (T), Assume_Valid => True) then
+               Error_Msg_N
+                 ("??float value out of range, infinity will be generated", N);
+
+            --  The literal may be the result of constant-folding of a non-
+            --  static subexpression of a larger expression (e.g. a conversion
+            --  of a non-static variable whose value happens to be known). At
+            --  this point we must reduce the value of the subexpression to a
+            --  machine number (RM 4.9 (38/2)).
+
+            elsif Nkind (N) = N_Real_Literal
+              and then Nkind (Parent (N)) in N_Subexpr
+            then
+               Rewrite (N, New_Copy (N));
+               Set_Realval
+                 (N, Machine (Base_Type (T), Realval (N), Round_Even, N));
+            end if;
          end if;
 
          return;