aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/sem_eval.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/sem_eval.adb')
-rw-r--r--gcc/ada/sem_eval.adb324
1 files changed, 206 insertions, 118 deletions
diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb
index 8553ce628..f7e774308 100644
--- a/gcc/ada/sem_eval.adb
+++ b/gcc/ada/sem_eval.adb
@@ -37,6 +37,7 @@ with Namet; use Namet;
with Nmake; use Nmake;
with Nlists; use Nlists;
with Opt; use Opt;
+with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Cat; use Sem_Cat;
@@ -198,7 +199,7 @@ package body Sem_Eval is
-- Tests to see if expression N whose single operand is Op1 is foldable,
-- i.e. the operand value is known at compile time. If the operation is
-- foldable, then Fold is True on return, and Stat indicates whether
- -- the result is static (i.e. both operands were static). Note that it
+ -- the result is static (i.e. the operand was static). Note that it
-- is quite possible for Fold to be True, and Stat to be False, since
-- there are cases in which we know the value of an operand even though
-- it is not technically static (e.g. the static lower bound of a range
@@ -232,7 +233,7 @@ package body Sem_Eval is
Stat : out Boolean;
Fold : out Boolean);
-- Same processing, except applies to an expression N with two operands
- -- Op1 and Op2.
+ -- Op1 and Op2. The result is static only if both operands are static.
function Test_In_Range
(N : Node_Id;
@@ -240,11 +241,11 @@ package body Sem_Eval is
Assume_Valid : Boolean;
Fixed_Int : Boolean;
Int_Real : Boolean) return Range_Membership;
- -- Common processing for Is_In_Range and Is_Out_Of_Range:
- -- Returns In_Range or Out_Of_Range if it can be guaranteed at compile time
- -- that expression N is known to be in or out of range of the subtype Typ.
- -- If not compile time known, Unknown is returned.
- -- See documentation of Is_In_Range for complete description of parameters.
+ -- Common processing for Is_In_Range and Is_Out_Of_Range: Returns In_Range
+ -- or Out_Of_Range if it can be guaranteed at compile time that expression
+ -- N is known to be in or out of range of the subtype Typ. If not compile
+ -- time known, Unknown is returned. See documentation of Is_In_Range for
+ -- complete description of parameters.
procedure To_Bits (U : Uint; B : out Bits);
-- Converts a Uint value to a bit string of length B'Length
@@ -743,6 +744,16 @@ package body Sem_Eval is
begin
Diff.all := No_Uint;
+ -- In preanalysis mode, always return Unknown, it is too early to be
+ -- thinking we know the result of a comparison, save that judgment for
+ -- the full analysis. This is particularly important in the case of
+ -- pre and postconditions, which otherwise can be prematurely collapsed
+ -- into having True or False conditions when this is inappropriate.
+
+ if not Full_Analysis then
+ return Unknown;
+ end if;
+
-- If either operand could raise constraint error, then we cannot
-- know the result at compile time (since CE may be raised!)
@@ -932,28 +943,80 @@ package body Sem_Eval is
end if;
end if;
- -- Try range analysis on variables and see if ranges are disjoint
+ -- First attempt is to decompose the expressions to extract a
+ -- constant offset resulting from the use of any of the forms:
+
+ -- expr + literal
+ -- expr - literal
+ -- typ'Succ (expr)
+ -- typ'Pred (expr)
+
+ -- Then we see if the two expressions are the same value, and if so
+ -- the result is obtained by comparing the offsets.
+
+ -- Note: the reason we do this test first is that it returns only
+ -- decisive results (with diff set), where other tests, like the
+ -- range test, may not be as so decisive. Consider for example
+ -- J .. J + 1. This code can conclude LT with a difference of 1,
+ -- even if the range of J is not known.
+
+ declare
+ Lnode : Node_Id;
+ Loffs : Uint;
+ Rnode : Node_Id;
+ Roffs : Uint;
+
+ begin
+ Compare_Decompose (L, Lnode, Loffs);
+ Compare_Decompose (R, Rnode, Roffs);
+
+ if Is_Same_Value (Lnode, Rnode) then
+ if Loffs = Roffs then
+ return EQ;
+
+ elsif Loffs < Roffs then
+ Diff.all := Roffs - Loffs;
+ return LT;
+
+ else
+ Diff.all := Loffs - Roffs;
+ return GT;
+ end if;
+ end if;
+ end;
+
+ -- Next, try range analysis and see if operand ranges are disjoint
declare
LOK, ROK : Boolean;
LLo, LHi : Uint;
RLo, RHi : Uint;
+ Single : Boolean;
+ -- True if each range is a single point
+
begin
Determine_Range (L, LOK, LLo, LHi, Assume_Valid);
Determine_Range (R, ROK, RLo, RHi, Assume_Valid);
if LOK and ROK then
+ Single := (LLo = LHi) and then (RLo = RHi);
+
if LHi < RLo then
+ if Single and Assume_Valid then
+ Diff.all := RLo - LLo;
+ end if;
+
return LT;
elsif RHi < LLo then
+ if Single and Assume_Valid then
+ Diff.all := LLo - RLo;
+ end if;
+
return GT;
- elsif LLo = LHi
- and then RLo = RHi
- and then LLo = RLo
- then
+ elsif Single and then LLo = RLo then
-- If the range includes a single literal and we can assume
-- validity then the result is known even if an operand is
@@ -1054,42 +1117,6 @@ package body Sem_Eval is
end if;
end if;
- -- Next attempt is to decompose the expressions to extract
- -- a constant offset resulting from the use of any of the forms:
-
- -- expr + literal
- -- expr - literal
- -- typ'Succ (expr)
- -- typ'Pred (expr)
-
- -- Then we see if the two expressions are the same value, and if so
- -- the result is obtained by comparing the offsets.
-
- declare
- Lnode : Node_Id;
- Loffs : Uint;
- Rnode : Node_Id;
- Roffs : Uint;
-
- begin
- Compare_Decompose (L, Lnode, Loffs);
- Compare_Decompose (R, Rnode, Roffs);
-
- if Is_Same_Value (Lnode, Rnode) then
- if Loffs = Roffs then
- return EQ;
-
- elsif Loffs < Roffs then
- Diff.all := Roffs - Loffs;
- return LT;
-
- else
- Diff.all := Loffs - Roffs;
- return GT;
- end if;
- end if;
- end;
-
-- Next attempt is to see if we have an entity compared with a
-- compile time known value, where there is a current value
-- conditional for the entity which can tell us the result.
@@ -1862,15 +1889,74 @@ package body Sem_Eval is
end;
end Eval_Concatenation;
- ---------------------------------
- -- Eval_Conditional_Expression --
- ---------------------------------
+ ----------------------
+ -- Eval_Entity_Name --
+ ----------------------
- -- We can fold to a static expression if the condition and both constituent
+ -- This procedure is used for identifiers and expanded names other than
+ -- named numbers (see Eval_Named_Integer, Eval_Named_Real. These are
+ -- static if they denote a static constant (RM 4.9(6)) or if the name
+ -- denotes an enumeration literal (RM 4.9(22)).
+
+ procedure Eval_Entity_Name (N : Node_Id) is
+ Def_Id : constant Entity_Id := Entity (N);
+ Val : Node_Id;
+
+ begin
+ -- Enumeration literals are always considered to be constants
+ -- and cannot raise constraint error (RM 4.9(22)).
+
+ if Ekind (Def_Id) = E_Enumeration_Literal then
+ Set_Is_Static_Expression (N);
+ return;
+
+ -- A name is static if it denotes a static constant (RM 4.9(5)), and
+ -- we also copy Raise_Constraint_Error. Notice that even if non-static,
+ -- it does not violate 10.2.1(8) here, since this is not a variable.
+
+ elsif Ekind (Def_Id) = E_Constant then
+
+ -- Deferred constants must always be treated as nonstatic
+ -- outside the scope of their full view.
+
+ if Present (Full_View (Def_Id))
+ and then not In_Open_Scopes (Scope (Def_Id))
+ then
+ Val := Empty;
+ else
+ Val := Constant_Value (Def_Id);
+ end if;
+
+ if Present (Val) then
+ Set_Is_Static_Expression
+ (N, Is_Static_Expression (Val)
+ and then Is_Static_Subtype (Etype (Def_Id)));
+ Set_Raises_Constraint_Error (N, Raises_Constraint_Error (Val));
+
+ if not Is_Static_Expression (N)
+ and then not Is_Generic_Type (Etype (N))
+ then
+ Validate_Static_Object_Name (N);
+ end if;
+
+ return;
+ end if;
+ end if;
+
+ -- Fall through if the name is not static
+
+ Validate_Static_Object_Name (N);
+ end Eval_Entity_Name;
+
+ ------------------------
+ -- Eval_If_Expression --
+ ------------------------
+
+ -- We can fold to a static expression if the condition and both dependent
-- expressions are static. Otherwise, the only required processing is to do
-- the check for non-static context for the then and else expressions.
- procedure Eval_Conditional_Expression (N : Node_Id) is
+ procedure Eval_If_Expression (N : Node_Id) is
Condition : constant Node_Id := First (Expressions (N));
Then_Expr : constant Node_Id := Next (Condition);
Else_Expr : constant Node_Id := Next (Then_Expr);
@@ -1939,66 +2025,7 @@ package body Sem_Eval is
end if;
Set_Is_Static_Expression (N, Rstat);
- end Eval_Conditional_Expression;
-
- ----------------------
- -- Eval_Entity_Name --
- ----------------------
-
- -- This procedure is used for identifiers and expanded names other than
- -- named numbers (see Eval_Named_Integer, Eval_Named_Real. These are
- -- static if they denote a static constant (RM 4.9(6)) or if the name
- -- denotes an enumeration literal (RM 4.9(22)).
-
- procedure Eval_Entity_Name (N : Node_Id) is
- Def_Id : constant Entity_Id := Entity (N);
- Val : Node_Id;
-
- begin
- -- Enumeration literals are always considered to be constants
- -- and cannot raise constraint error (RM 4.9(22)).
-
- if Ekind (Def_Id) = E_Enumeration_Literal then
- Set_Is_Static_Expression (N);
- return;
-
- -- A name is static if it denotes a static constant (RM 4.9(5)), and
- -- we also copy Raise_Constraint_Error. Notice that even if non-static,
- -- it does not violate 10.2.1(8) here, since this is not a variable.
-
- elsif Ekind (Def_Id) = E_Constant then
-
- -- Deferred constants must always be treated as nonstatic
- -- outside the scope of their full view.
-
- if Present (Full_View (Def_Id))
- and then not In_Open_Scopes (Scope (Def_Id))
- then
- Val := Empty;
- else
- Val := Constant_Value (Def_Id);
- end if;
-
- if Present (Val) then
- Set_Is_Static_Expression
- (N, Is_Static_Expression (Val)
- and then Is_Static_Subtype (Etype (Def_Id)));
- Set_Raises_Constraint_Error (N, Raises_Constraint_Error (Val));
-
- if not Is_Static_Expression (N)
- and then not Is_Generic_Type (Etype (N))
- then
- Validate_Static_Object_Name (N);
- end if;
-
- return;
- end if;
- end if;
-
- -- Fall through if the name is not static
-
- Validate_Static_Object_Name (N);
- end Eval_Entity_Name;
+ end Eval_If_Expression;
----------------------------
-- Eval_Indexed_Component --
@@ -3239,6 +3266,38 @@ package body Sem_Eval is
end if;
end Eval_Slice;
+ ---------------------------------
+ -- Eval_Static_Predicate_Check --
+ ---------------------------------
+
+ function Eval_Static_Predicate_Check
+ (N : Node_Id;
+ Typ : Entity_Id) return Boolean
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+ Pred : constant List_Id := Static_Predicate (Typ);
+ Test : Node_Id;
+
+ begin
+ if No (Pred) then
+ return True;
+ end if;
+
+ -- The static predicate is a list of alternatives in the proper format
+ -- for an Ada 2012 membership test. If the argument is a literal, the
+ -- membership test can be evaluated statically. The caller transforms
+ -- a result of False into a static contraint error.
+
+ Test := Make_In (Loc,
+ Left_Opnd => New_Copy_Tree (N),
+ Right_Opnd => Empty,
+ Alternatives => Pred);
+ Analyze_And_Resolve (Test, Standard_Boolean);
+
+ return Nkind (Test) = N_Identifier
+ and then Entity (Test) = Standard_True;
+ end Eval_Static_Predicate_Check;
+
-------------------------
-- Eval_String_Literal --
-------------------------
@@ -3987,12 +4046,18 @@ package body Sem_Eval is
-- We now have the literal with the right value, both the actual type
-- and the expected type of this literal are taken from the expression
- -- that was evaluated.
+ -- that was evaluated. So now we do the Analyze and Resolve.
+
+ -- Note that we have to reset Is_Static_Expression both after the
+ -- analyze step (because Resolve will evaluate the literal, which
+ -- will cause semantic errors if it is marked as static), and after
+ -- the Resolve step (since Resolve in some cases sets this flag).
Analyze (N);
Set_Is_Static_Expression (N, Static);
Set_Etype (N, Typ);
Resolve (N);
+ Set_Is_Static_Expression (N, Static);
end Fold_Str;
---------------
@@ -4041,12 +4106,18 @@ package body Sem_Eval is
-- We now have the literal with the right value, both the actual type
-- and the expected type of this literal are taken from the expression
- -- that was evaluated.
+ -- that was evaluated. So now we do the Analyze and Resolve.
+
+ -- Note that we have to reset Is_Static_Expression both after the
+ -- analyze step (because Resolve will evaluate the literal, which
+ -- will cause semantic errors if it is marked as static), and after
+ -- the Resolve step (since Resolve in some cases sets this flag).
Analyze (N);
Set_Is_Static_Expression (N, Static);
Set_Etype (N, Typ);
Resolve (N);
+ Set_Is_Static_Expression (N, Static);
end Fold_Uint;
----------------
@@ -4076,12 +4147,20 @@ package body Sem_Eval is
Set_Original_Entity (N, Ent);
- -- Both the actual and expected type comes from the original expression
+ -- We now have the literal with the right value, both the actual type
+ -- and the expected type of this literal are taken from the expression
+ -- that was evaluated. So now we do the Analyze and Resolve.
+
+ -- Note that we have to reset Is_Static_Expression both after the
+ -- analyze step (because Resolve will evaluate the literal, which
+ -- will cause semantic errors if it is marked as static), and after
+ -- the Resolve step (since Resolve in some cases sets this flag).
Analyze (N);
Set_Is_Static_Expression (N, Static);
Set_Etype (N, Typ);
Resolve (N);
+ Set_Is_Static_Expression (N, Static);
end Fold_Ureal;
---------------
@@ -5361,10 +5440,12 @@ package body Sem_Eval is
return;
end if;
- -- Type must be scalar or string type
+ -- Type must be scalar or string type (but allow Bignum, since this
+ -- is really a scalar type from our point of view in this diagnosis).
if not Is_Scalar_Type (Typ)
and then not Is_String_Type (Typ)
+ and then not Is_RTE (Typ, RE_Bignum)
then
Error_Msg_N
("static expression must have scalar or string type " &
@@ -5481,7 +5562,14 @@ package body Sem_Eval is
when N_Function_Call =>
Why_Not_Static_List (Parameter_Associations (N));
- Error_Msg_N ("non-static function call (RM 4.9(6,18))!", N);
+
+ -- Complain about non-static function call unless we have Bignum
+ -- which means that the underlying expression is really some
+ -- scalar arithmetic operation.
+
+ if not Is_RTE (Typ, RE_Bignum) then
+ Error_Msg_N ("non-static function call (RM 4.9(6,18))!", N);
+ end if;
when N_Parameter_Association =>
Why_Not_Static (Explicit_Actual_Parameter (N));