aboutsummaryrefslogtreecommitdiff
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.adb408
1 files changed, 350 insertions, 58 deletions
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 3f0b9b8..e5c3d85 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -6514,11 +6514,7 @@ package body Sem_Prag is
(C : out Convention_Id;
Ent : out Entity_Id)
is
- Id : Node_Id;
- E : Entity_Id;
- E1 : Entity_Id;
- Cname : Name_Id;
- Comp_Unit : Unit_Number_Type;
+ Cname : Name_Id;
procedure Diagnose_Multiple_Pragmas (S : Entity_Id);
-- Called if we have more than one Export/Import/Convention pragma.
@@ -6698,17 +6694,6 @@ package body Sem_Prag is
procedure Set_Convention_From_Pragma (E : Entity_Id) is
begin
- -- Ghost convention is allowed only for functions
-
- if Ekind (E) /= E_Function and then C = Convention_Ghost then
- Error_Msg_N
- ("& may not have Ghost convention", E);
- Error_Msg_N
- ("\only functions are permitted to have Ghost convention",
- E);
- return;
- end if;
-
-- Ada 2005 (AI-430): Check invalid attempt to change convention
-- for an overridden dispatching operation. Technically this is
-- an amendment and should only be done in Ada 2005 mode. However,
@@ -6719,16 +6704,9 @@ package body Sem_Prag is
and then Present (Overridden_Operation (E))
and then C /= Convention (Overridden_Operation (E))
then
- -- An attempt to override a function with a ghost function
- -- appears as a mismatch in conventions.
-
- if C = Convention_Ghost then
- Error_Msg_N ("ghost function & cannot be overriding", E);
- else
- Error_Pragma_Arg
- ("cannot change convention for overridden dispatching "
- & "operation", Arg1);
- end if;
+ Error_Pragma_Arg
+ ("cannot change convention for overridden dispatching "
+ & "operation", Arg1);
end if;
-- Special checks for Convention_Stdcall
@@ -6858,6 +6836,13 @@ package body Sem_Prag is
end if;
end Set_Convention_From_Pragma;
+ -- Local variables
+
+ Comp_Unit : Unit_Number_Type;
+ E : Entity_Id;
+ E1 : Entity_Id;
+ Id : Node_Id;
+
-- Start of processing for Process_Convention
begin
@@ -6919,11 +6904,10 @@ package body Sem_Prag is
("convention `Ada_Pass_By_Copy` not allowed for by-reference "
& "type", Arg1);
end if;
- end if;
-- Ada_Pass_By_Reference special checking
- if C = Convention_Ada_Pass_By_Reference then
+ elsif C = Convention_Ada_Pass_By_Reference then
if not Is_First_Subtype (E) then
Error_Pragma_Arg
("convention `Ada_Pass_By_Reference` only allowed for types",
@@ -6937,14 +6921,6 @@ package body Sem_Prag is
end if;
end if;
- -- Ghost special checking
-
- if Is_Ghost_Subprogram (E)
- and then Present (Overridden_Operation (E))
- then
- Error_Msg_N ("ghost function & cannot be overriding", E);
- end if;
-
-- Go to renamed subprogram if present, since convention applies to
-- the actual renamed entity, not to the renaming entity. If the
-- subprogram is inherited, go to parent subprogram.
@@ -6974,9 +6950,8 @@ package body Sem_Prag is
end if;
end if;
- -- Check that we are not applying this to a specless body
- -- Relax this check if Relaxed_RM_Semantics to accomodate other Ada
- -- compilers.
+ -- Check that we are not applying this to a specless body. Relax this
+ -- check if Relaxed_RM_Semantics to accomodate other Ada compilers.
if Is_Subprogram (E)
and then Nkind (Parent (Declaration_Node (E))) = N_Subprogram_Body
@@ -9914,7 +9889,7 @@ package body Sem_Prag is
-- SIMPLE_OPTION
-- | NAME_VALUE_OPTION
- -- SIMPLE_OPTION ::= identifier
+ -- SIMPLE_OPTION ::= Ghost
-- NAME_VALUE_OPTION ::=
-- Part_Of => ABSTRACT_STATE
@@ -9945,20 +9920,22 @@ package body Sem_Prag is
Non_Null_Seen : Boolean := False;
Null_Seen : Boolean := False;
- Pack_Id : Entity_Id;
- -- Entity of related package when pragma Abstract_State appears
-
- procedure Analyze_Abstract_State (State : Node_Id);
+ procedure Analyze_Abstract_State
+ (State : Node_Id;
+ Pack_Id : Entity_Id);
-- Verify the legality of a single state declaration. Create and
-- decorate a state abstraction entity and introduce it into the
- -- visibility chain.
+ -- visibility chain. Pack_Id denotes the entity or the related
+ -- package where pragma Abstract_State appears.
----------------------------
-- Analyze_Abstract_State --
----------------------------
- procedure Analyze_Abstract_State (State : Node_Id) is
-
+ procedure Analyze_Abstract_State
+ (State : Node_Id;
+ Pack_Id : Entity_Id)
+ is
-- Flags used to verify the consistency of options
AR_Seen : Boolean := False;
@@ -10301,6 +10278,13 @@ package body Sem_Prag is
Set_Refinement_Constituents (State_Id, New_Elmt_List);
Set_Part_Of_Constituents (State_Id, New_Elmt_List);
+ -- An abstract state declared within a Ghost scope becomes
+ -- Ghost (SPARK RM 6.9(2)).
+
+ if Within_Ghost_Scope then
+ Set_Is_Ghost_Entity (State_Id);
+ end if;
+
-- Establish a link between the state declaration and the
-- abstract state entity. Note that a null state remains as
-- N_Null and does not carry any linkages.
@@ -10382,9 +10366,7 @@ package body Sem_Prag is
Ancestor_Part (State));
end if;
- -- Catch an attempt to introduce a simple option which is
- -- currently not allowed. An exception to this is External
- -- defined without any properties.
+ -- Options External and Ghost appear as expressions
Opt := First (Expressions (State));
while Present (Opt) loop
@@ -10392,6 +10374,11 @@ package body Sem_Prag is
if Chars (Opt) = Name_External then
Analyze_External_Option (Opt);
+ elsif Chars (Opt) = Name_Ghost then
+ if Present (State_Id) then
+ Set_Is_Ghost_Entity (State_Id);
+ end if;
+
-- Option Part_Of without an encapsulating state is
-- illegal. (SPARK RM 7.1.4(9)).
@@ -10514,6 +10501,7 @@ package body Sem_Prag is
-- Local variables
Context : constant Node_Id := Parent (Parent (N));
+ Pack_Id : Entity_Id;
State : Node_Id;
-- Start of processing for Abstract_State
@@ -10537,12 +10525,20 @@ package body Sem_Prag is
State := Expression (Arg1);
Pack_Id := Defining_Entity (Context);
+ -- Mark the associated package as Ghost if it is subject to aspect
+ -- or pragma Ghost as this affects the declaration of an abstract
+ -- state.
+
+ if Is_Subject_To_Ghost (Unit_Declaration_Node (Pack_Id)) then
+ Set_Is_Ghost_Entity (Pack_Id);
+ end if;
+
-- Multiple non-null abstract states appear as an aggregate
if Nkind (State) = N_Aggregate then
State := First (Expressions (State));
while Present (State) loop
- Analyze_Abstract_State (State);
+ Analyze_Abstract_State (State, Pack_Id);
Next (State);
end loop;
@@ -10550,7 +10546,7 @@ package body Sem_Prag is
-- include malformed state declarations.
else
- Analyze_Abstract_State (State);
+ Analyze_Abstract_State (State, Pack_Id);
end if;
-- Save the pragma for retrieval by other tools
@@ -11073,6 +11069,7 @@ package body Sem_Prag is
-- Contract_Cases |
-- Debug |
-- Default_Initial_Condition |
+ -- Ghost |
-- Initial_Condition |
-- Loop_Invariant |
-- Loop_Variant |
@@ -11916,7 +11913,8 @@ package body Sem_Prag is
-- new form syntax.
when Pragma_Check_Policy => Check_Policy : declare
- Kind : Node_Id;
+ Ident : Node_Id;
+ Kind : Node_Id;
begin
GNAT_Pragma;
@@ -11936,7 +11934,7 @@ package body Sem_Prag is
-- identifier is Name.
if Nkind (Arg1) /= N_Pragma_Argument_Association
- or else Nam_In (Chars (Arg1), No_Name, Name_Name)
+ or else Nam_In (Chars (Arg1), No_Name, Name_Name)
then
-- Old syntax
@@ -11950,8 +11948,8 @@ package body Sem_Prag is
if Nam_In (Chars (Kind), Name_Name, Name_Policy) then
Error_Msg_Name_2 := Chars (Kind);
- Error_Pragma_Arg
- ("pragma% does not allow% as check name", Arg1);
+ Error_Pragma_Arg
+ ("pragma% does not allow% as check name", Arg1);
end if;
-- Check policy
@@ -11960,6 +11958,29 @@ package body Sem_Prag is
Check_Arg_Is_One_Of
(Arg2,
Name_On, Name_Off, Name_Check, Name_Disable, Name_Ignore);
+ Ident := Get_Pragma_Arg (Arg2);
+
+ if Chars (Kind) = Name_Ghost then
+
+ -- Pragma Check_Policy specifying a Ghost policy cannot
+ -- occur within a ghost subprogram or package.
+
+ if Within_Ghost_Scope then
+ Error_Pragma
+ ("pragma % cannot appear within ghost subprogram or "
+ & "package");
+
+ -- The policy identifier of pragma Ghost must be either
+ -- Check or Ignore (SPARK RM 6.9(7)).
+
+ elsif not Nam_In (Chars (Ident), Name_Check,
+ Name_Ignore)
+ then
+ Error_Pragma_Arg
+ ("argument of pragma % Ghost must be Check or Ignore",
+ Arg2);
+ end if;
+ end if;
-- And chain pragma on the Check_Policy_List for search
@@ -13910,7 +13931,7 @@ package body Sem_Prag is
begin
GNAT_Pragma;
Check_No_Identifiers;
- Check_At_Most_N_Arguments (1);
+ Check_At_Most_N_Arguments (1);
Subp := Empty;
Stmt := Prev (N);
@@ -13955,7 +13976,8 @@ package body Sem_Prag is
-- enclosing construct is the proper context. This check is done
-- after the traversal above to allow for duplicate detection.
- if Nkind (Context) = N_Subprogram_Body
+ if No (Subp)
+ and then Nkind (Context) = N_Subprogram_Body
and then No (Corresponding_Spec (Context))
then
Subp := Defining_Entity (Context);
@@ -14187,6 +14209,212 @@ package body Sem_Prag is
end if;
end Finalize_Storage;
+ -----------
+ -- Ghost --
+ -----------
+
+ -- pragma Ghost [ (boolean_EXPRESSION) ];
+
+ when Pragma_Ghost => Ghost : declare
+ Context : constant Node_Id := Parent (N);
+ Expr : Node_Id;
+ Id : Entity_Id;
+ Orig_Stmt : Node_Id;
+ Prev_Id : Entity_Id;
+ Stmt : Node_Id;
+
+ begin
+ GNAT_Pragma;
+ Check_No_Identifiers;
+ Check_At_Most_N_Arguments (1);
+
+ Id := Empty;
+ 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;
+
+ -- Protected and task types cannot be subject to pragma Ghost
+
+ elsif Nkind (Stmt) = N_Protected_Type_Declaration then
+ Error_Pragma ("pragma % cannot apply to a protected type");
+ return;
+
+ elsif Nkind (Stmt) = N_Task_Type_Declaration then
+ Error_Pragma ("pragma % cannot apply to a task type");
+ return;
+
+ -- Skip internally generated code
+
+ elsif not Comes_From_Source (Stmt) then
+ Orig_Stmt := Original_Node (Stmt);
+
+ -- When pragma Ghost applies to an untagged derivation, the
+ -- derivation is transformed into a [sub]type declaration.
+
+ if Nkind_In (Stmt, N_Full_Type_Declaration,
+ N_Subtype_Declaration)
+ and then Comes_From_Source (Orig_Stmt)
+ and then Nkind (Orig_Stmt) = N_Full_Type_Declaration
+ and then Nkind (Type_Definition (Orig_Stmt)) =
+ N_Derived_Type_Definition
+ then
+ Id := Defining_Entity (Stmt);
+ exit;
+
+ -- When pragma Ghost applies to an expression function, the
+ -- expression function is transformed into a subprogram.
+
+ elsif Nkind (Stmt) = N_Subprogram_Declaration
+ and then Comes_From_Source (Orig_Stmt)
+ and then Nkind (Orig_Stmt) = N_Expression_Function
+ then
+ Id := Defining_Entity (Stmt);
+ exit;
+ end if;
+
+ -- The pragma applies to a legal construct, stop the traversal
+
+ elsif Nkind_In (Stmt, N_Abstract_Subprogram_Declaration,
+ N_Full_Type_Declaration,
+ N_Generic_Subprogram_Declaration,
+ N_Object_Declaration,
+ N_Private_Extension_Declaration,
+ N_Private_Type_Declaration,
+ N_Subprogram_Declaration,
+ N_Subtype_Declaration)
+ then
+ Id := Defining_Entity (Stmt);
+ exit;
+
+ -- The pragma does not apply to a legal construct, issue an
+ -- error and stop the analysis.
+
+ else
+ Error_Pragma
+ ("pragma % must apply to an object, package, subprogram "
+ & "or type");
+ return;
+ end if;
+
+ Stmt := Prev (Stmt);
+ end loop;
+
+ if No (Id) then
+
+ -- When pragma Ghost is associated with a [generic] package, it
+ -- appears in the visible declarations.
+
+ if Nkind (Context) = N_Package_Specification
+ and then Present (Visible_Declarations (Context))
+ and then List_Containing (N) = Visible_Declarations (Context)
+ then
+ Id := Defining_Entity (Context);
+
+ -- Pragma Ghost applies to a stand alone subprogram body
+
+ elsif Nkind (Context) = N_Subprogram_Body
+ and then No (Corresponding_Spec (Context))
+ then
+ Id := Defining_Entity (Context);
+ end if;
+ end if;
+
+ if No (Id) then
+ Error_Pragma
+ ("pragma % must apply to an object, package, subprogram or "
+ & "type");
+ return;
+ end if;
+
+ -- A derived type or type extension cannot be subject to pragma
+ -- Ghost if either the parent type or one of the progenitor types
+ -- is not Ghost (SPARK RM 6.9(9)).
+
+ if Is_Derived_Type (Id) then
+ Check_Ghost_Derivation (Id);
+ end if;
+
+ -- Handle completions of types and constants that are subject to
+ -- pragma Ghost.
+
+ if Is_Record_Type (Id) or else Ekind (Id) = E_Constant then
+ Prev_Id := Incomplete_Or_Partial_View (Id);
+
+ if Present (Prev_Id) and then not Is_Ghost_Entity (Prev_Id) then
+ Error_Msg_Name_1 := Pname;
+
+ -- The full declaration of a deferred constant cannot be
+ -- subject to pragma Ghost unless the deferred declaration
+ -- is also Ghost (SPARK RM 6.9(10)).
+
+ if Ekind (Prev_Id) = E_Constant then
+ Error_Msg_Name_1 := Pname;
+ Error_Msg_NE (Fix_Error
+ ("pragma % must apply to declaration of deferred "
+ & "constant &"), N, Id);
+ return;
+
+ -- Pragma Ghost may appear on the full view of an incomplete
+ -- type because the incomplete declaration lacks aspects and
+ -- cannot be subject to pragma Ghost.
+
+ elsif Ekind (Prev_Id) = E_Incomplete_Type then
+ null;
+
+ -- The full declaration of a type cannot be subject to
+ -- pragma Ghost unless the partial view is also Ghost
+ -- (SPARK RM 6.9(10)).
+
+ else
+ Error_Msg_NE (Fix_Error
+ ("pragma % must apply to partial view of type &"),
+ N, Id);
+ return;
+ end if;
+ end if;
+ end if;
+
+ -- Analyze the Boolean expression (if any)
+
+ if Present (Arg1) then
+ Expr := Get_Pragma_Arg (Arg1);
+
+ Analyze_And_Resolve (Expr, Standard_Boolean);
+
+ if Is_OK_Static_Expression (Expr) then
+
+ -- "Ghostness" cannot be turned off once enabled within a
+ -- region (SPARK RM 6.9(7)).
+
+ if Is_False (Expr_Value (Expr))
+ and then Within_Ghost_Scope
+ then
+ Error_Pragma
+ ("pragma % with value False cannot appear in enabled "
+ & "ghost region");
+ return;
+ end if;
+
+ -- Otherwie the expression is not static
+
+ else
+ Error_Pragma_Arg
+ ("expression of pragma % must be static", Expr);
+ return;
+ end if;
+ end if;
+
+ Set_Is_Ghost_Entity (Id);
+ end Ghost;
+
------------
-- Global --
------------
@@ -23087,6 +23315,12 @@ package body Sem_Prag is
-------------------------
procedure Analyze_Constituent (Constit : Node_Id) is
+ procedure Check_Ghost_Constituent (Constit_Id : Entity_Id);
+ -- Verify that the constituent Constit_Id is a Ghost entity if the
+ -- abstract state being refined is also Ghost. If this is the case
+ -- verify that the Ghost policy in effect at the point of state
+ -- and constituent declaration is the same.
+
procedure Check_Matching_Constituent (Constit_Id : Entity_Id);
-- Determine whether constituent Constit denoted by its entity
-- Constit_Id appears in Hidden_States. Emit an error when the
@@ -23169,6 +23403,7 @@ package body Sem_Prag is
if Present (Encapsulating_State (Constit_Id)) then
if Encapsulating_State (Constit_Id) = State_Id then
+ Check_Ghost_Constituent (Constit_Id);
Remove (Part_Of_Constits, Constit_Id);
Collect_Constituent;
@@ -23197,6 +23432,8 @@ package body Sem_Prag is
-- been encountered.
if Node (State_Elmt) = Constit_Id then
+ Check_Ghost_Constituent (Constit_Id);
+
Remove_Elmt (Body_States, State_Elmt);
Collect_Constituent;
return;
@@ -23217,6 +23454,59 @@ package body Sem_Prag is
end if;
end Check_Matching_Constituent;
+ -----------------------------
+ -- Check_Ghost_Constituent --
+ -----------------------------
+
+ procedure Check_Ghost_Constituent (Constit_Id : Entity_Id) is
+ begin
+ if Is_Ghost_Entity (State_Id) then
+ if Is_Ghost_Entity (Constit_Id) then
+
+ -- The Ghost policy in effect at the point of abstract
+ -- state declaration and constituent must match
+ -- (SPARK RM 6.9(15)).
+
+ if Is_Checked_Ghost_Entity (State_Id)
+ and then Is_Ignored_Ghost_Entity (Constit_Id)
+ then
+ Error_Msg_Sloc := Sloc (Constit);
+
+ SPARK_Msg_N
+ ("incompatible ghost policies in effect", State);
+ SPARK_Msg_NE
+ ("\abstract state & declared with ghost policy "
+ & "Check", State, State_Id);
+ SPARK_Msg_NE
+ ("\constituent & declared # with ghost policy "
+ & "Ignore", State, Constit_Id);
+
+ elsif Is_Ignored_Ghost_Entity (State_Id)
+ and then Is_Checked_Ghost_Entity (Constit_Id)
+ then
+ Error_Msg_Sloc := Sloc (Constit);
+
+ SPARK_Msg_N
+ ("incompatible ghost policies in effect", State);
+ SPARK_Msg_NE
+ ("\abstract state & declared with ghost policy "
+ & "Ignore", State, State_Id);
+ SPARK_Msg_NE
+ ("\constituent & declared # with ghost policy "
+ & "Check", State, Constit_Id);
+ end if;
+
+ -- A constituent of a Ghost abstract state must be a Ghost
+ -- entity (SPARK RM 7.2.2(12)).
+
+ else
+ SPARK_Msg_NE
+ ("constituent of ghost state & must be ghost",
+ Constit, State_Id);
+ end if;
+ end if;
+ end Check_Ghost_Constituent;
+
-- Local variables
Constit_Id : Entity_Id;
@@ -25075,6 +25365,7 @@ package body Sem_Prag is
Pragma_External_Name_Casing => 0,
Pragma_Fast_Math => 0,
Pragma_Finalize_Storage_Only => 0,
+ Pragma_Ghost => 0,
Pragma_Global => -1,
Pragma_Ident => -1,
Pragma_Implementation_Defined => -1,
@@ -25466,6 +25757,7 @@ package body Sem_Prag is
Name_Contract_Cases |
Name_Debug |
Name_Default_Initial_Condition |
+ Name_Ghost |
Name_Initial_Condition |
Name_Invariant |
Name_uInvariant |