blob: 0d5c19e8c532685ceb026ebce28c1142721e54da [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S Y S T E M . V A L U E _ U _ S P E C --
-- --
-- S p e c --
-- --
-- Copyright (C) 2022-2022, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
-- This package contains the specification entities using for the formal
-- verification of the routines for scanning modular Unsigned values.
-- Preconditions in this unit are meant for analysis only, not for run-time
-- checking, so that the expected exceptions are raised. This is enforced by
-- setting the corresponding assertion policy to Ignore. Postconditions and
-- contract cases should not be executed at runtime as well, in order not to
-- slow down the execution of these functions.
pragma Assertion_Policy (Pre => Ignore,
Post => Ignore,
Contract_Cases => Ignore,
Ghost => Ignore,
Subprogram_Variant => Ignore);
with System.Val_Util; use System.Val_Util;
generic
type Uns is mod <>;
package System.Value_U_Spec with
Ghost,
SPARK_Mode,
Annotate => (GNATprove, Always_Return)
is
pragma Preelaborate;
type Uns_Option (Overflow : Boolean := False) is record
case Overflow is
when True =>
null;
when False =>
Value : Uns := 0;
end case;
end record;
function Wrap_Option (Value : Uns) return Uns_Option is
(Overflow => False, Value => Value);
function Only_Decimal_Ghost
(Str : String;
From, To : Integer)
return Boolean
is
(for all J in From .. To => Str (J) in '0' .. '9')
with
Pre => From > To or else (From >= Str'First and then To <= Str'Last);
-- Ghost function that returns True if S has only decimal characters
-- from index From to index To.
function Only_Hexa_Ghost (Str : String; From, To : Integer) return Boolean
is
(for all J in From .. To =>
Str (J) in '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' | '_')
with
Pre => From > To or else (From >= Str'First and then To <= Str'Last);
-- Ghost function that returns True if S has only hexadecimal characters
-- from index From to index To.
function Last_Hexa_Ghost (Str : String) return Positive
with
Pre => Str /= ""
and then Str (Str'First) in '0' .. '9' | 'a' .. 'f' | 'A' .. 'F',
Post => Last_Hexa_Ghost'Result in Str'Range
and then (if Last_Hexa_Ghost'Result < Str'Last then
Str (Last_Hexa_Ghost'Result + 1) not in
'0' .. '9' | 'a' .. 'f' | 'A' .. 'F' | '_')
and then Only_Hexa_Ghost (Str, Str'First, Last_Hexa_Ghost'Result);
-- Ghost function that returns the index of the last character in S that
-- is either an hexadecimal digit or an underscore, which necessarily
-- exists given the precondition on Str.
function Is_Based_Format_Ghost (Str : String) return Boolean
is
(Str /= ""
and then Str (Str'First) in '0' .. '9' | 'a' .. 'f' | 'A' .. 'F'
and then
(declare
L : constant Positive := Last_Hexa_Ghost (Str);
begin
Str (L) /= '_'
and then (for all J in Str'First .. L =>
(if Str (J) = '_' then Str (J + 1) /= '_'))));
-- Ghost function that determines if Str has the correct format for a
-- based number, consisting in a sequence of hexadecimal digits possibly
-- separated by single underscores. It may be followed by other characters.
function Hexa_To_Unsigned_Ghost (X : Character) return Uns is
(case X is
when '0' .. '9' => Character'Pos (X) - Character'Pos ('0'),
when 'a' .. 'f' => Character'Pos (X) - Character'Pos ('a') + 10,
when 'A' .. 'F' => Character'Pos (X) - Character'Pos ('A') + 10,
when others => raise Program_Error)
with
Pre => X in '0' .. '9' | 'a' .. 'f' | 'A' .. 'F';
-- Ghost function that computes the value corresponding to an hexadecimal
-- digit.
function Scan_Overflows_Ghost
(Digit : Uns;
Base : Uns;
Acc : Uns) return Boolean
is
(Digit >= Base
or else Acc > Uns'Last / Base
or else Uns'Last - Digit < Base * Acc);
-- Ghost function which returns True if Digit + Base * Acc overflows or
-- Digit is greater than Base, as this is used by the algorithm for the
-- test of overflow.
function Scan_Based_Number_Ghost
(Str : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0) return Uns_Option
with
Subprogram_Variant => (Increases => From),
Pre => Str'Last /= Positive'Last
and then
(From > To or else (From >= Str'First and then To <= Str'Last))
and then Only_Hexa_Ghost (Str, From, To);
-- Ghost function that recursively computes the based number in Str,
-- assuming Acc has been scanned already and scanning continues at index
-- From.
-- Lemmas unfolding the recursive definition of Scan_Based_Number_Ghost
procedure Lemma_Scan_Based_Number_Ghost_Base
(Str : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0)
with
Global => null,
Pre => Str'Last /= Positive'Last
and then
(From > To or else (From >= Str'First and then To <= Str'Last))
and then Only_Hexa_Ghost (Str, From, To),
Post =>
(if From > To
then Scan_Based_Number_Ghost (Str, From, To, Base, Acc) =
(Overflow => False, Value => Acc));
-- Base case: Scan_Based_Number_Ghost returns Acc if From is bigger than To
procedure Lemma_Scan_Based_Number_Ghost_Underscore
(Str : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0)
with
Global => null,
Pre => Str'Last /= Positive'Last
and then
(From > To or else (From >= Str'First and then To <= Str'Last))
and then Only_Hexa_Ghost (Str, From, To),
Post =>
(if From <= To and then Str (From) = '_'
then Scan_Based_Number_Ghost (Str, From, To, Base, Acc) =
Scan_Based_Number_Ghost (Str, From + 1, To, Base, Acc));
-- Underscore case: underscores are ignored while scanning
procedure Lemma_Scan_Based_Number_Ghost_Overflow
(Str : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0)
with
Global => null,
Pre => Str'Last /= Positive'Last
and then
(From > To or else (From >= Str'First and then To <= Str'Last))
and then Only_Hexa_Ghost (Str, From, To),
Post =>
(if From <= To
and then Str (From) /= '_'
and then Scan_Overflows_Ghost
(Hexa_To_Unsigned_Ghost (Str (From)), Base, Acc)
then Scan_Based_Number_Ghost (Str, From, To, Base, Acc) =
(Overflow => True));
-- Overflow case: scanning a digit which causes an overflow
procedure Lemma_Scan_Based_Number_Ghost_Step
(Str : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0)
with
Global => null,
Pre => Str'Last /= Positive'Last
and then
(From > To or else (From >= Str'First and then To <= Str'Last))
and then Only_Hexa_Ghost (Str, From, To),
Post =>
(if From <= To
and then Str (From) /= '_'
and then not Scan_Overflows_Ghost
(Hexa_To_Unsigned_Ghost (Str (From)), Base, Acc)
then Scan_Based_Number_Ghost (Str, From, To, Base, Acc) =
Scan_Based_Number_Ghost
(Str, From + 1, To, Base,
Base * Acc + Hexa_To_Unsigned_Ghost (Str (From))));
-- Normal case: scanning a digit without overflows
function Exponent_Unsigned_Ghost
(Value : Uns;
Exp : Natural;
Base : Uns := 10) return Uns_Option
with
Subprogram_Variant => (Decreases => Exp);
-- Ghost function that recursively computes Value * Base ** Exp
-- Lemmas unfolding the recursive definition of Exponent_Unsigned_Ghost
procedure Lemma_Exponent_Unsigned_Ghost_Base
(Value : Uns;
Exp : Natural;
Base : Uns := 10)
with
Post =>
(if Exp = 0 or Value = 0
then Exponent_Unsigned_Ghost (Value, Exp, Base) =
(Overflow => False, Value => Value));
-- Base case: Exponent_Unsigned_Ghost returns 0 if Value or Exp is 0
procedure Lemma_Exponent_Unsigned_Ghost_Overflow
(Value : Uns;
Exp : Natural;
Base : Uns := 10)
with
Post =>
(if Exp /= 0
and then Value /= 0
and then Scan_Overflows_Ghost (0, Base, Value)
then Exponent_Unsigned_Ghost (Value, Exp, Base) = (Overflow => True));
-- Overflow case: the next multiplication overflows
procedure Lemma_Exponent_Unsigned_Ghost_Step
(Value : Uns;
Exp : Natural;
Base : Uns := 10)
with
Post =>
(if Exp /= 0
and then Value /= 0
and then not Scan_Overflows_Ghost (0, Base, Value)
then Exponent_Unsigned_Ghost (Value, Exp, Base) =
Exponent_Unsigned_Ghost (Value * Base, Exp - 1, Base));
-- Normal case: exponentiation without overflows
function Is_Raw_Unsigned_Format_Ghost (Str : String) return Boolean is
(Is_Natural_Format_Ghost (Str)
and then
(declare
Last_Num_Init : constant Integer := Last_Number_Ghost (Str);
Starts_As_Based : constant Boolean :=
Last_Num_Init < Str'Last - 1
and then Str (Last_Num_Init + 1) in '#' | ':'
and then Str (Last_Num_Init + 2) in
'0' .. '9' | 'a' .. 'f' | 'A' .. 'F';
Last_Num_Based : constant Integer :=
(if Starts_As_Based
then Last_Hexa_Ghost (Str (Last_Num_Init + 2 .. Str'Last))
else Last_Num_Init);
Is_Based : constant Boolean :=
Starts_As_Based
and then Last_Num_Based < Str'Last
and then Str (Last_Num_Based + 1) = Str (Last_Num_Init + 1);
First_Exp : constant Integer :=
(if Is_Based then Last_Num_Based + 2 else Last_Num_Init + 1);
begin
(if Starts_As_Based then
Is_Based_Format_Ghost (Str (Last_Num_Init + 2 .. Str'Last))
and then Last_Num_Based < Str'Last)
and then Is_Opt_Exponent_Format_Ghost
(Str (First_Exp .. Str'Last))))
with
Pre => Str'Last /= Positive'Last;
-- Ghost function that determines if Str has the correct format for an
-- unsigned number without a sign character.
-- It is a natural number in base 10, optionally followed by a based
-- number surrounded by delimiters # or :, optionally followed by an
-- exponent part.
type Split_Value_Ghost is record
Value : Uns;
Base : Uns;
Expon : Natural;
end record;
function Scan_Split_No_Overflow_Ghost
(Str : String;
From, To : Integer)
return Boolean
is
(declare
Last_Num_Init : constant Integer :=
Last_Number_Ghost (Str (From .. To));
Init_Val : constant Uns_Option :=
Scan_Based_Number_Ghost (Str, From, Last_Num_Init);
Starts_As_Based : constant Boolean :=
Last_Num_Init < To - 1
and then Str (Last_Num_Init + 1) in '#' | ':'
and then Str (Last_Num_Init + 2) in
'0' .. '9' | 'a' .. 'f' | 'A' .. 'F';
Last_Num_Based : constant Integer :=
(if Starts_As_Based
then Last_Hexa_Ghost (Str (Last_Num_Init + 2 .. To))
else Last_Num_Init);
Based_Val : constant Uns_Option :=
(if Starts_As_Based and then not Init_Val.Overflow
then Scan_Based_Number_Ghost
(Str, Last_Num_Init + 2, Last_Num_Based, Init_Val.Value)
else Init_Val);
begin
not Init_Val.Overflow
and then
(Last_Num_Init >= To - 1
or else Str (Last_Num_Init + 1) not in '#' | ':'
or else Init_Val.Value in 2 .. 16)
and then
(not Starts_As_Based
or else not Based_Val.Overflow))
with
Pre => Str'Last /= Positive'Last
and then From in Str'Range
and then To in From .. Str'Last
and then Str (From) in '0' .. '9';
-- Ghost function that determines if an overflow might occur while scanning
-- the representation of an unsigned number. The computation overflows if
-- either:
-- * The computation of the decimal part overflows,
-- * The decimal part is followed by a valid delimiter for a based
-- part, and the number corresponding to the base is not a valid base,
-- or
-- * The computation of the based part overflows.
pragma Warnings (Off, "constant * is not referenced");
function Scan_Split_Value_Ghost
(Str : String;
From, To : Integer)
return Split_Value_Ghost
is
(declare
Last_Num_Init : constant Integer :=
Last_Number_Ghost (Str (From .. To));
Init_Val : constant Uns_Option :=
Scan_Based_Number_Ghost (Str, From, Last_Num_Init);
Starts_As_Based : constant Boolean :=
Last_Num_Init < To - 1
and then Str (Last_Num_Init + 1) in '#' | ':'
and then Str (Last_Num_Init + 2) in
'0' .. '9' | 'a' .. 'f' | 'A' .. 'F';
Last_Num_Based : constant Integer :=
(if Starts_As_Based
then Last_Hexa_Ghost (Str (Last_Num_Init + 2 .. To))
else Last_Num_Init);
Is_Based : constant Boolean :=
Starts_As_Based
and then Last_Num_Based < To
and then Str (Last_Num_Based + 1) = Str (Last_Num_Init + 1);
Based_Val : constant Uns_Option :=
(if Starts_As_Based and then not Init_Val.Overflow
then Scan_Based_Number_Ghost
(Str, Last_Num_Init + 2, Last_Num_Based, Init_Val.Value)
else Init_Val);
First_Exp : constant Integer :=
(if Is_Based then Last_Num_Based + 2 else Last_Num_Init + 1);
Expon : constant Natural :=
(if Starts_As_Exponent_Format_Ghost (Str (First_Exp .. To))
then Scan_Exponent_Ghost (Str (First_Exp .. To))
else 0);
Base : constant Uns :=
(if Is_Based then Init_Val.Value else 10);
Value : constant Uns :=
(if Is_Based then Based_Val.Value else Init_Val.Value);
begin
(Value => Value, Base => Base, Expon => Expon))
with
Pre => Str'Last /= Positive'Last
and then From in Str'Range
and then To in From .. Str'Last
and then Str (From) in '0' .. '9'
and then Scan_Split_No_Overflow_Ghost (Str, From, To);
-- Ghost function that scans an unsigned number without a sign character
-- and return a record containing the values scanned for its value, its
-- base, and its exponent.
pragma Warnings (On, "constant * is not referenced");
function Raw_Unsigned_No_Overflow_Ghost
(Str : String;
From, To : Integer)
return Boolean
is
(Scan_Split_No_Overflow_Ghost (Str, From, To)
and then
(declare
Val : constant Split_Value_Ghost := Scan_Split_Value_Ghost
(Str, From, To);
begin
not Exponent_Unsigned_Ghost
(Val.Value, Val.Expon, Val.Base).Overflow))
with
Pre => Str'Last /= Positive'Last
and then From in Str'Range
and then To in From .. Str'Last
and then Str (From) in '0' .. '9';
-- Ghost function that determines if the computation of the unsigned number
-- represented by Str will overflow. The computation overflows if either:
-- * The scan of the string overflows, or
-- * The computation of the exponentiation overflows.
function Scan_Raw_Unsigned_Ghost
(Str : String;
From, To : Integer)
return Uns
is
(declare
Val : constant Split_Value_Ghost := Scan_Split_Value_Ghost
(Str, From, To);
begin
Exponent_Unsigned_Ghost (Val.Value, Val.Expon, Val.Base).Value)
with
Pre => Str'Last /= Positive'Last
and then From in Str'Range
and then To in From .. Str'Last
and then Str (From) in '0' .. '9'
and then Raw_Unsigned_No_Overflow_Ghost (Str, From, To);
-- Ghost function that scans an unsigned number without a sign character
function Raw_Unsigned_Last_Ghost
(Str : String;
From, To : Integer)
return Positive
is
(declare
Last_Num_Init : constant Integer :=
Last_Number_Ghost (Str (From .. To));
Starts_As_Based : constant Boolean :=
Last_Num_Init < To - 1
and then Str (Last_Num_Init + 1) in '#' | ':'
and then Str (Last_Num_Init + 2) in
'0' .. '9' | 'a' .. 'f' | 'A' .. 'F';
Last_Num_Based : constant Integer :=
(if Starts_As_Based
then Last_Hexa_Ghost (Str (Last_Num_Init + 2 .. To))
else Last_Num_Init);
Is_Based : constant Boolean :=
Starts_As_Based
and then Last_Num_Based < To
and then Str (Last_Num_Based + 1) = Str (Last_Num_Init + 1);
First_Exp : constant Integer :=
(if Is_Based then Last_Num_Based + 2 else Last_Num_Init + 1);
begin
(if not Starts_As_Exponent_Format_Ghost (Str (First_Exp .. To))
then First_Exp
elsif Str (First_Exp + 1) in '-' | '+' then
Last_Number_Ghost (Str (First_Exp + 2 .. To)) + 1
else Last_Number_Ghost (Str (First_Exp + 1 .. To)) + 1))
with
Pre => Str'Last /= Positive'Last
and then From in Str'Range
and then To in From .. Str'Last
and then Str (From) in '0' .. '9';
-- Ghost function that returns the position of the cursor once an unsigned
-- number has been seen.
function Slide_To_1 (Str : String) return String
with
Post =>
Only_Space_Ghost (Str, Str'First, Str'Last) =
(for all J in Str'First .. Str'Last =>
Slide_To_1'Result (J - Str'First + 1) = ' ');
-- Slides Str so that it starts at 1
function Slide_If_Necessary (Str : String) return String is
(if Str'Last = Positive'Last then Slide_To_1 (Str) else Str);
-- If Str'Last = Positive'Last then slides Str so that it starts at 1
function Is_Unsigned_Ghost (Str : String) return Boolean is
(declare
Non_Blank : constant Positive := First_Non_Space_Ghost
(Str, Str'First, Str'Last);
Fst_Num : constant Positive :=
(if Str (Non_Blank) = '+' then Non_Blank + 1 else Non_Blank);
begin
Is_Raw_Unsigned_Format_Ghost (Str (Fst_Num .. Str'Last))
and then Raw_Unsigned_No_Overflow_Ghost (Str, Fst_Num, Str'Last)
and then Only_Space_Ghost
(Str, Raw_Unsigned_Last_Ghost (Str, Fst_Num, Str'Last), Str'Last))
with
Pre => not Only_Space_Ghost (Str, Str'First, Str'Last)
and then Str'Last /= Positive'Last;
-- Ghost function that determines if Str has the correct format for an
-- unsigned number, consisting in some blank characters, an optional
-- + sign, a raw unsigned number which does not overflow and then some
-- more blank characters.
function Is_Value_Unsigned_Ghost (Str : String; Val : Uns) return Boolean is
(declare
Non_Blank : constant Positive := First_Non_Space_Ghost
(Str, Str'First, Str'Last);
Fst_Num : constant Positive :=
(if Str (Non_Blank) = '+' then Non_Blank + 1 else Non_Blank);
begin
Val = Scan_Raw_Unsigned_Ghost (Str, Fst_Num, Str'Last))
with
Pre => not Only_Space_Ghost (Str, Str'First, Str'Last)
and then Str'Last /= Positive'Last
and then Is_Unsigned_Ghost (Str);
-- Ghost function that returns True if Val is the value corresponding to
-- the unsigned number represented by Str.
procedure Prove_Scan_Based_Number_Ghost_Eq
(Str1, Str2 : String;
From, To : Integer;
Base : Uns := 10;
Acc : Uns := 0)
with
Subprogram_Variant => (Increases => From),
Pre => Str1'Last /= Positive'Last
and then Str2'Last /= Positive'Last
and then
(From > To or else (From >= Str1'First and then To <= Str1'Last))
and then
(From > To or else (From >= Str2'First and then To <= Str2'Last))
and then Only_Hexa_Ghost (Str1, From, To)
and then (for all J in From .. To => Str1 (J) = Str2 (J)),
Post =>
Scan_Based_Number_Ghost (Str1, From, To, Base, Acc)
= Scan_Based_Number_Ghost (Str2, From, To, Base, Acc);
-- Scan_Based_Number_Ghost returns the same value on two slices which are
-- equal.
procedure Prove_Scan_Only_Decimal_Ghost
(Str : String;
Val : Uns)
with
Pre => Str'Last /= Positive'Last
and then Str'Length >= 2
and then Str (Str'First) = ' '
and then Only_Decimal_Ghost (Str, Str'First + 1, Str'Last)
and then Scan_Based_Number_Ghost (Str, Str'First + 1, Str'Last)
= Wrap_Option (Val),
Post => Is_Unsigned_Ghost (Slide_If_Necessary (Str))
and then
Is_Value_Unsigned_Ghost (Slide_If_Necessary (Str), Val);
-- Ghost lemma used in the proof of 'Image implementation, to prove that
-- the result of Value_Unsigned on a decimal string is the same as the
-- result of Scan_Based_Number_Ghost.
-- Bundle Uns type with other types, constants and subprograms used in
-- ghost code, so that this package can be instantiated once and used
-- multiple times as generic formal for a given Int type.
package Uns_Params is new System.Val_Util.Uns_Params
(Uns => Uns,
P_Uns_Option => Uns_Option,
P_Wrap_Option => Wrap_Option,
P_Hexa_To_Unsigned_Ghost => Hexa_To_Unsigned_Ghost,
P_Scan_Overflows_Ghost => Scan_Overflows_Ghost,
P_Is_Raw_Unsigned_Format_Ghost =>
Is_Raw_Unsigned_Format_Ghost,
P_Scan_Split_No_Overflow_Ghost =>
Scan_Split_No_Overflow_Ghost,
P_Raw_Unsigned_No_Overflow_Ghost =>
Raw_Unsigned_No_Overflow_Ghost,
P_Exponent_Unsigned_Ghost => Exponent_Unsigned_Ghost,
P_Lemma_Exponent_Unsigned_Ghost_Base =>
Lemma_Exponent_Unsigned_Ghost_Base,
P_Lemma_Exponent_Unsigned_Ghost_Overflow =>
Lemma_Exponent_Unsigned_Ghost_Overflow,
P_Lemma_Exponent_Unsigned_Ghost_Step =>
Lemma_Exponent_Unsigned_Ghost_Step,
P_Scan_Raw_Unsigned_Ghost => Scan_Raw_Unsigned_Ghost,
P_Lemma_Scan_Based_Number_Ghost_Base =>
Lemma_Scan_Based_Number_Ghost_Base,
P_Lemma_Scan_Based_Number_Ghost_Underscore =>
Lemma_Scan_Based_Number_Ghost_Underscore,
P_Lemma_Scan_Based_Number_Ghost_Overflow =>
Lemma_Scan_Based_Number_Ghost_Overflow,
P_Lemma_Scan_Based_Number_Ghost_Step =>
Lemma_Scan_Based_Number_Ghost_Step,
P_Raw_Unsigned_Last_Ghost => Raw_Unsigned_Last_Ghost,
P_Only_Decimal_Ghost => Only_Decimal_Ghost,
P_Scan_Based_Number_Ghost => Scan_Based_Number_Ghost,
P_Is_Unsigned_Ghost =>
Is_Unsigned_Ghost,
P_Is_Value_Unsigned_Ghost =>
Is_Value_Unsigned_Ghost,
P_Prove_Scan_Only_Decimal_Ghost =>
Prove_Scan_Only_Decimal_Ghost,
P_Prove_Scan_Based_Number_Ghost_Eq =>
Prove_Scan_Based_Number_Ghost_Eq);
private
----------------
-- Slide_To_1 --
----------------
function Slide_To_1 (Str : String) return String is
(declare
Res : constant String (1 .. Str'Length) := Str;
begin
Res);
end System.Value_U_Spec;