-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2009, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
--- ware Foundation; either version 2, or (at your option) any later ver- --
+-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
--- Public License distributed with GNAT; see file COPYING. If not, write --
--- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
--- Boston, MA 02110-1301, USA. --
+-- Public License distributed with GNAT; see file COPYING3. If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
with Opt; use Opt;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
+with Sem_Aux; use Sem_Aux;
with Sem_Case; use Sem_Case;
with Sem_Ch3; use Sem_Ch3;
with Sem_Ch8; use Sem_Ch8;
with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
+with Sem_SCIL; use Sem_SCIL;
with Sem_Type; use Sem_Type;
with Sem_Util; use Sem_Util;
with Sem_Warn; use Sem_Warn;
Decl : Node_Id;
procedure Diagnose_Non_Variable_Lhs (N : Node_Id);
- -- N is the node for the left hand side of an assignment, and it
- -- is not a variable. This routine issues an appropriate diagnostic.
+ -- N is the node for the left hand side of an assignment, and it is not
+ -- a variable. This routine issues an appropriate diagnostic.
procedure Kill_Lhs;
-- This is called to kill current value settings of a simple variable
-- Some special bad cases of entity names
elsif Is_Entity_Name (N) then
- if Ekind (Entity (N)) = E_In_Parameter then
- Error_Msg_N
- ("assignment to IN mode parameter not allowed", N);
-
- -- Private declarations in a protected object are turned into
- -- constants when compiling a protected function.
+ declare
+ Ent : constant Entity_Id := Entity (N);
- elsif Present (Scope (Entity (N)))
- and then Is_Protected_Type (Scope (Entity (N)))
- and then
- (Ekind (Current_Scope) = E_Function
- or else
- Ekind (Enclosing_Dynamic_Scope (Current_Scope)) = E_Function)
- then
- Error_Msg_N
- ("protected function cannot modify protected object", N);
+ begin
+ if Ekind (Ent) = E_In_Parameter then
+ Error_Msg_N
+ ("assignment to IN mode parameter not allowed", N);
+
+ -- Renamings of protected private components are turned into
+ -- constants when compiling a protected function. In the case
+ -- of single protected types, the private component appears
+ -- directly.
+
+ elsif (Is_Prival (Ent)
+ and then
+ (Ekind (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)))
+ then
+ Error_Msg_N
+ ("protected function cannot modify protected object", N);
- elsif Ekind (Entity (N)) = E_Loop_Parameter then
- Error_Msg_N
- ("assignment to loop parameter not allowed", N);
+ elsif Ekind (Ent) = E_Loop_Parameter then
+ Error_Msg_N
+ ("assignment to loop parameter not allowed", N);
- else
- Error_Msg_N
- ("left hand side of assignment must be a variable", N);
- end if;
+ else
+ Error_Msg_N
+ ("left hand side of assignment must be a variable", N);
+ end if;
+ end;
-- For indexed components or selected components, test prefix
-- If assignment operand is a component reference, then we get the
-- actual subtype of the component for the unconstrained case.
- elsif
- (Nkind (Opnd) = N_Selected_Component
- or else Nkind (Opnd) = N_Explicit_Dereference)
+ elsif Nkind_In (Opnd, N_Selected_Component, N_Explicit_Dereference)
and then not Is_Unchecked_Union (Opnd_Type)
then
Decl := Build_Actual_Subtype_Of_Component (Opnd_Type, Opnd);
-- Start of processing for Analyze_Assignment
begin
- Mark_Static_Coextensions (Rhs);
+ Mark_Coextensions (N, Rhs);
+
Analyze (Rhs);
Analyze (Lhs);
and then not Assignment_OK (Original_Node (Lhs))
and then not Is_Value_Type (T1)
then
+ -- CPP constructors can only be called in declarations
+
+ if Is_CPP_Constructor_Call (Rhs) then
+ Error_Msg_N ("invalid use of 'C'P'P constructor", Rhs);
+ else
+ Error_Msg_N
+ ("left hand of assignment must not be limited type", Lhs);
+ Explain_Limited_Type (T1, Lhs);
+ end if;
+ return;
+
+ -- Enforce RM 3.9.3 (8): left-hand side cannot be abstract
+
+ elsif Is_Interface (T1)
+ and then not Is_Class_Wide_Type (T1)
+ then
Error_Msg_N
- ("left hand of assignment must not be limited type", Lhs);
- Explain_Limited_Type (T1, Lhs);
+ ("target of assignment operation may not be abstract", Lhs);
return;
end if;
-- This is the point at which we check for an unset reference
Check_Unset_Reference (Rhs);
+ Check_Unprotected_Access (Lhs, Rhs);
-- Remaining steps are skipped if Rhs was syntactically in error
end if;
end if;
- -- Ada 2005 (AI-230 and AI-385): When the lhs type is an anonymous
- -- access type, apply an implicit conversion of the rhs to that type
- -- to force appropriate static and run-time accessibility checks.
+ -- Ada 2005 (AI-385): When the lhs type is an anonymous access type,
+ -- apply an implicit conversion of the rhs to that type to force
+ -- appropriate static and run-time accessibility checks. This applies
+ -- as well to anonymous access-to-subprogram types that are component
+ -- subtypes or formal parameters.
if Ada_Version >= Ada_05
- and then Ekind (T1) = E_Anonymous_Access_Type
+ and then Is_Access_Type (T1)
then
- Rewrite (Rhs, Convert_To (T1, Relocate_Node (Rhs)));
- Analyze_And_Resolve (Rhs, T1);
+ if Is_Local_Anonymous_Access (T1)
+ or else Ekind (T2) = E_Anonymous_Access_Subprogram_Type
+ then
+ Rewrite (Rhs, Convert_To (T1, Relocate_Node (Rhs)));
+ Analyze_And_Resolve (Rhs, T1);
+ end if;
end if;
- -- Ada 2005 (AI-231)
+ -- Ada 2005 (AI-231): Assignment to not null variable
if Ada_Version >= Ada_05
and then Can_Never_Be_Null (T1)
and then not Assignment_OK (Lhs)
then
- if Nkind (Rhs) = N_Null then
+ -- Case where we know the right hand side is null
+
+ if Known_Null (Rhs) then
Apply_Compile_Time_Constraint_Error
(N => Rhs,
- Msg => "(Ada 2005) NULL not allowed in null-excluding objects?",
+ Msg => "(Ada 2005) null not allowed in null-excluding objects?",
Reason => CE_Null_Not_Allowed);
+
+ -- We still mark this as a possible modification, that's necessary
+ -- to reset Is_True_Constant, and desirable for xref purposes.
+
+ Note_Possible_Modification (Lhs, Sure => True);
return;
+ -- If we know the right hand side is non-null, then we convert to the
+ -- target type, since we don't need a run time check in that case.
+
elsif not Can_Never_Be_Null (T2) then
- Rewrite (Rhs,
- Convert_To (T1, Relocate_Node (Rhs)));
+ Rewrite (Rhs, Convert_To (T1, Relocate_Node (Rhs)));
Analyze_And_Resolve (Rhs, T1);
end if;
end if;
-- Note: modifications of the Lhs may only be recorded after
-- checks have been applied.
- Note_Possible_Modification (Lhs);
+ Note_Possible_Modification (Lhs, Sure => True);
-- ??? a real accessibility check is needed when ???
and then Comes_From_Source (N)
- -- Where the entity is the same on both sides
+ -- Where the object is the same on both sides
- and then Is_Entity_Name (Lhs)
- and then Is_Entity_Name (Original_Node (Rhs))
- and then Entity (Lhs) = Entity (Original_Node (Rhs))
+ 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
and then Nkind (Original_Node (Rhs)) not in N_Op
then
- Error_Msg_NE
- ("?useless assignment of & to itself", N, Entity (Lhs));
+ if Nkind (Lhs) in N_Has_Entity then
+ Error_Msg_NE
+ ("?useless assignment of & to itself!", N, Entity (Lhs));
+ else
+ Error_Msg_N
+ ("?useless assignment of object to itself!", N);
+ end if;
end if;
-- Check for non-allowed composite assignment
Check_Elab_Assign (Lhs);
end if;
+ -- Set Referenced_As_LHS if appropriate. We only set this flag if the
+ -- assignment is a source assignment in the extended main source unit.
+ -- We are not interested in any reference information outside this
+ -- context, or in compiler generated assignment statements.
+
+ if Comes_From_Source (N)
+ and then In_Extended_Main_Source_Unit (Lhs)
+ then
+ 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
-- generate bogus warnings when an assignment is rewritten as
-- another assignment, and gets tied up with itself.
+ -- Note: we don't use Record_Last_Assignment here, because we
+ -- have lots of other stuff to do under control of this test.
+
if Warn_On_Modified_Unread
- and then Ekind (Ent) = E_Variable
+ and then Is_Assignable (Ent)
and then Comes_From_Source (N)
and then In_Extended_Main_Source_Unit (Ent)
then
- Warn_On_Useless_Assignment (Ent, Sloc (N));
+ Warn_On_Useless_Assignment (Ent, N);
Set_Last_Assignment (Ent, Lhs);
end if;
begin
-- Initialize unblocked exit count for statements of begin block
- -- plus one for each excption handler that is present.
+ -- plus one for each exception handler that is present.
Unblocked_Exit_Count := 1;
if Present (Decls) then
Analyze_Declarations (Decls);
Check_Completion;
+ Inspect_Deferred_Constant_Completion (Decls);
end if;
Analyze (HSS);
Dont_Care : Boolean;
Others_Present : Boolean;
+ pragma Warnings (Off, Last_Choice);
+ pragma Warnings (Off, Dont_Care);
+ -- 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
procedure Non_Static_Choice_Error (Choice : Node_Id);
-- Error routine invoked by the generic instantiation below when
- -- the case statment has a non static choice.
+ -- the case statement has a non static choice.
procedure Process_Statements (Alternative : Node_Id);
-- Analyzes all the statements associated to a case alternative.
-- a call to Number_Of_Choices to get the right number of entries.
Case_Table : Choice_Table_Type (1 .. Number_Of_Choices (N));
+ pragma Warnings (Off, Case_Table);
-- Start of processing for Analyze_Case_Statement
begin
Alt := First (Alternatives (N));
-
while Present (Alt) loop
if Alt /= Chosen then
Remove_Warning_Messages (Statements (Alt));
Analyze_And_Resolve (Cond, Any_Boolean);
Check_Unset_Reference (Cond);
end if;
+
+ -- Since the exit may take us out of a loop, any previous assignment
+ -- statement is not useless, so clear last assignment indications. It
+ -- is OK to keep other current values, since if the exit statement
+ -- does not exit, then the current values are still valid.
+
+ Kill_Current_Values (Last_Assignment_Only => True);
end Analyze_Exit_Statement;
----------------------------
begin
Check_Unreachable_Code (N);
+ Kill_Current_Values (Last_Assignment_Only => True);
Analyze (Label);
Label_Ent := Entity (Label);
if Present (Elsif_Parts (N)) then
E := First (Elsif_Parts (N));
-
while Present (E) loop
Remove_Warning_Messages (Then_Statements (E));
Next (E);
function One_Bound
(Original_Bound : Node_Id;
Analyzed_Bound : Node_Id) return Node_Id;
- -- Create one declaration followed by one assignment statement
- -- to capture the value of bound. We create a separate assignment
- -- in order to force the creation of a block in case the bound
- -- contains a call that uses the secondary stack.
+ -- Capture value of bound and return captured value
---------------
-- One_Bound --
if Analyzed (Original_Bound) then
return Original_Bound;
- elsif Nkind (Analyzed_Bound) = N_Integer_Literal
- or else Nkind (Analyzed_Bound) = N_Character_Literal
+ elsif Nkind_In (Analyzed_Bound, N_Integer_Literal,
+ N_Character_Literal)
or else Is_Entity_Name (Analyzed_Bound)
then
Analyze_And_Resolve (Original_Bound, Typ);
return Original_Bound;
-
- else
- Analyze_And_Resolve (Original_Bound, Typ);
end if;
+ -- Here we need to capture the value
+
+ Analyze_And_Resolve (Original_Bound, Typ);
+
Id :=
Make_Defining_Identifier (Loc,
Chars => New_Internal_Name ('S'));
+ -- 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
+ -- possible use of the secondary stack, we need to generate a
+ -- separate assignment statement to ensure the creation of a block
+ -- which will release the secondary stack.
+
+ -- We prefer the constant declaration, since it leaves us with a
+ -- 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_Before (Parent (N), Decl);
+ Analyze (Decl);
+ Rewrite (Original_Bound, New_Occurrence_Of (Id, Loc));
+ return Expression (Decl);
+ end if;
+
+ -- Here we make a declaration with a separate assignment statement
+
Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Id,
Name => New_Occurrence_Of (Id, Loc),
Expression => Relocate_Node (Original_Bound));
+ -- If the relocated node is a function call then check if some
+ -- SCIL node references it and needs readjustment.
+
+ if Generate_SCIL
+ and then Nkind (Original_Bound) = N_Function_Call
+ then
+ Adjust_SCIL_Node (Original_Bound, Expression (Assign));
+ end if;
+
Insert_Before (Parent (N), Assign);
Analyze (Assign);
Set_Ekind (Id, E_Loop_Parameter);
Set_Etype (Id, Etype (DS));
+
+ -- Treat a range as an implicit reference to the type, to
+ -- inhibit spurious warnings.
+
+ Generate_Reference (Base_Type (Etype (DS)), N, ' ');
Set_Is_Known_Valid (Id, True);
-- The loop is not a declarative part, so the only entity
L : constant Node_Id := Low_Bound (DS);
H : constant Node_Id := High_Bound (DS);
- Llo : Uint;
- Lhi : Uint;
- LOK : Boolean;
- Hlo : Uint;
- Hhi : Uint;
- HOK : Boolean;
-
begin
- Determine_Range (L, LOK, Llo, Lhi);
- Determine_Range (H, HOK, Hlo, Hhi);
-
-- If range of loop is null, issue warning
- if (LOK and HOK) and then Llo > Hhi then
-
+ if Compile_Time_Compare
+ (L, H, Assume_Valid => True) = GT
+ then
-- Suppress the warning if inside a generic
-- template or instance, since in practice
-- they tend to be dubious in these cases since
if not Inside_A_Generic
and then not In_Instance
then
- Error_Msg_N
- ("?loop range is null, loop will not execute",
- DS);
+ -- Specialize msg if invalid values could make
+ -- the loop non-null after all.
+
+ if Compile_Time_Compare
+ (L, H, Assume_Valid => False) = GT
+ then
+ Error_Msg_N
+ ("?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.
+
+ Set_Is_Null_Loop (Parent (N));
+
+ -- Here is where the loop could execute because
+ -- of invalid values, so issue appropriate
+ -- message and in this case we do not set the
+ -- Is_Null_Loop flag since the loop may execute.
+
+ else
+ Error_Msg_N
+ ("?loop range may be null, "
+ & "loop may not execute",
+ DS);
+ Error_Msg_N
+ ("?can only execute if invalid values "
+ & "are present",
+ DS);
+ end if;
end if;
- -- Since we know the range of the loop is null,
- -- set the appropriate flag to suppress any
- -- warnings that would otherwise be issued in
- -- the body of the loop that will not execute.
- -- We do this even in the generic case, since
- -- if it is dubious to warn on the null loop
- -- itself, it is certainly dubious to warn for
- -- conditions that occur inside it!
+ -- In either case, suppress warnings in the body of
+ -- the loop, since it is likely that these warnings
+ -- will be inappropriate if the loop never actually
+ -- executes, which is unlikely.
- Set_Is_Null_Loop (Parent (N));
+ Set_Suppress_Loop_Warnings (Parent (N));
-- The other case for a warning is a reverse loop
-- where the upper bound is the integer literal
elsif Reverse_Present (LP)
and then Nkind (Original_Node (H)) =
N_Integer_Literal
- and then (Intval (H) = Uint_0
+ and then (Intval (Original_Node (H)) = Uint_0
or else
- Intval (H) = Uint_1)
- and then Lhi > Hhi
+ Intval (Original_Node (H)) = Uint_1)
then
Error_Msg_N ("?loop range may be null", DS);
Error_Msg_N ("\?bounds may be wrong way round", DS);
Analyze (Id);
Ent := Entity (Id);
- Generate_Reference (Ent, Loop_Statement, ' ');
- Generate_Definition (Ent);
- -- If we found a label, mark its type. If not, ignore it, since it
- -- means we have a conflicting declaration, which would already have
- -- been diagnosed at declaration time. Set Label_Construct of the
- -- implicit label declaration, which is not created by the parser
- -- for generic units.
+ -- Guard against serious error (typically, a scope mismatch when
+ -- semantic analysis is requested) by creating loop entity to
+ -- continue analysis.
+
+ if No (Ent) then
+ if Total_Errors_Detected /= 0 then
+ Ent :=
+ New_Internal_Entity
+ (E_Loop, Current_Scope, Sloc (Loop_Statement), 'L');
+ else
+ raise Program_Error;
+ end if;
+
+ else
+ Generate_Reference (Ent, Loop_Statement, ' ');
+ Generate_Definition (Ent);
- if Ekind (Ent) = E_Label then
- Set_Ekind (Ent, E_Loop);
+ -- If we found a label, mark its type. If not, ignore it, since it
+ -- means we have a conflicting declaration, which would already
+ -- have been diagnosed at declaration time. Set Label_Construct
+ -- of the implicit label declaration, which is not created by the
+ -- parser for generic units.
- if Nkind (Parent (Ent)) = N_Implicit_Label_Declaration then
- Set_Label_Construct (Parent (Ent), Loop_Statement);
+ if Ekind (Ent) = E_Label then
+ Set_Ekind (Ent, E_Loop);
+
+ if Nkind (Parent (Ent)) = N_Implicit_Label_Declaration then
+ Set_Label_Construct (Parent (Ent), Loop_Statement);
+ end if;
end if;
end if;
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 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;
Push_Scope (Ent);
Process_End_Label (Loop_Statement, 'e', Ent);
End_Scope;
Kill_Current_Values;
- Check_Infinite_Loop_Warning (N);
+
+ -- Check for infinite loop. We skip this check for generated code, since
+ -- it justs waste time and makes debugging the routine called harder.
+
+ if Comes_From_Source (N) then
+ 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.
+
+ if No (Iter) and then not Has_Exit (Ent) then
+ Check_Unreachable_Code (N);
+ end if;
end Analyze_Loop_Statement;
----------------------------
-- the Ada RM annoyingly requires a useless return here!
if Nkind (Original_Node (N)) /= N_Raise_Statement
- or else Nkind (Nxt) /= N_Return_Statement
+ or else Nkind (Nxt) /= N_Simple_Return_Statement
then
-- The rather strange shenanigans with the warning message
-- here reflects the fact that Kill_Dead_Code is very good
-- Now issue the warning
- Error_Msg ("?unreachable code", Error_Loc);
+ Error_Msg ("?unreachable code!", Error_Loc);
end if;
-- If the unconditional transfer of control instruction is