blob: 2c3be8f4e439c8be636c2667a726de17655709fa [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- G H O S T --
-- --
-- B o d y --
-- --
-- Copyright (C) 2014-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. --
-- --
------------------------------------------------------------------------------
with Alloc; use Alloc;
with Aspects; use Aspects;
with Atree; use Atree;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
with Lib; use Lib;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Snames; use Snames;
with Table;
package body Ghost is
-- The following table contains the N_Compilation_Unit node for a unit that
-- is either subject to pragma Ghost with policy Ignore or contains ignored
-- Ghost code. The table is used in the removal of ignored Ghost code from
-- units.
package Ignored_Ghost_Units is new Table.Table (
Table_Component_Type => Node_Id,
Table_Index_Type => Int,
Table_Low_Bound => 0,
Table_Initial => Alloc.Ignored_Ghost_Units_Initial,
Table_Increment => Alloc.Ignored_Ghost_Units_Increment,
Table_Name => "Ignored_Ghost_Units");
-----------------------
-- Local Subprograms --
-----------------------
procedure Propagate_Ignored_Ghost_Code (N : Node_Id);
-- Subsidiary to Set_Ghost_Mode_xxx. Signal all enclosing scopes that they
-- now contain ignored Ghost code. Add the compilation unit containing N to
-- table Ignored_Ghost_Units for post processing.
----------------------------
-- Add_Ignored_Ghost_Unit --
----------------------------
procedure Add_Ignored_Ghost_Unit (Unit : Node_Id) is
begin
pragma Assert (Nkind (Unit) = N_Compilation_Unit);
-- Avoid duplicates in the table as pruning the same unit more than once
-- is wasteful. Since ignored Ghost code tends to be grouped up, check
-- the contents of the table in reverse.
for Index in reverse Ignored_Ghost_Units.First ..
Ignored_Ghost_Units.Last
loop
-- If the unit is already present in the table, do not add it again
if Unit = Ignored_Ghost_Units.Table (Index) then
return;
end if;
end loop;
-- If we get here, then this is the first time the unit is being added
Ignored_Ghost_Units.Append (Unit);
end Add_Ignored_Ghost_Unit;
----------------------------
-- Check_Ghost_Completion --
----------------------------
procedure Check_Ghost_Completion
(Partial_View : Entity_Id;
Full_View : Entity_Id)
is
Policy : constant Name_Id := Policy_In_Effect (Name_Ghost);
begin
-- The Ghost policy in effect at the point of declaration and at the
-- point of completion must match (SPARK RM 6.9(15)).
if Is_Checked_Ghost_Entity (Partial_View)
and then Policy = Name_Ignore
then
Error_Msg_Sloc := Sloc (Full_View);
Error_Msg_N ("incompatible ghost policies in effect", Partial_View);
Error_Msg_N ("\& declared with ghost policy Check", Partial_View);
Error_Msg_N ("\& completed # with ghost policy Ignore", Partial_View);
elsif Is_Ignored_Ghost_Entity (Partial_View)
and then Policy = Name_Check
then
Error_Msg_Sloc := Sloc (Full_View);
Error_Msg_N ("incompatible ghost policies in effect", Partial_View);
Error_Msg_N ("\& declared with ghost policy Ignore", Partial_View);
Error_Msg_N ("\& completed # with ghost policy Check", Partial_View);
end if;
end Check_Ghost_Completion;
-------------------------
-- Check_Ghost_Context --
-------------------------
procedure Check_Ghost_Context (Ghost_Id : Entity_Id; Ghost_Ref : Node_Id) is
procedure Check_Ghost_Policy (Id : Entity_Id; Err_N : Node_Id);
-- Verify that the Ghost policy at the point of declaration of entity Id
-- matches the policy at the point of reference. If this is not the case
-- emit an error at Err_N.
function Is_OK_Ghost_Context (Context : Node_Id) return Boolean;
-- Determine whether node Context denotes a Ghost-friendly context where
-- a Ghost entity can safely reside.
-------------------------
-- Is_OK_Ghost_Context --
-------------------------
function Is_OK_Ghost_Context (Context : Node_Id) return Boolean is
function Is_Ghost_Declaration (Decl : Node_Id) return Boolean;
-- Determine whether node Decl is a Ghost declaration or appears
-- within a Ghost declaration.
function Is_Ghost_Statement_Or_Pragma (N : Node_Id) return Boolean;
-- Determine whether statement or pragma N is Ghost or appears within
-- a Ghost statement or pragma. To qualify as such, N must either
-- 1) Occur within a ghost subprogram or package
-- 2) Denote a call to a ghost procedure
-- 3) Denote an assignment statement whose target is a ghost
-- variable.
-- 4) Denote a pragma that mentions a ghost entity
--------------------------
-- Is_Ghost_Declaration --
--------------------------
function Is_Ghost_Declaration (Decl : Node_Id) return Boolean is
Par : Node_Id;
Subp_Decl : Node_Id;
Subp_Id : Entity_Id;
begin
-- Climb the parent chain looking for an object declaration
Par := Decl;
while Present (Par) loop
if Is_Declaration (Par) then
-- A declaration is Ghost when it appears within a Ghost
-- package or subprogram.
if Ghost_Mode > None then
return True;
-- Otherwise the declaration may not have been analyzed yet,
-- determine whether it is subject to aspect/pragma Ghost.
else
return Is_Subject_To_Ghost (Par);
end if;
-- Special cases
-- A reference to a Ghost entity may appear as the default
-- expression of a formal parameter of a subprogram body. This
-- context must be treated as suitable because the relation
-- between the spec and the body has not been established and
-- the body is not marked as Ghost yet. The real check was
-- performed on the spec.
elsif Nkind (Par) = N_Parameter_Specification
and then Nkind (Parent (Parent (Par))) = N_Subprogram_Body
then
return True;
-- References to Ghost entities may be relocated in internally
-- generated bodies.
elsif Nkind (Par) = N_Subprogram_Body
and then not Comes_From_Source (Par)
then
Subp_Id := Corresponding_Spec (Par);
-- The original context is an expression function that has
-- been split into a spec and a body. The context is OK as
-- long as the the initial declaration is Ghost.
if Present (Subp_Id) then
Subp_Decl :=
Original_Node (Unit_Declaration_Node (Subp_Id));
if Nkind (Subp_Decl) = N_Expression_Function then
return Is_Subject_To_Ghost (Subp_Decl);
end if;
end if;
-- Otherwise this is either an internal body or an internal
-- completion. Both are OK because the real check was done
-- before expansion activities.
return True;
end if;
-- Prevent the search from going too far
if Is_Body_Or_Package_Declaration (Par) then
return False;
end if;
Par := Parent (Par);
end loop;
return False;
end Is_Ghost_Declaration;
----------------------------------
-- Is_Ghost_Statement_Or_Pragma --
----------------------------------
function Is_Ghost_Statement_Or_Pragma (N : Node_Id) return Boolean is
function Is_Ghost_Entity_Reference (N : Node_Id) return Boolean;
-- Determine whether an arbitrary node denotes a reference to a
-- Ghost entity.
-------------------------------
-- Is_Ghost_Entity_Reference --
-------------------------------
function Is_Ghost_Entity_Reference (N : Node_Id) return Boolean is
Ref : Node_Id;
begin
-- When the reference extracts a subcomponent, recover the
-- related object (SPARK RM 6.9(1)).
Ref := N;
while Nkind_In (Ref, N_Explicit_Dereference,
N_Indexed_Component,
N_Selected_Component,
N_Slice)
loop
Ref := Prefix (Ref);
end loop;
return
Is_Entity_Name (Ref)
and then Present (Entity (Ref))
and then Is_Ghost_Entity (Entity (Ref));
end Is_Ghost_Entity_Reference;
-- Local variables
Arg : Node_Id;
Stmt : Node_Id;
-- Start of processing for Is_Ghost_Statement_Or_Pragma
begin
if Nkind (N) = N_Pragma then
-- A pragma is Ghost when it appears within a Ghost package or
-- subprogram.
if Ghost_Mode > None then
return True;
end if;
-- A pragma is Ghost when it mentions a Ghost entity
Arg := First (Pragma_Argument_Associations (N));
while Present (Arg) loop
if Is_Ghost_Entity_Reference (Get_Pragma_Arg (Arg)) then
return True;
end if;
Next (Arg);
end loop;
end if;
Stmt := N;
while Present (Stmt) loop
if Is_Statement (Stmt) then
-- A statement is Ghost when it appears within a Ghost
-- package or subprogram.
if Ghost_Mode > None then
return True;
-- An assignment statement or a procedure call is Ghost when
-- the name denotes a Ghost entity.
elsif Nkind_In (Stmt, N_Assignment_Statement,
N_Procedure_Call_Statement)
then
return Is_Ghost_Entity_Reference (Name (Stmt));
end if;
-- Prevent the search from going too far
elsif Is_Body_Or_Package_Declaration (Stmt) then
return False;
end if;
Stmt := Parent (Stmt);
end loop;
return False;
end Is_Ghost_Statement_Or_Pragma;
-- Start of processing for Is_OK_Ghost_Context
begin
-- The Ghost entity appears within an assertion expression
if In_Assertion_Expr > 0 then
return True;
-- The Ghost entity is part of a declaration or its completion
elsif Is_Ghost_Declaration (Context) then
return True;
-- The Ghost entity is referenced within a Ghost statement
elsif Is_Ghost_Statement_Or_Pragma (Context) then
return True;
-- Routine Expand_Record_Extension creates a parent subtype without
-- inserting it into the tree. There is no good way of recognizing
-- this special case as there is no parent. Try to approximate the
-- context.
elsif No (Parent (Context)) and then Is_Tagged_Type (Ghost_Id) then
return True;
else
return False;
end if;
end Is_OK_Ghost_Context;
------------------------
-- Check_Ghost_Policy --
------------------------
procedure Check_Ghost_Policy (Id : Entity_Id; Err_N : Node_Id) is
Policy : constant Name_Id := Policy_In_Effect (Name_Ghost);
begin
-- The Ghost policy in effect a the point of declaration and at the
-- point of use must match (SPARK RM 6.9(14)).
if Is_Checked_Ghost_Entity (Id) and then Policy = Name_Ignore then
Error_Msg_Sloc := Sloc (Err_N);
Error_Msg_N ("incompatible ghost policies in effect", Err_N);
Error_Msg_NE ("\& declared with ghost policy Check", Err_N, Id);
Error_Msg_NE ("\& used # with ghost policy Ignore", Err_N, Id);
elsif Is_Ignored_Ghost_Entity (Id) and then Policy = Name_Check then
Error_Msg_Sloc := Sloc (Err_N);
Error_Msg_N ("incompatible ghost policies in effect", Err_N);
Error_Msg_NE ("\& declared with ghost policy Ignore", Err_N, Id);
Error_Msg_NE ("\& used # with ghost policy Check", Err_N, Id);
end if;
end Check_Ghost_Policy;
-- Start of processing for Check_Ghost_Context
begin
-- Once it has been established that the reference to the Ghost entity
-- is within a suitable context, ensure that the policy at the point of
-- declaration and at the point of use match.
if Is_OK_Ghost_Context (Ghost_Ref) then
Check_Ghost_Policy (Ghost_Id, Ghost_Ref);
-- Otherwise the Ghost entity appears in a non-Ghost context and affects
-- its behavior or value.
else
Error_Msg_N
("ghost entity cannot appear in this context (SPARK RM 6.9(12))",
Ghost_Ref);
end if;
end Check_Ghost_Context;
----------------------------
-- Check_Ghost_Derivation --
----------------------------
procedure Check_Ghost_Derivation (Typ : Entity_Id) is
Parent_Typ : constant Entity_Id := Etype (Typ);
Iface : Entity_Id;
Iface_Elmt : Elmt_Id;
begin
-- Allow untagged derivations from predefined types such as Integer as
-- those are not Ghost by definition.
if Is_Scalar_Type (Typ) and then Parent_Typ = Base_Type (Typ) then
null;
-- The parent type of a Ghost type extension must be Ghost
elsif not Is_Ghost_Entity (Parent_Typ) then
Error_Msg_N ("type extension & cannot be ghost", Typ);
Error_Msg_NE ("\parent type & is not ghost", Typ, Parent_Typ);
return;
end if;
-- All progenitors (if any) must be Ghost as well
if Is_Tagged_Type (Typ) and then Present (Interfaces (Typ)) then
Iface_Elmt := First_Elmt (Interfaces (Typ));
while Present (Iface_Elmt) loop
Iface := Node (Iface_Elmt);
if not Is_Ghost_Entity (Iface) then
Error_Msg_N ("type extension & cannot be ghost", Typ);
Error_Msg_NE ("\interface type & is not ghost", Typ, Iface);
return;
end if;
Next_Elmt (Iface_Elmt);
end loop;
end if;
end Check_Ghost_Derivation;
--------------------------------
-- Implements_Ghost_Interface --
--------------------------------
function Implements_Ghost_Interface (Typ : Entity_Id) return Boolean is
Iface_Elmt : Elmt_Id;
begin
-- Traverse the list of interfaces looking for a Ghost interface
if Is_Tagged_Type (Typ) and then Present (Interfaces (Typ)) then
Iface_Elmt := First_Elmt (Interfaces (Typ));
while Present (Iface_Elmt) loop
if Is_Ghost_Entity (Node (Iface_Elmt)) then
return True;
end if;
Next_Elmt (Iface_Elmt);
end loop;
end if;
return False;
end Implements_Ghost_Interface;
----------------
-- Initialize --
----------------
procedure Initialize is
begin
Ignored_Ghost_Units.Init;
end Initialize;
---------------------
-- Is_Ghost_Entity --
---------------------
function Is_Ghost_Entity (Id : Entity_Id) return Boolean is
begin
return Is_Checked_Ghost_Entity (Id) or else Is_Ignored_Ghost_Entity (Id);
end Is_Ghost_Entity;
-------------------------
-- Is_Subject_To_Ghost --
-------------------------
function Is_Subject_To_Ghost (N : Node_Id) return Boolean is
function Enables_Ghostness (Arg : Node_Id) return Boolean;
-- Determine whether aspect or pragma argument Arg enables "ghostness"
-----------------------
-- Enables_Ghostness --
-----------------------
function Enables_Ghostness (Arg : Node_Id) return Boolean is
Expr : Node_Id;
begin
Expr := Arg;
if Nkind (Expr) = N_Pragma_Argument_Association then
Expr := Get_Pragma_Arg (Expr);
end if;
-- Determine whether the expression of the aspect is static and
-- denotes True.
if Present (Expr) then
Preanalyze_And_Resolve (Expr);
return
Is_OK_Static_Expression (Expr)
and then Is_True (Expr_Value (Expr));
-- Otherwise Ghost defaults to True
else
return True;
end if;
end Enables_Ghostness;
-- Local variables
Id : constant Entity_Id := Defining_Entity (N);
Asp : Node_Id;
Decl : Node_Id;
Prev_Id : Entity_Id;
-- Start of processing for Is_Subject_To_Ghost
begin
-- The related entity of the declaration has not been analyzed yet, do
-- not inspect its attributes.
if Ekind (Id) = E_Void then
null;
elsif Is_Ghost_Entity (Id) then
return True;
-- The completion of a type or a constant is not fully analyzed when the
-- reference to the Ghost entity is resolved. Because the completion is
-- not marked as Ghost yet, inspect the partial view.
elsif Is_Record_Type (Id)
or else Ekind (Id) = E_Constant
or else (Nkind (N) = N_Object_Declaration
and then Constant_Present (N))
then
Prev_Id := Incomplete_Or_Partial_View (Id);
if Present (Prev_Id) and then Is_Ghost_Entity (Prev_Id) then
return True;
end if;
end if;
-- Examine the aspect specifications (if any) looking for aspect Ghost
if Permits_Aspect_Specifications (N) then
Asp := First (Aspect_Specifications (N));
while Present (Asp) loop
if Chars (Identifier (Asp)) = Name_Ghost then
return Enables_Ghostness (Expression (Asp));
end if;
Next (Asp);
end loop;
end if;
Decl := Empty;
-- When the context is a [generic] package declaration, pragma Ghost
-- resides in the visible declarations.
if Nkind_In (N, N_Generic_Package_Declaration,
N_Package_Declaration)
then
Decl := First (Visible_Declarations (Specification (N)));
-- When the context is a package or a subprogram body, pragma Ghost
-- resides in the declarative part.
elsif Nkind_In (N, N_Package_Body, N_Subprogram_Body) then
Decl := First (Declarations (N));
-- Otherwise pragma Ghost appears in the declarations following N
elsif Is_List_Member (N) then
Decl := Next (N);
end if;
while Present (Decl) loop
if Nkind (Decl) = N_Pragma
and then Pragma_Name (Decl) = Name_Ghost
then
return
Enables_Ghostness (First (Pragma_Argument_Associations (Decl)));
-- A source construct ends the region where pragma Ghost may appear,
-- stop the traversal.
elsif Comes_From_Source (Decl) then
exit;
end if;
Next (Decl);
end loop;
return False;
end Is_Subject_To_Ghost;
----------
-- Lock --
----------
procedure Lock is
begin
Ignored_Ghost_Units.Locked := True;
Ignored_Ghost_Units.Release;
end Lock;
----------------------------------
-- Propagate_Ignored_Ghost_Code --
----------------------------------
procedure Propagate_Ignored_Ghost_Code (N : Node_Id) is
Nod : Node_Id;
Scop : Entity_Id;
begin
-- Traverse the parent chain looking for blocks, packages and
-- subprograms or their respective bodies.
Nod := Parent (N);
while Present (Nod) loop
Scop := Empty;
if Nkind (Nod) = N_Block_Statement then
Scop := Entity (Identifier (Nod));
elsif Nkind_In (Nod, N_Package_Body,
N_Package_Declaration,
N_Subprogram_Body,
N_Subprogram_Declaration)
then
Scop := Defining_Entity (Nod);
end if;
-- The current node denotes a scoping construct
if Present (Scop) then
-- Stop the traversal when the scope already contains ignored
-- Ghost code as all enclosing scopes have already been marked.
if Contains_Ignored_Ghost_Code (Scop) then
exit;
-- Otherwise mark this scope and keep climbing
else
Set_Contains_Ignored_Ghost_Code (Scop);
end if;
end if;
Nod := Parent (Nod);
end loop;
-- The unit containing the ignored Ghost code must be post processed
-- before invoking the back end.
Add_Ignored_Ghost_Unit (Cunit (Get_Code_Unit (N)));
end Propagate_Ignored_Ghost_Code;
-------------------------------
-- Remove_Ignored_Ghost_Code --
-------------------------------
procedure Remove_Ignored_Ghost_Code is
procedure Prune_Tree (Root : Node_Id);
-- Remove all code marked as ignored Ghost from the tree of denoted by
-- Root.
----------------
-- Prune_Tree --
----------------
procedure Prune_Tree (Root : Node_Id) is
procedure Prune (N : Node_Id);
-- Remove a given node from the tree by rewriting it into null
function Prune_Node (N : Node_Id) return Traverse_Result;
-- Determine whether node N denotes an ignored Ghost construct. If
-- this is the case, rewrite N as a null statement. See the body for
-- special cases.
-----------
-- Prune --
-----------
procedure Prune (N : Node_Id) is
begin
-- Destroy any aspects that may be associated with the node
if Permits_Aspect_Specifications (N) and then Has_Aspects (N) then
Remove_Aspects (N);
end if;
Rewrite (N, Make_Null_Statement (Sloc (N)));
end Prune;
----------------
-- Prune_Node --
----------------
function Prune_Node (N : Node_Id) return Traverse_Result is
Id : Entity_Id;
begin
-- The node is either declared as ignored Ghost or is a byproduct
-- of expansion. Destroy it and stop the traversal on this branch.
if Is_Ignored_Ghost_Node (N) then
Prune (N);
return Skip;
-- Scoping constructs such as blocks, packages, subprograms and
-- bodies offer some flexibility with respect to pruning.
elsif Nkind_In (N, N_Block_Statement,
N_Package_Body,
N_Package_Declaration,
N_Subprogram_Body,
N_Subprogram_Declaration)
then
if Nkind (N) = N_Block_Statement then
Id := Entity (Identifier (N));
else
Id := Defining_Entity (N);
end if;
-- The scoping construct contains both living and ignored Ghost
-- code, let the traversal prune all relevant nodes.
if Contains_Ignored_Ghost_Code (Id) then
return OK;
-- Otherwise the construct contains only living code and should
-- not be pruned.
else
return Skip;
end if;
-- Otherwise keep searching for ignored Ghost nodes
else
return OK;
end if;
end Prune_Node;
procedure Prune_Nodes is new Traverse_Proc (Prune_Node);
-- Start of processing for Prune_Tree
begin
Prune_Nodes (Root);
end Prune_Tree;
-- Start of processing for Remove_Ignored_Ghost_Code
begin
for Index in Ignored_Ghost_Units.First .. Ignored_Ghost_Units.Last loop
Prune_Tree (Unit (Ignored_Ghost_Units.Table (Index)));
end loop;
end Remove_Ignored_Ghost_Code;
--------------------
-- Set_Ghost_Mode --
--------------------
procedure Set_Ghost_Mode (N : Node_Id; Prev_Id : Entity_Id := Empty) is
procedure Set_Ghost_Mode_From_Entity (Id : Entity_Id);
-- Set the value of global variable Ghost_Mode depending on the mode of
-- entity Id.
procedure Set_Ghost_Mode_From_Policy;
-- Set the value of global variable Ghost_Mode depending on the current
-- Ghost policy in effect.
--------------------------------
-- Set_Ghost_Mode_From_Entity --
--------------------------------
procedure Set_Ghost_Mode_From_Entity (Id : Entity_Id) is
begin
if Is_Checked_Ghost_Entity (Id) then
Ghost_Mode := Check;
elsif Is_Ignored_Ghost_Entity (Id) then
Ghost_Mode := Ignore;
Set_Is_Ignored_Ghost_Node (N);
Propagate_Ignored_Ghost_Code (N);
end if;
end Set_Ghost_Mode_From_Entity;
--------------------------------
-- Set_Ghost_Mode_From_Policy --
--------------------------------
procedure Set_Ghost_Mode_From_Policy is
Policy : constant Name_Id := Policy_In_Effect (Name_Ghost);
begin
if Policy = Name_Check then
Ghost_Mode := Check;
elsif Policy = Name_Ignore then
Ghost_Mode := Ignore;
Set_Is_Ignored_Ghost_Node (N);
Propagate_Ignored_Ghost_Code (N);
end if;
end Set_Ghost_Mode_From_Policy;
-- Local variables
Nam : Node_Id;
-- Start of processing for Set_Ghost_Mode
begin
-- The input node denotes one of the many declaration kinds that may be
-- subject to pragma Ghost.
if Is_Declaration (N) then
if Is_Subject_To_Ghost (N) then
Set_Ghost_Mode_From_Policy;
-- The declaration denotes the completion of a deferred constant,
-- pragma Ghost appears on the partial declaration.
elsif Nkind (N) = N_Object_Declaration
and then Constant_Present (N)
and then Present (Prev_Id)
then
Set_Ghost_Mode_From_Entity (Prev_Id);
-- The declaration denotes the full view of a private type, pragma
-- Ghost appears on the partial declaration.
elsif Nkind (N) = N_Full_Type_Declaration
and then Is_Private_Type (Defining_Entity (N))
and then Present (Prev_Id)
then
Set_Ghost_Mode_From_Entity (Prev_Id);
end if;
-- The input denotes an assignment or a procedure call. In this case
-- the Ghost mode is dictated by the name of the construct.
elsif Nkind_In (N, N_Assignment_Statement,
N_Procedure_Call_Statement)
then
-- When the reference extracts a subcomponent, recover the related
-- object (SPARK RM 6.9(1)).
Nam := Name (N);
while Nkind_In (Nam, N_Explicit_Dereference,
N_Indexed_Component,
N_Selected_Component,
N_Slice)
loop
Nam := Prefix (Nam);
end loop;
if Is_Entity_Name (Nam)
and then Present (Entity (Nam))
then
Set_Ghost_Mode_From_Entity (Entity (Nam));
end if;
-- The input denotes a package or subprogram body
elsif Nkind_In (N, N_Package_Body, N_Subprogram_Body) then
if (Present (Prev_Id) and then Is_Ghost_Entity (Prev_Id))
or else Is_Subject_To_Ghost (N)
then
Set_Ghost_Mode_From_Policy;
end if;
end if;
end Set_Ghost_Mode;
-------------------------------
-- Set_Ghost_Mode_For_Freeze --
-------------------------------
procedure Set_Ghost_Mode_For_Freeze (Id : Entity_Id; N : Node_Id) is
begin
if Is_Checked_Ghost_Entity (Id) then
Ghost_Mode := Check;
elsif Is_Ignored_Ghost_Entity (Id) then
Ghost_Mode := Ignore;
Propagate_Ignored_Ghost_Code (N);
end if;
end Set_Ghost_Mode_For_Freeze;
-------------------------
-- Set_Is_Ghost_Entity --
-------------------------
procedure Set_Is_Ghost_Entity (Id : Entity_Id) is
Policy : constant Name_Id := Policy_In_Effect (Name_Ghost);
begin
if Policy = Name_Check then
Set_Is_Checked_Ghost_Entity (Id);
elsif Policy = Name_Ignore then
Set_Is_Ignored_Ghost_Entity (Id);
end if;
end Set_Is_Ghost_Entity;
end Ghost;