blob: 4fe9007aacbe8473a4512432f907bb2ed72ab01c [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ P R A G --
-- --
-- B o d y --
-- --
-- Copyright (C) 1992-2015, 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 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 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. --
-- --
------------------------------------------------------------------------------
-- This unit contains the semantic processing for all pragmas, both language
-- and implementation defined. For most pragmas, the parser only does the
-- most basic job of checking the syntax, so Sem_Prag also contains the code
-- to complete the syntax checks. Certain pragmas are handled partially or
-- completely by the parser (see Par.Prag for further details).
with Aspects; use Aspects;
with Atree; use Atree;
with Casing; use Casing;
with Checks; use Checks;
with Csets; use Csets;
with Debug; use Debug;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
with Exp_Dist; use Exp_Dist;
with Exp_Util; use Exp_Util;
with Freeze; use Freeze;
with Ghost; use Ghost;
with Lib; use Lib;
with Lib.Writ; use Lib.Writ;
with Lib.Xref; use Lib.Xref;
with Namet.Sp; use Namet.Sp;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Output; use Output;
with Par_SCO; use Par_SCO;
with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Ch3; use Sem_Ch3;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch12; use Sem_Ch12;
with Sem_Ch13; use Sem_Ch13;
with Sem_Disp; use Sem_Disp;
with Sem_Dist; use Sem_Dist;
with Sem_Elim; use Sem_Elim;
with Sem_Eval; use Sem_Eval;
with Sem_Intr; use Sem_Intr;
with Sem_Mech; use Sem_Mech;
with Sem_Res; use Sem_Res;
with Sem_Type; use Sem_Type;
with Sem_Util; use Sem_Util;
with Sem_Warn; use Sem_Warn;
with Stand; use Stand;
with Sinfo; use Sinfo;
with Sinfo.CN; use Sinfo.CN;
with Sinput; use Sinput;
with Stringt; use Stringt;
with Stylesw; use Stylesw;
with Table;
with Targparm; use Targparm;
with Tbuild; use Tbuild;
with Ttypes;
with Uintp; use Uintp;
with Uname; use Uname;
with Urealp; use Urealp;
with Validsw; use Validsw;
with Warnsw; use Warnsw;
package body Sem_Prag is
----------------------------------------------
-- Common Handling of Import-Export Pragmas --
----------------------------------------------
-- In the following section, a number of Import_xxx and Export_xxx pragmas
-- are defined by GNAT. These are compatible with the DEC pragmas of the
-- same name, and all have the following common form and processing:
-- pragma Export_xxx
-- [Internal =>] LOCAL_NAME
-- [, [External =>] EXTERNAL_SYMBOL]
-- [, other optional parameters ]);
-- pragma Import_xxx
-- [Internal =>] LOCAL_NAME
-- [, [External =>] EXTERNAL_SYMBOL]
-- [, other optional parameters ]);
-- EXTERNAL_SYMBOL ::=
-- IDENTIFIER
-- | static_string_EXPRESSION
-- The internal LOCAL_NAME designates the entity that is imported or
-- exported, and must refer to an entity in the current declarative
-- part (as required by the rules for LOCAL_NAME).
-- The external linker name is designated by the External parameter if
-- given, or the Internal parameter if not (if there is no External
-- parameter, the External parameter is a copy of the Internal name).
-- If the External parameter is given as a string, then this string is
-- treated as an external name (exactly as though it had been given as an
-- External_Name parameter for a normal Import pragma).
-- If the External parameter is given as an identifier (or there is no
-- External parameter, so that the Internal identifier is used), then
-- the external name is the characters of the identifier, translated
-- to all lower case letters.
-- Note: the external name specified or implied by any of these special
-- Import_xxx or Export_xxx pragmas override an external or link name
-- specified in a previous Import or Export pragma.
-- Note: these and all other DEC-compatible GNAT pragmas allow full use of
-- named notation, following the standard rules for subprogram calls, i.e.
-- parameters can be given in any order if named notation is used, and
-- positional and named notation can be mixed, subject to the rule that all
-- positional parameters must appear first.
-- Note: All these pragmas are implemented exactly following the DEC design
-- and implementation and are intended to be fully compatible with the use
-- of these pragmas in the DEC Ada compiler.
--------------------------------------------
-- Checking for Duplicated External Names --
--------------------------------------------
-- It is suspicious if two separate Export pragmas use the same external
-- name. The following table is used to diagnose this situation so that
-- an appropriate warning can be issued.
-- The Node_Id stored is for the N_String_Literal node created to hold
-- the value of the external name. The Sloc of this node is used to
-- cross-reference the location of the duplication.
package Externals is new Table.Table (
Table_Component_Type => Node_Id,
Table_Index_Type => Int,
Table_Low_Bound => 0,
Table_Initial => 100,
Table_Increment => 100,
Table_Name => "Name_Externals");
-------------------------------------
-- Local Subprograms and Variables --
-------------------------------------
procedure Add_Item (Item : Entity_Id; To_List : in out Elist_Id);
-- Subsidiary routine to the analysis of pragmas Depends, Global and
-- Refined_State. Append an entity to a list. If the list is empty, create
-- a new list.
function Adjust_External_Name_Case (N : Node_Id) return Node_Id;
-- This routine is used for possible casing adjustment of an explicit
-- external name supplied as a string literal (the node N), according to
-- the casing requirement of Opt.External_Name_Casing. If this is set to
-- As_Is, then the string literal is returned unchanged, but if it is set
-- to Uppercase or Lowercase, then a new string literal with appropriate
-- casing is constructed.
function Appears_In (List : Elist_Id; Item_Id : Entity_Id) return Boolean;
-- Subsidiary to analysis of pragmas Depends, Global and Refined_Depends.
-- Query whether a particular item appears in a mixed list of nodes and
-- entities. It is assumed that all nodes in the list have entities.
function Check_Kind (Nam : Name_Id) return Name_Id;
-- This function is used in connection with pragmas Assert, Check,
-- and assertion aspects and pragmas, to determine if Check pragmas
-- (or corresponding assertion aspects or pragmas) are currently active
-- as determined by the presence of -gnata on the command line (which
-- sets the default), and the appearance of pragmas Check_Policy and
-- Assertion_Policy as configuration pragmas either in a configuration
-- pragma file, or at the start of the current unit, or locally given
-- Check_Policy and Assertion_Policy pragmas that are currently active.
--
-- The value returned is one of the names Check, Ignore, Disable (On
-- returns Check, and Off returns Ignore).
--
-- Note: for assertion kinds Pre'Class, Post'Class, Invariant'Class,
-- and Type_Invariant'Class, the name passed is Name_uPre, Name_uPost,
-- Name_uInvariant, or Name_uType_Invariant, which corresponds to _Pre,
-- _Post, _Invariant, or _Type_Invariant, which are special names used
-- in identifiers to represent these attribute references.
procedure Check_Postcondition_Use_In_Inlined_Subprogram
(Prag : Node_Id;
Subp_Id : Entity_Id);
-- Subsidiary to the analysis of pragmas Contract_Cases, Postcondition,
-- Precondition, Refined_Post and Test_Case. Emit a warning when pragma
-- Prag is associated with subprogram Subp_Id subject to Inline_Always.
procedure Check_State_And_Constituent_Use
(States : Elist_Id;
Constits : Elist_Id;
Context : Node_Id);
-- Subsidiary to the analysis of pragmas [Refined_]Depends, [Refined_]
-- Global and Initializes. Determine whether a state from list States and a
-- corresponding constituent from list Constits (if any) appear in the same
-- context denoted by Context. If this is the case, emit an error.
procedure Duplication_Error (Prag : Node_Id; Prev : Node_Id);
-- Subsidiary to routines Find_Related_Package_Or_Body and
-- Find_Related_Subprogram_Or_Body. Emit an error on pragma Prag that
-- duplicates previous pragma Prev.
function Find_Related_Package_Or_Body
(Prag : Node_Id;
Do_Checks : Boolean := False) return Node_Id;
-- Subsidiary to the analysis of pragmas Abstract_State, Initial_Condition,
-- Initializes and Refined_State. Find the declaration of the related
-- package [body] subject to pragma Prag. The return value is either
-- N_Package_Declaration, N_Package_Body or Empty if the placement of
-- the pragma is illegal. If flag Do_Checks is set, the routine reports
-- duplicate pragmas.
function Get_Argument
(Prag : Node_Id;
Spec_Id : Entity_Id := Empty) return Node_Id;
-- Obtain the argument of pragma Prag depending on context and the nature
-- of the pragma. The argument is extracted in the following manner:
--
-- When the pragma is generated from an aspect, return the corresponding
-- aspect for ASIS or when Spec_Id denotes a generic subprogram.
--
-- Otherwise return the first argument of Prag
--
-- Spec_Id denotes the entity of the subprogram spec where Prag resides
function Get_Base_Subprogram (Def_Id : Entity_Id) return Entity_Id;
-- If Def_Id refers to a renamed subprogram, then the base subprogram (the
-- original one, following the renaming chain) is returned. Otherwise the
-- entity is returned unchanged. Should be in Einfo???
function Get_SPARK_Mode_Type (N : Name_Id) return SPARK_Mode_Type;
-- Subsidiary to the analysis of pragma SPARK_Mode as well as subprogram
-- Get_SPARK_Mode_Type. Convert a name into a corresponding value of type
-- SPARK_Mode_Type.
function Has_Extra_Parentheses (Clause : Node_Id) return Boolean;
-- Subsidiary to the analysis of pragmas Depends and Refined_Depends.
-- Determine whether dependency clause Clause is surrounded by extra
-- parentheses. If this is the case, issue an error message.
function Is_Unconstrained_Or_Tagged_Item (Item : Entity_Id) return Boolean;
-- Subsidiary to Collect_Subprogram_Inputs_Outputs and the analysis of
-- pragma Depends. Determine whether the type of dependency item Item is
-- tagged, unconstrained array, unconstrained record or a record with at
-- least one unconstrained component.
procedure Record_Possible_Body_Reference
(State_Id : Entity_Id;
Ref : Node_Id);
-- Subsidiary to the analysis of pragmas [Refined_]Depends and [Refined_]
-- Global. Given an abstract state denoted by State_Id and a reference Ref
-- to it, determine whether the reference appears in a package body that
-- will eventually refine the state. If this is the case, record the
-- reference for future checks (see Analyze_Refined_State_In_Decls).
procedure Resolve_State (N : Node_Id);
-- Handle the overloading of state names by functions. When N denotes a
-- function, this routine finds the corresponding state and sets the entity
-- of N to that of the state.
procedure Rewrite_Assertion_Kind (N : Node_Id);
-- If N is Pre'Class, Post'Class, Invariant'Class, or Type_Invariant'Class,
-- then it is rewritten as an identifier with the corresponding special
-- name _Pre, _Post, _Invariant, or _Type_Invariant. Used by pragmas Check
-- and Check_Policy.
procedure Set_Elab_Unit_Name (N : Node_Id; With_Item : Node_Id);
-- Place semantic information on the argument of an Elaborate/Elaborate_All
-- pragma. Entity name for unit and its parents is taken from item in
-- previous with_clause that mentions the unit.
Dummy : Integer := 0;
pragma Volatile (Dummy);
-- Dummy volatile integer used in bodies of ip/rv to prevent optimization
procedure ip;
pragma No_Inline (ip);
-- A dummy procedure called when pragma Inspection_Point is analyzed. This
-- is just to help debugging the front end. If a pragma Inspection_Point
-- is added to a source program, then breaking on ip will get you to that
-- point in the program.
procedure rv;
pragma No_Inline (rv);
-- This is a dummy function called by the processing for pragma Reviewable.
-- It is there for assisting front end debugging. By placing a Reviewable
-- pragma in the source program, a breakpoint on rv catches this place in
-- the source, allowing convenient stepping to the point of interest.
--------------
-- Add_Item --
--------------
procedure Add_Item (Item : Entity_Id; To_List : in out Elist_Id) is
begin
Append_New_Elmt (Item, To => To_List);
end Add_Item;
-------------------------------
-- Adjust_External_Name_Case --
-------------------------------
function Adjust_External_Name_Case (N : Node_Id) return Node_Id is
CC : Char_Code;
begin
-- Adjust case of literal if required
if Opt.External_Name_Exp_Casing = As_Is then
return N;
else
-- Copy existing string
Start_String;
-- Set proper casing
for J in 1 .. String_Length (Strval (N)) loop
CC := Get_String_Char (Strval (N), J);
if Opt.External_Name_Exp_Casing = Uppercase
and then CC >= Get_Char_Code ('a')
and then CC <= Get_Char_Code ('z')
then
Store_String_Char (CC - 32);
elsif Opt.External_Name_Exp_Casing = Lowercase
and then CC >= Get_Char_Code ('A')
and then CC <= Get_Char_Code ('Z')
then
Store_String_Char (CC + 32);
else
Store_String_Char (CC);
end if;
end loop;
return
Make_String_Literal (Sloc (N),
Strval => End_String);
end if;
end Adjust_External_Name_Case;
-----------------------------------------
-- Analyze_Contract_Cases_In_Decl_Part --
-----------------------------------------
procedure Analyze_Contract_Cases_In_Decl_Part (N : Node_Id) is
Others_Seen : Boolean := False;
procedure Analyze_Contract_Case (CCase : Node_Id);
-- Verify the legality of a single contract case
---------------------------
-- Analyze_Contract_Case --
---------------------------
procedure Analyze_Contract_Case (CCase : Node_Id) is
Case_Guard : Node_Id;
Conseq : Node_Id;
Extra_Guard : Node_Id;
begin
if Nkind (CCase) = N_Component_Association then
Case_Guard := First (Choices (CCase));
Conseq := Expression (CCase);
-- Each contract case must have exactly one case guard
Extra_Guard := Next (Case_Guard);
if Present (Extra_Guard) then
Error_Msg_N
("contract case must have exactly one case guard",
Extra_Guard);
end if;
-- Check placement of OTHERS if available (SPARK RM 6.1.3(1))
if Nkind (Case_Guard) = N_Others_Choice then
if Others_Seen then
Error_Msg_N
("only one others choice allowed in contract cases",
Case_Guard);
else
Others_Seen := True;
end if;
elsif Others_Seen then
Error_Msg_N
("others must be the last choice in contract cases", N);
end if;
-- Preanalyze the case guard and consequence
if Nkind (Case_Guard) /= N_Others_Choice then
Preanalyze_Assert_Expression (Case_Guard, Standard_Boolean);
end if;
Preanalyze_Assert_Expression (Conseq, Standard_Boolean);
-- The contract case is malformed
else
Error_Msg_N ("wrong syntax in contract case", CCase);
end if;
end Analyze_Contract_Case;
-- Local variables
All_Cases : Node_Id;
CCase : Node_Id;
Spec_Id : Entity_Id;
Subp_Decl : Node_Id;
Subp_Id : Entity_Id;
Restore_Scope : Boolean := False;
-- Gets set True if we do a Push_Scope needing a Pop_Scope on exit
-- Start of processing for Analyze_Contract_Cases_In_Decl_Part
begin
Set_Analyzed (N);
Subp_Decl := Find_Related_Subprogram_Or_Body (N);
Spec_Id := Corresponding_Spec_Of (Subp_Decl);
Subp_Id := Defining_Entity (Subp_Decl);
All_Cases := Expression (Get_Argument (N, Subp_Id));
-- Single and multiple contract cases must appear in aggregate form. If
-- this is not the case, then either the parser of the analysis of the
-- pragma failed to produce an aggregate.
pragma Assert (Nkind (All_Cases) = N_Aggregate);
if Present (Component_Associations (All_Cases)) then
-- Ensure that the formal parameters are visible when analyzing all
-- clauses. This falls out of the general rule of aspects pertaining
-- to subprogram declarations. Skip the installation for subprogram
-- bodies because the formals are already visible.
if not In_Open_Scopes (Spec_Id) then
Restore_Scope := True;
Push_Scope (Spec_Id);
if Is_Generic_Subprogram (Spec_Id) then
Install_Generic_Formals (Spec_Id);
else
Install_Formals (Spec_Id);
end if;
end if;
CCase := First (Component_Associations (All_Cases));
while Present (CCase) loop
Analyze_Contract_Case (CCase);
Next (CCase);
end loop;
-- Currently it is not possible to inline pre/postconditions on a
-- subprogram subject to pragma Inline_Always.
Check_Postcondition_Use_In_Inlined_Subprogram (N, Spec_Id);
if Restore_Scope then
End_Scope;
end if;
else
Error_Msg_N ("wrong syntax for constract cases", N);
end if;
end Analyze_Contract_Cases_In_Decl_Part;
----------------------------------
-- Analyze_Depends_In_Decl_Part --
----------------------------------
procedure Analyze_Depends_In_Decl_Part (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
All_Inputs_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all the inputs processed so far.
-- The list is populated with unique entities because the same input
-- may appear in multiple input lists.
All_Outputs_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all the outputs processed so far.
-- The list is populated with unique entities because output items are
-- unique in a dependence relation.
Constits_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all constituents processed so far.
-- It aids in detecting illegal usage of a state and a corresponding
-- constituent in pragma [Refinde_]Depends.
Global_Seen : Boolean := False;
-- A flag set when pragma Global has been processed
Null_Output_Seen : Boolean := False;
-- A flag used to track the legality of a null output
Result_Seen : Boolean := False;
-- A flag set when Subp_Id'Result is processed
Spec_Id : Entity_Id;
-- The entity of the subprogram subject to pragma [Refined_]Depends
States_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all states processed so far. It
-- helps in detecting illegal usage of a state and a corresponding
-- constituent in pragma [Refined_]Depends.
Subp_Id : Entity_Id;
-- The entity of the subprogram [body or stub] subject to pragma
-- [Refined_]Depends.
Subp_Inputs : Elist_Id := No_Elist;
Subp_Outputs : Elist_Id := No_Elist;
-- Two lists containing the full set of inputs and output of the related
-- subprograms. Note that these lists contain both nodes and entities.
procedure Add_Item_To_Name_Buffer (Item_Id : Entity_Id);
-- Subsidiary routine to Check_Role and Check_Usage. Add the item kind
-- to the name buffer. The individual kinds are as follows:
-- E_Abstract_State - "state"
-- E_In_Parameter - "parameter"
-- E_In_Out_Parameter - "parameter"
-- E_Out_Parameter - "parameter"
-- E_Variable - "global"
procedure Analyze_Dependency_Clause
(Clause : Node_Id;
Is_Last : Boolean);
-- Verify the legality of a single dependency clause. Flag Is_Last
-- denotes whether Clause is the last clause in the relation.
procedure Check_Function_Return;
-- Verify that Funtion'Result appears as one of the outputs
-- (SPARK RM 6.1.5(10)).
procedure Check_Role
(Item : Node_Id;
Item_Id : Entity_Id;
Is_Input : Boolean;
Self_Ref : Boolean);
-- Ensure that an item fulfils its designated input and/or output role
-- as specified by pragma Global (if any) or the enclosing context. If
-- this is not the case, emit an error. Item and Item_Id denote the
-- attributes of an item. Flag Is_Input should be set when item comes
-- from an input list. Flag Self_Ref should be set when the item is an
-- output and the dependency clause has operator "+".
procedure Check_Usage
(Subp_Items : Elist_Id;
Used_Items : Elist_Id;
Is_Input : Boolean);
-- Verify that all items from Subp_Items appear in Used_Items. Emit an
-- error if this is not the case.
procedure Normalize_Clause (Clause : Node_Id);
-- Remove a self-dependency "+" from the input list of a clause
-----------------------------
-- Add_Item_To_Name_Buffer --
-----------------------------
procedure Add_Item_To_Name_Buffer (Item_Id : Entity_Id) is
begin
if Ekind (Item_Id) = E_Abstract_State then
Add_Str_To_Name_Buffer ("state");
elsif Is_Formal (Item_Id) then
Add_Str_To_Name_Buffer ("parameter");
elsif Ekind (Item_Id) = E_Variable then
Add_Str_To_Name_Buffer ("global");
-- The routine should not be called with non-SPARK items
else
raise Program_Error;
end if;
end Add_Item_To_Name_Buffer;
-------------------------------
-- Analyze_Dependency_Clause --
-------------------------------
procedure Analyze_Dependency_Clause
(Clause : Node_Id;
Is_Last : Boolean)
is
procedure Analyze_Input_List (Inputs : Node_Id);
-- Verify the legality of a single input list
procedure Analyze_Input_Output
(Item : Node_Id;
Is_Input : Boolean;
Self_Ref : Boolean;
Top_Level : Boolean;
Seen : in out Elist_Id;
Null_Seen : in out Boolean;
Non_Null_Seen : in out Boolean);
-- Verify the legality of a single input or output item. Flag
-- Is_Input should be set whenever Item is an input, False when it
-- denotes an output. Flag Self_Ref should be set when the item is an
-- output and the dependency clause has a "+". Flag Top_Level should
-- be set whenever Item appears immediately within an input or output
-- list. Seen is a collection of all abstract states, variables and
-- formals processed so far. Flag Null_Seen denotes whether a null
-- input or output has been encountered. Flag Non_Null_Seen denotes
-- whether a non-null input or output has been encountered.
------------------------
-- Analyze_Input_List --
------------------------
procedure Analyze_Input_List (Inputs : Node_Id) is
Inputs_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all inputs that appear in the
-- current input list.
Non_Null_Input_Seen : Boolean := False;
Null_Input_Seen : Boolean := False;
-- Flags used to check the legality of an input list
Input : Node_Id;
begin
-- Multiple inputs appear as an aggregate
if Nkind (Inputs) = N_Aggregate then
if Present (Component_Associations (Inputs)) then
SPARK_Msg_N
("nested dependency relations not allowed", Inputs);
elsif Present (Expressions (Inputs)) then
Input := First (Expressions (Inputs));
while Present (Input) loop
Analyze_Input_Output
(Item => Input,
Is_Input => True,
Self_Ref => False,
Top_Level => False,
Seen => Inputs_Seen,
Null_Seen => Null_Input_Seen,
Non_Null_Seen => Non_Null_Input_Seen);
Next (Input);
end loop;
-- Syntax error, always report
else
Error_Msg_N ("malformed input dependency list", Inputs);
end if;
-- Process a solitary input
else
Analyze_Input_Output
(Item => Inputs,
Is_Input => True,
Self_Ref => False,
Top_Level => False,
Seen => Inputs_Seen,
Null_Seen => Null_Input_Seen,
Non_Null_Seen => Non_Null_Input_Seen);
end if;
-- Detect an illegal dependency clause of the form
-- (null =>[+] null)
if Null_Output_Seen and then Null_Input_Seen then
SPARK_Msg_N
("null dependency clause cannot have a null input list",
Inputs);
end if;
end Analyze_Input_List;
--------------------------
-- Analyze_Input_Output --
--------------------------
procedure Analyze_Input_Output
(Item : Node_Id;
Is_Input : Boolean;
Self_Ref : Boolean;
Top_Level : Boolean;
Seen : in out Elist_Id;
Null_Seen : in out Boolean;
Non_Null_Seen : in out Boolean)
is
Is_Output : constant Boolean := not Is_Input;
Grouped : Node_Id;
Item_Id : Entity_Id;
begin
-- Multiple input or output items appear as an aggregate
if Nkind (Item) = N_Aggregate then
if not Top_Level then
SPARK_Msg_N ("nested grouping of items not allowed", Item);
elsif Present (Component_Associations (Item)) then
SPARK_Msg_N
("nested dependency relations not allowed", Item);
-- Recursively analyze the grouped items
elsif Present (Expressions (Item)) then
Grouped := First (Expressions (Item));
while Present (Grouped) loop
Analyze_Input_Output
(Item => Grouped,
Is_Input => Is_Input,
Self_Ref => Self_Ref,
Top_Level => False,
Seen => Seen,
Null_Seen => Null_Seen,
Non_Null_Seen => Non_Null_Seen);
Next (Grouped);
end loop;
-- Syntax error, always report
else
Error_Msg_N ("malformed dependency list", Item);
end if;
-- Process Function'Result in the context of a dependency clause
elsif Is_Attribute_Result (Item) then
Non_Null_Seen := True;
-- It is sufficent to analyze the prefix of 'Result in order to
-- establish legality of the attribute.
Analyze (Prefix (Item));
-- The prefix of 'Result must denote the function for which
-- pragma Depends applies (SPARK RM 6.1.5(11)).
if not Is_Entity_Name (Prefix (Item))
or else Ekind (Spec_Id) /= E_Function
or else Entity (Prefix (Item)) /= Spec_Id
then
Error_Msg_Name_1 := Name_Result;
SPARK_Msg_N
("prefix of attribute % must denote the enclosing "
& "function", Item);
-- Function'Result is allowed to appear on the output side of a
-- dependency clause (SPARK RM 6.1.5(6)).
elsif Is_Input then
SPARK_Msg_N ("function result cannot act as input", Item);
elsif Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null dependency items", Item);
else
Result_Seen := True;
end if;
-- Detect multiple uses of null in a single dependency list or
-- throughout the whole relation. Verify the placement of a null
-- output list relative to the other clauses (SPARK RM 6.1.5(12)).
elsif Nkind (Item) = N_Null then
if Null_Seen then
SPARK_Msg_N
("multiple null dependency relations not allowed", Item);
elsif Non_Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null dependency items", Item);
else
Null_Seen := True;
if Is_Output then
if not Is_Last then
SPARK_Msg_N
("null output list must be the last clause in a "
& "dependency relation", Item);
-- Catch a useless dependence of the form:
-- null =>+ ...
elsif Self_Ref then
SPARK_Msg_N
("useless dependence, null depends on itself", Item);
end if;
end if;
end if;
-- Default case
else
Non_Null_Seen := True;
if Null_Seen then
SPARK_Msg_N ("cannot mix null and non-null items", Item);
end if;
Analyze (Item);
Resolve_State (Item);
-- Find the entity of the item. If this is a renaming, climb
-- the renaming chain to reach the root object. Renamings of
-- non-entire objects do not yield an entity (Empty).
Item_Id := Entity_Of (Item);
if Present (Item_Id) then
if Ekind_In (Item_Id, E_Abstract_State,
E_In_Parameter,
E_In_Out_Parameter,
E_Out_Parameter,
E_Variable)
then
-- Ensure that the item fulfils its role as input and/or
-- output as specified by pragma Global or the enclosing
-- context.
Check_Role (Item, Item_Id, Is_Input, Self_Ref);
-- Detect multiple uses of the same state, variable or
-- formal parameter. If this is not the case, add the
-- item to the list of processed relations.
if Contains (Seen, Item_Id) then
SPARK_Msg_NE
("duplicate use of item &", Item, Item_Id);
else
Add_Item (Item_Id, Seen);
end if;
-- Detect illegal use of an input related to a null
-- output. Such input items cannot appear in other
-- input lists (SPARK RM 6.1.5(13)).
if Is_Input
and then Null_Output_Seen
and then Contains (All_Inputs_Seen, Item_Id)
then
SPARK_Msg_N
("input of a null output list cannot appear in "
& "multiple input lists", Item);
end if;
-- Add an input or a self-referential output to the list
-- of all processed inputs.
if Is_Input or else Self_Ref then
Add_Item (Item_Id, All_Inputs_Seen);
end if;
-- State related checks (SPARK RM 6.1.5(3))
if Ekind (Item_Id) = E_Abstract_State then
if Has_Visible_Refinement (Item_Id) then
SPARK_Msg_NE
("cannot mention state & in global refinement",
Item, Item_Id);
SPARK_Msg_N ("\use its constituents instead", Item);
return;
-- If the reference to the abstract state appears in
-- an enclosing package body that will eventually
-- refine the state, record the reference for future
-- checks.
else
Record_Possible_Body_Reference
(State_Id => Item_Id,
Ref => Item);
end if;
end if;
-- When the item renames an entire object, replace the
-- item with a reference to the object.
if Present (Renamed_Object (Entity (Item))) then
Rewrite (Item,
New_Occurrence_Of (Item_Id, Sloc (Item)));
Analyze (Item);
end if;
-- Add the entity of the current item to the list of
-- processed items.
if Ekind (Item_Id) = E_Abstract_State then
Add_Item (Item_Id, States_Seen);
end if;
if Ekind_In (Item_Id, E_Abstract_State, E_Variable)
and then Present (Encapsulating_State (Item_Id))
then
Add_Item (Item_Id, Constits_Seen);
end if;
-- All other input/output items are illegal
-- (SPARK RM 6.1.5(1)).
else
SPARK_Msg_N
("item must denote parameter, variable, or state",
Item);
end if;
-- All other input/output items are illegal
-- (SPARK RM 6.1.5(1)). This is a syntax error, always report.
else
Error_Msg_N
("item must denote parameter, variable, or state", Item);
end if;
end if;
end Analyze_Input_Output;
-- Local variables
Inputs : Node_Id;
Output : Node_Id;
Self_Ref : Boolean;
Non_Null_Output_Seen : Boolean := False;
-- Flag used to check the legality of an output list
-- Start of processing for Analyze_Dependency_Clause
begin
Inputs := Expression (Clause);
Self_Ref := False;
-- An input list with a self-dependency appears as operator "+" where
-- the actuals inputs are the right operand.
if Nkind (Inputs) = N_Op_Plus then
Inputs := Right_Opnd (Inputs);
Self_Ref := True;
end if;
-- Process the output_list of a dependency_clause
Output := First (Choices (Clause));
while Present (Output) loop
Analyze_Input_Output
(Item => Output,
Is_Input => False,
Self_Ref => Self_Ref,
Top_Level => True,
Seen => All_Outputs_Seen,
Null_Seen => Null_Output_Seen,
Non_Null_Seen => Non_Null_Output_Seen);
Next (Output);
end loop;
-- Process the input_list of a dependency_clause
Analyze_Input_List (Inputs);
end Analyze_Dependency_Clause;
---------------------------
-- Check_Function_Return --
---------------------------
procedure Check_Function_Return is
begin
if Ekind (Spec_Id) = E_Function and then not Result_Seen then
SPARK_Msg_NE
("result of & must appear in exactly one output list",
N, Spec_Id);
end if;
end Check_Function_Return;
----------------
-- Check_Role --
----------------
procedure Check_Role
(Item : Node_Id;
Item_Id : Entity_Id;
Is_Input : Boolean;
Self_Ref : Boolean)
is
procedure Find_Role
(Item_Is_Input : out Boolean;
Item_Is_Output : out Boolean);
-- Find the input/output role of Item_Id. Flags Item_Is_Input and
-- Item_Is_Output are set depending on the role.
procedure Role_Error
(Item_Is_Input : Boolean;
Item_Is_Output : Boolean);
-- Emit an error message concerning the incorrect use of Item in
-- pragma [Refined_]Depends. Flags Item_Is_Input and Item_Is_Output
-- denote whether the item is an input and/or an output.
---------------
-- Find_Role --
---------------
procedure Find_Role
(Item_Is_Input : out Boolean;
Item_Is_Output : out Boolean)
is
begin
Item_Is_Input := False;
Item_Is_Output := False;
-- Abstract state cases
if Ekind (Item_Id) = E_Abstract_State then
-- When pragma Global is present, the mode of the state may be
-- further constrained by setting a more restrictive mode.
if Global_Seen then
if Appears_In (Subp_Inputs, Item_Id) then
Item_Is_Input := True;
end if;
if Appears_In (Subp_Outputs, Item_Id) then
Item_Is_Output := True;
end if;
-- Otherwise the state has a default IN OUT mode
else
Item_Is_Input := True;
Item_Is_Output := True;
end if;
-- Parameter cases
elsif Ekind (Item_Id) = E_In_Parameter then
Item_Is_Input := True;
elsif Ekind (Item_Id) = E_In_Out_Parameter then
Item_Is_Input := True;
Item_Is_Output := True;
elsif Ekind (Item_Id) = E_Out_Parameter then
if Scope (Item_Id) = Spec_Id then
-- An OUT parameter of the related subprogram has mode IN
-- if its type is unconstrained or tagged because array
-- bounds, discriminants or tags can be read.
if Is_Unconstrained_Or_Tagged_Item (Item_Id) then
Item_Is_Input := True;
end if;
Item_Is_Output := True;
-- An OUT parameter of an enclosing subprogram behaves as a
-- read-write variable in which case the mode is IN OUT.
else
Item_Is_Input := True;
Item_Is_Output := True;
end if;
-- Variable cases
else pragma Assert (Ekind (Item_Id) = E_Variable);
-- When pragma Global is present, the mode of the variable may
-- be further constrained by setting a more restrictive mode.
if Global_Seen then
-- A variable has mode IN when its type is unconstrained or
-- tagged because array bounds, discriminants or tags can be
-- read.
if Appears_In (Subp_Inputs, Item_Id)
or else Is_Unconstrained_Or_Tagged_Item (Item_Id)
then
Item_Is_Input := True;
end if;
if Appears_In (Subp_Outputs, Item_Id) then
Item_Is_Output := True;
end if;
-- Otherwise the variable has a default IN OUT mode
else
Item_Is_Input := True;
Item_Is_Output := True;
end if;
end if;
end Find_Role;
----------------
-- Role_Error --
----------------
procedure Role_Error
(Item_Is_Input : Boolean;
Item_Is_Output : Boolean)
is
Error_Msg : Name_Id;
begin
Name_Len := 0;
-- When the item is not part of the input and the output set of
-- the related subprogram, then it appears as extra in pragma
-- [Refined_]Depends.
if not Item_Is_Input and then not Item_Is_Output then
Add_Item_To_Name_Buffer (Item_Id);
Add_Str_To_Name_Buffer
(" & cannot appear in dependence relation");
Error_Msg := Name_Find;
SPARK_Msg_NE (Get_Name_String (Error_Msg), Item, Item_Id);
Error_Msg_Name_1 := Chars (Subp_Id);
SPARK_Msg_NE
("\& is not part of the input or output set of subprogram %",
Item, Item_Id);
-- The mode of the item and its role in pragma [Refined_]Depends
-- are in conflict. Construct a detailed message explaining the
-- illegality (SPARK RM 6.1.5(5-6)).
else
if Item_Is_Input then
Add_Str_To_Name_Buffer ("read-only");
else
Add_Str_To_Name_Buffer ("write-only");
end if;
Add_Char_To_Name_Buffer (' ');
Add_Item_To_Name_Buffer (Item_Id);
Add_Str_To_Name_Buffer (" & cannot appear as ");
if Item_Is_Input then
Add_Str_To_Name_Buffer ("output");
else
Add_Str_To_Name_Buffer ("input");
end if;
Add_Str_To_Name_Buffer (" in dependence relation");
Error_Msg := Name_Find;
SPARK_Msg_NE (Get_Name_String (Error_Msg), Item, Item_Id);
end if;
end Role_Error;
-- Local variables
Item_Is_Input : Boolean;
Item_Is_Output : Boolean;
-- Start of processing for Check_Role
begin
Find_Role (Item_Is_Input, Item_Is_Output);
-- Input item
if Is_Input then
if not Item_Is_Input then
Role_Error (Item_Is_Input, Item_Is_Output);
end if;
-- Self-referential item
elsif Self_Ref then
if not Item_Is_Input or else not Item_Is_Output then
Role_Error (Item_Is_Input, Item_Is_Output);
end if;
-- Output item
elsif not Item_Is_Output then
Role_Error (Item_Is_Input, Item_Is_Output);
end if;
end Check_Role;
-----------------
-- Check_Usage --
-----------------
procedure Check_Usage
(Subp_Items : Elist_Id;
Used_Items : Elist_Id;
Is_Input : Boolean)
is
procedure Usage_Error (Item : Node_Id; Item_Id : Entity_Id);
-- Emit an error concerning the illegal usage of an item
-----------------
-- Usage_Error --
-----------------
procedure Usage_Error (Item : Node_Id; Item_Id : Entity_Id) is
Error_Msg : Name_Id;
begin
-- Input case
if Is_Input then
-- Unconstrained and tagged items are not part of the explicit
-- input set of the related subprogram, they do not have to be
-- present in a dependence relation and should not be flagged
-- (SPARK RM 6.1.5(8)).
if not Is_Unconstrained_Or_Tagged_Item (Item_Id) then
Name_Len := 0;
Add_Item_To_Name_Buffer (Item_Id);
Add_Str_To_Name_Buffer
(" & must appear in at least one input dependence list");
Error_Msg := Name_Find;
SPARK_Msg_NE (Get_Name_String (Error_Msg), Item, Item_Id);
end if;
-- Output case (SPARK RM 6.1.5(10))
else
Name_Len := 0;
Add_Item_To_Name_Buffer (Item_Id);
Add_Str_To_Name_Buffer
(" & must appear in exactly one output dependence list");
Error_Msg := Name_Find;
SPARK_Msg_NE (Get_Name_String (Error_Msg), Item, Item_Id);
end if;
end Usage_Error;
-- Local variables
Elmt : Elmt_Id;
Item : Node_Id;
Item_Id : Entity_Id;
-- Start of processing for Check_Usage
begin
if No (Subp_Items) then
return;
end if;
-- Each input or output of the subprogram must appear in a dependency
-- relation.
Elmt := First_Elmt (Subp_Items);
while Present (Elmt) loop
Item := Node (Elmt);
if Nkind (Item) = N_Defining_Identifier then
Item_Id := Item;
else
Item_Id := Entity_Of (Item);
end if;
-- The item does not appear in a dependency
if Present (Item_Id)
and then not Contains (Used_Items, Item_Id)
then
if Is_Formal (Item_Id) then
Usage_Error (Item, Item_Id);
-- States and global variables are not used properly only when
-- the subprogram is subject to pragma Global.
elsif Global_Seen then
Usage_Error (Item, Item_Id);
end if;
end if;
Next_Elmt (Elmt);
end loop;
end Check_Usage;
----------------------
-- Normalize_Clause --
----------------------
procedure Normalize_Clause (Clause : Node_Id) is
procedure Create_Or_Modify_Clause
(Output : Node_Id;
Outputs : Node_Id;
Inputs : Node_Id;
After : Node_Id;
In_Place : Boolean;
Multiple : Boolean);
-- Create a brand new clause to represent the self-reference or
-- modify the input and/or output lists of an existing clause. Output
-- denotes a self-referencial output. Outputs is the output list of a
-- clause. Inputs is the input list of a clause. After denotes the
-- clause after which the new clause is to be inserted. Flag In_Place
-- should be set when normalizing the last output of an output list.
-- Flag Multiple should be set when Output comes from a list with
-- multiple items.
-----------------------------
-- Create_Or_Modify_Clause --
-----------------------------
procedure Create_Or_Modify_Clause
(Output : Node_Id;
Outputs : Node_Id;
Inputs : Node_Id;
After : Node_Id;
In_Place : Boolean;
Multiple : Boolean)
is
procedure Propagate_Output
(Output : Node_Id;
Inputs : Node_Id);
-- Handle the various cases of output propagation to the input
-- list. Output denotes a self-referencial output item. Inputs is
-- the input list of a clause.
----------------------
-- Propagate_Output --
----------------------
procedure Propagate_Output
(Output : Node_Id;
Inputs : Node_Id)
is
function In_Input_List
(Item : Entity_Id;
Inputs : List_Id) return Boolean;
-- Determine whether a particulat item appears in the input
-- list of a clause.
-------------------
-- In_Input_List --
-------------------
function In_Input_List
(Item : Entity_Id;
Inputs : List_Id) return Boolean
is
Elmt : Node_Id;
begin
Elmt := First (Inputs);
while Present (Elmt) loop
if Entity_Of (Elmt) = Item then
return True;
end if;
Next (Elmt);
end loop;
return False;
end In_Input_List;
-- Local variables
Output_Id : constant Entity_Id := Entity_Of (Output);
Grouped : List_Id;
-- Start of processing for Propagate_Output
begin
-- The clause is of the form:
-- (Output =>+ null)
-- Remove null input and replace it with a copy of the output:
-- (Output => Output)
if Nkind (Inputs) = N_Null then
Rewrite (Inputs, New_Copy_Tree (Output));
-- The clause is of the form:
-- (Output =>+ (Input1, ..., InputN))
-- Determine whether the output is not already mentioned in the
-- input list and if not, add it to the list of inputs:
-- (Output => (Output, Input1, ..., InputN))
elsif Nkind (Inputs) = N_Aggregate then
Grouped := Expressions (Inputs);
if not In_Input_List
(Item => Output_Id,
Inputs => Grouped)
then
Prepend_To (Grouped, New_Copy_Tree (Output));
end if;
-- The clause is of the form:
-- (Output =>+ Input)
-- If the input does not mention the output, group the two
-- together:
-- (Output => (Output, Input))
elsif Entity_Of (Inputs) /= Output_Id then
Rewrite (Inputs,
Make_Aggregate (Loc,
Expressions => New_List (
New_Copy_Tree (Output),
New_Copy_Tree (Inputs))));
end if;
end Propagate_Output;
-- Local variables
Loc : constant Source_Ptr := Sloc (Clause);
New_Clause : Node_Id;
-- Start of processing for Create_Or_Modify_Clause
begin
-- A null output depending on itself does not require any
-- normalization.
if Nkind (Output) = N_Null then
return;
-- A function result cannot depend on itself because it cannot
-- appear in the input list of a relation (SPARK RM 6.1.5(10)).
elsif Is_Attribute_Result (Output) then
SPARK_Msg_N ("function result cannot depend on itself", Output);
return;
end if;
-- When performing the transformation in place, simply add the
-- output to the list of inputs (if not already there). This case
-- arises when dealing with the last output of an output list -
-- we perform the normalization in place to avoid generating a
-- malformed tree.
if In_Place then
Propagate_Output (Output, Inputs);
-- A list with multiple outputs is slowly trimmed until only
-- one element remains. When this happens, replace aggregate
-- with the element itself.
if Multiple then
Remove (Output);
Rewrite (Outputs, Output);
end if;
-- Default case
else
-- Unchain the output from its output list as it will appear in
-- a new clause. Note that we cannot simply rewrite the output
-- as null because this will violate the semantics of pragma
-- Depends.
Remove (Output);
-- Generate a new clause of the form:
-- (Output => Inputs)
New_Clause :=
Make_Component_Association (Loc,
Choices => New_List (Output),
Expression => New_Copy_Tree (Inputs));
-- The new clause contains replicated content that has already
-- been analyzed. There is not need to reanalyze it or
-- renormalize it again.
Set_Analyzed (New_Clause);
Propagate_Output
(Output => First (Choices (New_Clause)),
Inputs => Expression (New_Clause));
Insert_After (After, New_Clause);
end if;
end Create_Or_Modify_Clause;
-- Local variables
Outputs : constant Node_Id := First (Choices (Clause));
Inputs : Node_Id;
Last_Output : Node_Id;
Next_Output : Node_Id;
Output : Node_Id;
-- Start of processing for Normalize_Clause
begin
-- A self-dependency appears as operator "+". Remove the "+" from the
-- tree by moving the real inputs to their proper place.
if Nkind (Expression (Clause)) = N_Op_Plus then
Rewrite (Expression (Clause), Right_Opnd (Expression (Clause)));
Inputs := Expression (Clause);
-- Multiple outputs appear as an aggregate
if Nkind (Outputs) = N_Aggregate then
Last_Output := Last (Expressions (Outputs));
Output := First (Expressions (Outputs));
while Present (Output) loop
-- Normalization may remove an output from its list,
-- preserve the subsequent output now.
Next_Output := Next (Output);
Create_Or_Modify_Clause
(Output => Output,
Outputs => Outputs,
Inputs => Inputs,
After => Clause,
In_Place => Output = Last_Output,
Multiple => True);
Output := Next_Output;
end loop;
-- Solitary output
else
Create_Or_Modify_Clause
(Output => Outputs,
Outputs => Empty,
Inputs => Inputs,
After => Empty,
In_Place => True,
Multiple => False);
end if;
end if;
end Normalize_Clause;
-- Local variables
Clause : Node_Id;
Deps : Node_Id;
Errors : Nat;
Last_Clause : Node_Id;
Subp_Decl : Node_Id;
Restore_Scope : Boolean := False;
-- Gets set True if we do a Push_Scope needing a Pop_Scope on exit
-- Start of processing for Analyze_Depends_In_Decl_Part
begin
Set_Analyzed (N);
Subp_Decl := Find_Related_Subprogram_Or_Body (N);
Subp_Id := Defining_Entity (Subp_Decl);
Deps := Expression (Get_Argument (N, Subp_Id));
-- The logic in this routine is used to analyze both pragma Depends and
-- pragma Refined_Depends since they have the same syntax and base
-- semantics. Find the entity of the corresponding spec when analyzing
-- Refined_Depends.
Spec_Id := Corresponding_Spec_Of (Subp_Decl);
-- Empty dependency list
if Nkind (Deps) = N_Null then
-- Gather all states, variables and formal parameters that the
-- subprogram may depend on. These items are obtained from the
-- parameter profile or pragma [Refined_]Global (if available).
Collect_Subprogram_Inputs_Outputs
(Subp_Id => Subp_Id,
Subp_Inputs => Subp_Inputs,
Subp_Outputs => Subp_Outputs,
Global_Seen => Global_Seen);
-- Verify that every input or output of the subprogram appear in a
-- dependency.
Check_Usage (Subp_Inputs, All_Inputs_Seen, True);
Check_Usage (Subp_Outputs, All_Outputs_Seen, False);
Check_Function_Return;
-- Dependency clauses appear as component associations of an aggregate
elsif Nkind (Deps) = N_Aggregate then
-- Do not attempt to perform analysis of a syntactically illegal
-- clause as this will lead to misleading errors.
if Has_Extra_Parentheses (Deps) then
return;
end if;
if Present (Component_Associations (Deps)) then
Last_Clause := Last (Component_Associations (Deps));
-- Gather all states, variables and formal parameters that the
-- subprogram may depend on. These items are obtained from the
-- parameter profile or pragma [Refined_]Global (if available).
Collect_Subprogram_Inputs_Outputs
(Subp_Id => Subp_Id,
Subp_Inputs => Subp_Inputs,
Subp_Outputs => Subp_Outputs,
Global_Seen => Global_Seen);
-- Ensure that the formal parameters are visible when analyzing
-- all clauses. This falls out of the general rule of aspects
-- pertaining to subprogram declarations. Skip the installation
-- for subprogram bodies because the formals are already visible.
if not In_Open_Scopes (Spec_Id) then
Restore_Scope := True;
Push_Scope (Spec_Id);
if Is_Generic_Subprogram (Spec_Id) then
Install_Generic_Formals (Spec_Id);
else
Install_Formals (Spec_Id);
end if;
end if;
Clause := First (Component_Associations (Deps));
while Present (Clause) loop
Errors := Serious_Errors_Detected;
-- Normalization may create extra clauses that contain
-- replicated input and output names. There is no need to
-- reanalyze them.
if not Analyzed (Clause) then
Set_Analyzed (Clause);
Analyze_Dependency_Clause
(Clause => Clause,
Is_Last => Clause = Last_Clause);
end if;
-- Do not normalize a clause if errors were detected (count
-- of Serious_Errors has increased) because the inputs and/or
-- outputs may denote illegal items. Normalization is disabled
-- in ASIS mode as it alters the tree by introducing new nodes
-- similar to expansion.
if Serious_Errors_Detected = Errors and then not ASIS_Mode then
Normalize_Clause (Clause);
end if;
Next (Clause);
end loop;
if Restore_Scope then
End_Scope;
end if;
-- Verify that every input or output of the subprogram appear in a
-- dependency.
Check_Usage (Subp_Inputs, All_Inputs_Seen, True);
Check_Usage (Subp_Outputs, All_Outputs_Seen, False);
Check_Function_Return;
-- The dependency list is malformed. This is a syntax error, always
-- report.
else
Error_Msg_N ("malformed dependency relation", Deps);
return;
end if;
-- The top level dependency relation is malformed. This is a syntax
-- error, always report.
else
Error_Msg_N ("malformed dependency relation", Deps);
return;
end if;
-- Ensure that a state and a corresponding constituent do not appear
-- together in pragma [Refined_]Depends.
Check_State_And_Constituent_Use
(States => States_Seen,
Constits => Constits_Seen,
Context => N);
end Analyze_Depends_In_Decl_Part;
--------------------------------------------
-- Analyze_External_Property_In_Decl_Part --
--------------------------------------------
procedure Analyze_External_Property_In_Decl_Part
(N : Node_Id;
Expr_Val : out Boolean)
is
Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
Obj_Id : constant Entity_Id := Entity (Get_Pragma_Arg (Arg1));
Expr : constant Node_Id := Get_Pragma_Arg (Next (Arg1));
begin
Error_Msg_Name_1 := Pragma_Name (N);
-- An external property pragma must apply to an effectively volatile
-- object other than a formal subprogram parameter (SPARK RM 7.1.3(2)).
-- The check is performed at the end of the declarative region due to a
-- possible out-of-order arrangement of pragmas:
-- Obj : ...;
-- pragma Async_Readers (Obj);
-- pragma Volatile (Obj);
if not Is_Effectively_Volatile (Obj_Id) then
SPARK_Msg_N
("external property % must apply to a volatile object", N);
end if;
-- Ensure that the Boolean expression (if present) is static. A missing
-- argument defaults the value to True (SPARK RM 7.1.2(5)).
Expr_Val := True;
if Present (Expr) then
Analyze_And_Resolve (Expr, Standard_Boolean);
if Is_OK_Static_Expression (Expr) then
Expr_Val := Is_True (Expr_Value (Expr));
else
SPARK_Msg_N ("expression of % must be static", Expr);
end if;
end if;
end Analyze_External_Property_In_Decl_Part;
---------------------------------
-- Analyze_Global_In_Decl_Part --
---------------------------------
procedure Analyze_Global_In_Decl_Part (N : Node_Id) is
Constits_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all constituents processed so far.
-- It aids in detecting illegal usage of a state and a corresponding
-- constituent in pragma [Refinde_]Global.
Seen : Elist_Id := No_Elist;
-- A list containing the entities of all the items processed so far. It
-- plays a role in detecting distinct entities.
Spec_Id : Entity_Id;
-- The entity of the subprogram subject to pragma [Refined_]Global
States_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all states processed so far. It
-- helps in detecting illegal usage of a state and a corresponding
-- constituent in pragma [Refined_]Global.
Subp_Id : Entity_Id;
-- The entity of the subprogram [body or stub] subject to pragma
-- [Refined_]Global.
In_Out_Seen : Boolean := False;
Input_Seen : Boolean := False;
Output_Seen : Boolean := False;
Proof_Seen : Boolean := False;
-- Flags used to verify the consistency of modes
procedure Analyze_Global_List
(List : Node_Id;
Global_Mode : Name_Id := Name_Input);
-- Verify the legality of a single global list declaration. Global_Mode
-- denotes the current mode in effect.
-------------------------
-- Analyze_Global_List --
-------------------------
procedure Analyze_Global_List
(List : Node_Id;
Global_Mode : Name_Id := Name_Input)
is
procedure Analyze_Global_Item
(Item : Node_Id;
Global_Mode : Name_Id);
-- Verify the legality of a single global item declaration.
-- Global_Mode denotes the current mode in effect.
procedure Check_Duplicate_Mode
(Mode : Node_Id;
Status : in out Boolean);
-- Flag Status denotes whether a particular mode has been seen while
-- processing a global list. This routine verifies that Mode is not a
-- duplicate mode and sets the flag Status (SPARK RM 6.1.4(9)).
procedure Check_Mode_Restriction_In_Enclosing_Context
(Item : Node_Id;
Item_Id : Entity_Id);
-- Verify that an item of mode In_Out or Output does not appear as an
-- input in the Global aspect of an enclosing subprogram. If this is
-- the case, emit an error. Item and Item_Id are respectively the
-- item and its entity.
procedure Check_Mode_Restriction_In_Function (Mode : Node_Id);
-- Mode denotes either In_Out or Output. Depending on the kind of the
-- related subprogram, emit an error if those two modes apply to a
-- function (SPARK RM 6.1.4(10)).
-------------------------
-- Analyze_Global_Item --
-------------------------
procedure Analyze_Global_Item
(Item : Node_Id;
Global_Mode : Name_Id)
is
Item_Id : Entity_Id;
begin
-- Detect one of the following cases
-- with Global => (null, Name)
-- with Global => (Name_1, null, Name_2)
-- with Global => (Name, null)
if Nkind (Item) = N_Null then
SPARK_Msg_N ("cannot mix null and non-null global items", Item);
return;
end if;
Analyze (Item);
Resolve_State (Item);
-- Find the entity of the item. If this is a renaming, climb the
-- renaming chain to reach the root object. Renamings of non-
-- entire objects do not yield an entity (Empty).
Item_Id := Entity_Of (Item);
if Present (Item_Id) then
-- A global item may denote a formal parameter of an enclosing
-- subprogram (SPARK RM 6.1.4(6)). Do this check first to
-- provide a better error diagnostic.
if Is_Formal (Item_Id) then
if Scope (Item_Id) = Spec_Id then
SPARK_Msg_NE
("global item cannot reference parameter of subprogram",
Item, Spec_Id);
return;
end if;
-- A constant cannot act as a global item (SPARK RM 6.1.4(7)).
-- Do this check first to provide a better error diagnostic.
elsif Ekind (Item_Id) = E_Constant then
SPARK_Msg_N ("global item cannot denote a constant", Item);
-- A formal object may act as a global item inside a generic
elsif Is_Formal_Object (Item_Id) then
null;
-- The only legal references are those to abstract states and
-- variables (SPARK RM 6.1.4(4)).
elsif not Ekind_In (Item_Id, E_Abstract_State, E_Variable) then
SPARK_Msg_N
("global item must denote variable or state", Item);
return;
end if;
-- State related checks
if Ekind (Item_Id) = E_Abstract_State then
-- An abstract state with visible refinement cannot appear
-- in pragma [Refined_]Global as its place must be taken by
-- some of its constituents (SPARK RM 6.1.4(8)).
if Has_Visible_Refinement (Item_Id) then
SPARK_Msg_NE
("cannot mention state & in global refinement",
Item, Item_Id);
SPARK_Msg_N ("\use its constituents instead", Item);
return;
-- If the reference to the abstract state appears in an
-- enclosing package body that will eventually refine the
-- state, record the reference for future checks.
else
Record_Possible_Body_Reference
(State_Id => Item_Id,
Ref => Item);
end if;
-- Variable related checks. These are only relevant when
-- SPARK_Mode is on as they are not standard Ada legality
-- rules.
elsif SPARK_Mode = On
and then Is_Effectively_Volatile (Item_Id)
then
-- An effectively volatile object cannot appear as a global
-- item of a function (SPARK RM 7.1.3(9)).
if Ekind_In (Spec_Id, E_Function, E_Generic_Function) then
Error_Msg_NE
("volatile object & cannot act as global item of a "
& "function", Item, Item_Id);
return;
-- An effectively volatile object with external property
-- Effective_Reads set to True must have mode Output or
-- In_Out.
elsif Effective_Reads_Enabled (Item_Id)
and then Global_Mode = Name_Input
then
Error_Msg_NE
("volatile object & with property Effective_Reads must "
& "have mode In_Out or Output (SPARK RM 7.1.3(11))",
Item, Item_Id);
return;
end if;
end if;
-- When the item renames an entire object, replace the item
-- with a reference to the object.
if Present (Renamed_Object (Entity (Item))) then
Rewrite (Item, New_Occurrence_Of (Item_Id, Sloc (Item)));
Analyze (Item);
end if;
-- Some form of illegal construct masquerading as a name
-- (SPARK RM 6.1.4(4)).
else
Error_Msg_N ("global item must denote variable or state", Item);
return;
end if;
-- Verify that an output does not appear as an input in an
-- enclosing subprogram.
if Nam_In (Global_Mode, Name_In_Out, Name_Output) then
Check_Mode_Restriction_In_Enclosing_Context (Item, Item_Id);
end if;
-- The same entity might be referenced through various way.
-- Check the entity of the item rather than the item itself
-- (SPARK RM 6.1.4(11)).
if Contains (Seen, Item_Id) then
SPARK_Msg_N ("duplicate global item", Item);
-- Add the entity of the current item to the list of processed
-- items.
else
Add_Item (Item_Id, Seen);
if Ekind (Item_Id) = E_Abstract_State then
Add_Item (Item_Id, States_Seen);
end if;
if Ekind_In (Item_Id, E_Abstract_State, E_Variable)
and then Present (Encapsulating_State (Item_Id))
then
Add_Item (Item_Id, Constits_Seen);
end if;
end if;
end Analyze_Global_Item;
--------------------------
-- Check_Duplicate_Mode --
--------------------------
procedure Check_Duplicate_Mode
(Mode : Node_Id;
Status : in out Boolean)
is
begin
if Status then
SPARK_Msg_N ("duplicate global mode", Mode);
end if;
Status := True;
end Check_Duplicate_Mode;
-------------------------------------------------
-- Check_Mode_Restriction_In_Enclosing_Context --
-------------------------------------------------
procedure Check_Mode_Restriction_In_Enclosing_Context
(Item : Node_Id;
Item_Id : Entity_Id)
is
Context : Entity_Id;
Dummy : Boolean;
Inputs : Elist_Id := No_Elist;
Outputs : Elist_Id := No_Elist;
begin
-- Traverse the scope stack looking for enclosing subprograms
-- subject to pragma [Refined_]Global.
Context := Scope (Subp_Id);
while Present (Context) and then Context /= Standard_Standard loop
if Is_Subprogram (Context)
and then
(Present (Get_Pragma (Context, Pragma_Global))
or else
Present (Get_Pragma (Context, Pragma_Refined_Global)))
then
Collect_Subprogram_Inputs_Outputs
(Subp_Id => Context,
Subp_Inputs => Inputs,
Subp_Outputs => Outputs,
Global_Seen => Dummy);
-- The item is classified as In_Out or Output but appears as
-- an Input in an enclosing subprogram (SPARK RM 6.1.4(12)).
if Appears_In (Inputs, Item_Id)
and then not Appears_In (Outputs, Item_Id)
then
SPARK_Msg_NE
("global item & cannot have mode In_Out or Output",
Item, Item_Id);
SPARK_Msg_NE
("\item already appears as input of subprogram &",
Item, Context);
-- Stop the traversal once an error has been detected
exit;
end if;
end if;
Context := Scope (Context);
end loop;
end Check_Mode_Restriction_In_Enclosing_Context;
----------------------------------------
-- Check_Mode_Restriction_In_Function --
----------------------------------------
procedure Check_Mode_Restriction_In_Function (Mode : Node_Id) is
begin
if Ekind (Spec_Id) = E_Function then
SPARK_Msg_N
("global mode & is not applicable to functions", Mode);
end if;
end Check_Mode_Restriction_In_Function;
-- Local variables
Assoc : Node_Id;
Item : Node_Id;
Mode : Node_Id;
-- Start of processing for Analyze_Global_List
begin
if Nkind (List) = N_Null then
Set_Analyzed (List);
-- Single global item declaration
elsif Nkind_In (List, N_Expanded_Name,
N_Identifier,
N_Selected_Component)
then
Analyze_Global_Item (List, Global_Mode);
-- Simple global list or moded global list declaration
elsif Nkind (List) = N_Aggregate then
Set_Analyzed (List);
-- The declaration of a simple global list appear as a collection
-- of expressions.
if Present (Expressions (List)) then
if Present (Component_Associations (List)) then
SPARK_Msg_N
("cannot mix moded and non-moded global lists", List);
end if;
Item := First (Expressions (List));
while Present (Item) loop
Analyze_Global_Item (Item, Global_Mode);
Next (Item);
end loop;
-- The declaration of a moded global list appears as a collection
-- of component associations where individual choices denote
-- modes.
elsif Present (Component_Associations (List)) then
if Present (Expressions (List)) then
SPARK_Msg_N
("cannot mix moded and non-moded global lists", List);
end if;
Assoc := First (Component_Associations (List));
while Present (Assoc) loop
Mode := First (Choices (Assoc));
if Nkind (Mode) = N_Identifier then
if Chars (Mode) = Name_In_Out then
Check_Duplicate_Mode (Mode, In_Out_Seen);
Check_Mode_Restriction_In_Function (Mode);
elsif Chars (Mode) = Name_Input then
Check_Duplicate_Mode (Mode, Input_Seen);
elsif Chars (Mode) = Name_Output then
Check_Duplicate_Mode (Mode, Output_Seen);
Check_Mode_Restriction_In_Function (Mode);
elsif Chars (Mode) = Name_Proof_In then
Check_Duplicate_Mode (Mode, Proof_Seen);
else
SPARK_Msg_N ("invalid mode selector", Mode);
end if;
else
SPARK_Msg_N ("invalid mode selector", Mode);
end if;
-- Items in a moded list appear as a collection of
-- expressions. Reuse the existing machinery to analyze
-- them.
Analyze_Global_List
(List => Expression (Assoc),
Global_Mode => Chars (Mode));
Next (Assoc);
end loop;
-- Invalid tree
else
raise Program_Error;
end if;
-- Any other attempt to declare a global item is illegal. This is a
-- syntax error, always report.
else
Error_Msg_N ("malformed global list", List);
end if;
end Analyze_Global_List;
-- Local variables
Items : Node_Id;
Subp_Decl : Node_Id;
Restore_Scope : Boolean := False;
-- Set True if we do a Push_Scope requiring a Pop_Scope on exit
-- Start of processing for Analyze_Global_In_Decl_Part
begin
Set_Analyzed (N);
Subp_Decl := Find_Related_Subprogram_Or_Body (N);
Subp_Id := Defining_Entity (Subp_Decl);
Items := Expression (Get_Argument (N, Subp_Id));
-- The logic in this routine is used to analyze both pragma Global and
-- pragma Refined_Global since they have the same syntax and base
-- semantics. Find the entity of the corresponding spec when analyzing
-- Refined_Global.
Spec_Id := Corresponding_Spec_Of (Subp_Decl);
-- There is nothing to be done for a null global list
if Nkind (Items) = N_Null then
Set_Analyzed (Items);
-- Analyze the various forms of global lists and items. Note that some
-- of these may be malformed in which case the analysis emits error
-- messages.
else
-- Ensure that the formal parameters are visible when processing an
-- item. This falls out of the general rule of aspects pertaining to
-- subprogram declarations.
if not In_Open_Scopes (Spec_Id) then
Restore_Scope := True;
Push_Scope (Spec_Id);
if Is_Generic_Subprogram (Spec_Id) then
Install_Generic_Formals (Spec_Id);
else
Install_Formals (Spec_Id);
end if;
end if;
Analyze_Global_List (Items);
if Restore_Scope then
End_Scope;
end if;
end if;
-- Ensure that a state and a corresponding constituent do not appear
-- together in pragma [Refined_]Global.
Check_State_And_Constituent_Use
(States => States_Seen,
Constits => Constits_Seen,
Context => N);
end Analyze_Global_In_Decl_Part;
--------------------------------------------
-- Analyze_Initial_Condition_In_Decl_Part --
--------------------------------------------
procedure Analyze_Initial_Condition_In_Decl_Part (N : Node_Id) is
Expr : constant Node_Id := Expression (Get_Argument (N));
begin
Set_Analyzed (N);
-- The expression is preanalyzed because it has not been moved to its
-- final place yet. A direct analysis may generate side effects and this
-- is not desired at this point.
Preanalyze_Assert_Expression (Expr, Standard_Boolean);
end Analyze_Initial_Condition_In_Decl_Part;
--------------------------------------
-- Analyze_Initializes_In_Decl_Part --
--------------------------------------
procedure Analyze_Initializes_In_Decl_Part (N : Node_Id) is
Pack_Spec : constant Node_Id := Parent (N);
Pack_Id : constant Entity_Id := Defining_Entity (Parent (Pack_Spec));
Constits_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all constituents processed so far.
-- It aids in detecting illegal usage of a state and a corresponding
-- constituent in pragma Initializes.
Items_Seen : Elist_Id := No_Elist;
-- A list of all initialization items processed so far. This list is
-- used to detect duplicate items.
Non_Null_Seen : Boolean := False;
Null_Seen : Boolean := False;
-- Flags used to check the legality of a null initialization list
States_And_Vars : Elist_Id := No_Elist;
-- A list of all abstract states and variables declared in the visible
-- declarations of the related package. This list is used to detect the
-- legality of initialization items.
States_Seen : Elist_Id := No_Elist;
-- A list containing the entities of all states processed so far. It
-- helps in detecting illegal usage of a state and a corresponding
-- constituent in pragma Initializes.
procedure Analyze_Initialization_Item (Item : Node_Id);
-- Verify the legality of a single initialization item
procedure Analyze_Initialization_Item_With_Inputs (Item : Node_Id);
-- Verify the legality of a single initialization item followed by a
-- list of input items.
procedure Collect_States_And_Variables;
-- Inspect the visible declarations of the related package and gather
-- the entities of all abstract states and variables in States_And_Vars.
---------------------------------
-- Analyze_Initialization_Item --
---------------------------------
procedure Analyze_Initialization_Item (Item : Node_Id) is
Item_Id : Entity_Id;
begin
-- Null initialization list
if Nkind (Item) = N_Null then
if Null_Seen then
SPARK_Msg_N ("multiple null initializations not allowed", Item);
elsif Non_Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null initialization items", Item);
else
Null_Seen := True;
end if;
-- Initialization item
else
Non_Null_Seen := True;
if Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null initialization items", Item);
end if;
Analyze (Item);
Resolve_State (Item);
if Is_Entity_Name (Item) then
Item_Id := Entity_Of (Item);
if Ekind_In (Item_Id, E_Abstract_State, E_Variable) then
-- The state or variable must be declared in the visible
-- declarations of the package (SPARK RM 7.1.5(7)).
if not Contains (States_And_Vars, Item_Id) then
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("initialization item & must appear in the visible "
& "declarations of package %", Item, Item_Id);
-- Detect a duplicate use of the same initialization item
-- (SPARK RM 7.1.5(5)).
elsif Contains (Items_Seen, Item_Id) then
SPARK_Msg_N ("duplicate initialization item", Item);
-- The item is legal, add it to the list of processed states
-- and variables.
else
Add_Item (Item_Id, Items_Seen);
if Ekind (Item_Id) = E_Abstract_State then
Add_Item (Item_Id, States_Seen);
end if;
if Present (Encapsulating_State (Item_Id)) then
Add_Item (Item_Id, Constits_Seen);
end if;
end if;
-- The item references something that is not a state or a
-- variable (SPARK RM 7.1.5(3)).
else
SPARK_Msg_N
("initialization item must denote variable or state",
Item);
end if;
-- Some form of illegal construct masquerading as a name
-- (SPARK RM 7.1.5(3)). This is a syntax error, always report.
else
Error_Msg_N
("initialization item must denote variable or state", Item);
end if;
end if;
end Analyze_Initialization_Item;
---------------------------------------------
-- Analyze_Initialization_Item_With_Inputs --
---------------------------------------------
procedure Analyze_Initialization_Item_With_Inputs (Item : Node_Id) is
Inputs_Seen : Elist_Id := No_Elist;
-- A list of all inputs processed so far. This list is used to detect
-- duplicate uses of an input.
Non_Null_Seen : Boolean := False;
Null_Seen : Boolean := False;
-- Flags used to check the legality of an input list
procedure Analyze_Input_Item (Input : Node_Id);
-- Verify the legality of a single input item
------------------------
-- Analyze_Input_Item --
------------------------
procedure Analyze_Input_Item (Input : Node_Id) is
Input_Id : Entity_Id;
begin
-- Null input list
if Nkind (Input) = N_Null then
if Null_Seen then
SPARK_Msg_N
("multiple null initializations not allowed", Item);
elsif Non_Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null initialization item", Item);
else
Null_Seen := True;
end if;
-- Input item
else
Non_Null_Seen := True;
if Null_Seen then
SPARK_Msg_N
("cannot mix null and non-null initialization item", Item);
end if;
Analyze (Input);
Resolve_State (Input);
if Is_Entity_Name (Input) then
Input_Id := Entity_Of (Input);
if Ekind_In (Input_Id, E_Abstract_State,
E_In_Parameter,
E_In_Out_Parameter,
E_Out_Parameter,
E_Variable)
then
-- The input cannot denote states or variables declared
-- within the related package.
if Within_Scope (Input_Id, Current_Scope) then
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("input item & cannot denote a visible variable or "
& "state of package % (SPARK RM 7.1.5(4))",
Input, Input_Id);
-- Detect a duplicate use of the same input item
-- (SPARK RM 7.1.5(5)).
elsif Contains (Inputs_Seen, Input_Id) then
SPARK_Msg_N ("duplicate input item", Input);
-- Input is legal, add it to the list of processed inputs
else
Add_Item (Input_Id, Inputs_Seen);
if Ekind (Input_Id) = E_Abstract_State then
Add_Item (Input_Id, States_Seen);
end if;
if Ekind_In (Input_Id, E_Abstract_State, E_Variable)
and then Present (Encapsulating_State (Input_Id))
then
Add_Item (Input_Id, Constits_Seen);
end if;
end if;
-- The input references something that is not a state or a
-- variable (SPARK RM 7.1.5(3)).
else
SPARK_Msg_N
("input item must denote variable or state", Input);
end if;
-- Some form of illegal construct masquerading as a name
-- (SPARK RM 7.1.5(3)).
else
SPARK_Msg_N
("input item must denote variable or state", Input);
end if;
end if;
end Analyze_Input_Item;
-- Local variables
Inputs : constant Node_Id := Expression (Item);
Elmt : Node_Id;
Input : Node_Id;
Name_Seen : Boolean := False;
-- A flag used to detect multiple item names
-- Start of processing for Analyze_Initialization_Item_With_Inputs
begin
-- Inspect the name of an item with inputs
Elmt := First (Choices (Item));
while Present (Elmt) loop
if Name_Seen then
SPARK_Msg_N ("only one item allowed in initialization", Elmt);
else
Name_Seen := True;
Analyze_Initialization_Item (Elmt);
end if;
Next (Elmt);
end loop;
-- Multiple input items appear as an aggregate
if Nkind (Inputs) = N_Aggregate then
if Present (Expressions (Inputs)) then
Input := First (Expressions (Inputs));
while Present (Input) loop
Analyze_Input_Item (Input);
Next (Input);
end loop;
end if;
if Present (Component_Associations (Inputs)) then
SPARK_Msg_N
("inputs must appear in named association form", Inputs);
end if;
-- Single input item
else
Analyze_Input_Item (Inputs);
end if;
end Analyze_Initialization_Item_With_Inputs;
----------------------------------
-- Collect_States_And_Variables --
----------------------------------
procedure Collect_States_And_Variables is
Decl : Node_Id;
begin
-- Collect the abstract states defined in the package (if any)
if Present (Abstract_States (Pack_Id)) then
States_And_Vars := New_Copy_Elist (Abstract_States (Pack_Id));
end if;
-- Collect all variables the appear in the visible declarations of
-- the related package.
if Present (Visible_Declarations (Pack_Spec)) then
Decl := First (Visible_Declarations (Pack_Spec));
while Present (Decl) loop
if Nkind (Decl) = N_Object_Declaration
and then Ekind (Defining_Entity (Decl)) = E_Variable
and then Comes_From_Source (Decl)
then
Add_Item (Defining_Entity (Decl), States_And_Vars);
end if;
Next (Decl);
end loop;
end if;
end Collect_States_And_Variables;
-- Local variables
Inits : constant Node_Id := Expression (Get_Argument (N));
Init : Node_Id;
-- Start of processing for Analyze_Initializes_In_Decl_Part
begin
Set_Analyzed (N);
-- Nothing to do when the initialization list is empty
if Nkind (Inits) = N_Null then
return;
end if;
-- Single and multiple initialization clauses appear as an aggregate. If
-- this is not the case, then either the parser or the analysis of the
-- pragma failed to produce an aggregate.
pragma Assert (Nkind (Inits) = N_Aggregate);
-- Initialize the various lists used during analysis
Collect_States_And_Variables;
if Present (Expressions (Inits)) then
Init := First (Expressions (Inits));
while Present (Init) loop
Analyze_Initialization_Item (Init);
Next (Init);
end loop;
end if;
if Present (Component_Associations (Inits)) then
Init := First (Component_Associations (Inits));
while Present (Init) loop
Analyze_Initialization_Item_With_Inputs (Init);
Next (Init);
end loop;
end if;
-- Ensure that a state and a corresponding constituent do not appear
-- together in pragma Initializes.
Check_State_And_Constituent_Use
(States => States_Seen,
Constits => Constits_Seen,
Context => N);
end Analyze_Initializes_In_Decl_Part;
--------------------
-- Analyze_Pragma --
--------------------
procedure Analyze_Pragma (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Prag_Id : Pragma_Id;
Pname : Name_Id;
-- Name of the source pragma, or name of the corresponding aspect for
-- pragmas which originate in a source aspect. In the latter case, the
-- name may be different from the pragma name.
Pragma_Exit : exception;
-- This exception is used to exit pragma processing completely. It
-- is used when an error is detected, and no further processing is
-- required. It is also used if an earlier error has left the tree in
-- a state where the pragma should not be processed.
Arg_Count : Nat;
-- Number of pragma argument associations
Arg1 : Node_Id;
Arg2 : Node_Id;
Arg3 : Node_Id;
Arg4 : Node_Id;
-- First four pragma arguments (pragma argument association nodes, or
-- Empty if the corresponding argument does not exist).
type Name_List is array (Natural range <>) of Name_Id;
type Args_List is array (Natural range <>) of Node_Id;
-- Types used for arguments to Check_Arg_Order and Gather_Associations
-----------------------
-- Local Subprograms --
-----------------------
procedure Acquire_Warning_Match_String (Arg : Node_Id);
-- Used by pragma Warnings (Off, string), and Warn_As_Error (string) to
-- get the given string argument, and place it in Name_Buffer, adding
-- leading and trailing asterisks if they are not already present. The
-- caller has already checked that Arg is a static string expression.
procedure Ada_2005_Pragma;
-- Called for pragmas defined in Ada 2005, that are not in Ada 95. In
-- Ada 95 mode, these are implementation defined pragmas, so should be
-- caught by the No_Implementation_Pragmas restriction.
procedure Ada_2012_Pragma;
-- Called for pragmas defined in Ada 2012, that are not in Ada 95 or 05.
-- In Ada 95 or 05 mode, these are implementation defined pragmas, so
-- should be caught by the No_Implementation_Pragmas restriction.
procedure Analyze_Part_Of
(Item_Id : Entity_Id;
State : Node_Id;
Indic : Node_Id;
Legal : out Boolean);
-- Subsidiary to the analysis of pragmas Abstract_State and Part_Of.
-- Perform full analysis of indicator Part_Of. Item_Id is the entity of
-- an abstract state, variable or package instantiation. State is the
-- encapsulating state. Indic is the Part_Of indicator. Flag Legal is
-- set when the indicator is legal.
procedure Analyze_Pre_Post_Condition;
-- Subsidiary to the analysis of pragmas Precondition and Postcondition
procedure Analyze_Refined_Pragma
(Spec_Id : out Entity_Id;
Body_Id : out Entity_Id;
Legal : out Boolean);
-- Subsidiary routine to the analysis of body pragmas Refined_Depends,
-- Refined_Global and Refined_Post. Check the placement and related
-- context of the pragma. Spec_Id is the entity of the related
-- subprogram. Body_Id is the entity of the subprogram body. Flag
-- Legal is set when the pragma is properly placed.
procedure Check_Ada_83_Warning;
-- Issues a warning message for the current pragma if operating in Ada
-- 83 mode (used for language pragmas that are not a standard part of
-- Ada 83). This procedure does not raise Pragma_Exit. Also notes use
-- of 95 pragma.
procedure Check_Arg_Count (Required : Nat);
-- Check argument count for pragma is equal to given parameter. If not,
-- then issue an error message and raise Pragma_Exit.
-- Note: all routines whose name is Check_Arg_Is_xxx take an argument
-- Arg which can either be a pragma argument association, in which case
-- the check is applied to the expression of the association or an
-- expression directly.
procedure Check_Arg_Is_External_Name (Arg : Node_Id);
-- Check that an argument has the right form for an EXTERNAL_NAME
-- parameter of an extended import/export pragma. The rule is that the
-- name must be an identifier or string literal (in Ada 83 mode) or a
-- static string expression (in Ada 95 mode).
procedure Check_Arg_Is_Identifier (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is an
-- identifier. If not give error and raise Pragma_Exit.
procedure Check_Arg_Is_Integer_Literal (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is an integer
-- literal. If not give error and raise Pragma_Exit.
procedure Check_Arg_Is_Library_Level_Local_Name (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it has the proper
-- syntactic form for a local name and meets the semantic requirements
-- for a local name. The local name is analyzed as part of the
-- processing for this call. In addition, the local name is required
-- to represent an entity at the library level.
procedure Check_Arg_Is_Local_Name (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it has the proper
-- syntactic form for a local name and meets the semantic requirements
-- for a local name. The local name is analyzed as part of the
-- processing for this call.
procedure Check_Arg_Is_Locking_Policy (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is a valid
-- locking policy name. If not give error and raise Pragma_Exit.
procedure Check_Arg_Is_Partition_Elaboration_Policy (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is a valid
-- elaboration policy name. If not give error and raise Pragma_Exit.
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2 : Name_Id);
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3 : Name_Id);
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3, N4 : Name_Id);
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3, N4, N5 : Name_Id);
-- Check the specified argument Arg to make sure that it is an
-- identifier whose name matches either N1 or N2 (or N3, N4, N5 if
-- present). If not then give error and raise Pragma_Exit.
procedure Check_Arg_Is_Queuing_Policy (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is a valid
-- queuing policy name. If not give error and raise Pragma_Exit.
procedure Check_Arg_Is_OK_Static_Expression
(Arg : Node_Id;
Typ : Entity_Id := Empty);
-- Check the specified argument Arg to make sure that it is a static
-- expression of the given type (i.e. it will be analyzed and resolved
-- using this type, which can be any valid argument to Resolve, e.g.
-- Any_Integer is OK). If not, given error and raise Pragma_Exit. If
-- Typ is left Empty, then any static expression is allowed. Includes
-- checking that the argument does not raise Constraint_Error.
procedure Check_Arg_Is_Task_Dispatching_Policy (Arg : Node_Id);
-- Check the specified argument Arg to make sure that it is a valid task
-- dispatching policy name. If not give error and raise Pragma_Exit.
procedure Check_Arg_Order (Names : Name_List);
-- Checks for an instance of two arguments with identifiers for the
-- current pragma which are not in the sequence indicated by Names,
-- and if so, generates a fatal message about bad order of arguments.
procedure Check_At_Least_N_Arguments (N : Nat);
-- Check there are at least N arguments present
procedure Check_At_Most_N_Arguments (N : Nat);
-- Check there are no more than N arguments present
procedure Check_Component
(Comp : Node_Id;
UU_Typ : Entity_Id;
In_Variant_Part : Boolean := False);
-- Examine an Unchecked_Union component for correct use of per-object
-- constrained subtypes, and for restrictions on finalizable components.
-- UU_Typ is the related Unchecked_Union type. Flag In_Variant_Part
-- should be set when Comp comes from a record variant.
procedure Check_Declaration_Order (First : Node_Id; Second : Node_Id);
-- Subsidiary routine to the analysis of pragmas Abstract_State,
-- Initial_Condition and Initializes. Determine whether pragma First
-- appears before pragma Second. If this is not the case, emit an error.
procedure Check_Duplicate_Pragma (E : Entity_Id);
-- Check if a rep item of the same name as the current pragma is already
-- chained as a rep pragma to the given entity. If so give a message
-- about the duplicate, and then raise Pragma_Exit so does not return.
-- Note that if E is a type, then this routine avoids flagging a pragma
-- which applies to a parent type from which E is derived.
procedure Check_Duplicated_Export_Name (Nam : Node_Id);
-- Nam is an N_String_Literal node containing the external name set by
-- an Import or Export pragma (or extended Import or Export pragma).
-- This procedure checks for possible duplications if this is the export
-- case, and if found, issues an appropriate error message.
procedure Check_Expr_Is_OK_Static_Expression
(Expr : Node_Id;
Typ : Entity_Id := Empty);
-- Check the specified expression Expr to make sure that it is a static
-- expression of the given type (i.e. it will be analyzed and resolved
-- using this type, which can be any valid argument to Resolve, e.g.
-- Any_Integer is OK). If not, given error and raise Pragma_Exit. If
-- Typ is left Empty, then any static expression is allowed. Includes
-- checking that the expression does not raise Constraint_Error.
procedure Check_First_Subtype (Arg : Node_Id);
-- Checks that Arg, whose expression is an entity name, references a
-- first subtype.
procedure Check_Identifier (Arg : Node_Id; Id : Name_Id);
-- Checks that the given argument has an identifier, and if so, requires
-- it to match the given identifier name. If there is no identifier, or
-- a non-matching identifier, then an error message is given and
-- Pragma_Exit is raised.
procedure Check_Identifier_Is_One_Of (Arg : Node_Id; N1, N2 : Name_Id);
-- Checks that the given argument has an identifier, and if so, requires
-- it to match one of the given identifier names. If there is no
-- identifier, or a non-matching identifier, then an error message is
-- given and Pragma_Exit is raised.
procedure Check_In_Main_Program;
-- Common checks for pragmas that appear within a main program
-- (Priority, Main_Storage, Time_Slice, Relative_Deadline, CPU).
procedure Check_Interrupt_Or_Attach_Handler;
-- Common processing for first argument of pragma Interrupt_Handler or
-- pragma Attach_Handler.
procedure Check_Loop_Pragma_Placement;
-- Verify whether pragmas Loop_Invariant, Loop_Optimize and Loop_Variant
-- appear immediately within a construct restricted to loops, and that
-- pragmas Loop_Invariant and Loop_Variant are grouped together.
procedure Check_Is_In_Decl_Part_Or_Package_Spec;
-- Check that pragma appears in a declarative part, or in a package
-- specification, i.e. that it does not occur in a statement sequence
-- in a body.
procedure Check_No_Identifier (Arg : Node_Id);
-- Checks that the given argument does not have an identifier. If
-- an identifier is present, then an error message is issued, and
-- Pragma_Exit is raised.
procedure Check_No_Identifiers;
-- Checks that none of the arguments to the pragma has an identifier.
-- If any argument has an identifier, then an error message is issued,
-- and Pragma_Exit is raised.
procedure Check_No_Link_Name;
-- Checks that no link name is specified
procedure Check_Optional_Identifier (Arg : Node_Id; Id : Name_Id);
-- Checks if the given argument has an identifier, and if so, requires
-- it to match the given identifier name. If there is a non-matching
-- identifier, then an error message is given and Pragma_Exit is raised.
procedure Check_Optional_Identifier (Arg : Node_Id; Id : String);
-- Checks if the given argument has an identifier, and if so, requires
-- it to match the given identifier name. If there is a non-matching
-- identifier, then an error message is given and Pragma_Exit is raised.
-- In this version of the procedure, the identifier name is given as
-- a string with lower case letters.
procedure Check_Static_Constraint (Constr : Node_Id);
-- Constr is a constraint from an N_Subtype_Indication node from a
-- component constraint in an Unchecked_Union type. This routine checks
-- that the constraint is static as required by the restrictions for
-- Unchecked_Union.
procedure Check_Valid_Configuration_Pragma;
-- Legality checks for placement of a configuration pragma
procedure Check_Valid_Library_Unit_Pragma;
-- Legality checks for library unit pragmas. A special case arises for
-- pragmas in generic instances that come from copies of the original
-- library unit pragmas in the generic templates. In the case of other
-- than library level instantiations these can appear in contexts which
-- would normally be invalid (they only apply to the original template
-- and to library level instantiations), and they are simply ignored,
-- which is implemented by rewriting them as null statements.
procedure Check_Variant (Variant : Node_Id; UU_Typ : Entity_Id);
-- Check an Unchecked_Union variant for lack of nested variants and
-- presence of at least one component. UU_Typ is the related Unchecked_
-- Union type.
procedure Create_Generic_Template
(Prag : Node_Id;
Subp_Id : Entity_Id);
-- Subsidiary routine to the processing of pragmas Contract_Cases,
-- Depends, Global, Postcondition, Precondition and Test_Case. Create
-- a generic template for pragma Prag when Prag is a source construct
-- and the related context denoted by Subp_Id is a generic subprogram.
procedure Ensure_Aggregate_Form (Arg : Node_Id);
-- Subsidiary routine to the processing of pragmas Abstract_State,
-- Contract_Cases, Depends, Global, Initializes, Refined_Depends,
-- Refined_Global and Refined_State. Transform argument Arg into
-- an aggregate if not one already. N_Null is never transformed.
-- Arg may denote an aspect specification or a pragma argument
-- association.
procedure Error_Pragma (Msg : String);
pragma No_Return (Error_Pragma);
-- Outputs error message for current pragma. The message contains a %
-- that will be replaced with the pragma name, and the flag is placed
-- on the pragma itself. Pragma_Exit is then raised. Note: this routine
-- calls Fix_Error (see spec of that procedure for details).
procedure Error_Pragma_Arg (Msg : String; Arg : Node_Id);
pragma No_Return (Error_Pragma_Arg);
-- Outputs error message for current pragma. The message may contain
-- a % that will be replaced with the pragma name. The parameter Arg
-- may either be a pragma argument association, in which case the flag
-- is placed on the expression of this association, or an expression,
-- in which case the flag is placed directly on the expression. The
-- message is placed using Error_Msg_N, so the message may also contain
-- an & insertion character which will reference the given Arg value.
-- After placing the message, Pragma_Exit is raised. Note: this routine
-- calls Fix_Error (see spec of that procedure for details).
procedure Error_Pragma_Arg (Msg1, Msg2 : String; Arg : Node_Id);
pragma No_Return (Error_Pragma_Arg);
-- Similar to above form of Error_Pragma_Arg except that two messages
-- are provided, the second is a continuation comment starting with \.
procedure Error_Pragma_Arg_Ident (Msg : String; Arg : Node_Id);
pragma No_Return (Error_Pragma_Arg_Ident);
-- Outputs error message for current pragma. The message may contain a %
-- that will be replaced with the pragma name. The parameter Arg must be
-- a pragma argument association with a non-empty identifier (i.e. its
-- Chars field must be set), and the error message is placed on the
-- identifier. The message is placed using Error_Msg_N so the message
-- may also contain an & insertion character which will reference
-- the identifier. After placing the message, Pragma_Exit is raised.
-- Note: this routine calls Fix_Error (see spec of that procedure for
-- details).
procedure Error_Pragma_Ref (Msg : String; Ref : Entity_Id);
pragma No_Return (Error_Pragma_Ref);
-- Outputs error message for current pragma. The message may contain
-- a % that will be replaced with the pragma name. The parameter Ref
-- must be an entity whose name can be referenced by & and sloc by #.
-- After placing the message, Pragma_Exit is raised. Note: this routine
-- calls Fix_Error (see spec of that procedure for details).
function Find_Lib_Unit_Name return Entity_Id;
-- Used for a library unit pragma to find the entity to which the
-- library unit pragma applies, returns the entity found.
procedure Find_Program_Unit_Name (Id : Node_Id);
-- If the pragma is a compilation unit pragma, the id must denote the
-- compilation unit in the same compilation, and the pragma must appear
-- in the list of preceding or trailing pragmas. If it is a program
-- unit pragma that is not a compilation unit pragma, then the
-- identifier must be visible.
function Find_Unique_Parameterless_Procedure
(Name : Entity_Id;
Arg : Node_Id) return Entity_Id;
-- Used for a procedure pragma to find the unique parameterless
-- procedure identified by Name, returns it if it exists, otherwise
-- errors out and uses Arg as the pragma argument for the message.
function Fix_Error (Msg : String) return String;
-- This is called prior to issuing an error message. Msg is the normal
-- error message issued in the pragma case. This routine checks for the
-- case of a pragma coming from an aspect in the source, and returns a
-- message suitable for the aspect case as follows:
--
-- Each substring "pragma" is replaced by "aspect"
--
-- If "argument of" is at the start of the error message text, it is
-- replaced by "entity for".
--
-- If "argument" is at the start of the error message text, it is
-- replaced by "entity".
--
-- So for example, "argument of pragma X must be discrete type"
-- returns "entity for aspect X must be a discrete type".
-- Finally Error_Msg_Name_1 is set to the name of the aspect (which may
-- be different from the pragma name). If the current pragma results
-- from rewriting another pragma, then Error_Msg_Name_1 is set to the
-- original pragma name.
procedure Gather_Associations
(Names : Name_List;
Args : out Args_List);
-- This procedure is used to gather the arguments for a pragma that
-- permits arbitrary ordering of parameters using the normal rules
-- for named and positional parameters. The Names argument is a list
-- of Name_Id values that corresponds to the allowed pragma argument
-- association identifiers in order. The result returned in Args is
-- a list of corresponding expressions that are the pragma arguments.
-- Note that this is a list of expressions, not of pragma argument
-- associations (Gather_Associations has completely checked all the
-- optional identifiers when it returns). An entry in Args is Empty
-- on return if the corresponding argument is not present.
procedure GNAT_Pragma;
-- Called for all GNAT defined pragmas to check the relevant restriction
-- (No_Implementation_Pragmas).
function Is_Before_First_Decl
(Pragma_Node : Node_Id;
Decls : List_Id) return Boolean;
-- Return True if Pragma_Node is before the first declarative item in
-- Decls where Decls is the list of declarative items.
function Is_Configuration_Pragma return Boolean;
-- Determines if the placement of the current pragma is appropriate
-- for a configuration pragma.
function Is_In_Context_Clause return Boolean;
-- Returns True if pragma appears within the context clause of a unit,
-- and False for any other placement (does not generate any messages).
function Is_Static_String_Expression (Arg : Node_Id) return Boolean;
-- Analyzes the argument, and determines if it is a static string
-- expression, returns True if so, False if non-static or not String.
-- A special case is that a string literal returns True in Ada 83 mode
-- (which has no such thing as static string expressions). Note that
-- the call analyzes its argument, so this cannot be used for the case
-- where an identifier might not be declared.
procedure Pragma_Misplaced;
pragma No_Return (Pragma_Misplaced);
-- Issue fatal error message for misplaced pragma
procedure Process_Atomic_Independent_Shared_Volatile;
-- Common processing for pragmas Atomic, Independent, Shared, Volatile.
-- Note that Shared is an obsolete Ada 83 pragma and treated as being
-- identical in effect to pragma Atomic.
procedure Process_Compile_Time_Warning_Or_Error;
-- Common processing for Compile_Time_Error and Compile_Time_Warning
procedure Process_Convention
(C : out Convention_Id;
Ent : out Entity_Id);
-- Common processing for Convention, Interface, Import and Export.
-- Checks first two arguments of pragma, and sets the appropriate
-- convention value in the specified entity or entities. On return
-- C is the convention, Ent is the referenced entity.
procedure Process_Disable_Enable_Atomic_Sync (Nam : Name_Id);
-- Common processing for Disable/Enable_Atomic_Synchronization. Nam is
-- Name_Suppress for Disable and Name_Unsuppress for Enable.
procedure Process_Extended_Import_Export_Object_Pragma
(Arg_Internal : Node_Id;
Arg_External : Node_Id;
Arg_Size : Node_Id);
-- Common processing for the pragmas Import/Export_Object. The three
-- arguments correspond to the three named parameters of the pragmas. An
-- argument is empty if the corresponding parameter is not present in
-- the pragma.
procedure Process_Extended_Import_Export_Internal_Arg
(Arg_Internal : Node_Id := Empty);
-- Common processing for all extended Import and Export pragmas. The
-- argument is the pragma parameter for the Internal argument. If
-- Arg_Internal is empty or inappropriate, an error message is posted.
-- Otherwise, on normal return, the Entity_Field of Arg_Internal is
-- set to identify the referenced entity.
procedure Process_Extended_Import_Export_Subprogram_Pragma
(Arg_Internal : Node_Id;
Arg_External : Node_Id;
Arg_Parameter_Types : Node_Id;
Arg_Result_Type : Node_Id := Empty;
Arg_Mechanism : Node_Id;
Arg_Result_Mechanism : Node_Id := Empty);
-- Common processing for all extended Import and Export pragmas applying
-- to subprograms. The caller omits any arguments that do not apply to
-- the pragma in question (for example, Arg_Result_Type can be non-Empty
-- only in the Import_Function and Export_Function cases). The argument
-- names correspond to the allowed pragma association identifiers.
procedure Process_Generic_List;
-- Common processing for Share_Generic and Inline_Generic
procedure Process_Import_Or_Interface;
-- Common processing for Import or Interface
procedure Process_Import_Predefined_Type;
-- Processing for completing a type with pragma Import. This is used
-- to declare types that match predefined C types, especially for cases
-- without corresponding Ada predefined type.
type Inline_Status is (Suppressed, Disabled, Enabled);
-- Inline status of a subprogram, indicated as follows:
-- Suppressed: inlining is suppressed for the subprogram
-- Disabled: no inlining is requested for the subprogram
-- Enabled: inlining is requested/required for the subprogram
procedure Process_Inline (Status : Inline_Status);
-- Common processing for Inline, Inline_Always and No_Inline. Parameter
-- indicates the inline status specified by the pragma.
procedure Process_Interface_Name
(Subprogram_Def : Entity_Id;
Ext_Arg : Node_Id;
Link_Arg : Node_Id);
-- Given the last two arguments of pragma Import, pragma Export, or
-- pragma Interface_Name, performs validity checks and sets the
-- Interface_Name field of the given subprogram entity to the
-- appropriate external or link name, depending on the arguments given.
-- Ext_Arg is always present, but Link_Arg may be missing. Note that
-- Ext_Arg may represent the Link_Name if Link_Arg is missing, and
-- appropriate named notation is used for Ext_Arg. If neither Ext_Arg
-- nor Link_Arg is present, the interface name is set to the default
-- from the subprogram name.
procedure Process_Interrupt_Or_Attach_Handler;
-- Common processing for Interrupt and Attach_Handler pragmas
procedure Process_Restrictions_Or_Restriction_Warnings (Warn : Boolean);
-- Common processing for Restrictions and Restriction_Warnings pragmas.
-- Warn is True for Restriction_Warnings, or for Restrictions if the
-- flag Treat_Restrictions_As_Warnings is set, and False if this flag
-- is not set in the Restrictions case.
procedure Process_Suppress_Unsuppress (Suppress_Case : Boolean);
-- Common processing for Suppress and Unsuppress. The boolean parameter
-- Suppress_Case is True for the Suppress case, and False for the
-- Unsuppress case.
procedure Record_Independence_Check (N : Node_Id; E : Entity_Id);
-- Subsidiary to the analysis of pragmas Independent[_Components].
-- Record such a pragma N applied to entity E for future checks.
procedure Set_Exported (E : Entity_Id; Arg : Node_Id);
-- This procedure sets the Is_Exported flag for the given entity,
-- checking that the entity was not previously imported. Arg is
-- the argument that specified the entity. A check is also made
-- for exporting inappropriate entities.
procedure Set_Extended_Import_Export_External_Name
(Internal_Ent : Entity_Id;
Arg_External : Node_Id);
-- Common processing for all extended import export pragmas. The first
-- argument, Internal_Ent, is the internal entity, which has already
-- been checked for validity by the caller. Arg_External is from the
-- Import or Export pragma, and may be null if no External parameter
-- was present. If Arg_External is present and is a non-null string
-- (a null string is treated as the default), then the Interface_Name
-- field of Internal_Ent is set appropriately.
procedure Set_Imported (E : Entity_Id);
-- This procedure sets the Is_Imported flag for the given entity,
-- checking that it is not previously exported or imported.
procedure Set_Mechanism_Value (Ent : Entity_Id; Mech_Name : Node_Id);
-- Mech is a parameter passing mechanism (see Import_Function syntax
-- for MECHANISM_NAME). This routine checks that the mechanism argument
-- has the right form, and if not issues an error message. If the
-- argument has the right form then the Mechanism field of Ent is
-- set appropriately.
procedure Set_Rational_Profile;
-- Activate the set of configuration pragmas and permissions that make
-- up the Rational profile.
procedure Set_Ravenscar_Profile (N : Node_Id);
-- Activate the set of configuration pragmas and restrictions that make
-- up the Ravenscar Profile. N is the corresponding pragma node, which
-- is used for error messages on any constructs violating the profile.
----------------------------------
-- Acquire_Warning_Match_String --
----------------------------------
procedure Acquire_Warning_Match_String (Arg : Node_Id) is
begin
String_To_Name_Buffer
(Strval (Expr_Value_S (Get_Pragma_Arg (Arg))));
-- Add asterisk at start if not already there
if Name_Len > 0 and then Name_Buffer (1) /= '*' then
Name_Buffer (2 .. Name_Len + 1) :=
Name_Buffer (1 .. Name_Len);
Name_Buffer (1) := '*';
Name_Len := Name_Len + 1;
end if;
-- Add asterisk at end if not already there
if Name_Buffer (Name_Len) /= '*' then
Name_Len := Name_Len + 1;
Name_Buffer (Name_Len) := '*';
end if;
end Acquire_Warning_Match_String;
---------------------
-- Ada_2005_Pragma --
---------------------
procedure Ada_2005_Pragma is
begin
if Ada_Version <= Ada_95 then
Check_Restriction (No_Implementation_Pragmas, N);
end if;
end Ada_2005_Pragma;
---------------------
-- Ada_2012_Pragma --
---------------------
procedure Ada_2012_Pragma is
begin
if Ada_Version <= Ada_2005 then
Check_Restriction (No_Implementation_Pragmas, N);
end if;
end Ada_2012_Pragma;
---------------------
-- Analyze_Part_Of --
---------------------
procedure Analyze_Part_Of
(Item_Id : Entity_Id;
State : Node_Id;
Indic : Node_Id;
Legal : out Boolean)
is
Pack_Id : Entity_Id;
Placement : State_Space_Kind;
Parent_Unit : Entity_Id;
State_Id : Entity_Id;
begin
-- Assume that the pragma/option is illegal
Legal := False;
if Nkind_In (State, N_Expanded_Name,
N_Identifier,
N_Selected_Component)
then
Analyze (State);
Resolve_State (State);
if Is_Entity_Name (State)
and then Ekind (Entity (State)) = E_Abstract_State
then
State_Id := Entity (State);
else
SPARK_Msg_N
("indicator Part_Of must denote an abstract state", State);
return;
end if;
-- This is a syntax error, always report
else
Error_Msg_N
("indicator Part_Of must denote an abstract state", State);
return;
end if;
-- Determine where the state, variable or the package instantiation
-- lives with respect to the enclosing packages or package bodies (if
-- any). This placement dictates the legality of the encapsulating
-- state.
Find_Placement_In_State_Space
(Item_Id => Item_Id,
Placement => Placement,
Pack_Id => Pack_Id);
-- The item appears in a non-package construct with a declarative
-- part (subprogram, block, etc). As such, the item is not allowed
-- to be a part of an encapsulating state because the item is not
-- visible.
if Placement = Not_In_Package then
SPARK_Msg_N
("indicator Part_Of cannot appear in this context "
& "(SPARK RM 7.2.6(5))", Indic);
Error_Msg_Name_1 := Chars (Scope (State_Id));
SPARK_Msg_NE
("\& is not part of the hidden state of package %",
Indic, Item_Id);
-- The item appears in the visible state space of some package. In
-- general this scenario does not warrant Part_Of except when the
-- package is a private child unit and the encapsulating state is
-- declared in a parent unit or a public descendant of that parent
-- unit.
elsif Placement = Visible_State_Space then
if Is_Child_Unit (Pack_Id)
and then Is_Private_Descendant (Pack_Id)
then
-- A variable or state abstraction which is part of the
-- visible state of a private child unit (or one of its public
-- descendants) must have its Part_Of indicator specified. The
-- Part_Of indicator must denote a state abstraction declared
-- by either the parent unit of the private unit or by a public
-- descendant of that parent unit.
-- Find nearest private ancestor (which can be the current unit
-- itself).
Parent_Unit := Pack_Id;
while Present (Parent_Unit) loop
exit when Private_Present
(Parent (Unit_Declaration_Node (Parent_Unit)));
Parent_Unit := Scope (Parent_Unit);
end loop;
Parent_Unit := Scope (Parent_Unit);
if not Is_Child_Or_Sibling (Pack_Id, Scope (State_Id)) then
SPARK_Msg_NE
("indicator Part_Of must denote an abstract state of& "
& "or public descendant (SPARK RM 7.2.6(3))",
Indic, Parent_Unit);
elsif Scope (State_Id) = Parent_Unit
or else (Is_Ancestor_Package (Parent_Unit, Scope (State_Id))
and then
not Is_Private_Descendant (Scope (State_Id)))
then
null;
else
SPARK_Msg_NE
("indicator Part_Of must denote an abstract state of& "
& "or public descendant (SPARK RM 7.2.6(3))",
Indic, Parent_Unit);
end if;
-- Indicator Part_Of is not needed when the related package is not
-- a private child unit or a public descendant thereof.
else
SPARK_Msg_N
("indicator Part_Of cannot appear in this context "
& "(SPARK RM 7.2.6(5))", Indic);
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("\& is declared in the visible part of package %",
Indic, Item_Id);
end if;
-- When the item appears in the private state space of a package, the
-- encapsulating state must be declared in the same package.
elsif Placement = Private_State_Space then
if Scope (State_Id) /= Pack_Id then
SPARK_Msg_NE
("indicator Part_Of must designate an abstract state of "
& "package & (SPARK RM 7.2.6(2))", Indic, Pack_Id);
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("\& is declared in the private part of package %",
Indic, Item_Id);
end if;
-- Items declared in the body state space of a package do not need
-- Part_Of indicators as the refinement has already been seen.
else
SPARK_Msg_N
("indicator Part_Of cannot appear in this context "
& "(SPARK RM 7.2.6(5))", Indic);
if Scope (State_Id) = Pack_Id then
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("\& is declared in the body of package %", Indic, Item_Id);
end if;
end if;
Legal := True;
end Analyze_Part_Of;
--------------------------------
-- Analyze_Pre_Post_Condition --
--------------------------------
procedure Analyze_Pre_Post_Condition is
Prag_Iden : constant Node_Id := Pragma_Identifier (N);
Subp_Decl : Node_Id;
Subp_Id : Entity_Id;
Duplicates_OK : Boolean := False;
-- Flag set when a pre/postcondition allows multiple pragmas of the
-- same kind.
In_Body_OK : Boolean := False;
-- Flag set when a pre/postcondition is allowed to appear on a body
-- even though the subprogram may have a spec.
Is_Pre_Post : Boolean := False;
-- Flag set when the pragma is one of Pre, Pre_Class, Post or
-- Post_Class.
begin
-- Change the name of pragmas Pre, Pre_Class, Post and Post_Class to
-- offer uniformity among the various kinds of pre/postconditions by
-- rewriting the pragma identifier. This allows the retrieval of the
-- original pragma name by routine Original_Aspect_Pragma_Name.
if Comes_From_Source (N) then
if Nam_In (Pname, Name_Pre, Name_Pre_Class) then
Is_Pre_Post := True;
Set_Class_Present (N, Pname = Name_Pre_Class);
Rewrite (Prag_Iden, Make_Identifier (Loc, Name_Precondition));
elsif Nam_In (Pname, Name_Post, Name_Post_Class) then
Is_Pre_Post := True;
Set_Class_Present (N, Pname = Name_Post_Class);
Rewrite (Prag_Iden, Make_Identifier (Loc, Name_Postcondition));
end if;
end if;
-- Determine the semantics with respect to duplicates and placement
-- in a body. Pragmas Precondition and Postcondition were introduced
-- before aspects and are not subject to the same aspect-like rules.
if Nam_In (Pname, Name_Precondition, Name_Postcondition) then
Duplicates_OK := True;
In_Body_OK := True;
end if;
GNAT_Pragma;
-- Pragmas Pre, Pre_Class, Post and Post_Class allow for a single
-- argument without an identifier.
if Is_Pre_Post then
Check_Arg_Count (1);
Check_No_Identifiers;
-- Pragmas Precondition and Postcondition have complex argument
-- profile.
else
Check_At_Least_N_Arguments (1);
Check_At_Most_N_Arguments (2);
Check_Optional_Identifier (Arg1, Name_Check);
if Present (Arg2) then
Check_Optional_Identifier (Arg2, Name_Message);
Preanalyze_Spec_Expression
(Get_Pragma_Arg (Arg2), Standard_String);
end if;
end if;
-- For a pragma PPC in the extended main source unit, record enabled
-- status in SCO.
-- ??? nothing checks that the pragma is in the main source unit
if Is_Checked (N) and then not Split_PPC (N) then
Set_SCO_Pragma_Enabled (Loc);
end if;
-- Ensure the proper placement of the pragma
Subp_Decl :=
Find_Related_Subprogram_Or_Body (N, Do_Checks => not Duplicates_OK);
-- When a pre/postcondition pragma applies to an abstract subprogram,
-- its original form must be an aspect with 'Class.
if Nkind (Subp_Decl) = N_Abstract_Subprogram_Declaration then
if not From_Aspect_Specification (N) then
Error_Pragma
("pragma % cannot be applied to abstract subprogram");
elsif not Class_Present (N) then
Error_Pragma
("aspect % requires ''Class for abstract subprogram");
end if;
-- Entry declaration
elsif Nkind (Subp_Decl) = N_Entry_Declaration then
null;
-- Generic subprogram declaration
elsif Nkind (Subp_Decl) = N_Generic_Subprogram_Declaration then
null;
-- Subprogram body
elsif Nkind (Subp_Decl) = N_Subprogram_Body
and then (No (Corresponding_Spec (Subp_Decl)) or In_Body_OK)
then
null;
-- Subprogram body stub
elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub
and then (No (Corresponding_Spec_Of_Stub (Subp_Decl)) or In_Body_OK)
then
null;
-- Subprogram declaration
elsif Nkind (Subp_Decl) = N_Subprogram_Declaration then
-- AI05-0230: When a pre/postcondition pragma applies to a null
-- procedure, its original form must be an aspect with 'Class.
if Nkind (Specification (Subp_Decl)) = N_Procedure_Specification
and then Null_Present (Specification (Subp_Decl))
and then From_Aspect_Specification (N)
and then not Class_Present (N)
then
Error_Pragma ("aspect % requires ''Class for null procedure");
end if;
-- Otherwise the placement is illegal
else
Pragma_Misplaced;
return;
end if;
Subp_Id := Defining_Entity (Subp_Decl);
-- Construct a generic template for the pragma when the context is a
-- generic subprogram and the pragma is a source construct.
Create_Generic_Template (N, Subp_Id);
-- Fully analyze the pragma when it appears inside a subprogram
-- body because it cannot benefit from forward references.
if Nkind_In (Subp_Decl, N_Subprogram_Body,
N_Subprogram_Body_Stub)
then
Analyze_Pre_Post_Condition_In_Decl_Part (N);
end if;
-- Chain the pragma on the contract for further processing
Add_Contract_Item (N, Subp_Id);
end Analyze_Pre_Post_Condition;
----------------------------
-- Analyze_Refined_Pragma --
----------------------------
procedure Analyze_Refined_Pragma
(Spec_Id : out Entity_Id;
Body_Id : out Entity_Id;
Legal : out Boolean)
is
Body_Decl : Node_Id;
Spec_Decl : Node_Id;
begin
-- Assume that the pragma is illegal
Spec_Id := Empty;
Body_Id := Empty;
Legal := False;
GNAT_Pragma;
Check_Arg_Count (1);
Check_No_Identifiers;
-- Verify the placement of the pragma and check for duplicates. The
-- pragma must apply to a subprogram body [stub].
Body_Decl := Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
-- Extract the entities of the spec and body
if Nkind (Body_Decl) = N_Subprogram_Body then
Body_Id := Defining_Entity (Body_Decl);
Spec_Id := Corresponding_Spec (Body_Decl);
elsif Nkind (Body_Decl) = N_Subprogram_Body_Stub then
Body_Id := Defining_Entity (Body_Decl);
Spec_Id := Corresponding_Spec_Of_Stub (Body_Decl);
else
Pragma_Misplaced;
return;
end if;
-- The pragma must apply to the second declaration of a subprogram.
-- In other words, the body [stub] cannot acts as a spec.
if No (Spec_Id) then
Error_Pragma ("pragma % cannot apply to a stand alone body");
return;
-- Catch the case where the subprogram body is a subunit and acts as
-- the third declaration of the subprogram.
elsif Nkind (Parent (Body_Decl)) = N_Subunit then
Error_Pragma ("pragma % cannot apply to a subunit");
return;
end if;
-- The pragma can only apply to the body [stub] of a subprogram
-- declared in the visible part of a package. Retrieve the context of
-- the subprogram declaration.
Spec_Decl := Unit_Declaration_Node (Spec_Id);
if Nkind (Parent (Spec_Decl)) /= N_Package_Specification then
Error_Pragma
("pragma % must apply to the body of a subprogram declared in a "
& "package specification");
return;
end if;
-- If we get here, then the pragma is legal
if Nam_In (Pname, Name_Refined_Depends,
Name_Refined_Global,
Name_Refined_State)
then
Ensure_Aggregate_Form (Get_Argument (N));
end if;
Legal := True;
end Analyze_Refined_Pragma;
--------------------------
-- Check_Ada_83_Warning --
--------------------------
procedure Check_Ada_83_Warning is
begin
if Ada_Version = Ada_83 and then Comes_From_Source (N) then
Error_Msg_N ("(Ada 83) pragma& is non-standard??", N);
end if;
end Check_Ada_83_Warning;
---------------------
-- Check_Arg_Count --
---------------------
procedure Check_Arg_Count (Required : Nat) is
begin
if Arg_Count /= Required then
Error_Pragma ("wrong number of arguments for pragma%");
end if;
end Check_Arg_Count;
--------------------------------
-- Check_Arg_Is_External_Name --
--------------------------------
procedure Check_Arg_Is_External_Name (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
if Nkind (Argx) = N_Identifier then
return;
else
Analyze_And_Resolve (Argx, Standard_String);
if Is_OK_Static_Expression (Argx) then
return;
elsif Etype (Argx) = Any_Type then
raise Pragma_Exit;
-- An interesting special case, if we have a string literal and
-- we are in Ada 83 mode, then we allow it even though it will
-- not be flagged as static. This allows expected Ada 83 mode
-- use of external names which are string literals, even though
-- technically these are not static in Ada 83.
elsif Ada_Version = Ada_83
and then Nkind (Argx) = N_String_Literal
then
return;
-- Static expression that raises Constraint_Error. This has
-- already been flagged, so just exit from pragma processing.
elsif Is_OK_Static_Expression (Argx) then
raise Pragma_Exit;
-- Here we have a real error (non-static expression)
else
Error_Msg_Name_1 := Pname;
declare
Msg : constant String :=
"argument for pragma% must be a identifier or "
& "static string expression!";
begin
Flag_Non_Static_Expr (Fix_Error (Msg), Argx);
raise Pragma_Exit;
end;
end if;
end if;
end Check_Arg_Is_External_Name;
-----------------------------
-- Check_Arg_Is_Identifier --
-----------------------------
procedure Check_Arg_Is_Identifier (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
if Nkind (Argx) /= N_Identifier then
Error_Pragma_Arg
("argument for pragma% must be identifier", Argx);
end if;
end Check_Arg_Is_Identifier;
----------------------------------
-- Check_Arg_Is_Integer_Literal --
----------------------------------
procedure Check_Arg_Is_Integer_Literal (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
if Nkind (Argx) /= N_Integer_Literal then
Error_Pragma_Arg
("argument for pragma% must be integer literal", Argx);
end if;
end Check_Arg_Is_Integer_Literal;
-------------------------------------------
-- Check_Arg_Is_Library_Level_Local_Name --
-------------------------------------------
-- LOCAL_NAME ::=
-- DIRECT_NAME
-- | DIRECT_NAME'ATTRIBUTE_DESIGNATOR
-- | library_unit_NAME
procedure Check_Arg_Is_Library_Level_Local_Name (Arg : Node_Id) is
begin
Check_Arg_Is_Local_Name (Arg);
if not Is_Library_Level_Entity (Entity (Get_Pragma_Arg (Arg)))
and then Comes_From_Source (N)
then
Error_Pragma_Arg
("argument for pragma% must be library level entity", Arg);
end if;
end Check_Arg_Is_Library_Level_Local_Name;
-----------------------------
-- Check_Arg_Is_Local_Name --
-----------------------------
-- LOCAL_NAME ::=
-- DIRECT_NAME
-- | DIRECT_NAME'ATTRIBUTE_DESIGNATOR
-- | library_unit_NAME
procedure Check_Arg_Is_Local_Name (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Analyze (Argx);
if Nkind (Argx) not in N_Direct_Name
and then (Nkind (Argx) /= N_Attribute_Reference
or else Present (Expressions (Argx))
or else Nkind (Prefix (Argx)) /= N_Identifier)
and then (not Is_Entity_Name (Argx)
or else not Is_Compilation_Unit (Entity (Argx)))
then
Error_Pragma_Arg ("argument for pragma% must be local name", Argx);
end if;
-- No further check required if not an entity name
if not Is_Entity_Name (Argx) then
null;
else
declare
OK : Boolean;
Ent : constant Entity_Id := Entity (Argx);
Scop : constant Entity_Id := Scope (Ent);
begin
-- Case of a pragma applied to a compilation unit: pragma must
-- occur immediately after the program unit in the compilation.
if Is_Compilation_Unit (Ent) then
declare
Decl : constant Node_Id := Unit_Declaration_Node (Ent);
begin
-- Case of pragma placed immediately after spec
if Parent (N) = Aux_Decls_Node (Parent (Decl)) then
OK := True;
-- Case of pragma placed immediately after body
elsif Nkind (Decl) = N_Subprogram_Declaration
and then Present (Corresponding_Body (Decl))
then
OK := Parent (N) =
Aux_Decls_Node
(Parent (Unit_Declaration_Node
(Corresponding_Body (Decl))));
-- All other cases are illegal
else
OK := False;
end if;
end;
-- Special restricted placement rule from 10.2.1(11.8/2)
elsif Is_Generic_Formal (Ent)
and then Prag_Id = Pragma_Preelaborable_Initialization
then
OK := List_Containing (N) =
Generic_Formal_Declarations
(Unit_Declaration_Node (Scop));
-- If this is an aspect applied to a subprogram body, the
-- pragma is inserted in its declarative part.
elsif From_Aspect_Specification (N)
and then Ent = Current_Scope
and then
Nkind (Unit_Declaration_Node (Ent)) = N_Subprogram_Body
then
OK := True;
-- If the aspect is a predicate (possibly others ???) and the
-- context is a record type, this is a discriminant expression
-- within a type declaration, that freezes the predicated
-- subtype.
elsif From_Aspect_Specification (N)
and then Prag_Id = Pragma_Predicate
and then Ekind (Current_Scope) = E_Record_Type
and then Scop = Scope (Current_Scope)
then
OK := True;
-- Default case, just check that the pragma occurs in the scope
-- of the entity denoted by the name.
else
OK := Current_Scope = Scop;
end if;
if not OK then
Error_Pragma_Arg
("pragma% argument must be in same declarative part", Arg);
end if;
end;
end if;
end Check_Arg_Is_Local_Name;
---------------------------------
-- Check_Arg_Is_Locking_Policy --
---------------------------------
procedure Check_Arg_Is_Locking_Policy (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Is_Locking_Policy_Name (Chars (Argx)) then
Error_Pragma_Arg ("& is not a valid locking policy name", Argx);
end if;
end Check_Arg_Is_Locking_Policy;
-----------------------------------------------
-- Check_Arg_Is_Partition_Elaboration_Policy --
-----------------------------------------------
procedure Check_Arg_Is_Partition_Elaboration_Policy (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Is_Partition_Elaboration_Policy_Name (Chars (Argx)) then
Error_Pragma_Arg
("& is not a valid partition elaboration policy name", Argx);
end if;
end Check_Arg_Is_Partition_Elaboration_Policy;
-------------------------
-- Check_Arg_Is_One_Of --
-------------------------
procedure Check_Arg_Is_One_Of (Arg : Node_Id; N1, N2 : Name_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Nam_In (Chars (Argx), N1, N2) then
Error_Msg_Name_2 := N1;
Error_Msg_Name_3 := N2;
Error_Pragma_Arg ("argument for pragma% must be% or%", Argx);
end if;
end Check_Arg_Is_One_Of;
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3 : Name_Id)
is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Nam_In (Chars (Argx), N1, N2, N3) then
Error_Pragma_Arg ("invalid argument for pragma%", Argx);
end if;
end Check_Arg_Is_One_Of;
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3, N4 : Name_Id)
is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Nam_In (Chars (Argx), N1, N2, N3, N4) then
Error_Pragma_Arg ("invalid argument for pragma%", Argx);
end if;
end Check_Arg_Is_One_Of;
procedure Check_Arg_Is_One_Of
(Arg : Node_Id;
N1, N2, N3, N4, N5 : Name_Id)
is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Nam_In (Chars (Argx), N1, N2, N3, N4, N5) then
Error_Pragma_Arg ("invalid argument for pragma%", Argx);
end if;
end Check_Arg_Is_One_Of;
---------------------------------
-- Check_Arg_Is_Queuing_Policy --
---------------------------------
procedure Check_Arg_Is_Queuing_Policy (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Is_Queuing_Policy_Name (Chars (Argx)) then
Error_Pragma_Arg ("& is not a valid queuing policy name", Argx);
end if;
end Check_Arg_Is_Queuing_Policy;
---------------------------------------
-- Check_Arg_Is_OK_Static_Expression --
---------------------------------------
procedure Check_Arg_Is_OK_Static_Expression
(Arg : Node_Id;
Typ : Entity_Id := Empty)
is
begin
Check_Expr_Is_OK_Static_Expression (Get_Pragma_Arg (Arg), Typ);
end Check_Arg_Is_OK_Static_Expression;
------------------------------------------
-- Check_Arg_Is_Task_Dispatching_Policy --
------------------------------------------
procedure Check_Arg_Is_Task_Dispatching_Policy (Arg : Node_Id) is
Argx : constant Node_Id := Get_Pragma_Arg (Arg);
begin
Check_Arg_Is_Identifier (Argx);
if not Is_Task_Dispatching_Policy_Name (Chars (Argx)) then
Error_Pragma_Arg
("& is not an allowed task dispatching policy name", Argx);
end if;
end Check_Arg_Is_Task_Dispatching_Policy;
---------------------
-- Check_Arg_Order --
---------------------
procedure Check_Arg_Order (Names : Name_List) is
Arg : Node_Id;
Highest_So_Far : Natural := 0;
-- Highest index in Names seen do far
begin
Arg := Arg1;
for J in 1 .. Arg_Count loop
if Chars (Arg) /= No_Name then
for K in Names'Range loop
if Chars (Arg) = Names (K) then
if K < Highest_So_Far then
Error_Msg_Name_1 := Pname;
Error_Msg_N
("parameters out of order for pragma%", Arg);
Error_Msg_Name_1 := Names (K);
Error_Msg_Name_2 := Names (Highest_So_Far);
Error_Msg_N ("\% must appear before %", Arg);
raise Pragma_Exit;
else
Highest_So_Far := K;
end if;
end if;
end loop;
end if;
Arg := Next (Arg);
end loop;
end Check_Arg_Order;
--------------------------------
-- Check_At_Least_N_Arguments --
--------------------------------
procedure Check_At_Least_N_Arguments (N : Nat) is
begin
if Arg_Count < N then
Error_Pragma ("too few arguments for pragma%");
end if;
end Check_At_Least_N_Arguments;
-------------------------------
-- Check_At_Most_N_Arguments --
-------------------------------
procedure Check_At_Most_N_Arguments (N : Nat) is
Arg : Node_Id;
begin
if Arg_Count > N then
Arg := Arg1;
for J in 1 .. N loop
Next (Arg);
Error_Pragma_Arg ("too many arguments for pragma%", Arg);
end loop;
end if;
end Check_At_Most_N_Arguments;
---------------------
-- Check_Component --
---------------------
procedure Check_Component
(Comp : Node_Id;
UU_Typ : Entity_Id;
In_Variant_Part : Boolean := False)
is
Comp_Id : constant Entity_Id := Defining_Identifier (Comp);
Sindic : constant Node_Id :=
Subtype_Indication (Component_Definition (Comp));
Typ : constant Entity_Id := Etype (Comp_Id);
begin
-- Ada 2005 (AI-216): If a component subtype is subject to a per-
-- object constraint, then the component type shall be an Unchecked_
-- Union.
if Nkind (Sindic) = N_Subtype_Indication
and then Has_Per_Object_Constraint (Comp_Id)
and then not Is_Unchecked_Union (Etype (Subtype_Mark (Sindic)))
then
Error_Msg_N
("component subtype subject to per-object constraint "
& "must be an Unchecked_Union", Comp);
-- Ada 2012 (AI05-0026): For an unchecked union type declared within
-- the body of a generic unit, or within the body of any of its
-- descendant library units, no part of the type of a component
-- declared in a variant_part of the unchecked union type shall be of
-- a formal private type or formal private extension declared within
-- the formal part of the generic unit.
elsif Ada_Version >= Ada_2012
and then In_Generic_Body (UU_Typ)
and then In_Variant_Part
and then Is_Private_Type (Typ)
and then Is_Generic_Type (Typ)
then
Error_Msg_N
("component of unchecked union cannot be of generic type", Comp);
elsif Needs_Finalization (Typ) then
Error_Msg_N
("component of unchecked union cannot be controlled", Comp);
elsif Has_Task (Typ) then
Error_Msg_N
("component of unchecked union cannot have tasks", Comp);
end if;
end Check_Component;
-----------------------------
-- Check_Declaration_Order --
-----------------------------
procedure Check_Declaration_Order (First : Node_Id; Second : Node_Id) is
procedure Check_Aspect_Specification_Order;
-- Inspect the aspect specifications of the context to determine the
-- proper order.
--------------------------------------
-- Check_Aspect_Specification_Order --
--------------------------------------
procedure Check_Aspect_Specification_Order is
Asp_First : constant Node_Id := Corresponding_Aspect (First);
Asp_Second : constant Node_Id := Corresponding_Aspect (Second);
Asp : Node_Id;
begin
-- Both aspects must be part of the same aspect specification list
pragma Assert
(List_Containing (Asp_First) = List_Containing (Asp_Second));
-- Try to reach Second starting from First in a left to right
-- traversal of the aspect specifications.
Asp := Next (Asp_First);
while Present (Asp) loop
-- The order is ok, First is followed by Second
if Asp = Asp_Second then
return;
end if;
Next (Asp);
end loop;
-- If we get here, then the aspects are out of order
SPARK_Msg_N ("aspect % cannot come after aspect %", First);
end Check_Aspect_Specification_Order;
-- Local variables
Stmt : Node_Id;
-- Start of processing for Check_Declaration_Order
begin
-- Cannot check the order if one of the pragmas is missing
if No (First) or else No (Second) then
return;
end if;
-- Set up the error names in case the order is incorrect
Error_Msg_Name_1 := Pragma_Name (First);
Error_Msg_Name_2 := Pragma_Name (Second);
if From_Aspect_Specification (First) then
-- Both pragmas are actually aspects, check their declaration
-- order in the associated aspect specification list. Otherwise
-- First is an aspect and Second a source pragma.
if From_Aspect_Specification (Second) then
Check_Aspect_Specification_Order;
end if;
-- Abstract_States is a source pragma
else
if From_Aspect_Specification (Second) then
SPARK_Msg_N ("pragma % cannot come after aspect %", First);
-- Both pragmas are source constructs. Try to reach First from
-- Second by traversing the declarations backwards.
else
Stmt := Prev (Second);
while Present (Stmt) loop
-- The order is ok, First is followed by Second
if Stmt = First then