[multiple changes]
2011-08-02 Robert Dewar <dewar@adacore.com> * sem_ch3.adb: Minor reformatting Minor comment addition Minor error msg text change 2011-08-02 Javier Miranda <miranda@adacore.com> * sem_ch5.adb (Analyze_Iteration_Scheme.Uses_Secondary_Stack): New function. Used to be more precise when we generate a variable plus one assignment to remove side effects in the evaluation of the Bound expressions. (Analyze_Iteration_Scheme): Clean attribute analyzed in all the nodes of the bound expression to force its re-analysis and thus expand the associated transient scope (if required). Code cleanup replacing the previous code that declared the constant entity by an invocation to routine Force_Evaluation which centralizes this work in the frontend. From-SVN: r177124
This commit is contained in:
parent
d8b962d80e
commit
176dadf639
|
@ -1,3 +1,21 @@
|
|||
2011-08-02 Robert Dewar <dewar@adacore.com>
|
||||
|
||||
* sem_ch3.adb: Minor reformatting
|
||||
Minor comment addition
|
||||
Minor error msg text change
|
||||
|
||||
2011-08-02 Javier Miranda <miranda@adacore.com>
|
||||
|
||||
* sem_ch5.adb (Analyze_Iteration_Scheme.Uses_Secondary_Stack): New
|
||||
function. Used to be more precise when we generate a variable plus one
|
||||
assignment to remove side effects in the evaluation of the Bound
|
||||
expressions.
|
||||
(Analyze_Iteration_Scheme): Clean attribute analyzed in all the nodes
|
||||
of the bound expression to force its re-analysis and thus expand the
|
||||
associated transient scope (if required). Code cleanup replacing the
|
||||
previous code that declared the constant entity by an invocation to
|
||||
routine Force_Evaluation which centralizes this work in the frontend.
|
||||
|
||||
2011-08-02 Robert Dewar <dewar@adacore.com>
|
||||
|
||||
* einfo.adb (Is_Base_Type): Improve efficiency by using a flag table
|
||||
|
|
|
@ -1666,10 +1666,12 @@ package body Sem_Ch3 is
|
|||
-----------------------------------
|
||||
|
||||
procedure Analyze_Component_Declaration (N : Node_Id) is
|
||||
Id : constant Entity_Id := Defining_Identifier (N);
|
||||
E : constant Node_Id := Expression (N);
|
||||
T : Entity_Id;
|
||||
P : Entity_Id;
|
||||
Id : constant Entity_Id := Defining_Identifier (N);
|
||||
E : constant Node_Id := Expression (N);
|
||||
Typ : constant Node_Id :=
|
||||
Subtype_Indication (Component_Definition (N));
|
||||
T : Entity_Id;
|
||||
P : Entity_Id;
|
||||
|
||||
function Contains_POC (Constr : Node_Id) return Boolean;
|
||||
-- Determines whether a constraint uses the discriminant of a record
|
||||
|
@ -1773,8 +1775,6 @@ package body Sem_Ch3 is
|
|||
end if;
|
||||
end Is_Known_Limited;
|
||||
|
||||
Typ : constant Node_Id := Subtype_Indication (Component_Definition (N));
|
||||
|
||||
-- Start of processing for Analyze_Component_Declaration
|
||||
|
||||
begin
|
||||
|
@ -4005,8 +4005,9 @@ package body Sem_Ch3 is
|
|||
("subtype of Boolean cannot have constraint", N);
|
||||
end if;
|
||||
|
||||
-- Subtype of String shall have a lower index bound equal to 1 in SPARK
|
||||
-- or ALFA.
|
||||
-- String subtype must have a lower bound of 1 in SPARK/ALFA. Note that
|
||||
-- we do not need to test for the non-static case here, since that was
|
||||
-- already taken care of in Process_Range_Expr_In_Decl.
|
||||
|
||||
if Base_Type (T) = Standard_String
|
||||
and then Nkind (Subtype_Indication (N)) = N_Subtype_Indication
|
||||
|
@ -4015,6 +4016,7 @@ package body Sem_Ch3 is
|
|||
Cstr : constant Node_Id := Constraint (Subtype_Indication (N));
|
||||
Drange : Node_Id;
|
||||
Low : Node_Id;
|
||||
|
||||
begin
|
||||
if Nkind (Cstr) = N_Index_Or_Discriminant_Constraint
|
||||
and then List_Length (Constraints (Cstr)) = 1
|
||||
|
@ -4028,7 +4030,7 @@ package body Sem_Ch3 is
|
|||
and then Expr_Value (Low) /= 1
|
||||
then
|
||||
Check_Formal_Restriction
|
||||
("subtype of String must have 1 as lower bound", N);
|
||||
("String subtype must have lower bound of 1", N);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
@ -19011,6 +19013,7 @@ package body Sem_Ch3 is
|
|||
declare
|
||||
Typ : Node_Id;
|
||||
Ctxt : Node_Id;
|
||||
|
||||
begin
|
||||
if Nkind (Parent (Def)) = N_Full_Type_Declaration then
|
||||
Typ := Parent (Def);
|
||||
|
@ -19027,14 +19030,12 @@ package body Sem_Ch3 is
|
|||
then
|
||||
Check_Formal_Restriction
|
||||
("type should be defined in package specification", Typ);
|
||||
|
||||
elsif Nkind (Ctxt) /= N_Package_Specification
|
||||
or else
|
||||
Nkind (Parent (Parent (Ctxt))) /= N_Compilation_Unit
|
||||
or else Nkind (Parent (Parent (Ctxt))) /= N_Compilation_Unit
|
||||
then
|
||||
Check_Formal_Restriction
|
||||
("type should be defined in library unit package", Typ);
|
||||
else
|
||||
null;
|
||||
end if;
|
||||
end;
|
||||
end if;
|
||||
|
|
|
@ -95,9 +95,9 @@ package body Sem_Ch5 is
|
|||
procedure Set_Assignment_Type
|
||||
(Opnd : Node_Id;
|
||||
Opnd_Type : in out Entity_Id);
|
||||
-- Opnd is either the Lhs or Rhs of the assignment, and Opnd_Type
|
||||
-- is the nominal subtype. This procedure is used to deal with cases
|
||||
-- where the nominal subtype must be replaced by the actual subtype.
|
||||
-- Opnd is either the Lhs or Rhs of the assignment, and Opnd_Type is the
|
||||
-- nominal subtype. This procedure is used to deal with cases where the
|
||||
-- nominal subtype must be replaced by the actual subtype.
|
||||
|
||||
-------------------------------
|
||||
-- Diagnose_Non_Variable_Lhs --
|
||||
|
@ -105,8 +105,8 @@ package body Sem_Ch5 is
|
|||
|
||||
procedure Diagnose_Non_Variable_Lhs (N : Node_Id) is
|
||||
begin
|
||||
-- Not worth posting another error if left hand side already
|
||||
-- flagged as being illegal in some respect.
|
||||
-- Not worth posting another error if left hand side already flagged
|
||||
-- as being illegal in some respect.
|
||||
|
||||
if Error_Posted (N) then
|
||||
return;
|
||||
|
@ -130,8 +130,8 @@ package body Sem_Ch5 is
|
|||
elsif (Is_Prival (Ent)
|
||||
and then
|
||||
(Ekind (Current_Scope) = E_Function
|
||||
or else Ekind (Enclosing_Dynamic_Scope (
|
||||
Current_Scope)) = E_Function))
|
||||
or else Ekind (Enclosing_Dynamic_Scope
|
||||
(Current_Scope)) = E_Function))
|
||||
or else
|
||||
(Ekind (Ent) = E_Component
|
||||
and then Is_Protected_Type (Scope (Ent)))
|
||||
|
@ -202,10 +202,10 @@ package body Sem_Ch5 is
|
|||
Require_Entity (Opnd);
|
||||
|
||||
-- If the assignment operand is an in-out or out parameter, then we
|
||||
-- get the actual subtype (needed for the unconstrained case).
|
||||
-- If the operand is the actual in an entry declaration, then within
|
||||
-- the accept statement it is replaced with a local renaming, which
|
||||
-- may also have an actual subtype.
|
||||
-- get the actual subtype (needed for the unconstrained case). If the
|
||||
-- operand is the actual in an entry declaration, then within the
|
||||
-- accept statement it is replaced with a local renaming, which may
|
||||
-- also have an actual subtype.
|
||||
|
||||
if Is_Entity_Name (Opnd)
|
||||
and then (Ekind (Entity (Opnd)) = E_Out_Parameter
|
||||
|
@ -344,8 +344,8 @@ package body Sem_Ch5 is
|
|||
end if;
|
||||
end if;
|
||||
|
||||
-- The resulting assignment type is T1, so now we will resolve the
|
||||
-- left hand side of the assignment using this determined type.
|
||||
-- The resulting assignment type is T1, so now we will resolve the left
|
||||
-- hand side of the assignment using this determined type.
|
||||
|
||||
Resolve (Lhs, T1);
|
||||
|
||||
|
@ -353,8 +353,8 @@ package body Sem_Ch5 is
|
|||
|
||||
if not Is_Variable (Lhs) then
|
||||
|
||||
-- Ada 2005 (AI-327): Check assignment to the attribute Priority of
|
||||
-- a protected object.
|
||||
-- Ada 2005 (AI-327): Check assignment to the attribute Priority of a
|
||||
-- protected object.
|
||||
|
||||
declare
|
||||
Ent : Entity_Id;
|
||||
|
@ -452,9 +452,9 @@ package body Sem_Ch5 is
|
|||
("target of assignment operation must not be abstract", Lhs);
|
||||
end if;
|
||||
|
||||
-- Resolution may have updated the subtype, in case the left-hand
|
||||
-- side is a private protected component. Use the correct subtype
|
||||
-- to avoid scoping issues in the back-end.
|
||||
-- Resolution may have updated the subtype, in case the left-hand side
|
||||
-- is a private protected component. Use the correct subtype to avoid
|
||||
-- scoping issues in the back-end.
|
||||
|
||||
T1 := Etype (Lhs);
|
||||
|
||||
|
@ -631,7 +631,7 @@ package body Sem_Ch5 is
|
|||
Apply_Scalar_Range_Check (Rhs, Etype (Lhs));
|
||||
|
||||
-- For array types, verify that lengths match. If the right hand side
|
||||
-- if a function call that has been inlined, the assignment has been
|
||||
-- is a function call that has been inlined, the assignment has been
|
||||
-- rewritten as a block, and the constraint check will be applied to the
|
||||
-- assignment within the block.
|
||||
|
||||
|
@ -648,8 +648,8 @@ package body Sem_Ch5 is
|
|||
-- side is a type conversion to an unconstrained type, a length check
|
||||
-- is performed on the expression itself during expansion. In rare
|
||||
-- cases, the redundant length check is computed on an index type
|
||||
-- with a different representation, triggering incorrect code in
|
||||
-- the back end.
|
||||
-- with a different representation, triggering incorrect code in the
|
||||
-- back end.
|
||||
|
||||
Apply_Length_Check (Rhs, Etype (Lhs));
|
||||
|
||||
|
@ -679,11 +679,11 @@ package body Sem_Ch5 is
|
|||
|
||||
and then Same_Object (Lhs, Original_Node (Rhs))
|
||||
|
||||
-- But exclude the case where the right side was an operation
|
||||
-- that got rewritten (e.g. JUNK + K, where K was known to be
|
||||
-- zero). We don't want to warn in such a case, since it is
|
||||
-- reasonable to write such expressions especially when K is
|
||||
-- defined symbolically in some other package.
|
||||
-- But exclude the case where the right side was an operation that
|
||||
-- got rewritten (e.g. JUNK + K, where K was known to be zero). We
|
||||
-- don't want to warn in such a case, since it is reasonable to write
|
||||
-- such expressions especially when K is defined symbolically in some
|
||||
-- other package.
|
||||
|
||||
and then Nkind (Original_Node (Rhs)) not in N_Op
|
||||
then
|
||||
|
@ -722,11 +722,11 @@ package body Sem_Ch5 is
|
|||
Set_Referenced_Modified (Lhs, Out_Param => False);
|
||||
end if;
|
||||
|
||||
-- Final step. If left side is an entity, then we may be able to
|
||||
-- reset the current tracked values to new safe values. We only have
|
||||
-- something to do if the left side is an entity name, and expansion
|
||||
-- has not modified the node into something other than an assignment,
|
||||
-- and of course we only capture values if it is safe to do so.
|
||||
-- Final step. If left side is an entity, then we may be able to reset
|
||||
-- the current tracked values to new safe values. We only have something
|
||||
-- to do if the left side is an entity name, and expansion has not
|
||||
-- modified the node into something other than an assignment, and of
|
||||
-- course we only capture values if it is safe to do so.
|
||||
|
||||
if Is_Entity_Name (Lhs)
|
||||
and then Nkind (N) = N_Assignment_Statement
|
||||
|
@ -739,8 +739,8 @@ package body Sem_Ch5 is
|
|||
|
||||
-- If simple variable on left side, warn if this assignment
|
||||
-- blots out another one (rendering it useless) and note
|
||||
-- location of assignment in case no one references value.
|
||||
-- We only do this for source assignments, otherwise we can
|
||||
-- location of assignment in case no one references value. We
|
||||
-- only do this for source assignments, otherwise we can
|
||||
-- generate bogus warnings when an assignment is rewritten as
|
||||
-- another assignment, and gets tied up with itself.
|
||||
|
||||
|
@ -809,9 +809,8 @@ package body Sem_Ch5 is
|
|||
begin
|
||||
Check_Formal_Restriction ("block statement is not allowed", N);
|
||||
|
||||
-- If no handled statement sequence is present, things are really
|
||||
-- messed up, and we just return immediately (this is a defence
|
||||
-- against previous errors).
|
||||
-- If no handled statement sequence is present, things are really messed
|
||||
-- up, and we just return immediately (defence against previous errors).
|
||||
|
||||
if No (HSS) then
|
||||
return;
|
||||
|
@ -843,10 +842,9 @@ package body Sem_Ch5 is
|
|||
Analyze (Id);
|
||||
Ent := Entity (Id);
|
||||
|
||||
-- An error defense. If we have an identifier, but no entity,
|
||||
-- then something is wrong. If we have previous errors, then
|
||||
-- just remove the identifier and continue, otherwise raise
|
||||
-- an exception.
|
||||
-- An error defense. If we have an identifier, but no entity, then
|
||||
-- something is wrong. If previous errors, then just remove the
|
||||
-- identifier and continue, otherwise raise an exception.
|
||||
|
||||
if No (Ent) then
|
||||
if Total_Errors_Detected /= 0 then
|
||||
|
@ -887,9 +885,9 @@ package body Sem_Ch5 is
|
|||
Analyze (HSS);
|
||||
Process_End_Label (HSS, 'e', Ent);
|
||||
|
||||
-- If exception handlers are present, then we indicate that
|
||||
-- enclosing scopes contain a block with handlers. We only
|
||||
-- need to mark non-generic scopes.
|
||||
-- If exception handlers are present, then we indicate that enclosing
|
||||
-- scopes contain a block with handlers. We only need to mark non-
|
||||
-- generic scopes.
|
||||
|
||||
if Present (EH) then
|
||||
S := Scope (Ent);
|
||||
|
@ -932,17 +930,17 @@ package body Sem_Ch5 is
|
|||
-- Don't care about assigned values
|
||||
|
||||
Statements_Analyzed : Boolean := False;
|
||||
-- Set True if at least some statement sequences get analyzed.
|
||||
-- If False on exit, means we had a serious error that prevented
|
||||
-- full analysis of the case statement, and as a result it is not
|
||||
-- a good idea to output warning messages about unreachable code.
|
||||
-- Set True if at least some statement sequences get analyzed. If False
|
||||
-- on exit, means we had a serious error that prevented full analysis of
|
||||
-- the case statement, and as a result it is not a good idea to output
|
||||
-- warning messages about unreachable code.
|
||||
|
||||
Save_Unblocked_Exit_Count : constant Nat := Unblocked_Exit_Count;
|
||||
-- Recursively save value of this global, will be restored on exit
|
||||
|
||||
procedure Non_Static_Choice_Error (Choice : Node_Id);
|
||||
-- Error routine invoked by the generic instantiation below when
|
||||
-- the case statement has a non static choice.
|
||||
-- Error routine invoked by the generic instantiation below when the
|
||||
-- case statement has a non static choice.
|
||||
|
||||
procedure Process_Statements (Alternative : Node_Id);
|
||||
-- Analyzes all the statements associated with a case alternative.
|
||||
|
@ -981,16 +979,16 @@ package body Sem_Ch5 is
|
|||
Statements_Analyzed := True;
|
||||
|
||||
-- An interesting optimization. If the case statement expression
|
||||
-- is a simple entity, then we can set the current value within
|
||||
-- an alternative if the alternative has one possible value.
|
||||
-- is a simple entity, then we can set the current value within an
|
||||
-- alternative if the alternative has one possible value.
|
||||
|
||||
-- case N is
|
||||
-- when 1 => alpha
|
||||
-- when 2 | 3 => beta
|
||||
-- when others => gamma
|
||||
|
||||
-- Here we know that N is initially 1 within alpha, but for beta
|
||||
-- and gamma, we do not know anything more about the initial value.
|
||||
-- Here we know that N is initially 1 within alpha, but for beta and
|
||||
-- gamma, we do not know anything more about the initial value.
|
||||
|
||||
if Is_Entity_Name (Exp) then
|
||||
Ent := Entity (Exp);
|
||||
|
@ -1080,10 +1078,10 @@ package body Sem_Ch5 is
|
|||
return;
|
||||
end if;
|
||||
|
||||
-- If the case expression is a formal object of mode in out, then
|
||||
-- treat it as having a nonstatic subtype by forcing use of the base
|
||||
-- type (which has to get passed to Check_Case_Choices below). Also
|
||||
-- use base type when the case expression is parenthesized.
|
||||
-- If the case expression is a formal object of mode in out, then treat
|
||||
-- it as having a nonstatic subtype by forcing use of the base type
|
||||
-- (which has to get passed to Check_Case_Choices below). Also use base
|
||||
-- type when the case expression is parenthesized.
|
||||
|
||||
if Paren_Count (Exp) > 0
|
||||
or else (Is_Entity_Name (Exp)
|
||||
|
@ -1148,13 +1146,16 @@ package body Sem_Ch5 is
|
|||
----------------------------
|
||||
|
||||
-- If the exit includes a name, it must be the name of a currently open
|
||||
-- loop. Otherwise there must be an innermost open loop on the stack,
|
||||
-- to which the statement implicitly refers.
|
||||
-- loop. Otherwise there must be an innermost open loop on the stack, to
|
||||
-- which the statement implicitly refers.
|
||||
|
||||
-- Additionally, in formal mode:
|
||||
-- * the exit can only name the closest enclosing loop;
|
||||
-- * an exit with a when clause must be directly contained in a loop;
|
||||
-- * an exit without a when clause must be directly contained in an
|
||||
|
||||
-- The exit can only name the closest enclosing loop;
|
||||
|
||||
-- An exit with a when clause must be directly contained in a loop;
|
||||
|
||||
-- An exit without a when clause must be directly contained in an
|
||||
-- if-statement with no elsif or else, which is itself directly contained
|
||||
-- in a loop. The exit must be the last statement in the if-statement.
|
||||
|
||||
|
@ -1177,6 +1178,7 @@ package body Sem_Ch5 is
|
|||
if not In_Open_Scopes (U_Name) or else Ekind (U_Name) /= E_Loop then
|
||||
Error_Msg_N ("invalid loop name in exit statement", N);
|
||||
return;
|
||||
|
||||
else
|
||||
if Has_Loop_In_Inner_Open_Scopes (U_Name) then
|
||||
Check_Formal_Restriction
|
||||
|
@ -1185,6 +1187,7 @@ package body Sem_Ch5 is
|
|||
|
||||
Set_Has_Exit (U_Name);
|
||||
end if;
|
||||
|
||||
else
|
||||
U_Name := Empty;
|
||||
end if;
|
||||
|
@ -1194,7 +1197,8 @@ package body Sem_Ch5 is
|
|||
Kind := Ekind (Scope_Id);
|
||||
|
||||
if Kind = E_Loop
|
||||
and then (No (Target) or else Scope_Id = U_Name) then
|
||||
and then (No (Target) or else Scope_Id = U_Name)
|
||||
then
|
||||
Set_Has_Exit (Scope_Id);
|
||||
exit;
|
||||
|
||||
|
@ -1339,15 +1343,14 @@ package body Sem_Ch5 is
|
|||
|
||||
-- A special complication arises in the analysis of if statements
|
||||
|
||||
-- The expander has circuitry to completely delete code that it
|
||||
-- can tell will not be executed (as a result of compile time known
|
||||
-- conditions). In the analyzer, we ensure that code that will be
|
||||
-- deleted in this manner is analyzed but not expanded. This is
|
||||
-- obviously more efficient, but more significantly, difficulties
|
||||
-- arise if code is expanded and then eliminated (e.g. exception
|
||||
-- table entries disappear). Similarly, itypes generated in deleted
|
||||
-- code must be frozen from start, because the nodes on which they
|
||||
-- depend will not be available at the freeze point.
|
||||
-- The expander has circuitry to completely delete code that it can tell
|
||||
-- will not be executed (as a result of compile time known conditions). In
|
||||
-- the analyzer, we ensure that code that will be deleted in this manner is
|
||||
-- analyzed but not expanded. This is obviously more efficient, but more
|
||||
-- significantly, difficulties arise if code is expanded and then
|
||||
-- eliminated (e.g. exception table entries disappear). Similarly, itypes
|
||||
-- generated in deleted code must be frozen from start, because the nodes
|
||||
-- on which they depend will not be available at the freeze point.
|
||||
|
||||
procedure Analyze_If_Statement (N : Node_Id) is
|
||||
E : Node_Id;
|
||||
|
@ -1358,13 +1361,13 @@ package body Sem_Ch5 is
|
|||
Save_In_Deleted_Code : Boolean;
|
||||
|
||||
Del : Boolean := False;
|
||||
-- This flag gets set True if a True condition has been found,
|
||||
-- which means that remaining ELSE/ELSIF parts are deleted.
|
||||
-- This flag gets set True if a True condition has been found, which
|
||||
-- means that remaining ELSE/ELSIF parts are deleted.
|
||||
|
||||
procedure Analyze_Cond_Then (Cnode : Node_Id);
|
||||
-- This is applied to either the N_If_Statement node itself or
|
||||
-- to an N_Elsif_Part node. It deals with analyzing the condition
|
||||
-- and the THEN statements associated with it.
|
||||
-- This is applied to either the N_If_Statement node itself or to an
|
||||
-- N_Elsif_Part node. It deals with analyzing the condition and the THEN
|
||||
-- statements associated with it.
|
||||
|
||||
-----------------------
|
||||
-- Analyze_Cond_Then --
|
||||
|
@ -1390,8 +1393,8 @@ package body Sem_Ch5 is
|
|||
elsif Compile_Time_Known_Value (Cond) then
|
||||
Save_In_Deleted_Code := In_Deleted_Code;
|
||||
|
||||
-- If condition is True, then analyze the THEN statements
|
||||
-- and set no expansion for ELSE and ELSIF parts.
|
||||
-- If condition is True, then analyze the THEN statements and set
|
||||
-- no expansion for ELSE and ELSIF parts.
|
||||
|
||||
if Is_True (Expr_Value (Cond)) then
|
||||
Analyze_Statements (Tstm);
|
||||
|
@ -1419,9 +1422,9 @@ package body Sem_Ch5 is
|
|||
-- Start of Analyze_If_Statement
|
||||
|
||||
begin
|
||||
-- Initialize exit count for else statements. If there is no else
|
||||
-- part, this count will stay non-zero reflecting the fact that the
|
||||
-- uncovered else case is an unblocked exit.
|
||||
-- Initialize exit count for else statements. If there is no else part,
|
||||
-- this count will stay non-zero reflecting the fact that the uncovered
|
||||
-- else case is an unblocked exit.
|
||||
|
||||
Unblocked_Exit_Count := 1;
|
||||
Analyze_Cond_Then (N);
|
||||
|
@ -1481,9 +1484,8 @@ package body Sem_Ch5 is
|
|||
-- Analyze_Implicit_Label_Declaration --
|
||||
----------------------------------------
|
||||
|
||||
-- An implicit label declaration is generated in the innermost
|
||||
-- enclosing declarative part. This is done for labels as well as
|
||||
-- block and loop names.
|
||||
-- An implicit label declaration is generated in the innermost enclosing
|
||||
-- declarative part. This is done for labels, and block and loop names.
|
||||
|
||||
-- Note: any changes in this routine may need to be reflected in
|
||||
-- Analyze_Label_Entity.
|
||||
|
@ -1517,6 +1519,12 @@ package body Sem_Ch5 is
|
|||
-- to capture the bounds, so that the function result can be finalized
|
||||
-- in timely fashion.
|
||||
|
||||
function Has_Call_Using_Secondary_Stack (N : Node_Id) return Boolean;
|
||||
-- N is the node for an arbitrary construct. This function searches the
|
||||
-- construct N to see if any expressions within it contain function
|
||||
-- calls that use the secondary stack, returning True if any such call
|
||||
-- is found, and False otherwise.
|
||||
|
||||
--------------------
|
||||
-- Process_Bounds --
|
||||
--------------------
|
||||
|
@ -1571,8 +1579,6 @@ package body Sem_Ch5 is
|
|||
|
||||
Analyze_And_Resolve (Original_Bound, Typ);
|
||||
|
||||
Id := Make_Temporary (Loc, 'S', Original_Bound);
|
||||
|
||||
-- Normally, the best approach is simply to generate a constant
|
||||
-- declaration that captures the bound. However, there is a nasty
|
||||
-- case where this is wrong. If the bound is complex, and has a
|
||||
|
@ -1584,33 +1590,13 @@ package body Sem_Ch5 is
|
|||
-- proper trace of the value, useful in optimizations that get rid
|
||||
-- of junk range checks.
|
||||
|
||||
-- Probably we want something like the Side_Effect_Free routine
|
||||
-- in Exp_Util, but for now, we just optimize the cases of 'Last
|
||||
-- and 'First applied to an entity, since these are the important
|
||||
-- cases for range check optimizations.
|
||||
|
||||
if Nkind (Original_Bound) = N_Attribute_Reference
|
||||
and then (Attribute_Name (Original_Bound) = Name_First
|
||||
or else
|
||||
Attribute_Name (Original_Bound) = Name_Last)
|
||||
and then Is_Entity_Name (Prefix (Original_Bound))
|
||||
then
|
||||
Decl :=
|
||||
Make_Object_Declaration (Loc,
|
||||
Defining_Identifier => Id,
|
||||
Constant_Present => True,
|
||||
Object_Definition => New_Occurrence_Of (Typ, Loc),
|
||||
Expression => Relocate_Node (Original_Bound));
|
||||
|
||||
-- Insert declaration at proper place. If loop comes from an
|
||||
-- enclosing quantified expression, the insertion point is
|
||||
-- arbitrarily far up in the tree.
|
||||
|
||||
Insert_Action (Parent (N), Decl);
|
||||
Rewrite (Original_Bound, New_Occurrence_Of (Id, Loc));
|
||||
return Expression (Decl);
|
||||
if not Has_Call_Using_Secondary_Stack (N) then
|
||||
Force_Evaluation (Original_Bound);
|
||||
return Original_Bound;
|
||||
end if;
|
||||
|
||||
Id := Make_Temporary (Loc, 'R', Original_Bound);
|
||||
|
||||
-- Here we make a declaration with a separate assignment
|
||||
-- statement, and insert before loop header.
|
||||
|
||||
|
@ -1624,6 +1610,14 @@ package body Sem_Ch5 is
|
|||
Name => New_Occurrence_Of (Id, Loc),
|
||||
Expression => Relocate_Node (Original_Bound));
|
||||
|
||||
-- We must recursively clean in the relocated expression the flag
|
||||
-- analyzed to ensure that the expression is reanalyzed. Required
|
||||
-- to ensure that the transient scope is established now (because
|
||||
-- Establish_Transient_Scope discarded generating transient scopes
|
||||
-- in the analysis of the iteration scheme).
|
||||
|
||||
Reset_Analyzed_Flags (Expression (Assign));
|
||||
|
||||
Insert_Actions (Parent (N), New_List (Decl, Assign));
|
||||
|
||||
Rewrite (Original_Bound, New_Occurrence_Of (Id, Loc));
|
||||
|
@ -1638,11 +1632,11 @@ package body Sem_Ch5 is
|
|||
-- Start of processing for Process_Bounds
|
||||
|
||||
begin
|
||||
-- Determine expected type of range by analyzing separate copy
|
||||
-- Do the analysis and resolution of the copy of the bounds with
|
||||
-- expansion disabled, to prevent the generation of finalization
|
||||
-- actions on each bound. This prevents memory leaks when the
|
||||
-- bounds contain calls to functions returning controlled arrays.
|
||||
-- Determine expected type of range by analyzing separate copy Do the
|
||||
-- analysis and resolution of the copy of the bounds with expansion
|
||||
-- disabled, to prevent the generation of finalization actions on
|
||||
-- each bound. This prevents memory leaks when the bounds contain
|
||||
-- calls to functions returning controlled arrays.
|
||||
|
||||
Set_Parent (R_Copy, Parent (R));
|
||||
Save_Analysis := Full_Analysis;
|
||||
|
@ -1699,11 +1693,10 @@ package body Sem_Ch5 is
|
|||
|
||||
Typ := Etype (R_Copy);
|
||||
|
||||
-- If the type of the discrete range is Universal_Integer, then
|
||||
-- the bound's type must be resolved to Integer, and any object
|
||||
-- used to hold the bound must also have type Integer, unless the
|
||||
-- literal bounds are constant-folded expressions that carry a user-
|
||||
-- defined type.
|
||||
-- If the type of the discrete range is Universal_Integer, then the
|
||||
-- bound's type must be resolved to Integer, and any object used to
|
||||
-- hold the bound must also have type Integer, unless the literal
|
||||
-- bounds are constant-folded expressions with a user-defined type.
|
||||
|
||||
if Typ = Universal_Integer then
|
||||
if Nkind (Lo) = N_Integer_Literal
|
||||
|
@ -1789,12 +1782,70 @@ package body Sem_Ch5 is
|
|||
end if;
|
||||
end Check_Controlled_Array_Attribute;
|
||||
|
||||
------------------------------------
|
||||
-- Has_Call_Using_Secondary_Stack --
|
||||
------------------------------------
|
||||
|
||||
function Has_Call_Using_Secondary_Stack (N : Node_Id) return Boolean is
|
||||
|
||||
function Check_Call (N : Node_Id) return Traverse_Result;
|
||||
-- Check if N is a function call which uses the secondary stack
|
||||
|
||||
----------------
|
||||
-- Check_Call --
|
||||
----------------
|
||||
|
||||
function Check_Call (N : Node_Id) return Traverse_Result is
|
||||
Nam : Node_Id;
|
||||
Subp : Entity_Id;
|
||||
Return_Typ : Entity_Id;
|
||||
|
||||
begin
|
||||
if Nkind (N) = N_Function_Call then
|
||||
Nam := Name (N);
|
||||
|
||||
-- Call using access to subprogram with explicit dereference
|
||||
|
||||
if Nkind (Nam) = N_Explicit_Dereference then
|
||||
Subp := Etype (Nam);
|
||||
|
||||
-- Normal case
|
||||
|
||||
else
|
||||
Subp := Entity (Nam);
|
||||
end if;
|
||||
|
||||
Return_Typ := Etype (Subp);
|
||||
|
||||
if Is_Composite_Type (Return_Typ)
|
||||
and then not Is_Constrained (Return_Typ)
|
||||
then
|
||||
return Abandon;
|
||||
|
||||
elsif Sec_Stack_Needed_For_Return (Subp) then
|
||||
return Abandon;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Continue traversing the tree
|
||||
|
||||
return OK;
|
||||
end Check_Call;
|
||||
|
||||
function Check_Calls is new Traverse_Func (Check_Call);
|
||||
|
||||
-- Start of processing for Has_Call_Using_Secondary_Stack
|
||||
|
||||
begin
|
||||
return Check_Calls (N) = Abandon;
|
||||
end Has_Call_Using_Secondary_Stack;
|
||||
|
||||
-- Start of processing for Analyze_Iteration_Scheme
|
||||
|
||||
begin
|
||||
-- If this is a rewritten quantified expression, the iteration
|
||||
-- scheme has been analyzed already. Do no repeat analysis because
|
||||
-- the loop variable is already declared.
|
||||
-- If this is a rewritten quantified expression, the iteration scheme
|
||||
-- has been analyzed already. Do no repeat analysis because the loop
|
||||
-- variable is already declared.
|
||||
|
||||
if Analyzed (N) then
|
||||
return;
|
||||
|
@ -1812,8 +1863,8 @@ package body Sem_Ch5 is
|
|||
Cond : constant Node_Id := Condition (N);
|
||||
|
||||
begin
|
||||
-- For WHILE loop, verify that the condition is a Boolean
|
||||
-- expression and resolve and check it.
|
||||
-- For WHILE loop, verify that the condition is a Boolean expression
|
||||
-- and resolve and check it.
|
||||
|
||||
if Present (Cond) then
|
||||
Analyze_And_Resolve (Cond, Any_Boolean);
|
||||
|
@ -1835,8 +1886,8 @@ package body Sem_Ch5 is
|
|||
begin
|
||||
Enter_Name (Id);
|
||||
|
||||
-- We always consider the loop variable to be referenced,
|
||||
-- since the loop may be used just for counting purposes.
|
||||
-- We always consider the loop variable to be referenced, since
|
||||
-- the loop may be used just for counting purposes.
|
||||
|
||||
Generate_Reference (Id, N, ' ');
|
||||
|
||||
|
@ -2000,8 +2051,8 @@ package body Sem_Ch5 is
|
|||
if not Inside_A_Generic
|
||||
and then not In_Instance
|
||||
then
|
||||
-- Specialize msg if invalid values could make
|
||||
-- the loop non-null after all.
|
||||
-- Specialize msg if invalid values could make the
|
||||
-- loop non-null after all.
|
||||
|
||||
if Compile_Time_Compare
|
||||
(L, H, Assume_Valid => False) = GT
|
||||
|
@ -2010,9 +2061,9 @@ package body Sem_Ch5 is
|
|||
("?loop range is null, loop will not execute",
|
||||
DS);
|
||||
|
||||
-- Since we know the range of the loop is
|
||||
-- null, set the appropriate flag to remove
|
||||
-- the loop entirely during expansion.
|
||||
-- Since we know the range of the loop is null,
|
||||
-- set the appropriate flag to remove the loop
|
||||
-- entirely during expansion.
|
||||
|
||||
Set_Is_Null_Loop (Parent (N));
|
||||
|
||||
|
@ -2179,8 +2230,8 @@ package body Sem_Ch5 is
|
|||
begin
|
||||
if Present (Id) then
|
||||
|
||||
-- Make name visible, e.g. for use in exit statements. Loop
|
||||
-- labels are always considered to be referenced.
|
||||
-- Make name visible, e.g. for use in exit statements. Loop labels
|
||||
-- are always considered to be referenced.
|
||||
|
||||
Analyze (Id);
|
||||
Ent := Entity (Id);
|
||||
|
@ -2227,10 +2278,10 @@ package body Sem_Ch5 is
|
|||
Set_Parent (Ent, Loop_Statement);
|
||||
end if;
|
||||
|
||||
-- Kill current values on entry to loop, since statements in body of
|
||||
-- loop may have been executed before the loop is entered. Similarly we
|
||||
-- kill values after the loop, since we do not know that the body of the
|
||||
-- loop was executed.
|
||||
-- Kill current values on entry to loop, since statements in the body of
|
||||
-- the loop may have been executed before the loop is entered. Similarly
|
||||
-- we kill values after the loop, since we do not know that the body of
|
||||
-- the loop was executed.
|
||||
|
||||
Kill_Current_Values;
|
||||
Push_Scope (Ent);
|
||||
|
@ -2251,8 +2302,8 @@ package body Sem_Ch5 is
|
|||
Check_Infinite_Loop_Warning (N);
|
||||
end if;
|
||||
|
||||
-- Code after loop is unreachable if the loop has no WHILE or FOR
|
||||
-- and contains no EXIT statements within the body of the loop.
|
||||
-- Code after loop is unreachable if the loop has no WHILE or FOR and
|
||||
-- contains no EXIT statements within the body of the loop.
|
||||
|
||||
if No (Iter) and then not Has_Exit (Ent) then
|
||||
Check_Unreachable_Code (N);
|
||||
|
@ -2282,9 +2333,9 @@ package body Sem_Ch5 is
|
|||
|
||||
begin
|
||||
-- The labels declared in the statement list are reachable from
|
||||
-- statements in the list. We do this as a prepass so that any
|
||||
-- goto statement will be properly flagged if its target is not
|
||||
-- reachable. This is not required, but is nice behavior!
|
||||
-- statements in the list. We do this as a prepass so that any goto
|
||||
-- statement will be properly flagged if its target is not reachable.
|
||||
-- This is not required, but is nice behavior!
|
||||
|
||||
S := First (L);
|
||||
while Present (S) loop
|
||||
|
@ -2331,10 +2382,9 @@ package body Sem_Ch5 is
|
|||
|
||||
Conditional_Statements_End;
|
||||
|
||||
-- Make labels unreachable. Visibility is not sufficient, because
|
||||
-- labels in one if-branch for example are not reachable from the
|
||||
-- other branch, even though their declarations are in the enclosing
|
||||
-- declarative part.
|
||||
-- Make labels unreachable. Visibility is not sufficient, because labels
|
||||
-- in one if-branch for example are not reachable from the other branch,
|
||||
-- even though their declarations are in the enclosing declarative part.
|
||||
|
||||
S := First (L);
|
||||
while Present (S) loop
|
||||
|
@ -2365,9 +2415,8 @@ package body Sem_Ch5 is
|
|||
Nxt := Original_Node (Next (N));
|
||||
|
||||
-- If a label follows us, then we never have dead code, since
|
||||
-- someone could branch to the label, so we just ignore it,
|
||||
-- unless we are in formal mode where goto statements are not
|
||||
-- allowed.
|
||||
-- someone could branch to the label, so we just ignore it, unless
|
||||
-- we are in formal mode where goto statements are not allowed.
|
||||
|
||||
if Nkind (Nxt) = N_Label and then not Formal_Verification_Mode then
|
||||
return;
|
||||
|
@ -2433,10 +2482,10 @@ package body Sem_Ch5 is
|
|||
end if;
|
||||
end if;
|
||||
|
||||
-- If the unconditional transfer of control instruction is
|
||||
-- the last statement of a sequence, then see if our parent
|
||||
-- is one of the constructs for which we count unblocked exits,
|
||||
-- and if so, adjust the count.
|
||||
-- If the unconditional transfer of control instruction is the
|
||||
-- last statement of a sequence, then see if our parent is one of
|
||||
-- the constructs for which we count unblocked exits, and if so,
|
||||
-- adjust the count.
|
||||
|
||||
else
|
||||
P := Parent (N);
|
||||
|
|
Loading…
Reference in New Issue