From: Eric Botcazou <ebotca...@adacore.com> Even though the issue is not user-visible, it's a (minor) departure from the specification of the procedure.
gcc/ada/ChangeLog: * libgnat/s-valued.adb (Integer_to_Decimal): Add Extra parameter and use its value to call Bad_Value on boundary values. (Scan_Decimal): Adjust call to Integer_to_Decimal. (Value_Decimal): Likewise. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/libgnat/s-valued.adb | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/gcc/ada/libgnat/s-valued.adb b/gcc/ada/libgnat/s-valued.adb index dfef9a885e5..cc2cffc72a6 100644 --- a/gcc/ada/libgnat/s-valued.adb +++ b/gcc/ada/libgnat/s-valued.adb @@ -39,13 +39,15 @@ package body System.Value_D is -- We need an unsigned type large enough to represent the mantissa package Impl is new Value_R (Uns, 1, 2**(Int'Size - 1), Round => False); - -- We do not use the Extra digit for decimal fixed-point types + -- We do not use the Extra digit for decimal fixed-point types, except to + -- effectively ensure that overflow is detected near the boundaries. function Integer_to_Decimal (Str : String; Val : Uns; Base : Unsigned; ScaleB : Integer; + Extra : Unsigned; Minus : Boolean; Scale : Integer) return Int; -- Convert the real value from integer to decimal representation @@ -59,6 +61,7 @@ package body System.Value_D is Val : Uns; Base : Unsigned; ScaleB : Integer; + Extra : Unsigned; Minus : Boolean; Scale : Integer) return Int is @@ -126,6 +129,10 @@ package body System.Value_D is end if; end Unsigned_To_Signed; + -- Local variables + + E : Uns := Uns (Extra); + begin -- If the base of the value is 10 or its scaling factor is zero, then -- add the scales (they are defined in the opposite sense) and apply @@ -143,9 +150,10 @@ package body System.Value_D is end loop; while S > 0 loop - if V <= Uns'Last / 10 then - V := V * 10; + if V <= (Uns'Last - E) / 10 then + V := V * 10 + E; S := S - 1; + E := 0; else Bad_Value (Str); end if; @@ -193,8 +201,9 @@ package body System.Value_D is Z := 10 ** Integer'Max (0, -Scale); for J in 1 .. LS loop - if V <= Uns'Last / Uns (B) then - V := V * Uns (B); + if V <= (Uns'Last - E) / Uns (B) then + V := V * Uns (B) + E; + E := 0; else Bad_Value (Str); end if; @@ -207,7 +216,7 @@ package body System.Value_D is raise Program_Error; end if; - -- Perform a scale divide operation with rounding to match 'Image + -- Perform a scaled divide operation with rounding to match 'Image Scaled_Divide (Unsigned_To_Signed (V), Y, Z, Q, R, Round => True); @@ -238,7 +247,8 @@ package body System.Value_D is begin Val := Impl.Scan_Raw_Real (Str, Ptr, Max, Base, Scl, Extra, Minus); - return Integer_to_Decimal (Str, Val (1), Base, Scl (1), Minus, Scale); + return + Integer_to_Decimal (Str, Val (1), Base, Scl (1), Extra, Minus, Scale); end Scan_Decimal; ------------------- @@ -255,7 +265,8 @@ package body System.Value_D is begin Val := Impl.Value_Raw_Real (Str, Base, Scl, Extra, Minus); - return Integer_to_Decimal (Str, Val (1), Base, Scl (1), Minus, Scale); + return + Integer_to_Decimal (Str, Val (1), Base, Scl (1), Extra, Minus, Scale); end Value_Decimal; end System.Value_D; -- 2.43.0