aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/sem_eval.adb
diff options
context:
space:
mode:
authorRobert Dewar <dewar@adacore.com>2014-07-29 12:56:31 +0000
committerArnaud Charlet <charlet@gcc.gnu.org>2014-07-29 14:56:31 +0200
commitedab608853d34224b204dc42d751a3f90daabe39 (patch)
tree6cc8f3aef60cefb58f69e4a2c8d62232b4c13f10 /gcc/ada/sem_eval.adb
parentc5c780e6deb9cf337f4898db5716659698311d7d (diff)
downloadgcc-edab608853d34224b204dc42d751a3f90daabe39.zip
gcc-edab608853d34224b204dc42d751a3f90daabe39.tar.gz
gcc-edab608853d34224b204dc42d751a3f90daabe39.tar.bz2
sem_aggr.adb (Resolve_Array_Aggregate): Change Is_Static_Range to Is_OK_Static_Range.
2014-07-29 Robert Dewar <dewar@adacore.com> * sem_aggr.adb (Resolve_Array_Aggregate): Change Is_Static_Range to Is_OK_Static_Range. * sem_attr.adb (Eval_Attribute): Make sure we properly flag static attributes (Eval_Attribute, case Size): Handle size of zero properly (Eval_Attribute, case Value_Size): Handle size of zero properly. * sem_ch13.adb: Minor reformatting. * sem_ch3.adb (Process_Range_Expr_In_Decl): Change Is_Static_Range to Is_OK_Static_Range. * sem_eval.adb (Eval_Case_Expression): Total rewrite, was wrong in several ways (Is_Static_Range): Moved here from spec (Is_Static_Subtype): Moved here from spec Change some incorrect Is_Static_Subtype calls to Is_OK_Static_Subtype. * sem_eval.ads: Add comments to section on Is_Static_Expression/Raises_Constraint_Error (Is_OK_Static_Range): Add clarifying comments (Is_Static_Range): Moved to body (Is_Statically_Unevaluated): New function. * sem_util.ads, sem_util.adb (Is_Preelaborable_Expression): Change Is_Static_Range to Is_OK_Static_Range. * sinfo.ads: Additional commments for Is_Static_Expression noting that clients should almost always use Is_OK_Static_Expression instead. Many other changes throughout front end units to obey this rule. * tbuild.ads, tbuild.adb (New_Occurrence_Of): Set Is_Static_Expression for enumeration literal. * exp_ch5.adb, sem_intr.adb, sem_ch5.adb, exp_attr.adb, exp_ch9.adb, lib-writ.adb, sem_ch9.adb, einfo.ads, checks.adb, checks.ads, sem_prag.adb, sem_ch12.adb, freeze.adb, sem_res.adb, exp_ch4.adb, exp_ch6.adb, sem_ch4.adb, sem_ch6.adb, exp_aggr.adb, sem_cat.adb: Replace all occurrences of Is_Static_Expression by Is_OK_Static_Expression. From-SVN: r213159
Diffstat (limited to 'gcc/ada/sem_eval.adb')
-rw-r--r--gcc/ada/sem_eval.adb1149
1 files changed, 929 insertions, 220 deletions
diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb
index 67e43e1..27e1d20 100644
--- a/gcc/ada/sem_eval.adb
+++ b/gcc/ada/sem_eval.adb
@@ -123,6 +123,11 @@ package body Sem_Eval is
V : Uint;
end record;
+ type Match_Result is (Match, No_Match, Non_Static);
+ -- Result returned from functions that test for a matching result. If the
+ -- operands are not OK_Static then Non_Static will be returned. Otherwise
+ -- Match/No_Match is returned depending on whether the match succeeds.
+
type CV_Cache_Array is array (CV_Range) of CV_Entry;
CV_Cache : CV_Cache_Array := (others => (Node_High_Bound, Uint_0));
@@ -137,6 +142,37 @@ package body Sem_Eval is
-- Local Subprograms --
-----------------------
+ function Choice_Matches
+ (Expr : Node_Id;
+ Choice : Node_Id) return Match_Result;
+ -- Determines whether given value Expr matches the given Choice. The Expr
+ -- can be of discrete, real, or string type and must be a compile time
+ -- known value (it is an error to make the call if these conditions are
+ -- not met). The choice can be a range, subtype name, subtype indication,
+ -- or expression. The returned result is Non_Static if Choice is not
+ -- OK_Static, otherwise either Match or No_Match is returned depending
+ -- on whether Choice matches Expr. This is used for case expression
+ -- alternatives, and also for membership tests. In each case, more
+ -- possibilities are tested than the syntax allows (e.g. membership allows
+ -- subtype indications and non-discrete types, and case allows an OTHERS
+ -- choice), but it does not matter, since we have already done a full
+ -- semantic and syntax check of the construct, so the extra possibilities
+ -- just will not arise for correct expressions.
+ --
+ -- Note: if Choice_Matches finds that a choice raises Constraint_Error, e.g
+ -- a reference to a type, one of whose bounds raises Constraint_Error, then
+ -- it also sets the Raises_Constraint_Error flag on the Choice itself.
+
+ function Choices_Match
+ (Expr : Node_Id;
+ Choices : List_Id) return Match_Result;
+ -- This function applies Choice_Matches to each element of Choices. If the
+ -- result is No_Match, then it continues and checks the next element. If
+ -- the result is Match or Non_Static, this result is immediately given
+ -- as the result without checking the rest of the list. Expr can be of
+ -- discrete, real, or string type and must be a compile time known value
+ -- (it is an error to make the call if these conditions are not met).
+
function From_Bits (B : Bits; T : Entity_Id) return Uint;
-- Converts a bit string of length B'Length to a Uint value to be used for
-- a target of type T, which is a modular type. This procedure includes the
@@ -144,6 +180,32 @@ package body Sem_Eval is
-- (for a binary modulus, the bit string is the right length any way so all
-- is well).
+ function Is_Static_Choice (Choice : Node_Id) return Boolean;
+ -- Given a choice (from a case expression or membership test), returns
+ -- True if the choice is static. No test is made for raising of constraint
+ -- error, so this function is used only for legality tests.
+
+ function Is_Static_Choice_List (Choices : List_Id) return Boolean;
+ -- Given a choice list (from a case expression or membership test), return
+ -- True if all choices are static in the sense of Is_Static_Choice.
+
+ function Is_OK_Static_Choice (Choice : Node_Id) return Boolean;
+ -- Given a choice (from a case expression or membership test), returns
+ -- True if the choice is static and does not raise a Constraint_Error.
+
+ function Is_OK_Static_Choice_List (Choices : List_Id) return Boolean;
+ -- Given a choice list (from a case expression or membership test), return
+ -- True if all choices are static in the sense of Is_OK_Static_Choice.
+
+ function Is_Static_Range (N : Node_Id) return Boolean;
+ -- Determine if range is static, as defined in RM 4.9(26). The only allowed
+ -- argument is an N_Range node (but note that the semantic analysis of
+ -- equivalent range attribute references already turned them into the
+ -- equivalent range). This differs from Is_OK_Static_Range (which is what
+ -- must be used by clients) in that it does not care whether the bounds
+ -- raise Constraint_Error or not. Used for checking whether expressions are
+ -- static in the 4.9 sense (without worrying about exceptions).
+
function Get_String_Val (N : Node_Id) return Node_Id;
-- Given a tree node for a folded string or character value, returns the
-- corresponding string literal or character literal (one of the two must
@@ -254,6 +316,73 @@ package body Sem_Eval is
procedure To_Bits (U : Uint; B : out Bits);
-- Converts a Uint value to a bit string of length B'Length
+ -----------------------------------------------
+ -- Check_Expression_Against_Static_Predicate --
+ -----------------------------------------------
+
+ procedure Check_Expression_Against_Static_Predicate
+ (Expr : Node_Id;
+ Typ : Entity_Id)
+ is
+ begin
+ -- Nothing to do if expression is not known at compile time, or the
+ -- type has no static predicate set (will be the case for all non-scalar
+ -- types, so no need to make a special test for that).
+
+ if not (Has_Static_Predicate (Typ)
+ and then Compile_Time_Known_Value (Expr))
+ then
+ return;
+ end if;
+
+ -- Here we have a static predicate (note that it could have arisen from
+ -- 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???)
+
+ if Operating_Mode < Generate_Code then
+ return;
+ end if;
+
+ -- If we have the real case, then for now, not implemented
+
+ if not Is_Discrete_Type (Typ) then
+ Error_Msg_N ("??real predicate not applied", Expr);
+ return;
+ end if;
+
+ -- If static predicate matches, nothing to do
+
+ if Choices_Match (Expr, Static_Predicate (Typ)) = Match then
+ return;
+ end if;
+
+ -- Here we know that the predicate will fail
+
+ -- Special case of static expression failing a predicate (other than one
+ -- that was explicitly specified with a Dynamic_Predicate aspect). This
+ -- is the case where the expression is no longer considered static.
+
+ if Is_Static_Expression (Expr)
+ and then not Has_Dynamic_Predicate_Aspect (Typ)
+ then
+ Error_Msg_NE
+ ("??static expression fails static predicate check on &",
+ Expr, Typ);
+ Error_Msg_N
+ ("\??expression is no longer considered static", Expr);
+ Set_Is_Static_Expression (Expr, False);
+
+ -- In all other cases, this is just a warning that a test will fail.
+ -- It does not matter if the expression is static or not, or if the
+ -- predicate comes from a dynamic predicate aspect or not.
+
+ else
+ Error_Msg_NE
+ ("??expression fails predicate check on &", Expr, Typ);
+ end if;
+ end Check_Expression_Against_Static_Predicate;
------------------------------
-- Check_Non_Static_Context --
------------------------------
@@ -421,6 +550,167 @@ package body Sem_Eval is
end if;
end Check_String_Literal_Length;
+ --------------------
+ -- Choice_Matches --
+ --------------------
+
+ function Choice_Matches
+ (Expr : Node_Id;
+ Choice : Node_Id) return Match_Result
+ is
+ Etyp : constant Entity_Id := Etype (Expr);
+ Val : Uint;
+ ValR : Ureal;
+ ValS : Node_Id;
+
+ begin
+ pragma Assert (Compile_Time_Known_Value (Expr));
+ pragma Assert (Is_Scalar_Type (Etyp) or else Is_String_Type (Etyp));
+
+ if not Is_OK_Static_Choice (Choice) then
+ Set_Raises_Constraint_Error (Choice);
+ return Non_Static;
+
+ -- Discrete type case
+
+ elsif Is_Discrete_Type (Etype (Expr)) then
+ Val := Expr_Value (Expr);
+
+ if Nkind (Choice) = N_Range then
+ if Val >= Expr_Value (Low_Bound (Choice))
+ and then
+ Val <= Expr_Value (High_Bound (Choice))
+ then
+ return Match;
+ else
+ return No_Match;
+ end if;
+
+ elsif Nkind (Choice) = N_Subtype_Indication
+ or else
+ (Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)))
+ then
+ if Val >= Expr_Value (Type_Low_Bound (Etype (Choice)))
+ and then
+ Val <= Expr_Value (Type_High_Bound (Etype (Choice)))
+ then
+ return Match;
+ else
+ return No_Match;
+ end if;
+
+ elsif Nkind (Choice) = N_Others_Choice then
+ return Match;
+
+ else
+ if Val = Expr_Value (Choice) then
+ return Match;
+ else
+ return No_Match;
+ end if;
+ end if;
+
+ -- Real type case
+
+ elsif Is_Real_Type (Etype (Expr)) then
+ ValR := Expr_Value_R (Expr);
+
+ if Nkind (Choice) = N_Range then
+ if ValR >= Expr_Value_R (Low_Bound (Choice))
+ and then
+ ValR <= Expr_Value_R (High_Bound (Choice))
+ then
+ return Match;
+ else
+ return No_Match;
+ end if;
+
+ elsif Nkind (Choice) = N_Subtype_Indication
+ or else
+ (Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)))
+ then
+ if ValR >= Expr_Value_R (Type_Low_Bound (Etype (Choice)))
+ and then
+ ValR <= Expr_Value_R (Type_High_Bound (Etype (Choice)))
+ then
+ return Match;
+ else
+ return No_Match;
+ end if;
+
+ else
+ if ValR = Expr_Value_R (Choice) then
+ return Match;
+ else
+ return No_Match;
+ end if;
+ end if;
+
+ -- String type cases
+
+ else
+ pragma Assert (Is_String_Type (Etype (Expr)));
+ ValS := Expr_Value_S (Expr);
+
+ if Nkind (Choice) = N_Subtype_Indication
+ or else
+ (Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)))
+ then
+ if not Is_Constrained (Etype (Choice)) then
+ return Match;
+
+ else
+ declare
+ Typlen : constant Uint :=
+ String_Type_Len (Etype (Choice));
+ Strlen : constant Uint :=
+ UI_From_Int (String_Length (Strval (ValS)));
+ begin
+ if Typlen = Strlen then
+ return Match;
+ else
+ return No_Match;
+ end if;
+ end;
+ end if;
+
+ else
+ if String_Equal (Strval (ValS), Strval (Expr_Value_S (Choice)))
+ then
+ return Match;
+ else
+ return No_Match;
+ end if;
+ end if;
+ end if;
+ end Choice_Matches;
+
+ -------------------
+ -- Choices_Match --
+ -------------------
+
+ function Choices_Match
+ (Expr : Node_Id;
+ Choices : List_Id) return Match_Result
+ is
+ Choice : Node_Id;
+ Result : Match_Result;
+
+ begin
+ Choice := First (Choices);
+ while Present (Choice) loop
+ Result := Choice_Matches (Expr, Choice);
+
+ if Result /= No_Match then
+ return Result;
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ return No_Match;
+ end Choices_Match;
+
--------------------------
-- Compile_Time_Compare --
--------------------------
@@ -747,9 +1037,9 @@ package body Sem_Eval is
-- conditions when this is inappropriate.
if not (Full_Analysis
- or else (Is_Static_Expression (L)
+ or else (Is_OK_Static_Expression (L)
and then
- Is_Static_Expression (R)))
+ Is_OK_Static_Expression (R)))
then
return Unknown;
end if;
@@ -1565,8 +1855,11 @@ package body Sem_Eval is
Apply_Compile_Time_Constraint_Error
(N, "division by zero", CE_Divide_By_Zero,
Warn => not Stat);
+ Set_Raises_Constraint_Error (N);
return;
+ -- Otherwise we can do the division
+
else
Result := Left_Int / Right_Int;
end if;
@@ -1744,60 +2037,101 @@ package body Sem_Eval is
--------------------------
-- A conditional expression is static if all its conditions and dependent
- -- expressions are static.
+ -- expressions are static. Note that we do not care if the dependent
+ -- expressions raise CE, except for the one that will be selected.
procedure Eval_Case_Expression (N : Node_Id) is
- Alt : Node_Id;
- Choice : Node_Id;
- Is_Static : Boolean;
- Result : Node_Id;
- Val : Uint;
+ Alt : Node_Id;
+ Choice : Node_Id;
begin
- Result := Empty;
- Is_Static := True;
+ Set_Is_Static_Expression (N, False);
- if Is_Static_Expression (Expression (N)) then
- Val := Expr_Value (Expression (N));
- else
+ if not Is_Static_Expression (Expression (N)) then
Check_Non_Static_Context (Expression (N));
- Is_Static := False;
+ return;
end if;
+ -- First loop, make sure all the alternatives are static expressions
+ -- none of which raise Constraint_Error. We make the constraint error
+ -- check because part of the legality condition for a correct static
+ -- case expression is that the cases are covered, like any other case
+ -- expression. And we can't do that if any of the conditions raise an
+ -- exception, so we don't even try to evaluate if that is the case.
+
Alt := First (Alternatives (N));
+ while Present (Alt) loop
- Search : while Present (Alt) loop
- if not Is_Static
- or else not Is_Static_Expression (Expression (Alt))
- then
- Check_Non_Static_Context (Expression (Alt));
- Is_Static := False;
+ -- The expression must be static, but we don't care at this stage
+ -- if it raises Constraint_Error (the alternative might not match,
+ -- in which case the expression is statically unevaluated anyway).
- else
- Choice := First (Discrete_Choices (Alt));
- while Present (Choice) loop
- if Nkind (Choice) = N_Others_Choice then
- Result := Expression (Alt);
- exit Search;
+ if not Is_Static_Expression (Expression (Alt)) then
+ Check_Non_Static_Context (Expression (Alt));
+ return;
+ end if;
- elsif Expr_Value (Choice) = Val then
- Result := Expression (Alt);
- exit Search;
+ -- The choices of a case always have to be static, and cannot raise
+ -- an exception. If this condition is not met, then the expression
+ -- is plain illegal, so just abandon evaluation attempts. No need
+ -- to check non-static context when we have something illegal anyway.
- else
- Next (Choice);
- end if;
- end loop;
+ if not Is_OK_Static_Choice_List (Discrete_Choices (Alt)) then
+ return;
end if;
Next (Alt);
- end loop Search;
+ end loop;
- if Is_Static then
- Rewrite (N, Relocate_Node (Result));
+ -- OK, if the above loop gets through it means that all choices are OK
+ -- static (don't raise exceptions), so the whole case is static, and we
+ -- can find the matching alternative.
+
+ Set_Is_Static_Expression (N);
+
+ -- Now to deal with propagating a possible constraint error
+
+ -- If the selecting expression raises CE, propagate and we are done
+
+ if Raises_Constraint_Error (Expression (N)) then
+ Set_Raises_Constraint_Error (N);
+
+ -- Otherwise we need to check the alternatives to find the matching
+ -- one. CE's in other than the matching one are not relevant. But we
+ -- do need to check the matching one. Unlike the first loop, we do not
+ -- have to go all the way through, when we find the matching one, quit.
else
- Set_Is_Static_Expression (N, False);
+ Alt := First (Alternatives (N));
+ Search : loop
+
+ -- We must find a match among the alternatives, If not this must
+ -- be due to other errors, so just ignore, leaving as non-static.
+
+ if No (Alt) then
+ Set_Is_Static_Expression (N, False);
+ return;
+ end if;
+
+ -- Otherwise loop through choices of this alternative
+
+ Choice := First (Discrete_Choices (Alt));
+ while Present (Choice) loop
+
+ -- If we find a matching choice, then the Expression of this
+ -- alternative replaces N (Raises_Constraint_Error flag is
+ -- included, so we don't have to special case that).
+
+ if Choice_Matches (Expression (N), Choice) = Match then
+ Rewrite (N, Relocate_Node (Expression (Alt)));
+ return;
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ Next (Alt);
+ end loop Search;
end if;
end Eval_Case_Expression;
@@ -2001,8 +2335,17 @@ package body Sem_Eval is
Is_Static_Expression (Then_Expr)
and then
Is_Static_Expression (Else_Expr);
+ -- True if result is static
begin
+ -- If result not static, nothing to do, otherwise set static result
+
+ if not Rstat then
+ return;
+ else
+ Set_Is_Static_Expression (N);
+ end if;
+
-- If any operand is Any_Type, just propagate to result and do not try
-- to fold, this prevents cascaded errors.
@@ -2013,6 +2356,15 @@ package body Sem_Eval is
Set_Etype (N, Any_Type);
Set_Is_Static_Expression (N, False);
return;
+ end if;
+
+ -- If condition raises constraint error then we have already signalled
+ -- an error, and we just propagate to the result and do not fold.
+
+ if Raises_Constraint_Error (Condition) then
+ Set_Raises_Constraint_Error (N);
+ return;
+ end if;
-- Static case where we can fold. Note that we don't try to fold cases
-- where the condition is known at compile time, but the result is
@@ -2020,43 +2372,31 @@ package body Sem_Eval is
-- the expander puts in a redundant test and we remove it. Instead we
-- deal with these cases in the expander.
- elsif Rstat then
+ -- Select result operand
- -- Select result operand
-
- if Is_True (Expr_Value (Condition)) then
- Result := Then_Expr;
- Non_Result := Else_Expr;
- else
- Result := Else_Expr;
- Non_Result := Then_Expr;
- end if;
+ if Is_True (Expr_Value (Condition)) then
+ Result := Then_Expr;
+ Non_Result := Else_Expr;
+ else
+ Result := Else_Expr;
+ Non_Result := Then_Expr;
+ end if;
- -- Note that it does not matter if the non-result operand raises a
- -- Constraint_Error, but if the result raises constraint error then
- -- we replace the node with a raise constraint error. This will
- -- properly propagate Raises_Constraint_Error since this flag is
- -- set in Result.
+ -- Note that it does not matter if the non-result operand raises a
+ -- Constraint_Error, but if the result raises constraint error then we
+ -- replace the node with a raise constraint error. This will properly
+ -- propagate Raises_Constraint_Error since this flag is set in Result.
- if Raises_Constraint_Error (Result) then
- Rewrite_In_Raise_CE (N, Result);
- Check_Non_Static_Context (Non_Result);
+ if Raises_Constraint_Error (Result) then
+ Rewrite_In_Raise_CE (N, Result);
+ Check_Non_Static_Context (Non_Result);
- -- Otherwise the result operand replaces the original node
-
- else
- Rewrite (N, Relocate_Node (Result));
- end if;
-
- -- Case of condition not known at compile time
+ -- Otherwise the result operand replaces the original node
else
- Check_Non_Static_Context (Condition);
- Check_Non_Static_Context (Then_Expr);
- Check_Non_Static_Context (Else_Expr);
+ Rewrite (N, Relocate_Node (Result));
+ Set_Is_Static_Expression (N);
end if;
-
- Set_Is_Static_Expression (N, Rstat);
end Eval_If_Expression;
----------------------------
@@ -2356,132 +2696,78 @@ package body Sem_Eval is
procedure Eval_Membership_Op (N : Node_Id) is
Left : constant Node_Id := Left_Opnd (N);
Right : constant Node_Id := Right_Opnd (N);
- Def_Id : Entity_Id;
- Lo : Node_Id;
- Hi : Node_Id;
- Result : Boolean;
- Stat : Boolean;
- Fold : Boolean;
+ Alts : constant List_Id := Alternatives (N);
+ Result : Match_Result;
begin
-- Ignore if error in either operand, except to make sure that Any_Type
-- is properly propagated to avoid junk cascaded errors.
- if Etype (Left) = Any_Type or else Etype (Right) = Any_Type then
+ if Etype (Left) = Any_Type
+ or else (Present (Right) and then Etype (Right) = Any_Type)
+ then
Set_Etype (N, Any_Type);
return;
end if;
-- Ignore if types involved have predicates
+ -- Is this right for static predicates ???
+ -- And what about the alternatives ???
if Present (Predicate_Function (Etype (Left)))
- or else
- Present (Predicate_Function (Etype (Right)))
+ or else (Present (Right)
+ and then Present (Predicate_Function (Etype (Right))))
then
return;
end if;
- -- Case of right operand is a subtype name
-
- if Is_Entity_Name (Right) then
- Def_Id := Entity (Right);
+ -- If left operand non-static, then nothing to do
- if (Is_Scalar_Type (Def_Id) or else Is_String_Type (Def_Id))
- and then Is_OK_Static_Subtype (Def_Id)
- then
- Test_Expression_Is_Foldable (N, Left, Stat, Fold);
+ if not Is_Static_Expression (Left) then
+ return;
+ end if;
- if not Fold or else not Stat then
- return;
- end if;
- else
- Check_Non_Static_Context (Left);
- return;
- end if;
+ -- If choice is non-static, left operand is in non-static context
- -- For string membership tests we will check the length further on
+ if (Present (Right) and then not Is_Static_Choice (Right))
+ or else (Present (Alts) and then not Is_Static_Choice_List (Alts))
+ then
+ Check_Non_Static_Context (Left);
+ return;
+ end if;
- if not Is_String_Type (Def_Id) then
- Lo := Type_Low_Bound (Def_Id);
- Hi := Type_High_Bound (Def_Id);
- else
- Lo := Empty;
- Hi := Empty;
- end if;
+ -- Otherwise we definitely have a static expression
- -- Case of right operand is a range
+ Set_Is_Static_Expression (N);
- else
- if Is_Static_Range (Right) then
- Test_Expression_Is_Foldable (N, Left, Stat, Fold);
+ -- If left operand raises constraint error, propagate and we are done
- if not Fold or else not Stat then
- return;
+ if Raises_Constraint_Error (Left) then
+ Set_Raises_Constraint_Error (N, True);
- -- If one bound of range raises CE, then don't try to fold
-
- elsif not Is_OK_Static_Range (Right) then
- Check_Non_Static_Context (Left);
- return;
- end if;
+ -- See if we match
+ else
+ if Present (Right) then
+ Result := Choice_Matches (Left, Right);
else
- Check_Non_Static_Context (Left);
- return;
+ Result := Choices_Match (Left, Alts);
end if;
- -- Here we know range is an OK static range
+ -- If result is Non_Static, it means that we raise Constraint_Error,
+ -- since we already tested that the operands were themselves static.
- Lo := Low_Bound (Right);
- Hi := High_Bound (Right);
- end if;
-
- -- For strings we check that the length of the string expression is
- -- compatible with the string subtype if the subtype is constrained,
- -- or if unconstrained then the test is always true.
+ if Result = Non_Static then
+ Set_Raises_Constraint_Error (N);
- if Is_String_Type (Etype (Right)) then
- if not Is_Constrained (Etype (Right)) then
- Result := True;
+ -- Otherwise we have our result (flipped if NOT IN case)
else
- declare
- Typlen : constant Uint := String_Type_Len (Etype (Right));
- Strlen : constant Uint :=
- UI_From_Int
- (String_Length (Strval (Get_String_Val (Left))));
- begin
- Result := (Typlen = Strlen);
- end;
+ Fold_Uint
+ (N, Test ((Result = Match) xor (Nkind (N) = N_Not_In)), True);
+ Warn_On_Known_Condition (N);
end if;
-
- -- Fold the membership test. We know we have a static range and Lo and
- -- Hi are set to the expressions for the end points of this range.
-
- elsif Is_Real_Type (Etype (Right)) then
- declare
- Leftval : constant Ureal := Expr_Value_R (Left);
- begin
- Result := Expr_Value_R (Lo) <= Leftval
- and then Leftval <= Expr_Value_R (Hi);
- end;
-
- else
- declare
- Leftval : constant Uint := Expr_Value (Left);
- begin
- Result := Expr_Value (Lo) <= Leftval
- and then Leftval <= Expr_Value (Hi);
- end;
- end if;
-
- if Nkind (N) = N_Not_In then
- Result := not Result;
end if;
-
- Fold_Uint (N, Test (Result), True);
-
- Warn_On_Known_Condition (N);
end Eval_Membership_Op;
------------------------
@@ -3297,53 +3583,6 @@ 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);
-
- begin
- -- Discrete type case
-
- if Is_Discrete_Type (Typ) then
- declare
- Pred : constant List_Id := Static_Predicate (Typ);
- Test : Node_Id;
-
- begin
- pragma Assert (Present (Pred));
-
- -- 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. This
- -- is easier than running a full intepretation of the predicate
- -- expression, and more efficient in some cases.
-
- 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;
-
- -- Real type case
-
- else
- pragma Assert (Is_Real_Type (Typ));
- Error_Msg_N ("??real predicate not applied", N);
- return True;
- end if;
- end Eval_Static_Predicate_Check;
-
-------------------------
-- Eval_String_Literal --
-------------------------
@@ -4092,6 +4331,11 @@ package body Sem_Eval is
Typ : constant Entity_Id := Etype (N);
begin
+ if Raises_Constraint_Error (N) then
+ Set_Is_Static_Expression (N, Static);
+ return;
+ end if;
+
Rewrite (N, Make_String_Literal (Loc, Strval => Val));
-- We now have the literal with the right value, both the actual type
@@ -4120,6 +4364,11 @@ package body Sem_Eval is
Ent : Entity_Id;
begin
+ if Raises_Constraint_Error (N) then
+ Set_Is_Static_Expression (N, Static);
+ return;
+ end if;
+
-- If we are folding a named number, retain the entity in the literal,
-- for ASIS use.
@@ -4177,6 +4426,11 @@ package body Sem_Eval is
Ent : Entity_Id;
begin
+ if Raises_Constraint_Error (N) then
+ Set_Is_Static_Expression (N, Static);
+ return;
+ end if;
+
-- If we are folding a named number, retain the entity in the literal,
-- for ASIS use.
@@ -4400,6 +4654,60 @@ package body Sem_Eval is
end if;
end Is_Null_Range;
+ -------------------------
+ -- Is_OK_Static_Choice --
+ -------------------------
+
+ function Is_OK_Static_Choice (Choice : Node_Id) return Boolean is
+ begin
+ -- Check various possibilities for choice
+
+ -- Note: for membership tests, we test more cases than are possible
+ -- (in particular subtype indication), but it doesn't matter because
+ -- it just won't occur (we have already done a syntax check).
+
+ if Nkind (Choice) = N_Others_Choice then
+ return True;
+
+ elsif Nkind (Choice) = N_Range then
+ return Is_OK_Static_Range (Choice);
+
+ elsif Nkind (Choice) = N_Subtype_Indication
+ or else
+ (Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)))
+ then
+ return Is_OK_Static_Subtype (Etype (Choice));
+
+ else
+ return Is_OK_Static_Expression (Choice);
+ end if;
+ end Is_OK_Static_Choice;
+
+ ------------------------------
+ -- Is_OK_Static_Choice_List --
+ ------------------------------
+
+ function Is_OK_Static_Choice_List (Choices : List_Id) return Boolean is
+ Choice : Node_Id;
+
+ begin
+ if not Is_Static_Choice_List (Choices) then
+ return False;
+ end if;
+
+ Choice := First (Choices);
+ while Present (Choice) loop
+ if not Is_OK_Static_Choice (Choice) then
+ Set_Raises_Constraint_Error (Choice);
+ return False;
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ return True;
+ end Is_OK_Static_Choice_List;
+
-----------------------------
-- Is_OK_Static_Expression --
-----------------------------
@@ -4502,7 +4810,56 @@ package body Sem_Eval is
Out_Of_Range;
end Is_Out_Of_Range;
- ---------------------
+ ----------------------
+ -- Is_Static_Choice --
+ ----------------------
+
+ function Is_Static_Choice (Choice : Node_Id) return Boolean is
+ begin
+ -- Check various possibilities for choice
+
+ -- Note: for membership tests, we test more cases than are possible
+ -- (in particular subtype indication), but it doesn't matter because
+ -- it just won't occur (we have already done a syntax check).
+
+ if Nkind (Choice) = N_Others_Choice then
+ return True;
+
+ elsif Nkind (Choice) = N_Range then
+ return Is_Static_Range (Choice);
+
+ elsif Nkind (Choice) = N_Subtype_Indication
+ or else
+ (Is_Entity_Name (Choice) and then Is_Type (Entity (Choice)))
+ then
+ return Is_Static_Subtype (Etype (Choice));
+
+ else
+ return Is_Static_Expression (Choice);
+ end if;
+ end Is_Static_Choice;
+
+ ---------------------------
+ -- Is_Static_Choice_List --
+ ---------------------------
+
+ function Is_Static_Choice_List (Choices : List_Id) return Boolean is
+ Choice : Node_Id;
+
+ begin
+ Choice := First (Choices);
+ while Present (Choice) loop
+ if not Is_Static_Choice (Choice) then
+ return False;
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ return True;
+ end Is_Static_Choice_List;
+
+---------------------
-- Is_Static_Range --
---------------------
@@ -4513,7 +4870,7 @@ package body Sem_Eval is
function Is_Static_Range (N : Node_Id) return Boolean is
begin
- return Is_Static_Expression (Low_Bound (N))
+ return Is_Static_Expression (Low_Bound (N))
and then
Is_Static_Expression (High_Bound (N));
end Is_Static_Range;
@@ -4575,6 +4932,272 @@ package body Sem_Eval is
end if;
end Is_Static_Subtype;
+ -------------------------------
+ -- Is_Statically_Unevaluated --
+ -------------------------------
+
+ function Is_Statically_Unevaluated (Expr : Node_Id) return Boolean is
+ function Check_Case_Expr_Alternative
+ (CEA : Node_Id) return Match_Result;
+ -- We have a message emanating from the Expression of a case expression
+ -- alternative. We examine this alternative, as follows:
+ --
+ -- If the selecting expression of the parent case is non-static, or
+ -- if any of the discrete choices of the given case alternative are
+ -- non-static or raise Constraint_Error, return Non_Static.
+ --
+ -- Otherwise check if the selecting expression matches any of the given
+ -- discrete choices. If so the alternative is executed and we return
+ -- Open, otherwise, the alternative can never be executed, and so we
+ -- return Closed.
+
+ ---------------------------------
+ -- Check_Case_Expr_Alternative --
+ ---------------------------------
+
+ function Check_Case_Expr_Alternative
+ (CEA : Node_Id) return Match_Result
+ is
+ Case_Exp : constant Node_Id := Parent (CEA);
+ Choice : Node_Id;
+ Prev_CEA : Node_Id;
+
+ begin
+ pragma Assert (Nkind (Case_Exp) = N_Case_Expression);
+
+ -- Check selecting expression is static
+
+ if not Is_OK_Static_Expression (Expression (Case_Exp)) then
+ return Non_Static;
+ end if;
+
+ if not Is_OK_Static_Choice_List (Discrete_Choices (CEA)) then
+ return Non_Static;
+ end if;
+
+ -- All choices are now known to be static. Now see if alternative
+ -- matches one of the choices.
+
+ Choice := First (Discrete_Choices (CEA));
+ while Present (Choice) loop
+
+ -- Check various possibilities for choice, returning Closed if we
+ -- find the selecting value matches any of the choices. Note that
+ -- we know we are the last choice, so we don't have to keep going.
+
+ if Nkind (Choice) = N_Others_Choice then
+
+ -- Others choice is a bit annoying, it matches if none of the
+ -- previous alternatives matches (note that we know we are the
+ -- last alternative in this case, so we can just go backwards
+ -- from us to see if any previous one matches).
+
+ Prev_CEA := Prev (CEA);
+ while Present (Prev_CEA) loop
+ if Check_Case_Expr_Alternative (Prev_CEA) = Match then
+ return No_Match;
+ end if;
+
+ Prev (Prev_CEA);
+ end loop;
+
+ return Match;
+
+ -- Else we have a normal static choice
+
+ elsif Choice_Matches (Expression (Case_Exp), Choice) = Match then
+ return Match;
+ end if;
+
+ -- If we fall through, it means that the discrete choice did not
+ -- match the selecting expression, so continue.
+
+ Next (Choice);
+ end loop;
+
+ -- If we get through that loop then all choices were static, and
+ -- none of them matched the selecting expression. So return Closed.
+
+ return No_Match;
+ end Check_Case_Expr_Alternative;
+
+ -- Local variables
+
+ P : Node_Id;
+ OldP : Node_Id;
+ Choice : Node_Id;
+
+ -- Start of processing for Is_Statically_Unevaluated
+
+ begin
+ -- The (32.x) references here are from RM section 4.9
+
+ -- (32.1) An expression is statically unevaluated if it is part of ...
+
+ -- This means we have to climb the tree looking for one of the cases
+
+ P := Expr;
+ loop
+ OldP := P;
+ P := Parent (P);
+
+ -- (32.2) The right operand of a static short-circuit control form
+ -- whose value is determined by its left operand.
+
+ -- AND THEN with False as left operand
+
+ if Nkind (P) = N_And_Then
+ and then Compile_Time_Known_Value (Left_Opnd (P))
+ and then Is_False (Expr_Value (Left_Opnd (P)))
+ then
+ return True;
+
+ -- OR ELSE with True as left operand
+
+ elsif Nkind (P) = N_Or_Else
+ and then Compile_Time_Known_Value (Left_Opnd (P))
+ and then Is_True (Expr_Value (Left_Opnd (P)))
+ then
+ return True;
+
+ -- (32.3) A dependent_expression of an if_expression whose associated
+ -- condition is static and equals False.
+
+ elsif Nkind (P) = N_If_Expression then
+ declare
+ Cond : constant Node_Id := First (Expressions (P));
+ Texp : constant Node_Id := Next (Cond);
+ Fexp : constant Node_Id := Next (Texp);
+
+ begin
+ if Compile_Time_Known_Value (Cond) then
+
+ -- Condition is True and we are in the right operand
+
+ if Is_True (Expr_Value (Cond)) and then OldP = Fexp then
+ return True;
+
+ -- Condition is False and we are in the left operand
+
+ elsif Is_False (Expr_Value (Cond)) and then OldP = Texp then
+ return True;
+ end if;
+ end if;
+ end;
+
+ -- (32.4) A condition or dependent_expression of an if_expression
+ -- where the condition corresponding to at least one preceding
+ -- dependent_expression of the if_expression is static and equals
+ -- True.
+
+ -- This refers to cases like
+
+ -- (if 1 then 1 elsif 1/0=2 then 2 else 3)
+
+ -- But we expand elsif's out anyway, so the above looks like:
+
+ -- (if 1 then 1 else (if 1/0=2 then 2 else 3))
+
+ -- So for us this is caught by the above check for the 32.3 case.
+
+ -- (32.5) A dependent_expression of a case_expression whose
+ -- selecting_expression is static and whose value is not covered
+ -- by the corresponding discrete_choice_list.
+
+ elsif Nkind (P) = N_Case_Expression_Alternative then
+
+ -- First, we have to be in the expression to suppress messages.
+ -- If we are within one of the choices, we want the message.
+
+ if OldP = Expression (P) then
+
+ -- Statically unevaluated if alternative does not match
+
+ if Check_Case_Expr_Alternative (P) = No_Match then
+ return True;
+ end if;
+ end if;
+
+ -- (32.6) A choice_expression (or a simple_expression of a range
+ -- that occurs as a membership_choice of a membership_choice_list)
+ -- of a static membership test that is preceded in the enclosing
+ -- membership_choice_list by another item whose individual
+ -- membership test (see (RM 4.5.2)) statically yields True.
+
+ elsif Nkind (P) in N_Membership_Test then
+
+ -- Only possibly unevaluated if simple expression is static
+
+ if not Is_OK_Static_Expression (Left_Opnd (P)) then
+ null;
+
+ -- All members of the choice list must be static
+
+ elsif (Present (Right_Opnd (P))
+ and then not Is_OK_Static_Choice (Right_Opnd (P)))
+ or else (Present (Alternatives (P))
+ and then
+ not Is_OK_Static_Choice_List (Alternatives (P)))
+ then
+ null;
+
+ -- If expression is the one and only alternative, then it is
+ -- definitely not statically unevaluated, so we only have to
+ -- test the case where there are alternatives present.
+
+ elsif Present (Alternatives (P)) then
+
+ -- Look for previous matching Choice
+
+ Choice := First (Alternatives (P));
+ while Present (Choice) loop
+
+ -- If we reached us and no previous choices matched, this
+ -- is not the case where we are statically unevaluated.
+
+ exit when OldP = Choice;
+
+ -- If a previous choice matches, then that is the case where
+ -- we know our choice is statically unevaluated.
+
+ if Choice_Matches (Left_Opnd (P), Choice) = Match then
+ return True;
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ -- If we fall through the loop, we were not one of the choices,
+ -- we must have been the expression, so that is not covered by
+ -- this rule, and we keep going.
+
+ null;
+ end if;
+ end if;
+
+ -- OK, not statically unevaluated at this level, see if we should
+ -- keep climbing to look for a higher level reason.
+
+ -- Special case for component association in aggregates, where
+ -- we want to keep climbing up to the parent aggregate.
+
+ if Nkind (P) = N_Component_Association
+ and then Nkind (Parent (P)) = N_Aggregate
+ then
+ null;
+
+ -- All done if not still within subexpression
+
+ else
+ exit when Nkind (P) not in N_Subexpr;
+ end if;
+ end loop;
+
+ -- If we fall through the loop, not one of the cases covered!
+
+ return False;
+ end Is_Statically_Unevaluated;
+
--------------------
-- Not_Null_Range --
--------------------
@@ -4703,14 +5326,19 @@ package body Sem_Eval is
-------------------------
procedure Rewrite_In_Raise_CE (N : Node_Id; Exp : Node_Id) is
- Typ : constant Entity_Id := Etype (N);
+ Typ : constant Entity_Id := Etype (N);
+ Stat : constant Boolean := Is_Static_Expression (N);
begin
- -- If we want to raise CE in the condition of a N_Raise_CE node
- -- we may as well get rid of the condition.
+ -- If we want to raise CE in the condition of a N_Raise_CE node, we
+ -- can just clear the condition if the reason is appropriate. We do
+ -- not do this operation if the parent has a reason other than range
+ -- check failed, because otherwise we would change the reason.
if Present (Parent (N))
and then Nkind (Parent (N)) = N_Raise_Constraint_Error
+ and then Reason (Parent (N)) =
+ UI_From_Int (RT_Exception_Code'Pos (CE_Range_Check_Failed))
then
Set_Condition (Parent (N), Empty);
@@ -4721,7 +5349,7 @@ package body Sem_Eval is
Rewrite (N, Exp);
Set_Etype (N, Typ);
- -- Else build an explcit N_Raise_CE
+ -- Else build an explicit N_Raise_CE
else
Rewrite (N,
@@ -4730,6 +5358,11 @@ package body Sem_Eval is
Set_Raises_Constraint_Error (N);
Set_Etype (N, Typ);
end if;
+
+ -- Set proper flags in result
+
+ Set_Raises_Constraint_Error (N, True);
+ Set_Is_Static_Expression (N, Stat);
end Rewrite_In_Raise_CE;
---------------------
@@ -4772,9 +5405,9 @@ package body Sem_Eval is
-- If either subtype is nonstatic then they're not compatible
- elsif not Is_Static_Subtype (T1)
+ elsif not Is_OK_Static_Subtype (T1)
or else
- not Is_Static_Subtype (T2)
+ not Is_OK_Static_Subtype (T2)
then
return False;
@@ -4952,8 +5585,8 @@ package body Sem_Eval is
-- Otherwise bounds must be static and identical value
else
- if not Is_Static_Subtype (T1)
- or else not Is_Static_Subtype (T2)
+ if not Is_OK_Static_Subtype (T1)
+ or else not Is_OK_Static_Subtype (T2)
then
return False;
@@ -5041,8 +5674,8 @@ package body Sem_Eval is
Expr2 : constant Node_Id := Node (DA2);
begin
- if not Is_Static_Expression (Expr1)
- or else not Is_Static_Expression (Expr2)
+ if not Is_OK_Static_Expression (Expr1)
+ or else not Is_OK_Static_Expression (Expr2)
then
return False;
@@ -5445,6 +6078,8 @@ package body Sem_Eval is
N : constant Node_Id := Original_Node (Expr);
Typ : Entity_Id;
E : Entity_Id;
+ Alt : Node_Id;
+ Exp : Node_Id;
procedure Why_Not_Static_List (L : List_Id);
-- A version that can be called on a list of expressions. Finds all
@@ -5488,6 +6123,76 @@ package body Sem_Eval is
-- Test for constraint error raised
if Raises_Constraint_Error (Expr) then
+
+ -- Special case membership to find out which piece to flag
+
+ if Nkind (N) in N_Membership_Test then
+ if Raises_Constraint_Error (Left_Opnd (N)) then
+ Why_Not_Static (Left_Opnd (N));
+ return;
+
+ elsif Present (Right_Opnd (N))
+ and then Raises_Constraint_Error (Right_Opnd (N))
+ then
+ Why_Not_Static (Right_Opnd (N));
+ return;
+
+ else
+ pragma Assert (Present (Alternatives (N)));
+
+ Alt := First (Alternatives (N));
+ while Present (Alt) loop
+ if Raises_Constraint_Error (Alt) then
+ Why_Not_Static (Alt);
+ return;
+ else
+ Next (Alt);
+ end if;
+ end loop;
+ end if;
+
+ -- Special case a range to find out which bound to flag
+
+ elsif Nkind (N) = N_Range then
+ if Raises_Constraint_Error (Low_Bound (N)) then
+ Why_Not_Static (Low_Bound (N));
+ return;
+
+ elsif Raises_Constraint_Error (High_Bound (N)) then
+ Why_Not_Static (High_Bound (N));
+ return;
+ end if;
+
+ -- Special case attribute to see which part to flag
+
+ elsif Nkind (N) = N_Attribute_Reference then
+ if Raises_Constraint_Error (Prefix (N)) then
+ Why_Not_Static (Prefix (N));
+ return;
+ end if;
+
+ if Present (Expressions (N)) then
+ Exp := First (Expressions (N));
+ while Present (Exp) loop
+ if Raises_Constraint_Error (Exp) then
+ Why_Not_Static (Exp);
+ return;
+ end if;
+
+ Next (Exp);
+ end loop;
+ end if;
+
+ -- Special case a subtype name
+
+ elsif Is_Entity_Name (Expr) and then Is_Type (Entity (Expr)) then
+ Error_Msg_NE
+ ("!& is not a static subtype (RM 4.9(26))", N, Entity (Expr));
+ return;
+ end if;
+
+ -- End of special cases
+
Error_Msg_N
("!expression raises exception, cannot be static (RM 4.9(34))",
N);
@@ -5584,6 +6289,10 @@ package body Sem_Eval is
end if;
end Entity_Case;
+ elsif Is_Type (E) then
+ Error_Msg_NE
+ ("!& is not a static subtype (RM 4.9(26))", N, E);
+
else
Error_Msg_NE
("!& is not static constant or named number "
@@ -5653,7 +6362,7 @@ package body Sem_Eval is
("!attribute of generic type is never static "
& "(RM 4.9(7,8))", N);
- elsif Is_Static_Subtype (E) then
+ elsif Is_OK_Static_Subtype (E) then
null;
elsif Is_Scalar_Type (E) then
@@ -5747,7 +6456,7 @@ package body Sem_Eval is
Why_Not_Static (Expression (N));
if not Is_Scalar_Type (Entity (Subtype_Mark (N)))
- or else not Is_Static_Subtype (Entity (Subtype_Mark (N)))
+ or else not Is_OK_Static_Subtype (Entity (Subtype_Mark (N)))
then
Error_Msg_N
("!static conversion requires static scalar subtype result "