summaryrefslogtreecommitdiff
path: root/gcc/ada/sem_prag.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/sem_prag.adb')
-rw-r--r--gcc/ada/sem_prag.adb617
1 files changed, 589 insertions, 28 deletions
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 0bfcf0de491..070d7cbb48b 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -412,7 +412,7 @@ package body Sem_Prag is
Subp_Decl := Find_Related_Subprogram (N);
Subp_Id := Defining_Unit_Name (Specification (Subp_Decl));
- All_Cases := Expression (First (Pragma_Argument_Associations (N)));
+ All_Cases := Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
-- Multiple contract cases appear in aggregate form
@@ -1243,7 +1243,7 @@ package body Sem_Prag is
Subp_Decl := Find_Related_Subprogram (N);
Subp_Id := Defining_Unit_Name (Specification (Subp_Decl));
- Clause := Expression (First (Pragma_Argument_Associations (N)));
+ Clause := Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
-- Empty dependency list
@@ -1701,7 +1701,7 @@ package body Sem_Prag is
Subp_Decl := Find_Related_Subprogram (N);
Subp_Id := Defining_Unit_Name (Specification (Subp_Decl));
- List := Expression (First (Pragma_Argument_Associations (N)));
+ List := Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
-- There is nothing to be done for a null global list
@@ -1731,6 +1731,337 @@ package body Sem_Prag is
end if;
end Analyze_Global_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));
+
+ 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.
+
+ 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
+ -- A package with null initialization list is not allowed to have
+ -- additional initializations.
+
+ if Null_Seen then
+ Error_Msg_NE ("package & has null initialization", Item, Pack_Id);
+
+ -- Null initialization list
+
+ elsif Nkind (Item) = N_Null then
+
+ -- Catch a case where a null initialization item appears in a list
+ -- of non-null items.
+
+ if Non_Null_Seen then
+ Error_Msg_NE
+ ("package & has non-null initialization", Item, Pack_Id);
+ else
+ Null_Seen := True;
+ end if;
+
+ -- Initialization item
+
+ else
+ Non_Null_Seen := True;
+
+ Analyze (Item);
+
+ if Is_Entity_Name (Item) then
+ Item_Id := Entity (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.
+
+ if not Contains (States_And_Vars, Item_Id) then
+ Error_Msg_Name_1 := Chars (Pack_Id);
+ Error_Msg_NE
+ ("initialization item & must appear in the visible "
+ & "declarations of package %", Item, Item_Id);
+
+ -- Detect a duplicate use of the same initialization item
+
+ elsif Contains (Items_Seen, Item_Id) then
+ Error_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);
+ end if;
+
+ -- The item references something that is not a state or a
+ -- variable.
+
+ else
+ Error_Msg_N
+ ("initialization item must denote variable or state",
+ Item);
+ end if;
+
+ -- Some form of illegal construct masquerading as a name
+
+ 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
+ -- An initialization item with null inputs is not allowed to have
+ -- assitional inputs.
+
+ if Null_Seen then
+ Error_Msg_N ("item has null input list", Item);
+
+ -- Null input list
+
+ elsif Nkind (Input) = N_Null then
+
+ -- Catch a case where a null input appears in a list of non-
+ -- null inpits.
+
+ if Non_Null_Seen then
+ Error_Msg_N ("item has non-null input list", Item);
+ else
+ Null_Seen := True;
+ end if;
+
+ -- Input item
+
+ else
+ Non_Null_Seen := True;
+
+ Analyze (Input);
+
+ if Is_Entity_Name (Input) then
+ Input_Id := Entity (Input);
+
+ if Ekind_In (Input_Id, E_Abstract_State, E_Variable) then
+
+ -- The input cannot denote states or variables declared
+ -- within the visible declarations of the package.
+
+ if Contains (States_And_Vars, Input_Id) then
+ Error_Msg_Name_1 := Chars (Pack_Id);
+ Error_Msg_NE
+ ("input item & cannot denote a visible variable or "
+ & "state of package %", Input, Input_Id);
+
+ -- Detect a duplicate use of the same input item
+
+ elsif Contains (Inputs_Seen, Input_Id) then
+ Error_Msg_N ("duplicate input item", Input);
+
+ -- The input is legal, add it to the list of processed
+ -- inputs.
+
+ else
+ Add_Item (Input_Id, Inputs_Seen);
+ end if;
+
+ -- The input references something that is not a state or a
+ -- variable.
+
+ else
+ Error_Msg_N
+ ("input item must denote variable or state", Input);
+ end if;
+
+ -- Some form of illegal construct masquerading as a name
+
+ else
+ Error_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
+ Error_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
+ Error_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 :=
+ Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
+ Init : Node_Id;
+
+ -- Start of processing for Analyze_Initializes_In_Decl_Part
+
+ begin
+ Set_Analyzed (N);
+
+ -- Initialize the various lists used during analysis
+
+ Collect_States_And_Variables;
+
+ -- Multiple initialization clauses appear as an aggregate
+
+ if Nkind (Inits) = N_Aggregate then
+ 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;
+
+ -- Various forms of a single initialization clause. Note that these may
+ -- include malformed initializations.
+
+ else
+ Analyze_Initialization_Item (Inits);
+ end if;
+ end Analyze_Initializes_In_Decl_Part;
+
--------------------
-- Analyze_Pragma --
--------------------
@@ -1887,16 +2218,11 @@ package body Sem_Prag is
-- UU_Typ is the related Unchecked_Union type. Flag In_Variant_Part
-- should be set when Comp comes from a record variant.
- procedure Check_Test_Case;
- -- Called to process a test-case pragma. It starts with checking pragma
- -- arguments, and the rest of the treatment is similar to the one for
- -- pre- and postcondition in Check_Precondition_Postcondition, except
- -- the placement rules for the test-case pragma are stricter. These
- -- pragmas may only occur after a subprogram spec declared directly
- -- in a package spec unit. In this case, the pragma is chained to the
- -- subprogram in question (using Contract_Test_Cases and Next_Pragma)
- -- and analysis of the pragma is delayed till the end of the spec. In
- -- all other cases, an error message for bad placement is given.
+ procedure Check_Declaration_Order (States : Node_Id; Inits : Node_Id);
+ -- Subsidiary routine to the analysis of pragmas Abstract_State and
+ -- Initializes. Determine whether aspect/pragma Abstract_State denoted
+ -- by States is defined earlier than aspect/pragma Initializes denoted
+ -- by Inits.
procedure Check_Duplicate_Pragma (E : Entity_Id);
-- Check if a rep item of the same name as the current pragma is already
@@ -2013,6 +2339,17 @@ package body Sem_Prag is
-- that the constraint is static as required by the restrictions for
-- Unchecked_Union.
+ procedure Check_Test_Case;
+ -- Called to process a test-case pragma. It starts with checking pragma
+ -- arguments, and the rest of the treatment is similar to the one for
+ -- pre- and postcondition in Check_Precondition_Postcondition, except
+ -- the placement rules for the test-case pragma are stricter. These
+ -- pragmas may only occur after a subprogram spec declared directly
+ -- in a package spec unit. In this case, the pragma is chained to the
+ -- subprogram in question (using Contract_Test_Cases and Next_Pragma)
+ -- and analysis of the pragma is delayed till the end of the spec. In
+ -- all other cases, an error message for bad placement is given.
+
procedure Check_Valid_Configuration_Pragma;
-- Legality checks for placement of a configuration pragma
@@ -2907,6 +3244,109 @@ package body Sem_Prag is
end if;
end Check_Component;
+ -----------------------------
+ -- Check_Declaration_Order --
+ -----------------------------
+
+ procedure Check_Declaration_Order (States : Node_Id; Inits : 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_I : constant Node_Id := Corresponding_Aspect (Inits);
+ Asp_S : constant Node_Id := Corresponding_Aspect (States);
+ Asp : Node_Id;
+
+ States_Seen : Boolean := False;
+
+ begin
+ -- Both aspects must be part of the same aspect specification list
+
+ pragma Assert (List_Containing (Asp_I) = List_Containing (Asp_S));
+
+ Asp := First (List_Containing (Asp_I));
+ while Present (Asp) loop
+ if Get_Aspect_Id (Asp) = Aspect_Abstract_State then
+ States_Seen := True;
+
+ elsif Get_Aspect_Id (Asp) = Aspect_Initializes then
+ if not States_Seen then
+ Error_Msg_N
+ ("aspect % must come before aspect %", States);
+ end if;
+
+ exit;
+ end if;
+
+ Next (Asp);
+ end loop;
+ 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 (States) or else No (Inits) then
+ return;
+ end if;
+
+ -- Set up the error names in case the order is incorrect
+
+ Error_Msg_Name_1 := Name_Abstract_State;
+ Error_Msg_Name_2 := Name_Initializes;
+
+ if From_Aspect_Specification (States) then
+
+ -- Both pragmas are actually aspects, check their declaration
+ -- order in the associated aspect specification list. Otherwise
+ -- States is an aspect and Inits a source pragma.
+
+ if From_Aspect_Specification (Inits) then
+ Check_Aspect_Specification_Order;
+ end if;
+
+ -- Abstract_States is a source pragma
+
+ else
+ if From_Aspect_Specification (Inits) then
+ Error_Msg_N ("pragma % cannot come after aspect %", States);
+
+ -- Both pragmas are source constructs. Try to reach States from
+ -- Inits by traversing the declarations backwards.
+
+ else
+ Stmt := Prev (Inits);
+ while Present (Stmt) loop
+
+ -- The order is ok, Abstract_States is first followed by
+ -- Initializes.
+
+ if Nkind (Stmt) = N_Pragma
+ and then Pragma_Name (Stmt) = Name_Abstract_State
+ then
+ return;
+ end if;
+
+ Prev (Stmt);
+ end loop;
+
+ -- If we get here, then the pragmas are out of order
+
+ Error_Msg_N ("pragma % cannot come after pragma %", States);
+ end if;
+ end if;
+ end Check_Declaration_Order;
+
----------------------------
-- Check_Duplicate_Pragma --
----------------------------
@@ -8655,7 +9095,16 @@ package body Sem_Prag is
end if;
Pack_Id := Defining_Entity (Context);
- State := Expression (Arg1);
+ Add_Contract_Item (N, Pack_Id);
+
+ -- Verify the declaration order of aspects/pragmas Abstract_State
+ -- and Initializes.
+
+ Check_Declaration_Order
+ (States => N,
+ Inits => Get_Pragma (Pack_Id, Pragma_Initializes));
+
+ State := Expression (Arg1);
-- Multiple abstract states appear as an aggregate
@@ -12744,6 +13193,91 @@ package body Sem_Prag is
Initialize_Scalars := True;
end if;
+ -----------------
+ -- Initializes --
+ -----------------
+
+ -- pragma Initializes (INITIALIZATION_SPEC);
+
+ -- INITIALIZATION_SPEC ::= null | INITIALIZATION_LIST
+
+ -- INITIALIZATION_LIST ::=
+ -- INITIALIZATION_ITEM
+ -- | (INITIALIZATION_ITEM {, INITIALIZATION_ITEM})
+
+ -- INITIALIZATION_ITEM ::= name [=> INPUT_LIST]
+
+ -- INPUT_LIST ::=
+ -- null
+ -- | INPUT
+ -- | (INPUT {, INPUT})
+
+ -- INPUT ::= name
+
+ when Pragma_Initializes => Initializes : declare
+ Context : constant Node_Id := Parent (Parent (N));
+ Pack_Id : Entity_Id;
+ Stmt : Node_Id;
+
+ begin
+ GNAT_Pragma;
+ S14_Pragma;
+ Check_Arg_Count (1);
+
+ -- Ensure the proper placement of the pragma. Initializes must be
+ -- associated with a package declaration.
+
+ if not Nkind_In (Context, N_Generic_Package_Declaration,
+ N_Package_Declaration)
+ then
+ Pragma_Misplaced;
+ return;
+ end if;
+
+ Stmt := Prev (N);
+ while Present (Stmt) loop
+
+ -- Skip prior pragmas, but check for duplicates
+
+ if Nkind (Stmt) = N_Pragma then
+ if Pragma_Name (Stmt) = Pname then
+ Error_Msg_Name_1 := Pname;
+ Error_Msg_Sloc := Sloc (Stmt);
+ Error_Msg_N ("pragma % duplicates pragma declared #", N);
+ end if;
+
+ -- Skip internally generated code
+
+ elsif not Comes_From_Source (Stmt) then
+ null;
+
+ -- The pragma does not apply to a legal construct, issue an
+ -- error and stop the analysis.
+
+ else
+ Pragma_Misplaced;
+ return;
+ end if;
+
+ Stmt := Prev (Stmt);
+ end loop;
+
+ -- The pragma must be analyzed at the end of the visible
+ -- declarations of the related package. Save the pragma for later
+ -- (see Analyze_Initializes_In_Decl_Part) by adding it to the
+ -- contract of the package.
+
+ Pack_Id := Defining_Entity (Context);
+ Add_Contract_Item (N, Pack_Id);
+
+ -- Verify the declaration order of aspects/pragmas Abstract_State
+ -- and Initializes.
+
+ Check_Declaration_Order
+ (States => Get_Pragma (Pack_Id, Pragma_Abstract_State),
+ Inits => N);
+ end Initializes;
+
------------
-- Inline --
------------
@@ -16177,6 +16711,7 @@ package body Sem_Prag is
when Pragma_Refined_State => Refined_State : declare
Context : constant Node_Id := Parent (N);
Spec_Id : Entity_Id;
+ Stmt : Node_Id;
begin
GNAT_Pragma;
@@ -16191,6 +16726,34 @@ package body Sem_Prag is
return;
end if;
+ Stmt := Prev (N);
+ while Present (Stmt) loop
+
+ -- Skip prior pragmas, but check for duplicates
+
+ if Nkind (Stmt) = N_Pragma then
+ if Pragma_Name (Stmt) = Pname then
+ Error_Msg_Name_1 := Pname;
+ Error_Msg_Sloc := Sloc (Stmt);
+ Error_Msg_N ("pragma % duplicates pragma declared #", N);
+ end if;
+
+ -- Skip internally generated code
+
+ elsif not Comes_From_Source (Stmt) then
+ null;
+
+ -- The pragma does not apply to a legal construct, issue an
+ -- error and stop the analysis.
+
+ else
+ Pragma_Misplaced;
+ return;
+ end if;
+
+ Stmt := Prev (Stmt);
+ end loop;
+
-- State refinement is allowed only when the corresponding package
-- declaration has a non-null aspect/pragma Abstract_State.
@@ -16207,9 +16770,10 @@ package body Sem_Prag is
-- The pragma must be analyzed at the end of the declarations as
-- it has visibility over the whole declarative region. Save the
- -- pragma for later (see Analyze_Refined_Depends_In_Decl_Part).
+ -- pragma for later (see Analyze_Refined_Depends_In_Decl_Part) by
+ -- adding it to the contract of the package body.
- Set_Refined_State_Pragma (Defining_Entity (Context), N);
+ Add_Contract_Item (N, Defining_Entity (Context));
end Refined_State;
-----------------------
@@ -19647,9 +20211,9 @@ package body Sem_Prag is
procedure Analyze_Refinement_Clause (Clause : Node_Id);
-- Perform full analysis of a single refinement clause
- function Collect_Hidden_States return Elist_Id;
+ procedure Collect_Hidden_States;
-- Gather the entities of all hidden states that appear in the spec and
- -- body of the related package.
+ -- body of the related package in Hidden_States.
procedure Report_Unrefined_States;
-- Emit errors for all abstract states that have not been refined by
@@ -19938,9 +20502,7 @@ package body Sem_Prag is
-- Collect_Hidden_States --
---------------------------
- function Collect_Hidden_States return Elist_Id is
- Result : Elist_Id := No_Elist;
-
+ procedure Collect_Hidden_States is
procedure Collect_Hidden_States_In_Decls (Decls : List_Id);
-- Find all hidden states that appear in declarative list Decls and
-- append their entities to Result.
@@ -19963,7 +20525,7 @@ package body Sem_Prag is
begin
State_Elmt := First_Elmt (States);
while Present (State_Elmt) loop
- Add_Item (Node (State_Elmt), Result);
+ Add_Item (Node (State_Elmt), Hidden_States);
Next_Elmt (State_Elmt);
end loop;
@@ -19985,7 +20547,7 @@ package body Sem_Prag is
and then Ekind (Defining_Entity (Decl)) = E_Variable
and then Comes_From_Source (Decl)
then
- Add_Item (Defining_Entity (Decl), Result);
+ Add_Item (Defining_Entity (Decl), Hidden_States);
-- Gather the abstract states of a package along with all
-- hidden states in its visible declarations.
@@ -20014,8 +20576,6 @@ package body Sem_Prag is
Collect_Hidden_States_In_Decls (Private_Declarations (Pack_Spec));
Collect_Hidden_States_In_Decls (Declarations (Pack_Body));
-
- return Result;
end Collect_Hidden_States;
-----------------------------
@@ -20080,7 +20640,7 @@ package body Sem_Prag is
-- Local declarations
Clauses : constant Node_Id :=
- Expression (First (Pragma_Argument_Associations (N)));
+ Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
Clause : Node_Id;
-- Start of processing for Analyze_Refined_State_In_Decl_Part
@@ -20090,8 +20650,8 @@ package body Sem_Prag is
-- Initialize the various lists used during analysis
- Abstr_States := New_Copy_Elist (Abstract_States (Spec_Id));
- Hidden_States := Collect_Hidden_States;
+ Abstr_States := New_Copy_Elist (Abstract_States (Spec_Id));
+ Collect_Hidden_States;
-- Multiple state refinements appear as an aggregate
@@ -20814,6 +21374,7 @@ package body Sem_Prag is
Pragma_Independent => 0,
Pragma_Independent_Components => 0,
Pragma_Initialize_Scalars => -1,
+ Pragma_Initializes => -1,
Pragma_Inline => 0,
Pragma_Inline_Always => 0,
Pragma_Inline_Generic => 0,