Check_Ghost_Actuals;
end Mark_And_Set_Ghost_Instantiation;
+ ------------------------------------------
+ -- Check_Procedure_Call_Argument_Levels --
+ ------------------------------------------
+
+ procedure Check_Procedure_Call_Argument_Levels (N : Node_Id) is
+ procedure Check_Argument_Levels
+ (Actual : Entity_Id; Actual_Ref : Node_Id);
+ -- Check that the ghost assertion level of an actual is an assertion
+ -- level which depends on the ghost region where the procedure call
+ -- is located.
+
+ ---------------------------
+ -- Check_Argument_Levels --
+ ---------------------------
+
+ procedure Check_Argument_Levels
+ (Actual : Entity_Id; Actual_Ref : Node_Id)
+ is
+ Actual_Level : constant Entity_Id := Ghost_Assertion_Level (Actual);
+ Region_Level : constant Entity_Id :=
+ Ghost_Config.Ghost_Mode_Assertion_Level;
+ begin
+ -- If an assignment to a part of a ghost variable occurs in a ghost
+ -- entity, then the variable should be assertion-level-dependent on
+ -- this entity [This includes both assignment statements and passing
+ -- a ghost variable as an out or in out mode actual parameter.]
+ -- (SPARK RM 6.9(18)).
+
+ if Present (Region_Level)
+ and then not Is_Assertion_Level_Dependent
+ (Actual_Level, Region_Level)
+ then
+ Error_Msg_N (Assertion_Level_Error_Msg, Actual_Ref);
+ Error_Msg_Name_1 := Chars (Actual_Level);
+ Error_Msg_N ("\& has assertion level %", Actual_Ref);
+ Error_Msg_Name_1 := Chars (Region_Level);
+ Error_Msg_N ("\& is modified within a region with %", Actual_Ref);
+ Error_Msg_Name_1 := Chars (Region_Level);
+ Error_Msg_N
+ ("\assertion level of & should depend on %", Actual_Ref);
+ end if;
+ end Check_Argument_Levels;
+
+ -- Local variables
+
+ Actual : Node_Id;
+ Actual_Id : Entity_Id;
+ Formal : Node_Id;
+ Id : Entity_Id;
+ Orig_Actual : Node_Id;
+
+ -- Start of processing for Check_Procedure_Call_Argument_Levels
+
+ begin
+ if Nkind (N) not in N_Procedure_Call_Statement then
+ return;
+ end if;
+
+ -- Handle the access-to-subprogram case
+
+ if Ekind (Etype (Name (N))) = E_Subprogram_Type then
+ Id := Etype (Name (N));
+ else
+ Id := Get_Enclosing_Ghost_Entity (Name (N));
+ end if;
+
+ -- Check for context if we are able to derive the called subprogram and
+ -- we are not dealing with an expanded construct.
+
+ if Present (Id)
+ and then Comes_From_Source (N)
+ and then Ghost_Config.Ghost_Mode /= None
+ then
+ Orig_Actual := First_Actual (N);
+ Formal := First_Formal (Id);
+
+ while Present (Orig_Actual) loop
+ -- Similarly to Mark_And_Set_Ghost_Procedure_Call we need to
+ -- analyze the call argument first to get its level for this
+ -- analysis.
+
+ Actual :=
+ (if Analyzed (Orig_Actual)
+ then Orig_Actual
+ else New_Copy_Tree (Orig_Actual));
+ if not Analyzed (Actual) then
+ Preanalyze_Without_Errors (Actual);
+ end if;
+
+ if Ekind (Formal) in E_Out_Parameter | E_In_Out_Parameter then
+ Actual_Id := Get_Enclosing_Ghost_Entity (Actual);
+ if Present (Actual_Id) then
+ Check_Argument_Levels (Actual_Id, Orig_Actual);
+ end if;
+ end if;
+
+ Next_Formal (Formal);
+ Next_Actual (Orig_Actual);
+ end loop;
+ end if;
+ end Check_Procedure_Call_Argument_Levels;
+
---------------------------------------
-- Mark_And_Set_Ghost_Procedure_Call --
---------------------------------------