einfo.ads, einfo.adb (Static_Real_Or_String_Predicate): New function

2014-07-29  Robert Dewar  <dewar@adacore.com>

	* einfo.ads, einfo.adb (Static_Real_Or_String_Predicate): New function
	(Set_Static_Real_Or_String_Predicate): New procedure
	* sem_ch13.adb (Build_Predicate_Functions): Accomodate static
	string predicates (Is_Predicate_Static): Handle static string
	predicates.
	* sem_eval.adb (Real_Or_String_Static_Predicate_Matches):
	New procedure (Check_Expression_Against_Static_Predicate):
	Deal with static string predicates, now fully implemented
	(Eval_Relational_Op): Allow string equality/inequality as static
	if not comes from source.

From-SVN: r213162
This commit is contained in:
Robert Dewar 2014-07-29 13:03:49 +00:00 committed by Arnaud Charlet
parent 60f908dd02
commit fc3a3f3b7e
5 changed files with 247 additions and 34 deletions

View File

@ -1,3 +1,16 @@
2014-07-29 Robert Dewar <dewar@adacore.com>
* einfo.ads, einfo.adb (Static_Real_Or_String_Predicate): New function
(Set_Static_Real_Or_String_Predicate): New procedure
* sem_ch13.adb (Build_Predicate_Functions): Accomodate static
string predicates (Is_Predicate_Static): Handle static string
predicates.
* sem_eval.adb (Real_Or_String_Static_Predicate_Matches):
New procedure (Check_Expression_Against_Static_Predicate):
Deal with static string predicates, now fully implemented
(Eval_Relational_Op): Allow string equality/inequality as static
if not comes from source.
2014-07-29 Robert Dewar <dewar@adacore.com>
* sem_aggr.adb, exp_ch5.adb, sem_ch5.adb, exp_util.adb, einfo.adb,

View File

@ -223,6 +223,7 @@ package body Einfo is
-- PPC_Wrapper Node25
-- Related_Array_Object Node25
-- Static_Discrete_Predicate List25
-- Static_Real_Or_String_Predicate Node25
-- Task_Body_Procedure Node25
-- Dispatch_Table_Wrappers Elist26
@ -2977,6 +2978,12 @@ package body Einfo is
return List25 (Id);
end Static_Discrete_Predicate;
function Static_Real_Or_String_Predicate (Id : E) return N is
begin
pragma Assert (Is_Real_Type (Id) or else Is_String_Type (Id));
return Node25 (Id);
end Static_Real_Or_String_Predicate;
function Status_Flag_Or_Transient_Decl (Id : E) return N is
begin
pragma Assert (Ekind_In (Id, E_Constant, E_Variable));
@ -5767,6 +5774,13 @@ package body Einfo is
Set_List25 (Id, V);
end Set_Static_Discrete_Predicate;
procedure Set_Static_Real_Or_String_Predicate (Id : E; V : N) is
begin
pragma Assert ((Is_Real_Type (Id) or else Is_String_Type (Id))
and then Has_Predicates (Id));
Set_Node25 (Id, V);
end Set_Static_Real_Or_String_Predicate;
procedure Set_Status_Flag_Or_Transient_Decl (Id : E; V : E) is
begin
pragma Assert (Ekind_In (Id, E_Constant, E_Variable));
@ -9399,13 +9413,12 @@ package body Einfo is
E_Entry_Family =>
Write_Str ("PPC_Wrapper");
when E_Enumeration_Type |
E_Enumeration_Subtype |
E_Modular_Integer_Type |
E_Modular_Integer_Subtype |
E_Signed_Integer_Subtype =>
when Discrete_Kind =>
Write_Str ("Static_Discrete_Predicate");
when Real_Kind =>
Write_Str ("Static_Real_Or_String_Predicate");
when others =>
Write_Str ("Field25??");
end case;

View File

@ -3899,7 +3899,7 @@ package Einfo is
-- Static_Discrete_Predicate (List25)
-- Defined in discrete types/subtypes with static predicates (with the
-- two flags Has_Predicates set and Has_Static_Predicate set). Set if the
-- two flags Has_Predicates and Has_Static_Predicate set). Set if the
-- type/subtype has a static predicate. Points to a list of expression
-- and N_Range nodes that represent the predicate in canonical form. The
-- canonical form has entries sorted in ascending order, with duplicates
@ -3908,6 +3908,26 @@ package Einfo is
-- are fully analyzed and typed with the base type of the subtype. Note
-- that all entries are static and have values within the subtype range.
-- Static_Real_Or_String_Predicate (Node25)
-- Defined in real types/subtypes with static predicates (with the two
-- flags Has_Predicates and Has_Static_Predicate set). Set if the type
-- or subtype has a static predicate. Points to the return expression
-- of the predicate function. This is the original expression given as
-- the predicate except that occurrences of the type are replaced by
-- occurrences of the formal parameter of the predicate function (note
-- that the spec of this function including this formal parameter name)
-- is available from the Subprograms_For_Type field (it can be accessed
-- as Predicate_Function (typ). Also, in the case where a predicate is
-- inherited, the expression is of the form:
--
-- expression AND THEN xxxPredicate (typ2 (ent))
--
-- where typ2 is the type from which the predicate is inherited, ent is
-- the entity for the current predicate function, and xxxPredicate is the
-- inherited predicate (from typ2). Finally for a predicate that inherits
-- from another predicate but does not add a predicate of its own, the
-- expression may consist of the above xxxPredicate call on its own.
-- Status_Flag_Or_Transient_Decl (Node15)
-- Defined in variables and constants. Applies to objects that require
-- special treatment by the finalization machinery, such as extended
@ -5452,6 +5472,7 @@ package Einfo is
-- Scalar_Range (Node20)
-- Delta_Value (Ureal18)
-- Small_Value (Ureal21)
-- Static_Real_Or_String_Predicate (Node25)
-- Has_Machine_Radix_Clause (Flag83)
-- Machine_Radix_10 (Flag84)
-- Aft_Value (synth)
@ -5557,6 +5578,7 @@ package Einfo is
-- Float_Rep (Uint10) (Float_Rep_Kind)
-- Default_Aspect_Value (Node19) (base type only)
-- Scalar_Range (Node20)
-- Static_Real_Or_String_Predicate (Node25)
-- Machine_Emax_Value (synth)
-- Machine_Emin_Value (synth)
-- Machine_Mantissa_Value (synth)
@ -5777,6 +5799,7 @@ package Einfo is
-- Delta_Value (Ureal18)
-- Default_Aspect_Value (Node19) (base type only)
-- Scalar_Range (Node20)
-- Static_Real_Or_String_Predicate (Node25)
-- Small_Value (Ureal21)
-- Has_Small_Clause (Flag67)
-- Aft_Value (synth)
@ -6048,6 +6071,7 @@ package Einfo is
-- E_String_Subtype
-- First_Index (Node17)
-- Component_Type (Node20) (base type only)
-- Static_Real_Or_String_Predicate (Node25)
-- Is_Constrained (Flag12)
-- Next_Index (synth)
-- Number_Dimensions (synth)
@ -6791,6 +6815,7 @@ package Einfo is
function Static_Elaboration_Desired (Id : E) return B;
function Static_Initialization (Id : E) return N;
function Static_Discrete_Predicate (Id : E) return S;
function Static_Real_Or_String_Predicate (Id : E) return N;
function Status_Flag_Or_Transient_Decl (Id : E) return E;
function Storage_Size_Variable (Id : E) return E;
function Stored_Constraint (Id : E) return L;
@ -7425,6 +7450,7 @@ package Einfo is
procedure Set_Static_Elaboration_Desired (Id : E; V : B);
procedure Set_Static_Initialization (Id : E; V : N);
procedure Set_Static_Discrete_Predicate (Id : E; V : S);
procedure Set_Static_Real_Or_String_Predicate (Id : E; V : N);
procedure Set_Status_Flag_Or_Transient_Decl (Id : E; V : E);
procedure Set_Storage_Size_Variable (Id : E; V : E);
procedure Set_Stored_Constraint (Id : E; V : L);
@ -8209,6 +8235,7 @@ package Einfo is
pragma Inline (Static_Elaboration_Desired);
pragma Inline (Static_Initialization);
pragma Inline (Static_Discrete_Predicate);
pragma Inline (Static_Real_Or_String_Predicate);
pragma Inline (Status_Flag_Or_Transient_Decl);
pragma Inline (Storage_Size_Variable);
pragma Inline (Stored_Constraint);
@ -8642,6 +8669,7 @@ package Einfo is
pragma Inline (Set_Static_Elaboration_Desired);
pragma Inline (Set_Static_Initialization);
pragma Inline (Set_Static_Discrete_Predicate);
pragma Inline (Set_Static_Real_Or_String_Predicate);
pragma Inline (Set_Status_Flag_Or_Transient_Decl);
pragma Inline (Set_Storage_Size_Variable);
pragma Inline (Set_Stored_Constraint);

View File

@ -8002,10 +8002,16 @@ package body Sem_Ch13 is
-- yes even if we have an explicit Dynamic_Predicate present.
declare
PS : constant Boolean := Is_Predicate_Static (Expr, Object_Name);
PS : Boolean;
EN : Node_Id;
begin
if not Is_Scalar_Type (Typ) and then not Is_String_Type (Typ) then
PS := False;
else
PS := Is_Predicate_Static (Expr, Object_Name);
end if;
-- Case where we have a predicate-static aspect
if PS then
@ -8033,6 +8039,11 @@ package body Sem_Ch13 is
if No (Static_Discrete_Predicate (Typ)) then
Set_Has_Static_Predicate (Typ, False);
end if;
-- For real or string subtype, save predicate expression
elsif Is_Real_Type (Typ) or else Is_String_Type (Typ) then
Set_Static_Real_Or_String_Predicate (Typ, Expr);
end if;
-- Case of dynamic predicate (expression is not predicate-static)
@ -8060,14 +8071,13 @@ package body Sem_Ch13 is
-- Now post appropriate message
if Has_Static_Predicate_Aspect (Typ) then
if Is_Scalar_Type (Typ) then
if Is_Scalar_Type (Typ) or else Is_String_Type (Typ) then
Error_Msg_F
("expression is not predicate-static (RM 4.3.2(16-22))",
EN);
else
Error_Msg_FE
("static predicate not allowed for non-scalar type&",
EN, Typ);
Error_Msg_F
("static predicate requires scalar or string type", EN);
end if;
end if;
end if;
@ -10362,6 +10372,9 @@ package body Sem_Ch13 is
-- Is_Predicate_Static --
-------------------------
-- Note: the basic legality of the expression has already been checked, so
-- we don't need to worry about cases or ranges on strings for example.
function Is_Predicate_Static
(Expr : Node_Id;
Nam : Name_Id) return Boolean
@ -10462,12 +10475,6 @@ package body Sem_Ch13 is
-- Start of processing for Is_Predicate_Static
begin
-- Only scalar types can be predicate-static
if not Is_Scalar_Type (Etype (Expr)) then
return False;
end if;
-- Predicate_Static means one of the following holds. Numbers are the
-- corresponding paragraph numbers in (RM 3.2.4(16-22)).
@ -10502,7 +10509,20 @@ package body Sem_Ch13 is
-- operand is the current instance, and the other is a static
-- expression.
-- Note: the RM is clearly wrong here in not excluding string types.
-- Without this exclusion, we would allow expressions like X > "ABC"
-- to be considered as predicate-static, which is clearly not intended,
-- since the idea is for predicate-static to be a subset of normal
-- static expressions (and "DEF" > "ABC" is not a static expression).
-- However, we do allow internally generated (not from source) equality
-- and inequality operations to be valid on strings (this helps deal
-- with cases where we transform A in "ABC" to A = "ABC).
elsif Nkind (Expr) in N_Op_Compare
and then ((not Is_String_Type (Etype (Left_Opnd (Expr))))
or else (Nkind_In (Expr, N_Op_Eq, N_Op_Ne)
and then not Comes_From_Source (Expr)))
and then ((Is_Type_Ref (Left_Opnd (Expr))
and then Is_OK_Static_Expression (Right_Opnd (Expr)))
or else

View File

@ -227,6 +227,16 @@ package body Sem_Eval is
-- this is an illegality if N is static, and should generate a warning
-- otherwise.
function Real_Or_String_Static_Predicate_Matches
(Val : Node_Id;
Typ : Entity_Id) return Boolean;
-- This is the function used to evaluate real or string static predicates.
-- Val is an unanalyzed N_Real_Literal or N_String_Literal node, which
-- represents the value to be tested against the predicate. Typ is the
-- type with the predicate, from which the predicate expression can be
-- extracted. The result returned is True if the given value satisfies
-- the predicate.
procedure Rewrite_In_Raise_CE (N : Node_Id; Exp : Node_Id);
-- N and Exp are nodes representing an expression, Exp is known to raise
-- CE. N is rewritten in term of Exp in the optimal way.
@ -339,23 +349,36 @@ package body Sem_Eval is
-- an explicitly specified Dynamic_Predicate whose expression met the
-- rules for being predicate-static).
-- If we are not generating code, nothing more to do (why???)
-- Case of real static predicate
if Operating_Mode < Generate_Code then
return;
end if;
if Is_Real_Type (Typ) then
if Real_Or_String_Static_Predicate_Matches
(Val => Make_Real_Literal (Sloc (Expr), Expr_Value_R (Expr)),
Typ => Typ)
then
return;
end if;
-- If we have the real case, then for now, not implemented
-- Case of string static predicate
if not Is_Discrete_Type (Typ) then
Error_Msg_N ("??real predicate not applied", Expr);
return;
end if;
elsif Is_String_Type (Typ) then
if Real_Or_String_Static_Predicate_Matches
(Val => Expr_Value_S (Expr),
Typ => Typ)
then
return;
end if;
-- If static predicate matches, nothing to do
-- Case of discrete static predicate
if Choices_Match (Expr, Static_Discrete_Predicate (Typ)) = Match then
return;
else
pragma Assert (Is_Discrete_Type (Typ));
-- If static predicate matches, nothing to do
if Choices_Match (Expr, Static_Discrete_Predicate (Typ)) = Match then
return;
end if;
end if;
-- Here we know that the predicate will fail
@ -3052,6 +3075,10 @@ package body Sem_Eval is
-- both operands are static (RM 4.9(7), 4.9(20)), except that for strings,
-- the result is never static, even if the operands are.
-- However, for internally generated nodes, we allow string equality and
-- inequality to be static. This is because we rewrite A in "ABC" as an
-- equality test A = "ABC", and the former is definitely static.
procedure Eval_Relational_Op (N : Node_Id) is
Left : constant Node_Id := Left_Opnd (N);
Right : constant Node_Id := Right_Opnd (N);
@ -3289,9 +3316,16 @@ package body Sem_Eval is
-- Only comparisons of scalars can give static results. In
-- particular, comparisons of strings never yield a static
-- result, even if both operands are static strings.
-- result, even if both operands are static strings, except that
-- as noted above, we allow equality/inequality for strings.
if not Is_Scalar_Type (Typ) then
if Is_String_Type (Typ)
and then not Comes_From_Source (N)
and then Nkind_In (N, N_Op_Eq, N_Op_Ne)
then
null;
elsif not Is_Scalar_Type (Typ) then
Is_Static_Expression := False;
Set_Is_Static_Expression (N, False);
end if;
@ -3307,9 +3341,8 @@ package body Sem_Eval is
Otype := Find_Universal_Operator_Type (N);
end if;
-- For static real type expressions, we cannot use
-- Compile_Time_Compare since it worries about run-time
-- results which are not exact.
-- For static real type expressions, do not use Compile_Time_Compare
-- since it worries about run-time results which are not exact.
if Is_Static_Expression and then Is_Real_Type (Typ) then
declare
@ -5322,6 +5355,112 @@ package body Sem_Eval is
end if;
end Predicates_Match;
---------------------------------------------
-- Real_Or_String_Static_Predicate_Matches --
---------------------------------------------
function Real_Or_String_Static_Predicate_Matches
(Val : Node_Id;
Typ : Entity_Id) return Boolean
is
Expr : constant Node_Id := Static_Real_Or_String_Predicate (Typ);
-- The predicate expression from the type
Pfun : constant Entity_Id := Predicate_Function (Typ);
-- The entity for the predicate function
Ent_Name : constant Name_Id := Chars (First_Formal (Pfun));
-- The name of the formal of the predicate function. Occurrences of the
-- type name in Expr have been rewritten as references to this formal,
-- and it has a unique name, so we can identify references by this name.
Copy : Node_Id;
-- Copy of the predicate function tree
function Process (N : Node_Id) return Traverse_Result;
-- Function used to process nodes during the traversal in which we will
-- find occurrences of the entity name, and replace such occurrences
-- by a real literal with the value to be tested.
procedure Traverse is new Traverse_Proc (Process);
-- The actual traversal procedure
-------------
-- Process --
-------------
function Process (N : Node_Id) return Traverse_Result is
begin
if Nkind (N) = N_Identifier and then Chars (N) = Ent_Name then
declare
Nod : constant Node_Id := New_Copy (Val);
begin
Set_Sloc (Nod, Sloc (N));
Rewrite (N, Nod);
return Skip;
end;
else
return OK;
end if;
end Process;
-- Start of processing for Real_Or_String_Static_Predicate_Matches
begin
-- First deal with special case of inherited predicate, where the
-- predicate expression looks like:
-- Expr and then xxPredicate (typ (Ent))
-- where Expr is the predicate expression for this level, and the
-- right operand is the call to evaluate the inherited predicate.
if Nkind (Expr) = N_And_Then
and then Nkind (Right_Opnd (Expr)) = N_Function_Call
then
-- OK we have the inherited case, so make a call to evaluate the
-- inherited predicate. If that fails, so do we!
if not
Real_Or_String_Static_Predicate_Matches
(Val => Val,
Typ => Etype (First_Formal (Entity (Name (Right_Opnd (Expr))))))
then
return False;
end if;
-- Use the left operand for the continued processing
Copy := Copy_Separate_Tree (Left_Opnd (Expr));
-- Case where call to predicate function appears on its own
elsif Nkind (Expr) = N_Function_Call then
-- Here the result is just the result of calling the inner predicate
return
Real_Or_String_Static_Predicate_Matches
(Val => Val,
Typ => Etype (First_Formal (Entity (Name (Expr)))));
-- If no inherited predicate, copy whole expression
else
Copy := Copy_Separate_Tree (Expr);
end if;
-- Now we replace occurrences of the entity by the value
Traverse (Copy);
-- And analyze the resulting static expression to see if it is True
Analyze_And_Resolve (Copy, Standard_Boolean);
return Is_True (Expr_Value (Copy));
end Real_Or_String_Static_Predicate_Matches;
-------------------------
-- Rewrite_In_Raise_CE --
-------------------------