blob: 48d9e52b752d7d9af90cbdc1ec49e9ab3e7df533 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ U T I L --
-- --
-- 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. --
-- --
------------------------------------------------------------------------------
with Aspects; use Aspects;
with Atree; use Atree;
with Casing; use Casing;
with Checks; use Checks;
with Debug; use Debug;
with Elists; use Elists;
with Errout; use Errout;
with Exp_Ch11; use Exp_Ch11;
with Exp_Disp; use Exp_Disp;
with Exp_Unst; use Exp_Unst;
with Exp_Util; use Exp_Util;
with Fname; use Fname;
with Freeze; use Freeze;
with Lib; use Lib;
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 Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Attr; use Sem_Attr;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch13; use Sem_Ch13;
with Sem_Disp; use Sem_Disp;
with Sem_Eval; use Sem_Eval;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
with Sem_Warn; use Sem_Warn;
with Sem_Type; use Sem_Type;
with Sinfo; use Sinfo;
with Sinput; use Sinput;
with Stand; use Stand;
with Style;
with Stringt; use Stringt;
with Targparm; use Targparm;
with Tbuild; use Tbuild;
with Ttypes; use Ttypes;
with Uname; use Uname;
with GNAT.HTable; use GNAT.HTable;
package body Sem_Util is
----------------------------------------
-- Global Variables for New_Copy_Tree --
----------------------------------------
-- These global variables are used by New_Copy_Tree. See description of the
-- body of this subprogram for details. Global variables can be safely used
-- by New_Copy_Tree, since there is no case of a recursive call from the
-- processing inside New_Copy_Tree.
NCT_Hash_Threshold : constant := 20;
-- If there are more than this number of pairs of entries in the map, then
-- Hash_Tables_Used will be set, and the hash tables will be initialized
-- and used for the searches.
NCT_Hash_Tables_Used : Boolean := False;
-- Set to True if hash tables are in use
NCT_Table_Entries : Nat := 0;
-- Count entries in table to see if threshold is reached
NCT_Hash_Table_Setup : Boolean := False;
-- Set to True if hash table contains data. We set this True if we setup
-- the hash table with data, and leave it set permanently from then on,
-- this is a signal that second and subsequent users of the hash table
-- must clear the old entries before reuse.
subtype NCT_Header_Num is Int range 0 .. 511;
-- Defines range of headers in hash tables (512 headers)
-----------------------
-- Local Subprograms --
-----------------------
function Build_Component_Subtype
(C : List_Id;
Loc : Source_Ptr;
T : Entity_Id) return Node_Id;
-- This function builds the subtype for Build_Actual_Subtype_Of_Component
-- and Build_Discriminal_Subtype_Of_Component. C is a list of constraints,
-- Loc is the source location, T is the original subtype.
function Has_Enabled_Property
(Item_Id : Entity_Id;
Property : Name_Id) return Boolean;
-- Subsidiary to routines Async_xxx_Enabled and Effective_xxx_Enabled.
-- Determine whether an abstract state or a variable denoted by entity
-- Item_Id has enabled property Property.
function Has_Null_Extension (T : Entity_Id) return Boolean;
-- T is a derived tagged type. Check whether the type extension is null.
-- If the parent type is fully initialized, T can be treated as such.
function Is_Fully_Initialized_Variant (Typ : Entity_Id) return Boolean;
-- Subsidiary to Is_Fully_Initialized_Type. For an unconstrained type
-- with discriminants whose default values are static, examine only the
-- components in the selected variant to determine whether all of them
-- have a default.
------------------------------
-- Abstract_Interface_List --
------------------------------
function Abstract_Interface_List (Typ : Entity_Id) return List_Id is
Nod : Node_Id;
begin
if Is_Concurrent_Type (Typ) then
-- If we are dealing with a synchronized subtype, go to the base
-- type, whose declaration has the interface list.
-- Shouldn't this be Declaration_Node???
Nod := Parent (Base_Type (Typ));
if Nkind (Nod) = N_Full_Type_Declaration then
return Empty_List;
end if;
elsif Ekind (Typ) = E_Record_Type_With_Private then
if Nkind (Parent (Typ)) = N_Full_Type_Declaration then
Nod := Type_Definition (Parent (Typ));
elsif Nkind (Parent (Typ)) = N_Private_Type_Declaration then
if Present (Full_View (Typ))
and then
Nkind (Parent (Full_View (Typ))) = N_Full_Type_Declaration
then
Nod := Type_Definition (Parent (Full_View (Typ)));
-- If the full-view is not available we cannot do anything else
-- here (the source has errors).
else
return Empty_List;
end if;
-- Support for generic formals with interfaces is still missing ???
elsif Nkind (Parent (Typ)) = N_Formal_Type_Declaration then
return Empty_List;
else
pragma Assert
(Nkind (Parent (Typ)) = N_Private_Extension_Declaration);
Nod := Parent (Typ);
end if;
elsif Ekind (Typ) = E_Record_Subtype then
Nod := Type_Definition (Parent (Etype (Typ)));
elsif Ekind (Typ) = E_Record_Subtype_With_Private then
-- Recurse, because parent may still be a private extension. Also
-- note that the full view of the subtype or the full view of its
-- base type may (both) be unavailable.
return Abstract_Interface_List (Etype (Typ));
else pragma Assert ((Ekind (Typ)) = E_Record_Type);
if Nkind (Parent (Typ)) = N_Formal_Type_Declaration then
Nod := Formal_Type_Definition (Parent (Typ));
else
Nod := Type_Definition (Parent (Typ));
end if;
end if;
return Interface_List (Nod);
end Abstract_Interface_List;
--------------------------------
-- Add_Access_Type_To_Process --
--------------------------------
procedure Add_Access_Type_To_Process (E : Entity_Id; A : Entity_Id) is
L : Elist_Id;
begin
Ensure_Freeze_Node (E);
L := Access_Types_To_Process (Freeze_Node (E));
if No (L) then
L := New_Elmt_List;
Set_Access_Types_To_Process (Freeze_Node (E), L);
end if;
Append_Elmt (A, L);
end Add_Access_Type_To_Process;
--------------------------
-- Add_Block_Identifier --
--------------------------
procedure Add_Block_Identifier (N : Node_Id; Id : out Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
begin
pragma Assert (Nkind (N) = N_Block_Statement);
-- The block already has a label, return its entity
if Present (Identifier (N)) then
Id := Entity (Identifier (N));
-- Create a new block label and set its attributes
else
Id := New_Internal_Entity (E_Block, Current_Scope, Loc, 'B');
Set_Etype (Id, Standard_Void_Type);
Set_Parent (Id, N);
Set_Identifier (N, New_Occurrence_Of (Id, Loc));
Set_Block_Node (Id, Identifier (N));
end if;
end Add_Block_Identifier;
-----------------------
-- Add_Contract_Item --
-----------------------
procedure Add_Contract_Item (Prag : Node_Id; Id : Entity_Id) is
Items : Node_Id := Contract (Id);
procedure Add_Classification;
-- Prepend Prag to the list of classifications
procedure Add_Contract_Test_Case;
-- Prepend Prag to the list of contract and test cases
procedure Add_Pre_Post_Condition;
-- Prepend Prag to the list of pre- and postconditions
------------------------
-- Add_Classification --
------------------------
procedure Add_Classification is
begin
Set_Next_Pragma (Prag, Classifications (Items));
Set_Classifications (Items, Prag);
end Add_Classification;
----------------------------
-- Add_Contract_Test_Case --
----------------------------
procedure Add_Contract_Test_Case is
begin
Set_Next_Pragma (Prag, Contract_Test_Cases (Items));
Set_Contract_Test_Cases (Items, Prag);
end Add_Contract_Test_Case;
----------------------------
-- Add_Pre_Post_Condition --
----------------------------
procedure Add_Pre_Post_Condition is
begin
Set_Next_Pragma (Prag, Pre_Post_Conditions (Items));
Set_Pre_Post_Conditions (Items, Prag);
end Add_Pre_Post_Condition;
-- Local variables
Prag_Nam : Name_Id;
-- Start of processing for Add_Contract_Item
begin
-- A contract must contain only pragmas
pragma Assert (Nkind (Prag) = N_Pragma);
Prag_Nam := Pragma_Name (Prag);
-- Create a new contract when adding the first item
if No (Items) then
Items := Make_Contract (Sloc (Id));
Set_Contract (Id, Items);
end if;
-- Contract items related to [generic] packages or instantiations. The
-- applicable pragmas are:
-- Abstract_States
-- Initial_Condition
-- Initializes
-- Part_Of (instantiation only)
if Ekind_In (Id, E_Generic_Package, E_Package) then
if Nam_In (Prag_Nam, Name_Abstract_State,
Name_Initial_Condition,
Name_Initializes)
then
Add_Classification;
-- Indicator Part_Of must be associated with a package instantiation
elsif Prag_Nam = Name_Part_Of and then Is_Generic_Instance (Id) then
Add_Classification;
-- The pragma is not a proper contract item
else
raise Program_Error;
end if;
-- Contract items related to package bodies. The applicable pragmas are:
-- Refined_States
elsif Ekind (Id) = E_Package_Body then
if Prag_Nam = Name_Refined_State then
Add_Classification;
-- The pragma is not a proper contract item
else
raise Program_Error;
end if;
-- Contract items related to subprogram or entry declarations. The
-- applicable pragmas are:
-- Contract_Cases
-- Depends
-- Extensions_Visible
-- Global
-- Postcondition
-- Precondition
-- Test_Case
elsif Ekind_In (Id, E_Entry, E_Entry_Family)
or else Is_Generic_Subprogram (Id)
or else Is_Subprogram (Id)
then
if Nam_In (Prag_Nam, Name_Postcondition, Name_Precondition) then
Add_Pre_Post_Condition;
elsif Nam_In (Prag_Nam, Name_Contract_Cases, Name_Test_Case) then
Add_Contract_Test_Case;
elsif Nam_In (Prag_Nam, Name_Depends,
Name_Extensions_Visible,
Name_Global)
then
Add_Classification;
-- The pragma is not a proper contract item
else
raise Program_Error;
end if;
-- Contract items related to subprogram bodies. Applicable pragmas are:
-- Postcondition
-- Precondition
-- Refined_Depends
-- Refined_Global
-- Refined_Post
elsif Ekind (Id) = E_Subprogram_Body then
if Nam_In (Prag_Nam, Name_Refined_Depends, Name_Refined_Global) then
Add_Classification;
elsif Nam_In (Prag_Nam, Name_Postcondition,
Name_Precondition,
Name_Refined_Post)
then
Add_Pre_Post_Condition;
-- The pragma is not a proper contract item
else
raise Program_Error;
end if;
-- Contract items related to variables. Applicable pragmas are:
-- Async_Readers
-- Async_Writers
-- Effective_Reads
-- Effective_Writes
-- Part_Of
elsif Ekind (Id) = E_Variable then
if Nam_In (Prag_Nam, Name_Async_Readers,
Name_Async_Writers,
Name_Effective_Reads,
Name_Effective_Writes,
Name_Part_Of)
then
Add_Classification;
-- The pragma is not a proper contract item
else
raise Program_Error;
end if;
end if;
end Add_Contract_Item;
----------------------------
-- Add_Global_Declaration --
----------------------------
procedure Add_Global_Declaration (N : Node_Id) is
Aux_Node : constant Node_Id := Aux_Decls_Node (Cunit (Current_Sem_Unit));
begin
if No (Declarations (Aux_Node)) then
Set_Declarations (Aux_Node, New_List);
end if;
Append_To (Declarations (Aux_Node), N);
Analyze (N);
end Add_Global_Declaration;
--------------------------------
-- Address_Integer_Convert_OK --
--------------------------------
function Address_Integer_Convert_OK (T1, T2 : Entity_Id) return Boolean is
begin
if Allow_Integer_Address
and then ((Is_Descendent_Of_Address (T1)
and then Is_Private_Type (T1)
and then Is_Integer_Type (T2))
or else
(Is_Descendent_Of_Address (T2)
and then Is_Private_Type (T2)
and then Is_Integer_Type (T1)))
then
return True;
else
return False;
end if;
end Address_Integer_Convert_OK;
-----------------
-- Addressable --
-----------------
-- For now, just 8/16/32/64. but analyze later if AAMP is special???
function Addressable (V : Uint) return Boolean is
begin
return V = Uint_8 or else
V = Uint_16 or else
V = Uint_32 or else
V = Uint_64;
end Addressable;
function Addressable (V : Int) return Boolean is
begin
return V = 8 or else
V = 16 or else
V = 32 or else
V = 64;
end Addressable;
---------------------------------
-- Aggregate_Constraint_Checks --
---------------------------------
procedure Aggregate_Constraint_Checks
(Exp : Node_Id;
Check_Typ : Entity_Id)
is
Exp_Typ : constant Entity_Id := Etype (Exp);
begin
if Raises_Constraint_Error (Exp) then
return;
end if;
-- Ada 2005 (AI-230): Generate a conversion to an anonymous access
-- component's type to force the appropriate accessibility checks.
-- Ada 2005 (AI-231): Generate conversion to the null-excluding
-- type to force the corresponding run-time check
if Is_Access_Type (Check_Typ)
and then ((Is_Local_Anonymous_Access (Check_Typ))
or else (Can_Never_Be_Null (Check_Typ)
and then not Can_Never_Be_Null (Exp_Typ)))
then
Rewrite (Exp, Convert_To (Check_Typ, Relocate_Node (Exp)));
Analyze_And_Resolve (Exp, Check_Typ);
Check_Unset_Reference (Exp);
end if;
-- This is really expansion activity, so make sure that expansion is
-- on and is allowed. In GNATprove mode, we also want check flags to
-- be added in the tree, so that the formal verification can rely on
-- those to be present. In GNATprove mode for formal verification, some
-- treatment typically only done during expansion needs to be performed
-- on the tree, but it should not be applied inside generics. Otherwise,
-- this breaks the name resolution mechanism for generic instances.
if not Expander_Active
and (Inside_A_Generic or not Full_Analysis or not GNATprove_Mode)
then
return;
end if;
-- First check if we have to insert discriminant checks
if Has_Discriminants (Exp_Typ) then
Apply_Discriminant_Check (Exp, Check_Typ);
-- Next emit length checks for array aggregates
elsif Is_Array_Type (Exp_Typ) then
Apply_Length_Check (Exp, Check_Typ);
-- Finally emit scalar and string checks. If we are dealing with a
-- scalar literal we need to check by hand because the Etype of
-- literals is not necessarily correct.
elsif Is_Scalar_Type (Exp_Typ)
and then Compile_Time_Known_Value (Exp)
then
if Is_Out_Of_Range (Exp, Base_Type (Check_Typ)) then
Apply_Compile_Time_Constraint_Error
(Exp, "value not in range of}??", CE_Range_Check_Failed,
Ent => Base_Type (Check_Typ),
Typ => Base_Type (Check_Typ));
elsif Is_Out_Of_Range (Exp, Check_Typ) then
Apply_Compile_Time_Constraint_Error
(Exp, "value not in range of}??", CE_Range_Check_Failed,
Ent => Check_Typ,
Typ => Check_Typ);
elsif not Range_Checks_Suppressed (Check_Typ) then
Apply_Scalar_Range_Check (Exp, Check_Typ);
end if;
-- Verify that target type is also scalar, to prevent view anomalies
-- in instantiations.
elsif (Is_Scalar_Type (Exp_Typ)
or else Nkind (Exp) = N_String_Literal)
and then Is_Scalar_Type (Check_Typ)
and then Exp_Typ /= Check_Typ
then
if Is_Entity_Name (Exp)
and then Ekind (Entity (Exp)) = E_Constant
then
-- If expression is a constant, it is worthwhile checking whether
-- it is a bound of the type.
if (Is_Entity_Name (Type_Low_Bound (Check_Typ))
and then Entity (Exp) = Entity (Type_Low_Bound (Check_Typ)))
or else
(Is_Entity_Name (Type_High_Bound (Check_Typ))
and then Entity (Exp) = Entity (Type_High_Bound (Check_Typ)))
then
return;
else
Rewrite (Exp, Convert_To (Check_Typ, Relocate_Node (Exp)));
Analyze_And_Resolve (Exp, Check_Typ);
Check_Unset_Reference (Exp);
end if;
-- Could use a comment on this case ???
else
Rewrite (Exp, Convert_To (Check_Typ, Relocate_Node (Exp)));
Analyze_And_Resolve (Exp, Check_Typ);
Check_Unset_Reference (Exp);
end if;
end if;
end Aggregate_Constraint_Checks;
-----------------------
-- Alignment_In_Bits --
-----------------------
function Alignment_In_Bits (E : Entity_Id) return Uint is
begin
return Alignment (E) * System_Storage_Unit;
end Alignment_In_Bits;
---------------------------------
-- Append_Inherited_Subprogram --
---------------------------------
procedure Append_Inherited_Subprogram (S : Entity_Id) is
Par : constant Entity_Id := Alias (S);
-- The parent subprogram
Scop : constant Entity_Id := Scope (Par);
-- The scope of definition of the parent subprogram
Typ : constant Entity_Id := Defining_Entity (Parent (S));
-- The derived type of which S is a primitive operation
Decl : Node_Id;
Next_E : Entity_Id;
begin
if Ekind (Current_Scope) = E_Package
and then In_Private_Part (Current_Scope)
and then Has_Private_Declaration (Typ)
and then Is_Tagged_Type (Typ)
and then Scop = Current_Scope
then
-- The inherited operation is available at the earliest place after
-- the derived type declaration ( RM 7.3.1 (6/1)). This is only
-- relevant for type extensions. If the parent operation appears
-- after the type extension, the operation is not visible.
Decl := First
(Visible_Declarations
(Package_Specification (Current_Scope)));
while Present (Decl) loop
if Nkind (Decl) = N_Private_Extension_Declaration
and then Defining_Entity (Decl) = Typ
then
if Sloc (Decl) > Sloc (Par) then
Next_E := Next_Entity (Par);
Set_Next_Entity (Par, S);
Set_Next_Entity (S, Next_E);
return;
else
exit;
end if;
end if;
Next (Decl);
end loop;
end if;
-- If partial view is not a type extension, or it appears before the
-- subprogram declaration, insert normally at end of entity list.
Append_Entity (S, Current_Scope);
end Append_Inherited_Subprogram;
-----------------------------------------
-- Apply_Compile_Time_Constraint_Error --
-----------------------------------------
procedure Apply_Compile_Time_Constraint_Error
(N : Node_Id;
Msg : String;
Reason : RT_Exception_Code;
Ent : Entity_Id := Empty;
Typ : Entity_Id := Empty;
Loc : Source_Ptr := No_Location;
Rep : Boolean := True;
Warn : Boolean := False)
is
Stat : constant Boolean := Is_Static_Expression (N);
R_Stat : constant Node_Id :=
Make_Raise_Constraint_Error (Sloc (N), Reason => Reason);
Rtyp : Entity_Id;
begin
if No (Typ) then
Rtyp := Etype (N);
else
Rtyp := Typ;
end if;
Discard_Node
(Compile_Time_Constraint_Error (N, Msg, Ent, Loc, Warn => Warn));
if not Rep then
return;
end if;
-- Now we replace the node by an N_Raise_Constraint_Error node
-- This does not need reanalyzing, so set it as analyzed now.
Rewrite (N, R_Stat);
Set_Analyzed (N, True);
Set_Etype (N, Rtyp);
Set_Raises_Constraint_Error (N);
-- Now deal with possible local raise handling
Possible_Local_Raise (N, Standard_Constraint_Error);
-- If the original expression was marked as static, the result is
-- still marked as static, but the Raises_Constraint_Error flag is
-- always set so that further static evaluation is not attempted.
if Stat then
Set_Is_Static_Expression (N);
end if;
end Apply_Compile_Time_Constraint_Error;
---------------------------
-- Async_Readers_Enabled --
---------------------------
function Async_Readers_Enabled (Id : Entity_Id) return Boolean is
begin
return Has_Enabled_Property (Id, Name_Async_Readers);
end Async_Readers_Enabled;
---------------------------
-- Async_Writers_Enabled --
---------------------------
function Async_Writers_Enabled (Id : Entity_Id) return Boolean is
begin
return Has_Enabled_Property (Id, Name_Async_Writers);
end Async_Writers_Enabled;
--------------------------------------
-- Available_Full_View_Of_Component --
--------------------------------------
function Available_Full_View_Of_Component (T : Entity_Id) return Boolean is
ST : constant Entity_Id := Scope (T);
SCT : constant Entity_Id := Scope (Component_Type (T));
begin
return In_Open_Scopes (ST)
and then In_Open_Scopes (SCT)
and then Scope_Depth (ST) >= Scope_Depth (SCT);
end Available_Full_View_Of_Component;
-------------------
-- Bad_Attribute --
-------------------
procedure Bad_Attribute
(N : Node_Id;
Nam : Name_Id;
Warn : Boolean := False)
is
begin
Error_Msg_Warn := Warn;
Error_Msg_N ("unrecognized attribute&<<", N);
-- Check for possible misspelling
Error_Msg_Name_1 := First_Attribute_Name;
while Error_Msg_Name_1 <= Last_Attribute_Name loop
if Is_Bad_Spelling_Of (Nam, Error_Msg_Name_1) then
Error_Msg_N -- CODEFIX
("\possible misspelling of %<<", N);
exit;
end if;
Error_Msg_Name_1 := Error_Msg_Name_1 + 1;
end loop;
end Bad_Attribute;
--------------------------------
-- Bad_Predicated_Subtype_Use --
--------------------------------
procedure Bad_Predicated_Subtype_Use
(Msg : String;
N : Node_Id;
Typ : Entity_Id;
Suggest_Static : Boolean := False)
is
Gen : Entity_Id;
begin
-- Avoid cascaded errors
if Error_Posted (N) then
return;
end if;
if Inside_A_Generic then
Gen := Current_Scope;
while Present (Gen) and then Ekind (Gen) /= E_Generic_Package loop
Gen := Scope (Gen);
end loop;
if No (Gen) then
return;
end if;
if Is_Generic_Formal (Typ) and then Is_Discrete_Type (Typ) then
Set_No_Predicate_On_Actual (Typ);
end if;
elsif Has_Predicates (Typ) then
if Is_Generic_Actual_Type (Typ) then
-- The restriction on loop parameters is only that the type
-- should have no dynamic predicates.
if Nkind (Parent (N)) = N_Loop_Parameter_Specification
and then not Has_Dynamic_Predicate_Aspect (Typ)
and then Is_OK_Static_Subtype (Typ)
then
return;
end if;
Gen := Current_Scope;
while not Is_Generic_Instance (Gen) loop
Gen := Scope (Gen);
end loop;
pragma Assert (Present (Gen));
if Ekind (Gen) = E_Package and then In_Package_Body (Gen) then
Error_Msg_Warn := SPARK_Mode /= On;
Error_Msg_FE (Msg & "<<", N, Typ);
Error_Msg_F ("\Program_Error [<<", N);
Insert_Action (N,
Make_Raise_Program_Error (Sloc (N),
Reason => PE_Bad_Predicated_Generic_Type));
else
Error_Msg_FE (Msg & "<<", N, Typ);
end if;
else
Error_Msg_FE (Msg, N, Typ);
end if;
-- Emit an optional suggestion on how to remedy the error if the
-- context warrants it.
if Suggest_Static and then Has_Static_Predicate (Typ) then
Error_Msg_FE ("\predicate of & should be marked static", N, Typ);
end if;
end if;
end Bad_Predicated_Subtype_Use;
-----------------------------------------
-- Bad_Unordered_Enumeration_Reference --
-----------------------------------------
function Bad_Unordered_Enumeration_Reference
(N : Node_Id;
T : Entity_Id) return Boolean
is
begin
return Is_Enumeration_Type (T)
and then Warn_On_Unordered_Enumeration_Type
and then not Is_Generic_Type (T)
and then Comes_From_Source (N)
and then not Has_Pragma_Ordered (T)
and then not In_Same_Extended_Unit (N, T);
end Bad_Unordered_Enumeration_Reference;
--------------------------
-- Build_Actual_Subtype --
--------------------------
function Build_Actual_Subtype
(T : Entity_Id;
N : Node_Or_Entity_Id) return Node_Id
is
Loc : Source_Ptr;
-- Normally Sloc (N), but may point to corresponding body in some cases
Constraints : List_Id;
Decl : Node_Id;
Discr : Entity_Id;
Hi : Node_Id;
Lo : Node_Id;
Subt : Entity_Id;
Disc_Type : Entity_Id;
Obj : Node_Id;
begin
Loc := Sloc (N);
if Nkind (N) = N_Defining_Identifier then
Obj := New_Occurrence_Of (N, Loc);
-- If this is a formal parameter of a subprogram declaration, and
-- we are compiling the body, we want the declaration for the
-- actual subtype to carry the source position of the body, to
-- prevent anomalies in gdb when stepping through the code.
if Is_Formal (N) then
declare
Decl : constant Node_Id := Unit_Declaration_Node (Scope (N));
begin
if Nkind (Decl) = N_Subprogram_Declaration
and then Present (Corresponding_Body (Decl))
then
Loc := Sloc (Corresponding_Body (Decl));
end if;
end;
end if;
else
Obj := N;
end if;
if Is_Array_Type (T) then
Constraints := New_List;
for J in 1 .. Number_Dimensions (T) loop
-- Build an array subtype declaration with the nominal subtype and
-- the bounds of the actual. Add the declaration in front of the
-- local declarations for the subprogram, for analysis before any
-- reference to the formal in the body.
Lo :=
Make_Attribute_Reference (Loc,
Prefix =>
Duplicate_Subexpr_No_Checks (Obj, Name_Req => True),
Attribute_Name => Name_First,
Expressions => New_List (
Make_Integer_Literal (Loc, J)));
Hi :=
Make_Attribute_Reference (Loc,
Prefix =>
Duplicate_Subexpr_No_Checks (Obj, Name_Req => True),
Attribute_Name => Name_Last,
Expressions => New_List (
Make_Integer_Literal (Loc, J)));
Append (Make_Range (Loc, Lo, Hi), Constraints);
end loop;
-- If the type has unknown discriminants there is no constrained
-- subtype to build. This is never called for a formal or for a
-- lhs, so returning the type is ok ???
elsif Has_Unknown_Discriminants (T) then
return T;
else
Constraints := New_List;
-- Type T is a generic derived type, inherit the discriminants from
-- the parent type.
if Is_Private_Type (T)
and then No (Full_View (T))
-- T was flagged as an error if it was declared as a formal
-- derived type with known discriminants. In this case there
-- is no need to look at the parent type since T already carries
-- its own discriminants.
and then not Error_Posted (T)
then
Disc_Type := Etype (Base_Type (T));
else
Disc_Type := T;
end if;
Discr := First_Discriminant (Disc_Type);
while Present (Discr) loop
Append_To (Constraints,
Make_Selected_Component (Loc,
Prefix =>
Duplicate_Subexpr_No_Checks (Obj),
Selector_Name => New_Occurrence_Of (Discr, Loc)));
Next_Discriminant (Discr);
end loop;
end if;
Subt := Make_Temporary (Loc, 'S', Related_Node => N);
Set_Is_Internal (Subt);
Decl :=
Make_Subtype_Declaration (Loc,
Defining_Identifier => Subt,
Subtype_Indication =>
Make_Subtype_Indication (Loc,
Subtype_Mark => New_Occurrence_Of (T, Loc),
Constraint =>
Make_Index_Or_Discriminant_Constraint (Loc,
Constraints => Constraints)));
Mark_Rewrite_Insertion (Decl);
return Decl;
end Build_Actual_Subtype;
---------------------------------------
-- Build_Actual_Subtype_Of_Component --
---------------------------------------
function Build_Actual_Subtype_Of_Component
(T : Entity_Id;
N : Node_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (N);
P : constant Node_Id := Prefix (N);
D : Elmt_Id;
Id : Node_Id;
Index_Typ : Entity_Id;
Desig_Typ : Entity_Id;
-- This is either a copy of T, or if T is an access type, then it is
-- the directly designated type of this access type.
function Build_Actual_Array_Constraint return List_Id;
-- If one or more of the bounds of the component depends on
-- discriminants, build actual constraint using the discriminants
-- of the prefix.
function Build_Actual_Record_Constraint return List_Id;
-- Similar to previous one, for discriminated components constrained
-- by the discriminant of the enclosing object.
-----------------------------------
-- Build_Actual_Array_Constraint --
-----------------------------------
function Build_Actual_Array_Constraint return List_Id is
Constraints : constant List_Id := New_List;
Indx : Node_Id;
Hi : Node_Id;
Lo : Node_Id;
Old_Hi : Node_Id;
Old_Lo : Node_Id;
begin
Indx := First_Index (Desig_Typ);
while Present (Indx) loop
Old_Lo := Type_Low_Bound (Etype (Indx));
Old_Hi := Type_High_Bound (Etype (Indx));
if Denotes_Discriminant (Old_Lo) then
Lo :=
Make_Selected_Component (Loc,
Prefix => New_Copy_Tree (P),
Selector_Name => New_Occurrence_Of (Entity (Old_Lo), Loc));
else
Lo := New_Copy_Tree (Old_Lo);
-- The new bound will be reanalyzed in the enclosing
-- declaration. For literal bounds that come from a type
-- declaration, the type of the context must be imposed, so
-- insure that analysis will take place. For non-universal
-- types this is not strictly necessary.
Set_Analyzed (Lo, False);
end if;
if Denotes_Discriminant (Old_Hi) then
Hi :=
Make_Selected_Component (Loc,
Prefix => New_Copy_Tree (P),
Selector_Name => New_Occurrence_Of (Entity (Old_Hi), Loc));
else
Hi := New_Copy_Tree (Old_Hi);
Set_Analyzed (Hi, False);
end if;
Append (Make_Range (Loc, Lo, Hi), Constraints);
Next_Index (Indx);
end loop;
return Constraints;
end Build_Actual_Array_Constraint;
------------------------------------
-- Build_Actual_Record_Constraint --
------------------------------------
function Build_Actual_Record_Constraint return List_Id is
Constraints : constant List_Id := New_List;
D : Elmt_Id;
D_Val : Node_Id;
begin
D := First_Elmt (Discriminant_Constraint (Desig_Typ));
while Present (D) loop
if Denotes_Discriminant (Node (D)) then
D_Val := Make_Selected_Component (Loc,
Prefix => New_Copy_Tree (P),
Selector_Name => New_Occurrence_Of (Entity (Node (D)), Loc));
else
D_Val := New_Copy_Tree (Node (D));
end if;
Append (D_Val, Constraints);
Next_Elmt (D);
end loop;
return Constraints;
end Build_Actual_Record_Constraint;
-- Start of processing for Build_Actual_Subtype_Of_Component
begin
-- Why the test for Spec_Expression mode here???
if In_Spec_Expression then
return Empty;
-- More comments for the rest of this body would be good ???
elsif Nkind (N) = N_Explicit_Dereference then
if Is_Composite_Type (T)
and then not Is_Constrained (T)
and then not (Is_Class_Wide_Type (T)
and then Is_Constrained (Root_Type (T)))
and then not Has_Unknown_Discriminants (T)
then
-- If the type of the dereference is already constrained, it is an
-- actual subtype.
if Is_Array_Type (Etype (N))
and then Is_Constrained (Etype (N))
then
return Empty;
else
Remove_Side_Effects (P);
return Build_Actual_Subtype (T, N);
end if;
else
return Empty;
end if;
end if;
if Ekind (T) = E_Access_Subtype then
Desig_Typ := Designated_Type (T);
else
Desig_Typ := T;
end if;
if Ekind (Desig_Typ) = E_Array_Subtype then
Id := First_Index (Desig_Typ);
while Present (Id) loop
Index_Typ := Underlying_Type (Etype (Id));
if Denotes_Discriminant (Type_Low_Bound (Index_Typ))
or else
Denotes_Discriminant (Type_High_Bound (Index_Typ))
then
Remove_Side_Effects (P);
return
Build_Component_Subtype
(Build_Actual_Array_Constraint, Loc, Base_Type (T));
end if;
Next_Index (Id);
end loop;
elsif Is_Composite_Type (Desig_Typ)
and then Has_Discriminants (Desig_Typ)
and then not Has_Unknown_Discriminants (Desig_Typ)
then
if Is_Private_Type (Desig_Typ)
and then No (Discriminant_Constraint (Desig_Typ))
then
Desig_Typ := Full_View (Desig_Typ);
end if;
D := First_Elmt (Discriminant_Constraint (Desig_Typ));
while Present (D) loop
if Denotes_Discriminant (Node (D)) then
Remove_Side_Effects (P);
return
Build_Component_Subtype (
Build_Actual_Record_Constraint, Loc, Base_Type (T));
end if;
Next_Elmt (D);
end loop;
end if;
-- If none of the above, the actual and nominal subtypes are the same
return Empty;
end Build_Actual_Subtype_Of_Component;
-----------------------------
-- Build_Component_Subtype --
-----------------------------
function Build_Component_Subtype
(C : List_Id;
Loc : Source_Ptr;
T : Entity_Id) return Node_Id
is
Subt : Entity_Id;
Decl : Node_Id;
begin
-- Unchecked_Union components do not require component subtypes
if Is_Unchecked_Union (T) then
return Empty;
end if;
Subt := Make_Temporary (Loc, 'S');
Set_Is_Internal (Subt);
Decl :=
Make_Subtype_Declaration (Loc,
Defining_Identifier => Subt,
Subtype_Indication =>
Make_Subtype_Indication (Loc,
Subtype_Mark => New_Occurrence_Of (Base_Type (T), Loc),
Constraint =>
Make_Index_Or_Discriminant_Constraint (Loc,
Constraints => C)));
Mark_Rewrite_Insertion (Decl);
return Decl;
end Build_Component_Subtype;
----------------------------------
-- Build_Default_Init_Cond_Call --
----------------------------------
function Build_Default_Init_Cond_Call
(Loc : Source_Ptr;
Obj_Id : Entity_Id;
Typ : Entity_Id) return Node_Id
is
Proc_Id : constant Entity_Id := Default_Init_Cond_Procedure (Typ);
Formal_Typ : constant Entity_Id := Etype (First_Formal (Proc_Id));
begin
return
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (Proc_Id, Loc),
Parameter_Associations => New_List (
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Occurrence_Of (Formal_Typ, Loc),
Expression => New_Occurrence_Of (Obj_Id, Loc))));
end Build_Default_Init_Cond_Call;
----------------------------------------------
-- Build_Default_Init_Cond_Procedure_Bodies --
----------------------------------------------
procedure Build_Default_Init_Cond_Procedure_Bodies (Priv_Decls : List_Id) is
procedure Build_Default_Init_Cond_Procedure_Body (Typ : Entity_Id);
-- If type Typ is subject to pragma Default_Initial_Condition, build the
-- body of the procedure which verifies the assumption of the pragma at
-- run time. The generated body is added after the type declaration.
--------------------------------------------
-- Build_Default_Init_Cond_Procedure_Body --
--------------------------------------------
procedure Build_Default_Init_Cond_Procedure_Body (Typ : Entity_Id) is
Param_Id : Entity_Id;
-- The entity of the sole formal parameter of the default initial
-- condition procedure.
procedure Replace_Type_Reference (N : Node_Id);
-- Replace a single reference to type Typ with a reference to formal
-- parameter Param_Id.
----------------------------
-- Replace_Type_Reference --
----------------------------
procedure Replace_Type_Reference (N : Node_Id) is
begin
Rewrite (N, New_Occurrence_Of (Param_Id, Sloc (N)));
end Replace_Type_Reference;
procedure Replace_Type_References is
new Replace_Type_References_Generic (Replace_Type_Reference);
-- Local variables
Loc : constant Source_Ptr := Sloc (Typ);
Prag : constant Node_Id :=
Get_Pragma (Typ, Pragma_Default_Initial_Condition);
Proc_Id : constant Entity_Id := Default_Init_Cond_Procedure (Typ);
Spec_Decl : constant Node_Id := Unit_Declaration_Node (Proc_Id);
Body_Decl : Node_Id;
Expr : Node_Id;
Stmt : Node_Id;
-- Start of processing for Build_Default_Init_Cond_Procedure_Body
begin
-- The procedure should be generated only for [sub]types subject to
-- pragma Default_Initial_Condition. Types that inherit the pragma do
-- not get this specialized procedure.
pragma Assert (Has_Default_Init_Cond (Typ));
pragma Assert (Present (Prag));
pragma Assert (Present (Proc_Id));
-- Nothing to do if the body was already built
if Present (Corresponding_Body (Spec_Decl)) then
return;
end if;
Param_Id := First_Formal (Proc_Id);
-- The pragma has an argument. Note that the argument is analyzed
-- after all references to the current instance of the type are
-- replaced.
if Present (Pragma_Argument_Associations (Prag)) then
Expr :=
Get_Pragma_Arg (First (Pragma_Argument_Associations (Prag)));
if Nkind (Expr) = N_Null then
Stmt := Make_Null_Statement (Loc);
-- Preserve the original argument of the pragma by replicating it.
-- Replace all references to the current instance of the type with
-- references to the formal parameter.
else
Expr := New_Copy_Tree (Expr);
Replace_Type_References (Expr, Typ);
-- Generate:
-- pragma Check (Default_Initial_Condition, <Expr>);
Stmt :=
Make_Pragma (Loc,
Pragma_Identifier =>
Make_Identifier (Loc, Name_Check),
Pragma_Argument_Associations => New_List (
Make_Pragma_Argument_Association (Loc,
Expression =>
Make_Identifier (Loc,
Chars => Name_Default_Initial_Condition)),
Make_Pragma_Argument_Association (Loc,
Expression => Expr)));
end if;
-- Otherwise the pragma appears without an argument
else
Stmt := Make_Null_Statement (Loc);
end if;
-- Generate:
-- procedure <Typ>Default_Init_Cond (I : <Typ>) is
-- begin
-- <Stmt>;
-- end <Typ>Default_Init_Cond;
Body_Decl :=
Make_Subprogram_Body (Loc,
Specification =>
Copy_Separate_Tree (Specification (Spec_Decl)),
Declarations => Empty_List,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (Stmt)));
-- Link the spec and body of the default initial condition procedure
-- to prevent the generation of a duplicate body.
Set_Corresponding_Body (Spec_Decl, Defining_Entity (Body_Decl));
Set_Corresponding_Spec (Body_Decl, Proc_Id);
Insert_After_And_Analyze (Declaration_Node (Typ), Body_Decl);
end Build_Default_Init_Cond_Procedure_Body;
-- Local variables
Decl : Node_Id;
Typ : Entity_Id;
-- Start of processing for Build_Default_Init_Cond_Procedure_Bodies
begin
-- Inspect the private declarations looking for [sub]type declarations
Decl := First (Priv_Decls);
while Present (Decl) loop
if Nkind_In (Decl, N_Full_Type_Declaration,
N_Subtype_Declaration)
then
Typ := Defining_Entity (Decl);
-- Guard against partially decorate types due to previous errors
if Is_Type (Typ) then
-- If the type is subject to pragma Default_Initial_Condition,
-- generate the body of the internal procedure which verifies
-- the assertion of the pragma at run time.
if Has_Default_Init_Cond (Typ) then
Build_Default_Init_Cond_Procedure_Body (Typ);
-- A derived type inherits the default initial condition
-- procedure from its parent type.
elsif Has_Inherited_Default_Init_Cond (Typ) then
Inherit_Default_Init_Cond_Procedure (Typ);
end if;
end if;
end if;
Next (Decl);
end loop;
end Build_Default_Init_Cond_Procedure_Bodies;
---------------------------------------------------
-- Build_Default_Init_Cond_Procedure_Declaration --
---------------------------------------------------
procedure Build_Default_Init_Cond_Procedure_Declaration (Typ : Entity_Id) is
Loc : constant Source_Ptr := Sloc (Typ);
Prag : constant Node_Id :=
Get_Pragma (Typ, Pragma_Default_Initial_Condition);
Proc_Id : Entity_Id;
begin
-- The procedure should be generated only for types subject to pragma
-- Default_Initial_Condition. Types that inherit the pragma do not get
-- this specialized procedure.
pragma Assert (Has_Default_Init_Cond (Typ));
pragma Assert (Present (Prag));
-- Nothing to do if default initial condition procedure already built
if Present (Default_Init_Cond_Procedure (Typ)) then
return;
end if;
Proc_Id :=
Make_Defining_Identifier (Loc,
Chars => New_External_Name (Chars (Typ), "Default_Init_Cond"));
-- Associate default initial condition procedure with the private type
Set_Ekind (Proc_Id, E_Procedure);
Set_Is_Default_Init_Cond_Procedure (Proc_Id);
Set_Default_Init_Cond_Procedure (Typ, Proc_Id);
-- Generate:
-- procedure <Typ>Default_Init_Cond (Inn : <Typ>);
Insert_After_And_Analyze (Prag,
Make_Subprogram_Declaration (Loc,
Specification =>
Make_Procedure_Specification (Loc,
Defining_Unit_Name => Proc_Id,
Parameter_Specifications => New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => Make_Temporary (Loc, 'I'),
Parameter_Type => New_Occurrence_Of (Typ, Loc))))));
end Build_Default_Init_Cond_Procedure_Declaration;
---------------------------
-- Build_Default_Subtype --
---------------------------
function Build_Default_Subtype
(T : Entity_Id;
N : Node_Id) return Entity_Id
is
Loc : constant Source_Ptr := Sloc (N);
Disc : Entity_Id;
Bas : Entity_Id;
-- The base type that is to be constrained by the defaults
begin
if not Has_Discriminants (T) or else Is_Constrained (T) then
return T;
end if;
Bas := Base_Type (T);
-- If T is non-private but its base type is private, this is the
-- completion of a subtype declaration whose parent type is private
-- (see Complete_Private_Subtype in Sem_Ch3). The proper discriminants
-- are to be found in the full view of the base. Check that the private
-- status of T and its base differ.
if Is_Private_Type (Bas)
and then not Is_Private_Type (T)
and then Present (Full_View (Bas))
then
Bas := Full_View (Bas);
end if;
Disc := First_Discriminant (T);
if No (Discriminant_Default_Value (Disc)) then
return T;
end if;
declare
Act : constant Entity_Id := Make_Temporary (Loc, 'S');
Constraints : constant List_Id := New_List;
Decl : Node_Id;
begin
while Present (Disc) loop
Append_To (Constraints,
New_Copy_Tree (Discriminant_Default_Value (Disc)));
Next_Discriminant (Disc);
end loop;
Decl :=
Make_Subtype_Declaration (Loc,
Defining_Identifier => Act,
Subtype_Indication =>
Make_Subtype_Indication (Loc,
Subtype_Mark => New_Occurrence_Of (Bas, Loc),
Constraint =>
Make_Index_Or_Discriminant_Constraint (Loc,
Constraints => Constraints)));
Insert_Action (N, Decl);
Analyze (Decl);
return Act;
end;
end Build_Default_Subtype;
--------------------------------------------
-- Build_Discriminal_Subtype_Of_Component --
--------------------------------------------
function Build_Discriminal_Subtype_Of_Component
(T : Entity_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (T);
D : Elmt_Id;
Id : Node_Id;
function Build_Discriminal_Array_Constraint return List_Id;
-- If one or more of the bounds of the component depends on
-- discriminants, build actual constraint using the discriminants
-- of the prefix.
function Build_Discriminal_Record_Constraint return List_Id;
-- Similar to previous one, for discriminated components constrained by
-- the discriminant of the enclosing object.
----------------------------------------
-- Build_Discriminal_Array_Constraint --
----------------------------------------
function Build_Discriminal_Array_Constraint return List_Id is
Constraints : constant List_Id := New_List;
Indx : Node_Id;
Hi : Node_Id;
Lo : Node_Id;
Old_Hi : Node_Id;
Old_Lo : Node_Id;
begin
Indx := First_Index (T);
while Present (Indx) loop
Old_Lo := Type_Low_Bound (Etype (Indx));
Old_Hi := Type_High_Bound (Etype (Indx));
if Denotes_Discriminant (Old_Lo) then
Lo := New_Occurrence_Of (Discriminal (Entity (Old_Lo)), Loc);
else
Lo := New_Copy_Tree (Old_Lo);
end if;
if Denotes_Discriminant (Old_Hi) then
Hi := New_Occurrence_Of (Discriminal (Entity (Old_Hi)), Loc);
else
Hi := New_Copy_Tree (Old_Hi);
end if;
Append (Make_Range (Loc, Lo, Hi), Constraints);
Next_Index (Indx);
end loop;
return Constraints;
end Build_Discriminal_Array_Constraint;
-----------------------------------------
-- Build_Discriminal_Record_Constraint --
-----------------------------------------
function Build_Discriminal_Record_Constraint return List_Id is
Constraints : constant List_Id := New_List;
D : Elmt_Id;
D_Val : Node_Id;
begin
D := First_Elmt (Discriminant_Constraint (T));
while Present (D) loop
if Denotes_Discriminant (Node (D)) then
D_Val :=
New_Occurrence_Of (Discriminal (Entity (Node (D))), Loc);
else
D_Val := New_Copy_Tree (Node (D));
end if;
Append (D_Val, Constraints);
Next_Elmt (D);
end loop;
return Constraints;
end Build_Discriminal_Record_Constraint;
-- Start of processing for Build_Discriminal_Subtype_Of_Component
begin
if Ekind (T) = E_Array_Subtype then
Id := First_Index (T);
while Present (Id) loop
if Denotes_Discriminant (Type_Low_Bound (Etype (Id)))
or else
Denotes_Discriminant (Type_High_Bound (Etype (Id)))
then
return Build_Component_Subtype
(Build_Discriminal_Array_Constraint, Loc, T);
end if;
Next_Index (Id);
end loop;
elsif Ekind (T) = E_Record_Subtype
and then Has_Discriminants (T)
and then not Has_Unknown_Discriminants (T)
then
D := First_Elmt (Discriminant_Constraint (T));
while Present (D) loop
if Denotes_Discriminant (Node (D)) then
return Build_Component_Subtype
(Build_Discriminal_Record_Constraint, Loc, T);
end if;
Next_Elmt (D);
end loop;
end if;
-- If none of the above, the actual and nominal subtypes are the same
return Empty;
end Build_Discriminal_Subtype_Of_Component;
------------------------------
-- Build_Elaboration_Entity --
------------------------------
procedure Build_Elaboration_Entity (N : Node_Id; Spec_Id : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
Decl : Node_Id;
Elab_Ent : Entity_Id;
procedure Set_Package_Name (Ent : Entity_Id);
-- Given an entity, sets the fully qualified name of the entity in
-- Name_Buffer, with components separated by double underscores. This
-- is a recursive routine that climbs the scope chain to Standard.
----------------------
-- Set_Package_Name --
----------------------
procedure Set_Package_Name (Ent : Entity_Id) is
begin
if Scope (Ent) /= Standard_Standard then
Set_Package_Name (Scope (Ent));
declare
Nam : constant String := Get_Name_String (Chars (Ent));
begin
Name_Buffer (Name_Len + 1) := '_';
Name_Buffer (Name_Len + 2) := '_';
Name_Buffer (Name_Len + 3 .. Name_Len + Nam'Length + 2) := Nam;
Name_Len := Name_Len + Nam'Length + 2;
end;
else
Get_Name_String (Chars (Ent));
end if;
end Set_Package_Name;
-- Start of processing for Build_Elaboration_Entity
begin
-- Ignore call if already constructed
if Present (Elaboration_Entity (Spec_Id)) then
return;
-- Ignore in ASIS mode, elaboration entity is not in source and plays
-- no role in analysis.
elsif ASIS_Mode then
return;
-- See if we need elaboration entity. We always need it for the dynamic
-- elaboration model, since it is needed to properly generate the PE
-- exception for access before elaboration.
elsif Dynamic_Elaboration_Checks then
null;
-- For the static model, we don't need the elaboration counter if this
-- unit is sure to have no elaboration code, since that means there
-- is no elaboration unit to be called. Note that we can't just decide
-- after the fact by looking to see whether there was elaboration code,
-- because that's too late to make this decision.
elsif Restriction_Active (No_Elaboration_Code) then
return;
-- Similarly, for the static model, we can skip the elaboration counter
-- if we have the No_Multiple_Elaboration restriction, since for the
-- static model, that's the only purpose of the counter (to avoid
-- multiple elaboration).
elsif Restriction_Active (No_Multiple_Elaboration) then
return;
end if;
-- Here we need the elaboration entity
-- Construct name of elaboration entity as xxx_E, where xxx is the unit
-- name with dots replaced by double underscore. We have to manually
-- construct this name, since it will be elaborated in the outer scope,
-- and thus will not have the unit name automatically prepended.
Set_Package_Name (Spec_Id);
Add_Str_To_Name_Buffer ("_E");
-- Create elaboration counter
Elab_Ent := Make_Defining_Identifier (Loc, Chars => Name_Find);
Set_Elaboration_Entity (Spec_Id, Elab_Ent);
Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Elab_Ent,
Object_Definition =>
New_Occurrence_Of (Standard_Short_Integer, Loc),
Expression => Make_Integer_Literal (Loc, Uint_0));
Push_Scope (Standard_Standard);
Add_Global_Declaration (Decl);
Pop_Scope;
-- Reset True_Constant indication, since we will indeed assign a value
-- to the variable in the binder main. We also kill the Current_Value
-- and Last_Assignment fields for the same reason.
Set_Is_True_Constant (Elab_Ent, False);
Set_Current_Value (Elab_Ent, Empty);
Set_Last_Assignment (Elab_Ent, Empty);
-- We do not want any further qualification of the name (if we did not
-- do this, we would pick up the name of the generic package in the case
-- of a library level generic instantiation).
Set_Has_Qualified_Name (Elab_Ent);
Set_Has_Fully_Qualified_Name (Elab_Ent);
end Build_Elaboration_Entity;
--------------------------------
-- Build_Explicit_Dereference --
--------------------------------
procedure Build_Explicit_Dereference
(Expr : Node_Id;
Disc : Entity_Id)
is
Loc : constant Source_Ptr := Sloc (Expr);
begin
-- An entity of a type with a reference aspect is overloaded with
-- both interpretations: with and without the dereference. Now that
-- the dereference is made explicit, set the type of the node properly,
-- to prevent anomalies in the backend. Same if the expression is an
-- overloaded function call whose return type has a reference aspect.
if Is_Entity_Name (Expr) then
Set_Etype (Expr, Etype (Entity (Expr)));
elsif Nkind (Expr) = N_Function_Call then
Set_Etype (Expr, Etype (Name (Expr)));
end if;
Set_Is_Overloaded (Expr, False);
-- The expression will often be a generalized indexing that yields a
-- container element that is then dereferenced, in which case the
-- generalized indexing call is also non-overloaded.
if Nkind (Expr) = N_Indexed_Component
and then Present (Generalized_Indexing (Expr))
then
Set_Is_Overloaded (Generalized_Indexing (Expr), False);
end if;
Rewrite (Expr,
Make_Explicit_Dereference (Loc,
Prefix =>
Make_Selected_Component (Loc,
Prefix => Relocate_Node (Expr),
Selector_Name => New_Occurrence_Of (Disc, Loc))));
Set_Etype (Prefix (Expr), Etype (Disc));
Set_Etype (Expr, Designated_Type (Etype (Disc)));
end Build_Explicit_Dereference;
-----------------------------------
-- Cannot_Raise_Constraint_Error --
-----------------------------------
function Cannot_Raise_Constraint_Error (Expr : Node_Id) return Boolean is
begin
if Compile_Time_Known_Value (Expr) then
return True;
elsif Do_Range_Check (Expr) then
return False;
elsif Raises_Constraint_Error (Expr) then
return False;
else
case Nkind (Expr) is
when N_Identifier =>
return True;
when N_Expanded_Name =>
return True;
when N_Selected_Component =>
return not Do_Discriminant_Check (Expr);
when N_Attribute_Reference =>
if Do_Overflow_Check (Expr) then
return False;
elsif No (Expressions (Expr)) then
return True;
else
declare
N : Node_Id;
begin
N := First (Expressions (Expr));
while Present (N) loop
if Cannot_Raise_Constraint_Error (N) then
Next (N);
else
return False;
end if;
end loop;
return True;
end;
end if;
when N_Type_Conversion =>
if Do_Overflow_Check (Expr)
or else Do_Length_Check (Expr)
or else Do_Tag_Check (Expr)
then
return False;
else
return Cannot_Raise_Constraint_Error (Expression (Expr));
end if;
when N_Unchecked_Type_Conversion =>
return Cannot_Raise_Constraint_Error (Expression (Expr));
when N_Unary_Op =>
if Do_Overflow_Check (Expr) then
return False;
else
return Cannot_Raise_Constraint_Error (Right_Opnd (Expr));
end if;
when N_Op_Divide |
N_Op_Mod |
N_Op_Rem
=>
if Do_Division_Check (Expr)
or else
Do_Overflow_Check (Expr)
then
return False;
else
return
Cannot_Raise_Constraint_Error (Left_Opnd (Expr))
and then
Cannot_Raise_Constraint_Error (Right_Opnd (Expr));
end if;
when N_Op_Add |
N_Op_And |
N_Op_Concat |
N_Op_Eq |
N_Op_Expon |
N_Op_Ge |
N_Op_Gt |
N_Op_Le |
N_Op_Lt |
N_Op_Multiply |
N_Op_Ne |
N_Op_Or |
N_Op_Rotate_Left |
N_Op_Rotate_Right |
N_Op_Shift_Left |
N_Op_Shift_Right |
N_Op_Shift_Right_Arithmetic |
N_Op_Subtract |
N_Op_Xor
=>
if Do_Overflow_Check (Expr) then
return False;
else
return
Cannot_Raise_Constraint_Error (Left_Opnd (Expr))
and then
Cannot_Raise_Constraint_Error (Right_Opnd (Expr));
end if;
when others =>
return False;
end case;
end if;
end Cannot_Raise_Constraint_Error;
-----------------------------------------
-- Check_Dynamically_Tagged_Expression --
-----------------------------------------
procedure Check_Dynamically_Tagged_Expression
(Expr : Node_Id;
Typ : Entity_Id;
Related_Nod : Node_Id)
is
begin
pragma Assert (Is_Tagged_Type (Typ));
-- In order to avoid spurious errors when analyzing the expanded code,
-- this check is done only for nodes that come from source and for
-- actuals of generic instantiations.
if (Comes_From_Source (Related_Nod)
or else In_Generic_Actual (Expr))
and then (Is_Class_Wide_Type (Etype (Expr))
or else Is_Dynamically_Tagged (Expr))
and then Is_Tagged_Type (Typ)
and then not Is_Class_Wide_Type (Typ)
then
Error_Msg_N ("dynamically tagged expression not allowed!", Expr);
end if;
end Check_Dynamically_Tagged_Expression;
--------------------------
-- Check_Fully_Declared --
--------------------------
procedure Check_Fully_Declared (T : Entity_Id; N : Node_Id) is
begin
if Ekind (T) = E_Incomplete_Type then
-- Ada 2005 (AI-50217): If the type is available through a limited
-- with_clause, verify that its full view has been analyzed.
if From_Limited_With (T)
and then Present (Non_Limited_View (T))
and then Ekind (Non_Limited_View (T)) /= E_Incomplete_Type
then
-- The non-limited view is fully declared
null;
else
Error_Msg_NE
("premature usage of incomplete}", N, First_Subtype (T));
end if;
-- Need comments for these tests ???
elsif Has_Private_Component (T)
and then not Is_Generic_Type (Root_Type (T))
and then not In_Spec_Expression
then
-- Special case: if T is the anonymous type created for a single
-- task or protected object, use the name of the source object.
if Is_Concurrent_Type (T)
and then not Comes_From_Source (T)
and then Nkind (N) = N_Object_Declaration
then
Error_Msg_NE
("type of& has incomplete component",
N, Defining_Identifier (N));
else
Error_Msg_NE
("premature usage of incomplete}",
N, First_Subtype (T));
end if;
end if;
end Check_Fully_Declared;
-------------------------------------
-- Check_Function_Writable_Actuals --
-------------------------------------
procedure Check_Function_Writable_Actuals (N : Node_Id) is
Writable_Actuals_List : Elist_Id := No_Elist;
Identifiers_List : Elist_Id := No_Elist;
Error_Node : Node_Id := Empty;
procedure Collect_Identifiers (N : Node_Id);
-- In a single traversal of subtree N collect in Writable_Actuals_List
-- all the actuals of functions with writable actuals, and in the list
-- Identifiers_List collect all the identifiers that are not actuals of
-- functions with writable actuals. If a writable actual is referenced
-- twice as writable actual then Error_Node is set to reference its
-- second occurrence, the error is reported, and the tree traversal
-- is abandoned.
function Get_Function_Id (Call : Node_Id) return Entity_Id;
-- Return the entity associated with the function call
procedure Preanalyze_Without_Errors (N : Node_Id);
-- Preanalyze N without reporting errors. Very dubious, you can't just
-- go analyzing things more than once???
-------------------------
-- Collect_Identifiers --
-------------------------
procedure Collect_Identifiers (N : Node_Id) is
function Check_Node (N : Node_Id) return Traverse_Result;
-- Process a single node during the tree traversal to collect the
-- writable actuals of functions and all the identifiers which are
-- not writable actuals of functions.
function Contains (List : Elist_Id; N : Node_Id) return Boolean;
-- Returns True if List has a node whose Entity is Entity (N)
-------------------------
-- Check_Function_Call --
-------------------------
function Check_Node (N : Node_Id) return Traverse_Result is
Is_Writable_Actual : Boolean := False;
Id : Entity_Id;
begin
if Nkind (N) = N_Identifier then
-- No analysis possible if the entity is not decorated
if No (Entity (N)) then
return Skip;
-- Don't collect identifiers of packages, called functions, etc
elsif Ekind_In (Entity (N), E_Package,
E_Function,
E_Procedure,
E_Entry)
then
return Skip;
-- Analyze if N is a writable actual of a function
elsif Nkind (Parent (N)) = N_Function_Call then
declare
Call : constant Node_Id := Parent (N);
Actual : Node_Id;
Formal : Node_Id;
begin
Id := Get_Function_Id (Call);
-- In case of previous error, no check is possible
if No (Id) then
return Abandon;
end if;
Formal := First_Formal (Id);
Actual := First_Actual (Call);
while Present (Actual) and then Present (Formal) loop
if Actual = N then
if Ekind_In (Formal, E_Out_Parameter,
E_In_Out_Parameter)
then
Is_Writable_Actual := True;
end if;
exit;
end if;
Next_Formal (Formal);
Next_Actual (Actual);
end loop;
end;
end if;
if Is_Writable_Actual then
if Contains (Writable_Actuals_List, N) then
Error_Msg_NE
("value may be affected by call to& "
& "because order of evaluation is arbitrary", N, Id);
Error_Node := N;
return Abandon;
end if;
Append_New_Elmt (N, To => Writable_Actuals_List);
else
if Identifiers_List = No_Elist then
Identifiers_List := New_Elmt_List;
end if;
Append_Unique_Elmt (N, Identifiers_List);
end if;
end if;
return OK;
end Check_Node;
--------------
-- Contains --
--------------
function Contains
(List : Elist_Id;
N : Node_Id) return Boolean
is
pragma Assert (Nkind (N) in N_Has_Entity);
Elmt : Elmt_Id;
begin
if List = No_Elist then
return False;
end if;
Elmt := First_Elmt (List);
while Present (Elmt) loop
if Entity (Node (Elmt)) = Entity (N) then
return True;
else
Next_Elmt (Elmt);
end if;
end loop;
return False;
end Contains;
------------------
-- Do_Traversal --
------------------
procedure Do_Traversal is new Traverse_Proc (Check_Node);
-- The traversal procedure
-- Start of processing for Collect_Identifiers
begin
if Present (Error_Node) then
return;
end if;
if Nkind (N) in N_Subexpr and then Is_OK_Static_Expression (N) then
return;
end if;
Do_Traversal (N);
end Collect_Identifiers;
---------------------
-- Get_Function_Id --
---------------------
function Get_Function_Id (Call : Node_Id) return Entity_Id is
Nam : constant Node_Id := Name (Call);
Id : Entity_Id;
begin
if Nkind (Nam) = N_Explicit_Dereference then
Id := Etype (Nam);
pragma Assert (Ekind (Id) = E_Subprogram_Type);
elsif Nkind (Nam) = N_Selected_Component then
Id := Entity (Selector_Name (Nam));
elsif Nkind (Nam) = N_Indexed_Component then
Id := Entity (Selector_Name (Prefix (Nam)));
else
Id := Entity (Nam);
end if;
return Id;
end Get_Function_Id;
---------------------------
-- Preanalyze_Expression --
---------------------------
procedure Preanalyze_Without_Errors (N : Node_Id) is
Status : constant Boolean := Get_Ignore_Errors;
begin
Set_Ignore_Errors (True);
Preanalyze (N);
Set_Ignore_Errors (Status);
end Preanalyze_Without_Errors;
-- Start of processing for Check_Function_Writable_Actuals
begin
-- The check only applies to Ada 2012 code, and only to constructs that
-- have multiple constituents whose order of evaluation is not specified
-- by the language.
if Ada_Version < Ada_2012
or else (not (Nkind (N) in N_Op)
and then not (Nkind (N) in N_Membership_Test)
and then not Nkind_In (N, N_Range,
N_Aggregate,
N_Extension_Aggregate,
N_Full_Type_Declaration,
N_Function_Call,
N_Procedure_Call_Statement,
N_Entry_Call_Statement))
or else (Nkind (N) = N_Full_Type_Declaration
and then not Is_Record_Type (Defining_Identifier (N)))
-- In addition, this check only applies to source code, not to code
-- generated by constraint checks.
or else not Comes_From_Source (N)
then
return;
end if;
-- If a construct C has two or more direct constituents that are names
-- or expressions whose evaluation may occur in an arbitrary order, at
-- least one of which contains a function call with an in out or out
-- parameter, then the construct is legal only if: for each name N that
-- is passed as a parameter of mode in out or out to some inner function
-- call C2 (not including the construct C itself), there is no other
-- name anywhere within a direct constituent of the construct C other
-- than the one containing C2, that is known to refer to the same
-- object (RM 6.4.1(6.17/3)).
case Nkind (N) is
when N_Range =>
Collect_Identifiers (Low_Bound (N));
Collect_Identifiers (High_Bound (N));
when N_Op | N_Membership_Test =>
declare
Expr : Node_Id;
begin
Collect_Identifiers (Left_Opnd (N));
if Present (Right_Opnd (N)) then
Collect_Identifiers (Right_Opnd (N));
end if;
if Nkind_In (N, N_In, N_Not_In)
and then Present (Alternatives (N))
then
Expr := First (Alternatives (N));
while Present (Expr) loop
Collect_Identifiers (Expr);
Next (Expr);
end loop;
end if;
end;
when N_Full_Type_Declaration =>
declare
function Get_Record_Part (N : Node_Id) return Node_Id;
-- Return the record part of this record type definition
function Get_Record_Part (N : Node_Id) return Node_Id is
Type_Def : constant Node_Id := Type_Definition (N);
begin
if Nkind (Type_Def) = N_Derived_Type_Definition then
return Record_Extension_Part (Type_Def);
else
return Type_Def;
end if;
end Get_Record_Part;
Comp : Node_Id;
Def_Id : Entity_Id := Defining_Identifier (N);
Rec : Node_Id := Get_Record_Part (N);
begin
-- No need to perform any analysis if the record has no
-- components
if No (Rec) or else No (Component_List (Rec)) then
return;
end if;
-- Collect the identifiers starting from the deepest
-- derivation. Done to report the error in the deepest
-- derivation.
loop
if Present (Component_List (Rec)) then
Comp := First (Component_Items (Component_List (Rec)));
while Present (Comp) loop
if Nkind (Comp) = N_Component_Declaration
and then Present (Expression (Comp))
then
Collect_Identifiers (Expression (Comp));
end if;
Next (Comp);
end loop;
end if;
exit when No (Underlying_Type (Etype (Def_Id)))
or else Base_Type (Underlying_Type (Etype (Def_Id)))
= Def_Id;
Def_Id := Base_Type (Underlying_Type (Etype (Def_Id)));
Rec := Get_Record_Part (Parent (Def_Id));
end loop;
end;
when N_Subprogram_Call |
N_Entry_Call_Statement =>
declare
Id : constant Entity_Id := Get_Function_Id (N);
Formal : Node_Id;
Actual : Node_Id;
begin
Formal := First_Formal (Id);
Actual := First_Actual (N);
while Present (Actual) and then Present (Formal) loop
if Ekind_In (Formal, E_Out_Parameter,
E_In_Out_Parameter)
then
Collect_Identifiers (Actual);
end if;
Next_Formal (Formal);
Next_Actual (Actual);
end loop;
end;
when N_Aggregate |
N_Extension_Aggregate =>
declare
Assoc : Node_Id;
Choice : Node_Id;
Comp_Expr : Node_Id;
begin
-- Handle the N_Others_Choice of array aggregates with static
-- bounds. There is no need to perform this analysis in
-- aggregates without static bounds since we cannot evaluate
-- if the N_Others_Choice covers several elements. There is
-- no need to handle the N_Others choice of record aggregates
-- since at this stage it has been already expanded by
-- Resolve_Record_Aggregate.
if Is_Array_Type (Etype (N))
and then Nkind (N) = N_Aggregate
and then Present (Aggregate_Bounds (N))
and then Compile_Time_Known_Bounds (Etype (N))
and then Expr_Value (High_Bound (Aggregate_Bounds (N)))
>
Expr_Value (Low_Bound (Aggregate_Bounds (N)))
then
declare
Count_Components : Uint := Uint_0;
Num_Components : Uint;
Others_Assoc : Node_Id;
Others_Choice : Node_Id := Empty;
Others_Box_Present : Boolean := False;
begin
-- Count positional associations
if Present (Expressions (N)) then
Comp_Expr := First (Expressions (N));
while Present (Comp_Expr) loop
Count_Components := Count_Components + 1;
Next (Comp_Expr);
end loop;
end if;
-- Count the rest of elements and locate the N_Others
-- choice (if any)
Assoc := First (Component_Associations (N));
while Present (Assoc) loop
Choice := First (Choices (Assoc));
while Present (Choice) loop
if Nkind (Choice) = N_Others_Choice then
Others_Assoc := Assoc;
Others_Choice := Choice;
Others_Box_Present := Box_Present (Assoc);
-- Count several components
elsif Nkind_In (Choice, N_Range,
N_Subtype_Indication)
or else (Is_Entity_Name (Choice)
and then Is_Type (Entity (Choice)))
then
declare
L, H : Node_Id;
begin
Get_Index_Bounds (Choice, L, H);
pragma Assert
(Compile_Time_Known_Value (L)
and then Compile_Time_Known_Value (H));
Count_Components :=
Count_Components
+ Expr_Value (H) - Expr_Value (L) + 1;
end;
-- Count single component. No other case available
-- since we are handling an aggregate with static
-- bounds.
else
pragma Assert (Is_OK_Static_Expression (Choice)
or else Nkind (Choice) = N_Identifier
or else Nkind (Choice) = N_Integer_Literal);
Count_Components := Count_Components + 1;
end if;
Next (Choice);
end loop;
Next (Assoc);
end loop;
Num_Components :=
Expr_Value (High_Bound (Aggregate_Bounds (N))) -
Expr_Value (Low_Bound (Aggregate_Bounds (N))) + 1;
pragma Assert (Count_Components <= Num_Components);
-- Handle the N_Others choice if it covers several
-- components
if Present (Others_Choice)
and then (Num_Components - Count_Components) > 1
then
if not Others_Box_Present then
-- At this stage, if expansion is active, the
-- expression of the others choice has not been
-- analyzed. Hence we generate a duplicate and
-- we analyze it silently to have available the
-- minimum decoration required to collect the
-- identifiers.
if not Expander_Active then
Comp_Expr := Expression (Others_Assoc);
else
Comp_Expr :=
New_Copy_Tree (Expression (Others_Assoc));
Preanalyze_Without_Errors (Comp_Expr);
end if;
Collect_Identifiers (Comp_Expr);
if Writable_Actuals_List /= No_Elist then
-- As suggested by Robert, at current stage we
-- report occurrences of this case as warnings.
Error_Msg_N
("writable function parameter may affect "
& "value in other component because order "
& "of evaluation is unspecified??",
Node (First_Elmt (Writable_Actuals_List)));
end if;
end if;
end if;
end;
end if;
-- Handle ancestor part of extension aggregates
if Nkind (N) = N_Extension_Aggregate then
Collect_Identifiers (Ancestor_Part (N));
end if;
-- Handle positional associations
if Present (Expressions (N)) then
Comp_Expr := First (Expressions (N));
while Present (Comp_Expr) loop
if not Is_OK_Static_Expression (Comp_Expr) then
Collect_Identifiers (Comp_Expr);
end if;
Next (Comp_Expr);
end loop;
end if;
-- Handle discrete associations
if Present (Component_Associations (N)) then
Assoc := First (Component_Associations (N));
while Present (Assoc) loop
if not Box_Present (Assoc) then
Choice := First (Choices (Assoc));
while Present (Choice) loop
-- For now we skip discriminants since it requires
-- performing the analysis in two phases: first one
-- analyzing discriminants and second one analyzing
-- the rest of components since discriminants are
-- evaluated prior to components: too much extra
-- work to detect a corner case???
if Nkind (Choice) in N_Has_Entity
and then Present (Entity (Choice))
and then Ekind (Entity (Choice)) = E_Discriminant
then
null;
elsif Box_Present (Assoc) then
null;
else
if not Analyzed (Expression (Assoc)) then
Comp_Expr :=
New_Copy_Tree (Expression (Assoc));
Set_Parent (Comp_Expr, Parent (N));
Preanalyze_Without_Errors (Comp_Expr);
else
Comp_Expr := Expression (Assoc);
end if;
Collect_Identifiers (Comp_Expr);
end if;
Next (Choice);
end loop;
end if;
Next (Assoc);
end loop;
end if;
end;
when others =>
return;
end case;
-- No further action needed if we already reported an error
if Present (Error_Node) then
return;
end if;
-- Check if some writable argument of a function is referenced
if Writable_Actuals_List /= No_Elist
and then Identifiers_List /= No_Elist
then
declare
Elmt_1 : Elmt_Id;
Elmt_2 : Elmt_Id;
begin
Elmt_1 := First_Elmt (Writable_Actuals_List);
while Present (Elmt_1) loop
Elmt_2 := First_Elmt (Identifiers_List);
while Present (Elmt_2) loop
if Entity (Node (Elmt_1)) = Entity (Node (Elmt_2)) then
case Nkind (Parent (Node (Elmt_2))) is
when N_Aggregate |
N_Component_Association |
N_Component_Declaration =>
Error_Msg_N
("value may be affected by call in other "
& "component because they are evaluated "
& "in unspecified order",
Node (Elmt_2));
when N_In | N_Not_In =>
Error_Msg_N
("value may be affected by call in other "
& "alternative because they are evaluated "
& "in unspecified order",
Node (Elmt_2));
when others =>
Error_Msg_N
("value of actual may be affected by call in "
& "other actual because they are evaluated "
& "in unspecified order",
Node (Elmt_2));
end case;
end if;
Next_Elmt (Elmt_2);
end loop;
Next_Elmt (Elmt_1);
end loop;
end;
end if;
end Check_Function_Writable_Actuals;
--------------------------------
-- Check_Implicit_Dereference --
--------------------------------
procedure Check_Implicit_Dereference (N : Node_Id; Typ : Entity_Id) is
Disc : Entity_Id;
Desig : Entity_Id;
Nam : Node_Id;
begin
if Nkind (N) = N_Indexed_Component
and then Present (Generalized_Indexing (N))
then
Nam := Generalized_Indexing (N);
else
Nam := N;
end if;
if Ada_Version < Ada_2012
or else not Has_Implicit_Dereference (Base_Type (Typ))
then
return;
elsif not Comes_From_Source (N)
and then Nkind (N) /= N_Indexed_Component
then
return;
elsif Is_Entity_Name (Nam) and then Is_Type (Entity (Nam)) then
null;
else
Disc := First_Discriminant (Typ);
while Present (Disc) loop
if Has_Implicit_Dereference (Disc) then
Desig := Designated_Type (Etype (Disc));
Add_One_Interp (Nam, Disc, Desig);
-- If the node is a generalized indexing, add interpretation
-- to that node as well, for subsequent resolution.
if Nkind (N) = N_Indexed_Component then
Add_One_Interp (N, Disc, Desig);
end if;
-- If the operation comes from a generic unit and the context
-- is a selected component, the selector name may be global
-- and set in the instance already. Remove the entity to
-- force resolution of the selected component, and the
-- generation of an explicit dereference if needed.
if In_Instance
and then Nkind (Parent (Nam)) = N_Selected_Component
then
Set_Entity (Selector_Name (Parent (Nam)), Empty);
end if;
exit;
end if;
Next_Discriminant (Disc);
end loop;
end if;
end Check_Implicit_Dereference;
----------------------------------
-- Check_Internal_Protected_Use --
----------------------------------
procedure Check_Internal_Protected_Use (N : Node_Id; Nam : Entity_Id) is
S : Entity_Id;
Prot : Entity_Id;
begin
S := Current_Scope;
while Present (S) loop
if S = Standard_Standard then
return;
elsif Ekind (S) = E_Function
and then Ekind (Scope (S)) = E_Protected_Type
then
Prot := Scope (S);
exit;
end if;
S := Scope (S);
end loop;
if Scope (Nam) = Prot and then Ekind (Nam) /= E_Function then
-- An indirect function call (e.g. a callback within a protected
-- function body) is not statically illegal. If the access type is
-- anonymous and is the type of an access parameter, the scope of Nam
-- will be the protected type, but it is not a protected operation.
if Ekind (Nam) = E_Subprogram_Type
and then
Nkind (Associated_Node_For_Itype (Nam)) = N_Function_Specification
then
null;
elsif Nkind (N) = N_Subprogram_Renaming_Declaration then
Error_Msg_N
("within protected function cannot use protected "
& "procedure in renaming or as generic actual", N);
elsif Nkind (N) = N_Attribute_Reference then
Error_Msg_N
("within protected function cannot take access of "
& " protected procedure", N);
else
Error_Msg_N
("within protected function, protected object is constant", N);
Error_Msg_N
("\cannot call operation that may modify it", N);
end if;
end if;
end Check_Internal_Protected_Use;
---------------------------------------
-- Check_Later_Vs_Basic_Declarations --
---------------------------------------
procedure Check_Later_Vs_Basic_Declarations
(Decls : List_Id;
During_Parsing : Boolean)
is
Body_Sloc : Source_Ptr;
Decl : Node_Id;
function Is_Later_Declarative_Item (Decl : Node_Id) return Boolean;
-- Return whether Decl is considered as a declarative item.
-- When During_Parsing is True, the semantics of Ada 83 is followed.
-- When During_Parsing is False, the semantics of SPARK is followed.
-------------------------------
-- Is_Later_Declarative_Item --
-------------------------------
function Is_Later_Declarative_Item (Decl : Node_Id) return Boolean is
begin
if Nkind (Decl) in N_Later_Decl_Item then
return True;
elsif Nkind (Decl) = N_Pragma then
return True;
elsif During_Parsing then
return False;
-- In SPARK, a package declaration is not considered as a later
-- declarative item.
elsif Nkind (Decl) = N_Package_Declaration then
return False;
-- In SPARK, a renaming is considered as a later declarative item
elsif Nkind (Decl) in N_Renaming_Declaration then
return True;
else
return False;
end if;
end Is_Later_Declarative_Item;
-- Start of Check_Later_Vs_Basic_Declarations
begin
Decl := First (Decls);
-- Loop through sequence of basic declarative items
Outer : while Present (Decl) loop
if not Nkind_In (Decl, N_Subprogram_Body, N_Package_Body, N_Task_Body)
and then Nkind (Decl) not in N_Body_Stub
then
Next (Decl);
-- Once a body is encountered, we only allow later declarative
-- items. The inner loop checks the rest of the list.
else
Body_Sloc := Sloc (Decl);
Inner : while Present (Decl) loop
if not Is_Later_Declarative_Item (Decl) then
if During_Parsing then
if Ada_Version = Ada_83 then
Error_Msg_Sloc := Body_Sloc;
Error_Msg_N
("(Ada 83) decl cannot appear after body#", Decl);
end if;
else
Error_Msg_Sloc := Body_Sloc;
Check_SPARK_05_Restriction
("decl cannot appear after body#", Decl);
end if;
end if;
Next (Decl);
end loop Inner;
end if;
end loop Outer;
end Check_Later_Vs_Basic_Declarations;
-------------------------
-- Check_Nested_Access --
-------------------------
procedure Check_Nested_Access (N : Node_Id; Ent : Entity_Id) is
Scop : constant Entity_Id := Current_Scope;
Current_Subp : Entity_Id;
Enclosing : Entity_Id;
begin
-- Currently only enabled for VM back-ends for efficiency, should we
-- enable it more systematically? Probably not unless someone actually
-- needs it. It will be needed for C generation and is activated if the
-- Opt.Unnest_Subprogram_Mode flag is set True.
if (VM_Target /= No_VM or else Unnest_Subprogram_Mode)
and then Scope (Ent) /= Empty
and then not Is_Library_Level_Entity (Ent)
-- Comment the exclusion of imported entities ???
and then not Is_Imported (Ent)
then
-- In both the VM case and in Unnest_Subprogram_Mode, we mark
-- variables, constants, and loop parameters.
if Ekind_In (Ent, E_Variable, E_Constant, E_Loop_Parameter) then
null;
-- In Unnest_Subprogram_Mode, we also mark types and formals
elsif Unnest_Subprogram_Mode
and then (Is_Type (Ent) or else Is_Formal (Ent))
then
null;
-- All other cases, do not mark
else
return;
end if;
-- Get current subprogram that is relevant
if Is_Subprogram (Scop)
or else Is_Generic_Subprogram (Scop)
or else Is_Entry (Scop)
then
Current_Subp := Scop;
else
Current_Subp := Current_Subprogram;
end if;
Enclosing := Enclosing_Subprogram (Ent);
-- Set flag if uplevel reference
if Enclosing /= Empty and then Enclosing /= Current_Subp then
if Is_Type (Ent) then
Check_Uplevel_Reference_To_Type (Ent);
else
Set_Has_Uplevel_Reference (Ent, True);
if Unnest_Subprogram_Mode then
Set_Has_Uplevel_Reference (Current_Subp, True);
Note_Uplevel_Reference (N, Enclosing);
end if;
end if;
end if;
end if;
end Check_Nested_Access;
---------------------------
-- Check_No_Hidden_State --
---------------------------
procedure Check_No_Hidden_State (Id : Entity_Id) is
function Has_Null_Abstract_State (Pkg : Entity_Id) return Boolean;
-- Determine whether the entity of a package denoted by Pkg has a null
-- abstract state.
-----------------------------
-- Has_Null_Abstract_State --
-----------------------------
function Has_Null_Abstract_State (Pkg : Entity_Id) return Boolean is
States : constant Elist_Id := Abstract_States (Pkg);
begin
-- Check first available state of related package. A null abstract
-- state always appears as the sole element of the state list.
return
Present (States)
and then Is_Null_State (Node (First_Elmt (States)));
end Has_Null_Abstract_State;
-- Local variables
Context : Entity_Id := Empty;
Not_Visible : Boolean := False;
Scop : Entity_Id;
-- Start of processing for Check_No_Hidden_State
begin
pragma Assert (Ekind_In (Id, E_Abstract_State, E_Variable));
-- Find the proper context where the object or state appears
Scop := Scope (Id);
while Present (Scop) loop
Context := Scop;
-- Keep track of the context's visibility
Not_Visible := Not_Visible or else In_Private_Part (Context);
-- Prevent the search from going too far
if Context = Standard_Standard then
return;
-- Objects and states that appear immediately within a subprogram or
-- inside a construct nested within a subprogram do not introduce a
-- hidden state. They behave as local variable declarations.
elsif Is_Subprogram (Context) then
return;
-- When examining a package body, use the entity of the spec as it
-- carries the abstract state declarations.
elsif Ekind (Context) = E_Package_Body then
Context := Spec_Entity (Context);
end if;
-- Stop the traversal when a package subject to a null abstract state
-- has been found.
if Ekind_In (Context, E_Generic_Package, E_Package)
and then Has_Null_Abstract_State (Context)
then
exit;
end if;
Scop := Scope (Scop);
end loop;
-- At this point we know that there is at least one package with a null
-- abstract state in visibility. Emit an error message unconditionally
-- if the entity being processed is a state because the placement of the
-- related package is irrelevant. This is not the case for objects as
-- the intermediate context matters.
if Present (Context)
and then (Ekind (Id) = E_Abstract_State or else Not_Visible)
then
Error_Msg_N ("cannot introduce hidden state &", Id);
Error_Msg_NE ("\package & has null abstract state", Id, Context);
end if;
end Check_No_Hidden_State;
------------------------------------------
-- Check_Potentially_Blocking_Operation --
------------------------------------------
procedure Check_Potentially_Blocking_Operation (N : Node_Id) is
S : Entity_Id;
begin
-- N is one of the potentially blocking operations listed in 9.5.1(8).
-- When pragma Detect_Blocking is active, the run time will raise
-- Program_Error. Here we only issue a warning, since we generally
-- support the use of potentially blocking operations in the absence
-- of the pragma.
-- Indirect blocking through a subprogram call cannot be diagnosed
-- statically without interprocedural analysis, so we do not attempt
-- to do it here.
S := Scope (Current_Scope);
while Present (S) and then S /= Standard_Standard loop
if Is_Protected_Type (S) then
Error_Msg_N
("potentially blocking operation in protected operation??", N);
return;
end if;
S := Scope (S);
end loop;
end Check_Potentially_Blocking_Operation;
---------------------------------
-- Check_Result_And_Post_State --
---------------------------------
procedure Check_Result_And_Post_State (Subp_Id : Entity_Id) is
procedure Check_Result_And_Post_State_In_Pragma
(Prag : Node_Id;
Result_Seen : in out Boolean);
-- Determine whether pragma Prag mentions attribute 'Result and whether
-- the pragma contains an expression that evaluates differently in pre-
-- and post-state. Prag is a [refined] postcondition or a contract-cases
-- pragma. Result_Seen is set when the pragma mentions attribute 'Result
function Has_In_Out_Parameter (Subp_Id : Entity_Id) return Boolean;
-- Determine whether subprogram Subp_Id contains at least one IN OUT
-- formal parameter.
-------------------------------------------
-- Check_Result_And_Post_State_In_Pragma --
-------------------------------------------
procedure Check_Result_And_Post_State_In_Pragma
(Prag : Node_Id;
Result_Seen : in out Boolean)
is
procedure Check_Expression (Expr : Node_Id);
-- Perform the 'Result and post-state checks on a given expression
function Is_Function_Result (N : Node_Id) return Traverse_Result;
-- Attempt to find attribute 'Result in a subtree denoted by N
function Is_Trivial_Boolean (N : Node_Id) return Boolean;
-- Determine whether source node N denotes "True" or "False"
function Mentions_Post_State (N : Node_Id) return Boolean;
-- Determine whether a subtree denoted by N mentions any construct
-- that denotes a post-state.
procedure Check_Function_Result is
new Traverse_Proc (Is_Function_Result);
----------------------
-- Check_Expression --
----------------------
procedure Check_Expression (Expr : Node_Id) is
begin
if not Is_Trivial_Boolean (Expr) then
Check_Function_Result (Expr);
if not Mentions_Post_State (Expr) then
if Pragma_Name (Prag) = Name_Contract_Cases then
Error_Msg_NE
("contract case does not check the outcome of calling "
& "&?T?", Expr, Subp_Id);
elsif Pragma_Name (Prag) = Name_Refined_Post then
Error_Msg_NE
("refined postcondition does not check the outcome of "
& "calling &?T?", Prag, Subp_Id);
else
Error_Msg_NE
("postcondition does not check the outcome of calling "
& "&?T?", Prag, Subp_Id);
end if;
end if;
end if;
end Check_Expression;
------------------------
-- Is_Function_Result --
------------------------
function Is_Function_Result (N : Node_Id) return Traverse_Result is
begin
if Is_Attribute_Result (N) then
Result_Seen := True;
return Abandon;
-- Continue the traversal
else
return OK;
end if;
end Is_Function_Result;
------------------------
-- Is_Trivial_Boolean --
------------------------
function Is_Trivial_Boolean (N : Node_Id) return Boolean is
begin
return
Comes_From_Source (N)
and then Is_Entity_Name (N)
and then (Entity (N) = Standard_True
or else
Entity (N) = Standard_False);
end Is_Trivial_Boolean;
-------------------------
-- Mentions_Post_State --
-------------------------
function Mentions_Post_State (N : Node_Id) return Boolean is
Post_State_Seen : Boolean := False;
function Is_Post_State (N : Node_Id) return Traverse_Result;
-- Attempt to find a construct that denotes a post-state. If this
-- is the case, set flag Post_State_Seen.
-------------------
-- Is_Post_State --
-------------------
function Is_Post_State (N : Node_Id) return Traverse_Result is
Ent : Entity_Id;
begin
if Nkind_In (N, N_Explicit_Dereference, N_Function_Call) then
Post_State_Seen := True;
return Abandon;
elsif Nkind_In (N, N_Expanded_Name, N_Identifier) then
Ent := Entity (N);
-- The entity may be modifiable through an implicit
-- dereference.
if No (Ent)
or else Ekind (Ent) in Assignable_Kind
or else (Is_Access_Type (Etype (Ent))
and then Nkind (Parent (N)) =
N_Selected_Component)
then
Post_State_Seen := True;
return Abandon;
end if;
elsif Nkind (N) = N_Attribute_Reference then
if Attribute_Name (N) = Name_Old then
return Skip;
elsif Attribute_Name (N) = Name_Result then
Post_State_Seen := True;
return Abandon;
end if;
end if;
return OK;
end Is_Post_State;
procedure Find_Post_State is new Traverse_Proc (Is_Post_State);
-- Start of processing for Mentions_Post_State
begin
Find_Post_State (N);
return Post_State_Seen;
end Mentions_Post_State;
-- Local variables
Expr : constant Node_Id :=
Get_Pragma_Arg
(First (Pragma_Argument_Associations (Prag)));
Nam : constant Name_Id := Pragma_Name (Prag);
CCase : Node_Id;
-- Start of processing for Check_Result_And_Post_State_In_Pragma
begin
-- Examine all consequences
if Nam = Name_Contract_Cases then
CCase := First (Component_Associations (Expr));
while Present (CCase) loop
Check_Expression (Expression (CCase));
Next (CCase);
end loop;
-- Examine the expression of a postcondition
else pragma Assert (Nam_In (Nam, Name_Postcondition,
Name_Refined_Post));
Check_Expression (Expr);
end if;
end Check_Result_And_Post_State_In_Pragma;
--------------------------
-- Has_In_Out_Parameter --
--------------------------
function Has_In_Out_Parameter (Subp_Id : Entity_Id) return Boolean is
Formal : Entity_Id;
begin
-- Traverse the formals looking for an IN OUT parameter
Formal := First_Formal (Subp_Id);
while Present (Formal) loop
if Ekind (Formal) = E_In_Out_Parameter then
return True;
end if;
Next_Formal (Formal);
end loop;
return False;
end Has_In_Out_Parameter;
-- Local variables
Items : constant Node_Id := Contract (Subp_Id);
Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id);
Case_Prag : Node_Id := Empty;
Post_Prag : Node_Id := Empty;
Prag : Node_Id;
Seen_In_Case : Boolean := False;
Seen_In_Post : Boolean := False;
Spec_Id : Entity_Id;
-- Start of processing for Check_Result_And_Post_State
begin
-- The lack of attribute 'Result or a post-state is classified as a
-- suspicious contract. Do not perform the check if the corresponding
-- swich is not set.
if not Warn_On_Suspicious_Contract then
return;
-- Nothing to do if there is no contract
elsif No (Items) then
return;
end if;
-- Retrieve the entity of the subprogram spec (if any)
if Nkind (Subp_Decl) = N_Subprogram_Body
and then Present (Corresponding_Spec (Subp_Decl))
then
Spec_Id := Corresponding_Spec (Subp_Decl);
elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub
and then Present (Corresponding_Spec_Of_Stub (Subp_Decl))
then
Spec_Id := Corresponding_Spec_Of_Stub (Subp_Decl);
else
Spec_Id := Subp_Id;
end if;
-- Examine all postconditions for attribute 'Result and a post-state
Prag := Pre_Post_Conditions (Items);
while Present (Prag) loop
if Nam_In (Pragma_Name (Prag), Name_Postcondition,
Name_Refined_Post)
and then not Error_Posted (Prag)
then
Post_Prag := Prag;
Check_Result_And_Post_State_In_Pragma (Prag, Seen_In_Post);
end if;
Prag := Next_Pragma (Prag);
end loop;
-- Examine the contract cases of the subprogram for attribute 'Result
-- and a post-state.
Prag := Contract_Test_Cases (Items);
while Present (Prag) loop
if Pragma_Name (Prag) = Name_Contract_Cases
and then not Error_Posted (Prag)
then
Case_Prag := Prag;
Check_Result_And_Post_State_In_Pragma (Prag, Seen_In_Case);
end if;
Prag := Next_Pragma (Prag);
end loop;
-- Do not emit any errors if the subprogram is not a function
if not Ekind_In (Spec_Id, E_Function, E_Generic_Function) then
null;
-- Regardless of whether the function has postconditions or contract
-- cases, or whether they mention attribute 'Result, an IN OUT formal
-- parameter is always treated as a result.
elsif Has_In_Out_Parameter (Spec_Id) then
null;
-- The function has both a postcondition and contract cases and they do
-- not mention attribute 'Result.
elsif Present (Case_Prag)
and then not Seen_In_Case
and then Present (Post_Prag)
and then not Seen_In_Post
then
Error_Msg_N
("neither postcondition nor contract cases mention function "
& "result?T?", Post_Prag);
-- The function has contract cases only and they do not mention
-- attribute 'Result.
elsif Present (Case_Prag) and then not Seen_In_Case then
Error_Msg_N ("contract cases do not mention result?T?", Case_Prag);
-- The function has postconditions only and they do not mention
-- attribute 'Result.
elsif Present (Post_Prag) and then not Seen_In_Post then
Error_Msg_N
("postcondition does not mention function result?T?", Post_Prag);
end if;
end Check_Result_And_Post_State;
------------------------------
-- Check_Unprotected_Access --
------------------------------
procedure Check_Unprotected_Access
(Context : Node_Id;
Expr : Node_Id)
is
Cont_Encl_Typ : Entity_Id;
Pref_Encl_Typ : Entity_Id;
function Enclosing_Protected_Type (Obj : Node_Id) return Entity_Id;
-- Check whether Obj is a private component of a protected object.
-- Return the protected type where the component resides, Empty
-- otherwise.
function Is_Public_Operation return Boolean;
-- Verify that the enclosing operation is callable from outside the
-- protected object, to minimize false positives.
------------------------------
-- Enclosing_Protected_Type --
------------------------------
function Enclosing_Protected_Type (Obj : Node_Id) return Entity_Id is
begin
if Is_Entity_Name (Obj) then
declare
Ent : Entity_Id := Entity (Obj);
begin
-- The object can be a renaming of a private component, use
-- the original record component.
if Is_Prival (Ent) then
Ent := Prival_Link (Ent);
end if;
if Is_Protected_Type (Scope (Ent)) then
return Scope (Ent);
end if;
end;
end if;
-- For indexed and selected components, recursively check the prefix
if Nkind_In (Obj, N_Indexed_Component, N_Selected_Component) then
return Enclosing_Protected_Type (Prefix (Obj));
-- The object does not denote a protected component
else
return Empty;
end if;
end Enclosing_Protected_Type;
-------------------------
-- Is_Public_Operation --
-------------------------
function Is_Public_Operation return Boolean is
S : Entity_Id;
E : Entity_Id;
begin
S := Current_Scope;
while Present (S) and then S /= Pref_Encl_Typ loop
if Scope (S) = Pref_Encl_Typ then
E := First_Entity (Pref_Encl_Typ);
while Present (E)
and then E /= First_Private_Entity (Pref_Encl_Typ)
loop
if E = S then
return True;
end if;
Next_Entity (E);
end loop;
end if;
S := Scope (S);
end loop;
return False;
end Is_Public_Operation;
-- Start of processing for Check_Unprotected_Access
begin
if Nkind (Expr) = N_Attribute_Reference
and then Attribute_Name (Expr) = Name_Unchecked_Access
then
Cont_Encl_Typ := Enclosing_Protected_Type (Context);
Pref_Encl_Typ := Enclosing_Protected_Type (Prefix (Expr));
-- Check whether we are trying to export a protected component to a
-- context with an equal or lower access level.
if Present (Pref_Encl_Typ)
and then No (Cont_Encl_Typ)
and then Is_Public_Operation
and then Scope_Depth (Pref_Encl_Typ) >=
Object_Access_Level (Context)
then
Error_Msg_N
("??possible unprotected access to protected data", Expr);
end if;
end if;
end Check_Unprotected_Access;
------------------------
-- Collect_Interfaces --
------------------------
procedure Collect_Interfaces
(T : Entity_Id;
Ifaces_List : out Elist_Id;
Exclude_Parents : Boolean := False;
Use_Full_View : Boolean := True)
is
procedure Collect (Typ : Entity_Id);
-- Subsidiary subprogram used to traverse the whole list
-- of directly and indirectly implemented interfaces
-------------
-- Collect --
-------------
procedure Collect (Typ : Entity_Id) is
Ancestor : Entity_Id;
Full_T : Entity_Id;
Id : Node_Id;
Iface : Entity_Id;
begin
Full_T := Typ;
-- Handle private types and subtypes
if Use_Full_View
and then Is_Private_Type (Typ)
and then Present (Full_View (Typ))
then
Full_T := Full_View (Typ);
if Ekind (Full_T) = E_Record_Subtype then
Full_T := Full_View (Etype (Typ));
end if;
end if;
-- Include the ancestor if we are generating the whole list of
-- abstract interfaces.
if Etype (Full_T) /= Typ
-- Protect the frontend against wrong sources. For example:
-- package P is
-- type A is tagged null record;
-- type B is new A with private;
-- type C is new A with private;
-- private
-- type B is new C with null record;
-- type C is new B with null record;
-- end P;
and then Etype (Full_T) /= T
then
Ancestor := Etype (Full_T);
Collect (Ancestor);
if Is_Interface (Ancestor) and then not Exclude_Parents then
Append_Unique_Elmt (Ancestor, Ifaces_List);
end if;
end if;
-- Traverse the graph of ancestor interfaces
if Is_Non_Empty_List (Abstract_Interface_List (Full_T)) then
Id := First (Abstract_Interface_List (Full_T));
while Present (Id) loop
Iface := Etype (Id);
-- Protect against wrong uses. For example:
-- type I is interface;
-- type O is tagged null record;
-- type Wrong is new I and O with null record; -- ERROR
if Is_Interface (Iface) then
if Exclude_Parents
and then Etype (T) /= T
and then Interface_Present_In_Ancestor (Etype (T), Iface)
then
null;
else
Collect (Iface);
Append_Unique_Elmt (Iface, Ifaces_List);
end if;
end if;
Next (Id);
end loop;
end if;
end Collect;
-- Start of processing for Collect_Interfaces
begin
pragma Assert (Is_Tagged_Type (T) or else Is_Concurrent_Type (T));
Ifaces_List := New_Elmt_List;
Collect (T);
end Collect_Interfaces;
----------------------------------
-- Collect_Interface_Components --
----------------------------------
procedure Collect_Interface_Components
(Tagged_Type : Entity_Id;
Components_List : out Elist_Id)
is
procedure Collect (Typ : Entity_Id);
-- Subsidiary subprogram used to climb to the parents
-------------
-- Collect --
-------------
procedure Collect (Typ : Entity_Id) is
Tag_Comp : Entity_Id;
Parent_Typ : Entity_Id;
begin
-- Handle private types
if Present (Full_View (Etype (Typ))) then
Parent_Typ := Full_View (Etype (Typ));
else
Parent_Typ := Etype (Typ);
end if;
if Parent_Typ /= Typ
-- Protect the frontend against wrong sources. For example:
-- package P is
-- type A is tagged null record;
-- type B is new A with private;
-- type C is new A with private;
-- private
-- type B is new C with null record;
-- type C is new B with null record;
-- end P;
and then Parent_Typ /= Tagged_Type
then
Collect (Parent_Typ);
end if;
-- Collect the components containing tags of secondary dispatch
-- tables.
Tag_Comp := Next_Tag_Component (First_Tag_Component (Typ));
while Present (Tag_Comp) loop
pragma Assert (Present (Related_Type (Tag_Comp)));
Append_Elmt (Tag_Comp, Components_List);
Tag_Comp := Next_Tag_Component (Tag_Comp);
end loop;
end Collect;
-- Start of processing for Collect_Interface_Components
begin
pragma Assert (Ekind (Tagged_Type) = E_Record_Type
and then Is_Tagged_Type (Tagged_Type));
Components_List := New_Elmt_List;
Collect (Tagged_Type);
end Collect_Interface_Components;
-----------------------------
-- Collect_Interfaces_Info --
-----------------------------
procedure Collect_Interfaces_Info
(T : Entity_Id;
Ifaces_List : out Elist_Id;
Components_List : out Elist_Id;
Tags_List : out Elist_Id)
is
Comps_List : Elist_Id;
Comp_Elmt : Elmt_Id;
Comp_Iface : Entity_Id;
Iface_Elmt : Elmt_Id;
Iface : Entity_Id;
function Search_Tag (Iface : Entity_Id) return Entity_Id;
-- Search for the secondary tag associated with the interface type
-- Iface that is implemented by T.
----------------
-- Search_Tag --
----------------
function Search_Tag (Iface : Entity_Id) return Entity_Id is
ADT : Elmt_Id;
begin
if not Is_CPP_Class (T) then
ADT := Next_Elmt (Next_Elmt (First_Elmt (Access_Disp_Table (T))));
else
ADT := Next_Elmt (First_Elmt (Access_Disp_Table (T)));
end if;
while Present (ADT)
and then Is_Tag (Node (ADT))
and then Related_Type (Node (ADT)) /= Iface
loop
-- Skip secondary dispatch table referencing thunks to user
-- defined primitives covered by this interface.
pragma Assert (Has_Suffix (Node (ADT), 'P'));
Next_Elmt (ADT);
-- Skip secondary dispatch tables of Ada types
if not Is_CPP_Class (T) then
-- Skip secondary dispatch table referencing thunks to
-- predefined primitives.
pragma Assert (Has_Suffix (Node (ADT), 'Y'));
Next_Elmt (ADT);
-- Skip secondary dispatch table referencing user-defined
-- primitives covered by this interface.
pragma Assert (Has_Suffix (Node (ADT), 'D'));
Next_Elmt (ADT);
-- Skip secondary dispatch table referencing predefined
-- primitives.
pragma Assert (Has_Suffix (Node (ADT), 'Z'));
Next_Elmt (ADT);
end if;
end loop;
pragma Assert (Is_Tag (Node (ADT)));
return Node (ADT);
end Search_Tag;
-- Start of processing for Collect_Interfaces_Info
begin
Collect_Interfaces (T, Ifaces_List);
Collect_Interface_Components (T, Comps_List);
-- Search for the record component and tag associated with each
-- interface type of T.
Components_List := New_Elmt_List;
Tags_List := New_Elmt_List;
Iface_Elmt := First_Elmt (Ifaces_List);
while Present (Iface_Elmt) loop
Iface := Node (Iface_Elmt);
-- Associate the primary tag component and the primary dispatch table
-- with all the interfaces that are parents of T
if Is_Ancestor (Iface, T, Use_Full_View => True) then
Append_Elmt (First_Tag_Component (T), Components_List);
Append_Elmt (Node (First_Elmt (Access_Disp_Table (T))), Tags_List);
-- Otherwise search for the tag component and secondary dispatch
-- table of Iface
else
Comp_Elmt := First_Elmt (Comps_List);
while Present (Comp_Elmt) loop
Comp_Iface := Related_Type (Node (Comp_Elmt));
if Comp_Iface = Iface
or else Is_Ancestor (Iface, Comp_Iface, Use_Full_View => True)
then
Append_Elmt (Node (Comp_Elmt), Components_List);
Append_Elmt (Search_Tag (Comp_Iface), Tags_List);
exit;
end if;
Next_Elmt (Comp_Elmt);
end loop;
pragma Assert (Present (Comp_Elmt));
end if;
Next_Elmt (Iface_Elmt);
end loop;
end Collect_Interfaces_Info;
---------------------
-- Collect_Parents --
---------------------
procedure Collect_Parents
(T : Entity_Id;
List : out Elist_Id;
Use_Full_View : Boolean := True)
is
Current_Typ : Entity_Id := T;
Parent_Typ : Entity_Id;
begin
List := New_Elmt_List;
-- No action if the if the type has no parents
if T = Etype (T) then
return;
end if;
loop
Parent_Typ := Etype (Current_Typ);
if Is_Private_Type (Parent_Typ)
and then Present (Full_View (Parent_Typ))
and then Use_Full_View
then
Parent_Typ := Full_View (Base_Type (Parent_Typ));
end if;
Append_Elmt (Parent_Typ, List);
exit when Parent_Typ = Current_Typ;
Current_Typ := Parent_Typ;
end loop;
end Collect_Parents;
----------------------------------
-- Collect_Primitive_Operations --
----------------------------------
function Collect_Primitive_Operations (T : Entity_Id) return Elist_Id is
B_Type : constant Entity_Id := Base_Type (T);
B_Decl : constant Node_Id := Original_Node (Parent (B_Type));
B_Scope : Entity_Id := Scope (B_Type);
Op_List : Elist_Id;
Formal : Entity_Id;
Is_Prim : Boolean;
Is_Type_In_Pkg : Boolean;
Formal_Derived : Boolean := False;
Id : Entity_Id;
function Match (E : Entity_Id) return Boolean;
-- True if E's base type is B_Type, or E is of an anonymous access type
-- and the base type of its designated type is B_Type.
-----------
-- Match --
-----------
function Match (E : Entity_Id) return Boolean is
Etyp : Entity_Id := Etype (E);
begin
if Ekind (Etyp) = E_Anonymous_Access_Type then
Etyp := Designated_Type (Etyp);
end if;
-- In Ada 2012 a primitive operation may have a formal of an
-- incomplete view of the parent type.
return Base_Type (Etyp) = B_Type
or else
(Ada_Version >= Ada_2012
and then Ekind (Etyp) = E_Incomplete_Type
and then Full_View (Etyp) = B_Type);
end Match;
-- Start of processing for Collect_Primitive_Operations
begin
-- For tagged types, the primitive operations are collected as they
-- are declared, and held in an explicit list which is simply returned.
if Is_Tagged_Type (B_Type) then
return Primitive_Operations (B_Type);
-- An untagged generic type that is a derived type inherits the
-- primitive operations of its parent type. Other formal types only
-- have predefined operators, which are not explicitly represented.
elsif Is_Generic_Type (B_Type) then
if Nkind (B_Decl) = N_Formal_Type_Declaration
and then Nkind (Formal_Type_Definition (B_Decl)) =
N_Formal_Derived_Type_Definition
then
Formal_Derived := True;
else
return New_Elmt_List;
end if;
end if;
Op_List := New_Elmt_List;
if B_Scope = Standard_Standard then
if B_Type = Standard_String then
Append_Elmt (Standard_Op_Concat, Op_List);
elsif B_Type = Standard_Wide_String then
Append_Elmt (Standard_Op_Concatw, Op_List);
else
null;
end if;
-- Locate the primitive subprograms of the type
else
-- The primitive operations appear after the base type, except
-- if the derivation happens within the private part of B_Scope
-- and the type is a private type, in which case both the type
-- and some primitive operations may appear before the base
-- type, and the list of candidates starts after the type.
if In_Open_Scopes (B_Scope)
and then Scope (T) = B_Scope
and then In_Private_Part (B_Scope)
then
Id := Next_Entity (T);
-- In Ada 2012, If the type has an incomplete partial view, there
-- may be primitive operations declared before the full view, so
-- we need to start scanning from the incomplete view, which is
-- earlier on the entity chain.
elsif Nkind (Parent (B_Type)) = N_Full_Type_Declaration
and then Present (Incomplete_View (Parent (B_Type)))
then
Id := Defining_Entity (Incomplete_View (Parent (B_Type)));
else
Id := Next_Entity (B_Type);
end if;
-- Set flag if this is a type in a package spec
Is_Type_In_Pkg :=
Is_Package_Or_Generic_Package (B_Scope)
and then
Nkind (Parent (Declaration_Node (First_Subtype (T)))) /=
N_Package_Body;
while Present (Id) loop
-- Test whether the result type or any of the parameter types of
-- each subprogram following the type match that type when the
-- type is declared in a package spec, is a derived type, or the
-- subprogram is marked as primitive. (The Is_Primitive test is
-- needed to find primitives of nonderived types in declarative
-- parts that happen to override the predefined "=" operator.)
-- Note that generic formal subprograms are not considered to be
-- primitive operations and thus are never inherited.
if Is_Overloadable (Id)
and then (Is_Type_In_Pkg
or else Is_Derived_Type (B_Type)
or else Is_Primitive (Id))
and then Nkind (Parent (Parent (Id)))
not in N_Formal_Subprogram_Declaration
then
Is_Prim := False;
if Match (Id) then
Is_Prim := True;
else
Formal := First_Formal (Id);
while Present (Formal) loop
if Match (Formal) then
Is_Prim := True;
exit;
end if;
Next_Formal (Formal);
end loop;
end if;
-- For a formal derived type, the only primitives are the ones
-- inherited from the parent type. Operations appearing in the
-- package declaration are not primitive for it.
if Is_Prim
and then (not Formal_Derived or else Present (Alias (Id)))
then
-- In the special case of an equality operator aliased to
-- an overriding dispatching equality belonging to the same
-- type, we don't include it in the list of primitives.
-- This avoids inheriting multiple equality operators when
-- deriving from untagged private types whose full type is
-- tagged, which can otherwise cause ambiguities. Note that
-- this should only happen for this kind of untagged parent
-- type, since normally dispatching operations are inherited
-- using the type's Primitive_Operations list.
if Chars (Id) = Name_Op_Eq
and then Is_Dispatching_Operation (Id)
and then Present (Alias (Id))
and then Present (Overridden_Operation (Alias (Id)))
and then Base_Type (Etype (First_Entity (Id))) =
Base_Type (Etype (First_Entity (Alias (Id))))
then
null;
-- Include the subprogram in the list of primitives
else
Append_Elmt (Id, Op_List);
end if;
end if;
end if;
Next_Entity (Id);
-- For a type declared in System, some of its operations may
-- appear in the target-specific extension to System.
if No (Id)
and then B_Scope = RTU_Entity (System)
and then Present_System_Aux
then
B_Scope := System_Aux_Id;
Id := First_Entity (System_Aux_Id);
end if;
end loop;
end if;
return Op_List;
end Collect_Primitive_Operations;
-----------------------------------
-- Compile_Time_Constraint_Error --
-----------------------------------
function Compile_Time_Constraint_Error
(N : Node_Id;
Msg : String;
Ent : Entity_Id := Empty;
Loc : Source_Ptr := No_Location;
Warn : Boolean := False) return Node_Id
is
Msgc : String (1 .. Msg'Length + 3);
-- Copy of message, with room for possible ?? or << and ! at end
Msgl : Natural;
Wmsg : Boolean;
Eloc : Source_Ptr;
-- Start of processing for Compile_Time_Constraint_Error
begin
-- If this is a warning, convert it into an error if we are in code
-- subject to SPARK_Mode being set ON.
Error_Msg_Warn := SPARK_Mode /= On;
-- A static constraint error in an instance body is not a fatal error.
-- we choose to inhibit the message altogether, because there is no
-- obvious node (for now) on which to post it. On the other hand the
-- offending node must be replaced with a constraint_error in any case.
-- No messages are generated if we already posted an error on this node
if not Error_Posted (N) then
if Loc /= No_Location then
Eloc := Loc;
else
Eloc := Sloc (N);
end if;
-- Copy message to Msgc, converting any ? in the message into
-- < instead, so that we have an error in GNATprove mode.
Msgl := Msg'Length;
for J in 1 .. Msgl loop
if Msg (J) = '?' and then (J = 1 or else Msg (J) /= ''') then
Msgc (J) := '<';
else
Msgc (J) := Msg (J);
end if;
end loop;
-- Message is a warning, even in Ada 95 case
if Msg (Msg'Last) = '?' or else Msg (Msg'Last) = '<' then
Wmsg := True;
-- In Ada 83, all messages are warnings. In the private part and
-- the body of an instance, constraint_checks are only warnings.
-- We also make this a warning if the Warn parameter is set.
elsif Warn
or else (Ada_Version = Ada_83 and then Comes_From_Source (N))
then
Msgl := Msgl + 1;
Msgc (Msgl) := '<';
Msgl := Msgl + 1;
Msgc (Msgl) := '<';
Wmsg := True;
elsif In_Instance_Not_Visible then
Msgl := Msgl + 1;
Msgc (Msgl) := '<';
Msgl := Msgl + 1;
Msgc (Msgl) := '<';
Wmsg := True;
-- Otherwise we have a real error message (Ada 95 static case)
-- and we make this an unconditional message. Note that in the
-- warning case we do not make the message unconditional, it seems
-- quite reasonable to delete messages like this (about exceptions
-- that will be raised) in dead code.
else
Wmsg := False;
Msgl := Msgl + 1;
Msgc (Msgl) := '!';
end if;
-- One more test, skip the warning if the related expression is
-- statically unevaluated, since we don't want to warn about what
-- will happen when something is evaluated if it never will be
-- evaluated.
if not Is_Statically_Unevaluated (N) then
Error_Msg_Warn := SPARK_Mode /= On;
if Present (Ent) then
Error_Msg_NEL (Msgc (1 .. Msgl), N, Ent, Eloc);
else
Error_Msg_NEL (Msgc (1 .. Msgl), N, Etype (N), Eloc);
end if;
if Wmsg then
-- Check whether the context is an Init_Proc
if Inside_Init_Proc then
declare
Conc_Typ : constant Entity_Id :=
Corresponding_Concurrent_Type
(Entity (Parameter_Type (First
(Parameter_Specifications
(Parent (Current_Scope))))));
begin
-- Don't complain if the corresponding concurrent type
-- doesn't come from source (i.e. a single task/protected
-- object).
if Present (Conc_Typ)
and then not Comes_From_Source (Conc_Typ)
then
Error_Msg_NEL
("\& [<<", N, Standard_Constraint_Error, Eloc);
else
if GNATprove_Mode then
Error_Msg_NEL
("\& would have been raised for objects of this "
& "type", N, Standard_Constraint_Error, Eloc);
else
Error_Msg_NEL
("\& will be raised for objects of this type??",
N, Standard_Constraint_Error, Eloc);
end if;
end if;
end;
else
Error_Msg_NEL ("\& [<<", N, Standard_Constraint_Error, Eloc);
end if;
else
Error_Msg ("\static expression fails Constraint_Check", Eloc);
Set_Error_Posted (N);
end if;
end if;
end if;
return N;
end Compile_Time_Constraint_Error;
-----------------------
-- Conditional_Delay --
-----------------------
procedure Conditional_Delay (New_Ent, Old_Ent : Entity_Id) is
begin
if Has_Delayed_Freeze (Old_Ent) and then not Is_Frozen (Old_Ent) then
Set_Has_Delayed_Freeze (New_Ent);
end if;
end Conditional_Delay;
----------------------------
-- Contains_Refined_State --
----------------------------
function Contains_Refined_State (Prag : Node_Id) return Boolean is
function Has_State_In_Dependency (List : Node_Id) return Boolean;
-- Determine whether a dependency list mentions a state with a visible
-- refinement.
function Has_State_In_Global (List : Node_Id) return Boolean;
-- Determine whether a global list mentions a state with a visible
-- refinement.
function Is_Refined_State (Item : Node_Id) return Boolean;
-- Determine whether Item is a reference to an abstract state with a
-- visible refinement.
-----------------------------
-- Has_State_In_Dependency --
-----------------------------
function Has_State_In_Dependency (List : Node_Id) return Boolean is
Clause : Node_Id;
Output : Node_Id;
begin
-- A null dependency list does not mention any states
if Nkind (List) = N_Null then
return False;
-- Dependency clauses appear as component associations of an
-- aggregate.
elsif Nkind (List) = N_Aggregate
and then Present (Component_Associations (List))
then
Clause := First (Component_Associations (List));
while Present (Clause) loop
-- Inspect the outputs of a dependency clause
Output := First (Choices (Clause));
while Present (Output) loop
if Is_Refined_State (Output) then
return True;
end if;
Next (Output);
end loop;
-- Inspect the outputs of a dependency clause
if Is_Refined_State (Expression (Clause)) then
return True;
end if;
Next (Clause);
end loop;
-- If we get here, then none of the dependency clauses mention a
-- state with visible refinement.
return False;
-- An illegal pragma managed to sneak in
else
raise Program_Error;
end if;
end Has_State_In_Dependency;
-------------------------
-- Has_State_In_Global --
-------------------------
function Has_State_In_Global (List : Node_Id) return Boolean is
Item : Node_Id;
begin
-- A null global list does not mention any states
if Nkind (List) = N_Null then
return False;
-- Simple global list or moded global list declaration
elsif Nkind (List) = N_Aggregate then
-- The declaration of a simple global list appear as a collection
-- of expressions.
if Present (Expressions (List)) then
Item := First (Expressions (List));
while Present (Item) loop
if Is_Refined_State (Item) then
return True;
end if;
Next (Item);
end loop;
-- The declaration of a moded global list appears as a collection
-- of component associations where individual choices denote
-- modes.
else
Item := First (Component_Associations (List));
while Present (Item) loop
if Has_State_In_Global (Expression (Item)) then
return True;
end if;
Next (Item);
end loop;
end if;
-- If we get here, then the simple/moded global list did not
-- mention any states with a visible refinement.
return False;
-- Single global item declaration
elsif Is_Entity_Name (List) then
return Is_Refined_State (List);
-- An illegal pragma managed to sneak in
else
raise Program_Error;
end if;
end Has_State_In_Global;
----------------------
-- Is_Refined_State --
----------------------
function Is_Refined_State (Item : Node_Id) return Boolean is
Elmt : Node_Id;
Item_Id : Entity_Id;
begin
if Nkind (Item) = N_Null then
return False;
-- States cannot be subject to attribute 'Result. This case arises
-- in dependency relations.