2006-10-31 Ed Schonberg <schonberg@adacore.com> * sem_ch10.ads, sem_ch10.adb (Check_Redundant_Withs, Process_Body_Clauses): If the context of a body includes a use clause for P.Q then a with_clause for P in the same body is not redundant, even if the spec also has a with_clause on P. Add missing continuation mark to error msg (Build_Limited_Views): A limited view of a type is tagged if its declaration includes a record extension. (Analyze_Proper_Body): Set Corresponding_Stub field in N_Subunit node, even if the subunit has errors. This avoids malfunction by Lib.Check_Same_Extended_Unit in the presence of syntax errors. (Analyze_Compilation_Unit): Add circuit to make sure we get proper generation of obsolescent messages for with statements (cannot do this too early, or we cannot implement avoiding the messages in the case of obsolescent units withing obsolescent units). (Install_Siblings): If the with_clause is on a remote descendant of an ancestor of the current compilation unit, find whether there is a sibling child unit that is immediately visible. (Remove_Private_With_Clauses): New procedure, invoked after completing the analysis of the private part of a nested package, to remove from visibility the private with_clauses of the enclosing package declaration. (Analyze_With_Clause): Remove Check_Obsolescent call, this checking is now centralized in Generate_Reference. (Install_Limited_Context_Clauses): Remove superfluous error message associated with unlimited view visible through use and renamings. In addition, at the point in which the error is reported, we add the backslash to the text of the error to ensure that it is reported as a single error message. Use new // insertion for some continuation messages (Expand_Limited_With_Clause): Use copy of name rather than name itself, to create implicit with_clause for parent unit mentioned in original limited_with_clause. (Install_Limited_With_Unit): Set entity of parent identifiers if the unit is a child unit. For ASIS queries. (Analyze_Subunit): If the subunit appears within a child unit, make all ancestor child units directly visible again. From-SVN: r118287
5649 lines
196 KiB
Ada
5649 lines
196 KiB
Ada
------------------------------------------------------------------------------
|
|
-- --
|
|
-- GNAT COMPILER COMPONENTS --
|
|
-- --
|
|
-- S E M _ C H 1 0 --
|
|
-- --
|
|
-- B o d y --
|
|
-- --
|
|
-- Copyright (C) 1992-2006, 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 2, 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 COPYING. If not, write --
|
|
-- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
|
|
-- Boston, MA 02110-1301, USA. --
|
|
-- --
|
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
with Atree; use Atree;
|
|
with Debug; use Debug;
|
|
with Einfo; use Einfo;
|
|
with Errout; use Errout;
|
|
with Exp_Util; use Exp_Util;
|
|
with Fname; use Fname;
|
|
with Fname.UF; use Fname.UF;
|
|
with Freeze; use Freeze;
|
|
with Impunit; use Impunit;
|
|
with Inline; use Inline;
|
|
with Lib; use Lib;
|
|
with Lib.Load; use Lib.Load;
|
|
with Lib.Xref; use Lib.Xref;
|
|
with Namet; use Namet;
|
|
with Nlists; use Nlists;
|
|
with Nmake; use Nmake;
|
|
with Opt; use Opt;
|
|
with Output; use Output;
|
|
with Restrict; use Restrict;
|
|
with Rtsfind; use Rtsfind;
|
|
with Sem; use Sem;
|
|
with Sem_Ch3; use Sem_Ch3;
|
|
with Sem_Ch6; use Sem_Ch6;
|
|
with Sem_Ch7; use Sem_Ch7;
|
|
with Sem_Ch8; use Sem_Ch8;
|
|
with Sem_Dist; use Sem_Dist;
|
|
with Sem_Prag; use Sem_Prag;
|
|
with Sem_Util; use Sem_Util;
|
|
with Sem_Warn; use Sem_Warn;
|
|
with Stand; use Stand;
|
|
with Sinfo; use Sinfo;
|
|
with Sinfo.CN; use Sinfo.CN;
|
|
with Sinput; use Sinput;
|
|
with Snames; use Snames;
|
|
with Style; use Style;
|
|
with Stylesw; use Stylesw;
|
|
with Tbuild; use Tbuild;
|
|
with Ttypes; use Ttypes;
|
|
with Uname; use Uname;
|
|
|
|
package body Sem_Ch10 is
|
|
|
|
-----------------------
|
|
-- Local Subprograms --
|
|
-----------------------
|
|
|
|
procedure Analyze_Context (N : Node_Id);
|
|
-- Analyzes items in the context clause of compilation unit
|
|
|
|
procedure Build_Limited_Views (N : Node_Id);
|
|
-- Build and decorate the list of shadow entities for a package mentioned
|
|
-- in a limited_with clause. If the package was not previously analyzed
|
|
-- then it also performs a basic decoration of the real entities; this
|
|
-- is required to do not pass non-decorated entities to the back-end.
|
|
-- Implements Ada 2005 (AI-50217).
|
|
|
|
procedure Check_Body_Needed_For_SAL (Unit_Name : Entity_Id);
|
|
-- Check whether the source for the body of a compilation unit must
|
|
-- be included in a standalone library.
|
|
|
|
procedure Check_With_Type_Clauses (N : Node_Id);
|
|
-- If N is a body, verify that any with_type clauses on the spec, or
|
|
-- on the spec of any parent, have a matching with_clause.
|
|
|
|
procedure Check_Private_Child_Unit (N : Node_Id);
|
|
-- If a with_clause mentions a private child unit, the compilation
|
|
-- unit must be a member of the same family, as described in 10.1.2 (8).
|
|
|
|
procedure Check_Stub_Level (N : Node_Id);
|
|
-- Verify that a stub is declared immediately within a compilation unit,
|
|
-- and not in an inner frame.
|
|
|
|
procedure Expand_With_Clause (Item : Node_Id; Nam : Node_Id; N : Node_Id);
|
|
-- When a child unit appears in a context clause, the implicit withs on
|
|
-- parents are made explicit, and with clauses are inserted in the context
|
|
-- clause before the one for the child. If a parent in the with_clause
|
|
-- is a renaming, the implicit with_clause is on the renaming whose name
|
|
-- is mentioned in the with_clause, and not on the package it renames.
|
|
-- N is the compilation unit whose list of context items receives the
|
|
-- implicit with_clauses.
|
|
|
|
function Get_Parent_Entity (Unit : Node_Id) return Entity_Id;
|
|
-- Get defining entity of parent unit of a child unit. In most cases this
|
|
-- is the defining entity of the unit, but for a child instance whose
|
|
-- parent needs a body for inlining, the instantiation node of the parent
|
|
-- has not yet been rewritten as a package declaration, and the entity has
|
|
-- to be retrieved from the Instance_Spec of the unit.
|
|
|
|
procedure Implicit_With_On_Parent (Child_Unit : Node_Id; N : Node_Id);
|
|
-- If the main unit is a child unit, implicit withs are also added for
|
|
-- all its ancestors.
|
|
|
|
function In_Chain (E : Entity_Id) return Boolean;
|
|
-- Check that the shadow entity is not already in the homonym chain, for
|
|
-- example through a limited_with clause in a parent unit.
|
|
|
|
procedure Install_Context_Clauses (N : Node_Id);
|
|
-- Subsidiary to Install_Context and Install_Parents. Process only with_
|
|
-- and use_clauses for current unit and its library unit if any.
|
|
|
|
procedure Install_Limited_Context_Clauses (N : Node_Id);
|
|
-- Subsidiary to Install_Context. Process only limited with_clauses
|
|
-- for current unit. Implements Ada 2005 (AI-50217).
|
|
|
|
procedure Install_Limited_Withed_Unit (N : Node_Id);
|
|
-- Place shadow entities for a limited_with package in the visibility
|
|
-- structures for the current compilation. Implements Ada 2005 (AI-50217).
|
|
|
|
procedure Install_Withed_Unit
|
|
(With_Clause : Node_Id;
|
|
Private_With_OK : Boolean := False);
|
|
-- If the unit is not a child unit, make unit immediately visible.
|
|
-- The caller ensures that the unit is not already currently installed.
|
|
-- The flag Private_With_OK is set true in Install_Private_With_Clauses,
|
|
-- which is called when compiling the private part of a package, or
|
|
-- installing the private declarations of a parent unit.
|
|
|
|
procedure Install_Parents (Lib_Unit : Node_Id; Is_Private : Boolean);
|
|
-- This procedure establishes the context for the compilation of a child
|
|
-- unit. If Lib_Unit is a child library spec then the context of the parent
|
|
-- is installed, and the parent itself made immediately visible, so that
|
|
-- the child unit is processed in the declarative region of the parent.
|
|
-- Install_Parents makes a recursive call to itself to ensure that all
|
|
-- parents are loaded in the nested case. If Lib_Unit is a library body,
|
|
-- the only effect of Install_Parents is to install the private decls of
|
|
-- the parents, because the visible parent declarations will have been
|
|
-- installed as part of the context of the corresponding spec.
|
|
|
|
procedure Install_Siblings (U_Name : Entity_Id; N : Node_Id);
|
|
-- In the compilation of a child unit, a child of any of the ancestor
|
|
-- units is directly visible if it is visible, because the parent is in
|
|
-- an enclosing scope. Iterate over context to find child units of U_Name
|
|
-- or of some ancestor of it.
|
|
|
|
function Is_Child_Spec (Lib_Unit : Node_Id) return Boolean;
|
|
-- Lib_Unit is a library unit which may be a spec or a body. Is_Child_Spec
|
|
-- returns True if Lib_Unit is a library spec which is a child spec, i.e.
|
|
-- a library spec that has a parent. If the call to Is_Child_Spec returns
|
|
-- True, then Parent_Spec (Lib_Unit) is non-Empty and points to the
|
|
-- compilation unit for the parent spec.
|
|
--
|
|
-- Lib_Unit can also be a subprogram body that acts as its own spec. If
|
|
-- the Parent_Spec is non-empty, this is also a child unit.
|
|
|
|
procedure Remove_With_Type_Clause (Name : Node_Id);
|
|
-- Remove imported type and its enclosing package from visibility, and
|
|
-- remove attributes of imported type so they don't interfere with its
|
|
-- analysis (should it appear otherwise in the context).
|
|
|
|
procedure Remove_Context_Clauses (N : Node_Id);
|
|
-- Subsidiary of previous one. Remove use_ and with_clauses
|
|
|
|
procedure Remove_Limited_With_Clause (N : Node_Id);
|
|
-- Remove from visibility the shadow entities introduced for a package
|
|
-- mentioned in a limited_with clause. Implements Ada 2005 (AI-50217).
|
|
|
|
procedure Remove_Parents (Lib_Unit : Node_Id);
|
|
-- Remove_Parents checks if Lib_Unit is a child spec. If so then the parent
|
|
-- contexts established by the corresponding call to Install_Parents are
|
|
-- removed. Remove_Parents contains a recursive call to itself to ensure
|
|
-- that all parents are removed in the nested case.
|
|
|
|
procedure Remove_Unit_From_Visibility (Unit_Name : Entity_Id);
|
|
-- Reset all visibility flags on unit after compiling it, either as a
|
|
-- main unit or as a unit in the context.
|
|
|
|
procedure Unchain (E : Entity_Id);
|
|
-- Remove single entity from visibility list
|
|
|
|
procedure Analyze_Proper_Body (N : Node_Id; Nam : Entity_Id);
|
|
-- Common processing for all stubs (subprograms, tasks, packages, and
|
|
-- protected cases). N is the stub to be analyzed. Once the subunit
|
|
-- name is established, load and analyze. Nam is the non-overloadable
|
|
-- entity for which the proper body provides a completion. Subprogram
|
|
-- stubs are handled differently because they can be declarations.
|
|
|
|
--------------------------
|
|
-- Limited_With_Clauses --
|
|
--------------------------
|
|
|
|
-- Limited_With clauses are the mechanism chosen for Ada05 to support
|
|
-- mutually recursive types declared in different units. A limited_with
|
|
-- clause that names package P in the context of unit U makes the types
|
|
-- declared in the visible part of P available within U, but with the
|
|
-- restriction that these types can only be used as incomplete types.
|
|
-- The limited_with clause does not impose a semantic dependence on P,
|
|
-- and it is possible for two packages to have limited_with_clauses on
|
|
-- each other without creating an elaboration circularity.
|
|
|
|
-- To support this feature, the analysis of a limited_with clause must
|
|
-- create an abbreviated view of the package, without performing any
|
|
-- semantic analysis on it. This "package abstract" contains shadow
|
|
-- types that are in one-one correspondence with the real types in the
|
|
-- package, and that have the properties of incomplete types.
|
|
|
|
-- The implementation creates two element lists: one to chain the shadow
|
|
-- entities, and one to chain the corresponding type entities in the tree
|
|
-- of the package. Links between corresponding entities in both chains
|
|
-- allow the compiler to select the proper view of a given type, depending
|
|
-- on the context. Note that in contrast with the handling of private
|
|
-- types, the limited view and the non-limited view of a type are treated
|
|
-- as separate entities, and no entity exchange needs to take place, which
|
|
-- makes the implementation must simpler than could be feared.
|
|
|
|
------------------------------
|
|
-- Analyze_Compilation_Unit --
|
|
------------------------------
|
|
|
|
procedure Analyze_Compilation_Unit (N : Node_Id) is
|
|
Unit_Node : constant Node_Id := Unit (N);
|
|
Lib_Unit : Node_Id := Library_Unit (N);
|
|
Spec_Id : Node_Id;
|
|
Main_Cunit : constant Node_Id := Cunit (Main_Unit);
|
|
Par_Spec_Name : Unit_Name_Type;
|
|
Unum : Unit_Number_Type;
|
|
|
|
procedure Check_Redundant_Withs
|
|
(Context_Items : List_Id;
|
|
Spec_Context_Items : List_Id := No_List);
|
|
-- Determine whether the context list of a compilation unit contains
|
|
-- redundant with clauses. When checking body clauses against spec
|
|
-- clauses, set Context_Items to the context list of the body and
|
|
-- Spec_Context_Items to that of the spec. Parent packages are not
|
|
-- examined for documentation purposes.
|
|
|
|
procedure Generate_Parent_References (N : Node_Id; P_Id : Entity_Id);
|
|
-- Generate cross-reference information for the parents of child units.
|
|
-- N is a defining_program_unit_name, and P_Id is the immediate parent.
|
|
|
|
---------------------------
|
|
-- Check_Redundant_Withs --
|
|
---------------------------
|
|
|
|
procedure Check_Redundant_Withs
|
|
(Context_Items : List_Id;
|
|
Spec_Context_Items : List_Id := No_List)
|
|
is
|
|
Clause : Node_Id;
|
|
|
|
procedure Process_Body_Clauses
|
|
(Context_List : List_Id;
|
|
Clause : Node_Id;
|
|
Used : in out Boolean;
|
|
Used_Type_Or_Elab : in out Boolean);
|
|
-- Examine the context clauses of a package body, trying to match
|
|
-- the name entity of Clause with any list element. If the match
|
|
-- occurs on a use package clause, set Used to True, for a use
|
|
-- type clause, pragma Elaborate or pragma Elaborate_All, set
|
|
-- Used_Type_Or_Elab to True.
|
|
|
|
procedure Process_Spec_Clauses
|
|
(Context_List : List_Id;
|
|
Clause : Node_Id;
|
|
Used : in out Boolean;
|
|
Withed : in out Boolean;
|
|
Exit_On_Self : Boolean := False);
|
|
-- Examine the context clauses of a package spec, trying to match
|
|
-- the name entity of Clause with any list element. If the match
|
|
-- occurs on a use package clause, set Used to True, for a with
|
|
-- package clause other than Clause, set Withed to True. Limited
|
|
-- with clauses, implicitly generated with clauses and withs
|
|
-- having pragmas Elaborate or Elaborate_All applied to them are
|
|
-- skipped. Exit_On_Self is used to control the search loop and
|
|
-- force an exit whenever Clause sees itself in the search.
|
|
|
|
--------------------------
|
|
-- Process_Body_Clauses --
|
|
--------------------------
|
|
|
|
procedure Process_Body_Clauses
|
|
(Context_List : List_Id;
|
|
Clause : Node_Id;
|
|
Used : in out Boolean;
|
|
Used_Type_Or_Elab : in out Boolean)
|
|
is
|
|
Nam_Ent : constant Entity_Id := Entity (Name (Clause));
|
|
Cont_Item : Node_Id;
|
|
Prag_Unit : Node_Id;
|
|
Subt_Mark : Node_Id;
|
|
Use_Item : Node_Id;
|
|
|
|
begin
|
|
Used := False;
|
|
Used_Type_Or_Elab := False;
|
|
|
|
Cont_Item := First (Context_List);
|
|
while Present (Cont_Item) loop
|
|
|
|
-- Package use clause
|
|
|
|
if Nkind (Cont_Item) = N_Use_Package_Clause
|
|
and then not Used
|
|
then
|
|
-- Search through use clauses
|
|
|
|
Use_Item := First (Names (Cont_Item));
|
|
while Present (Use_Item) and then not Used loop
|
|
|
|
-- Case of a direct use of the one we are looking for
|
|
|
|
if Entity (Use_Item) = Nam_Ent then
|
|
Used := True;
|
|
|
|
-- Handle nested case, as in "with P; use P.Q.R"
|
|
|
|
else
|
|
declare
|
|
UE : Node_Id;
|
|
|
|
begin
|
|
-- Loop through prefixes looking for match
|
|
|
|
UE := Use_Item;
|
|
while Nkind (UE) = N_Expanded_Name loop
|
|
if Entity (Prefix (UE)) = Nam_Ent then
|
|
Used := True;
|
|
exit;
|
|
end if;
|
|
|
|
UE := Prefix (UE);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
Next (Use_Item);
|
|
end loop;
|
|
|
|
-- Type use clause
|
|
|
|
elsif Nkind (Cont_Item) = N_Use_Type_Clause
|
|
and then not Used_Type_Or_Elab
|
|
then
|
|
Subt_Mark := First (Subtype_Marks (Cont_Item));
|
|
while Present (Subt_Mark)
|
|
and then not Used_Type_Or_Elab
|
|
loop
|
|
if Entity (Prefix (Subt_Mark)) = Nam_Ent then
|
|
Used_Type_Or_Elab := True;
|
|
end if;
|
|
|
|
Next (Subt_Mark);
|
|
end loop;
|
|
|
|
-- Pragma Elaborate or Elaborate_All
|
|
|
|
elsif Nkind (Cont_Item) = N_Pragma
|
|
and then
|
|
(Chars (Cont_Item) = Name_Elaborate
|
|
or else
|
|
Chars (Cont_Item) = Name_Elaborate_All)
|
|
and then not Used_Type_Or_Elab
|
|
then
|
|
Prag_Unit :=
|
|
First (Pragma_Argument_Associations (Cont_Item));
|
|
while Present (Prag_Unit)
|
|
and then not Used_Type_Or_Elab
|
|
loop
|
|
if Entity (Expression (Prag_Unit)) = Nam_Ent then
|
|
Used_Type_Or_Elab := True;
|
|
end if;
|
|
|
|
Next (Prag_Unit);
|
|
end loop;
|
|
end if;
|
|
|
|
Next (Cont_Item);
|
|
end loop;
|
|
end Process_Body_Clauses;
|
|
|
|
--------------------------
|
|
-- Process_Spec_Clauses --
|
|
--------------------------
|
|
|
|
procedure Process_Spec_Clauses
|
|
(Context_List : List_Id;
|
|
Clause : Node_Id;
|
|
Used : in out Boolean;
|
|
Withed : in out Boolean;
|
|
Exit_On_Self : Boolean := False)
|
|
is
|
|
Nam_Ent : constant Entity_Id := Entity (Name (Clause));
|
|
Cont_Item : Node_Id;
|
|
Use_Item : Node_Id;
|
|
|
|
begin
|
|
Used := False;
|
|
Withed := False;
|
|
|
|
Cont_Item := First (Context_List);
|
|
while Present (Cont_Item) loop
|
|
|
|
-- Stop the search since the context items after Cont_Item
|
|
-- have already been examined in a previous iteration of
|
|
-- the reverse loop in Check_Redundant_Withs.
|
|
|
|
if Exit_On_Self
|
|
and Cont_Item = Clause
|
|
then
|
|
exit;
|
|
end if;
|
|
|
|
-- Package use clause
|
|
|
|
if Nkind (Cont_Item) = N_Use_Package_Clause
|
|
and then not Used
|
|
then
|
|
Use_Item := First (Names (Cont_Item));
|
|
while Present (Use_Item) and then not Used loop
|
|
if Entity (Use_Item) = Nam_Ent then
|
|
Used := True;
|
|
end if;
|
|
|
|
Next (Use_Item);
|
|
end loop;
|
|
|
|
-- Package with clause. Avoid processing self, implicitly
|
|
-- generated with clauses or limited with clauses. Note
|
|
-- that we examine with clauses having pragmas Elaborate
|
|
-- or Elaborate_All applied to them due to cases such as:
|
|
--
|
|
-- with Pack;
|
|
-- with Pack;
|
|
-- pragma Elaborate (Pack);
|
|
--
|
|
-- In this case, the second with clause is redundant since
|
|
-- the pragma applies only to the first "with Pack;".
|
|
|
|
elsif Nkind (Cont_Item) = N_With_Clause
|
|
and then not Implicit_With (Cont_Item)
|
|
and then not Limited_Present (Cont_Item)
|
|
and then Cont_Item /= Clause
|
|
and then Entity (Name (Cont_Item)) = Nam_Ent
|
|
then
|
|
Withed := True;
|
|
end if;
|
|
|
|
Next (Cont_Item);
|
|
end loop;
|
|
end Process_Spec_Clauses;
|
|
|
|
-- Start of processing for Check_Redundant_Withs
|
|
|
|
begin
|
|
Clause := Last (Context_Items);
|
|
while Present (Clause) loop
|
|
|
|
-- Avoid checking implicitly generated with clauses, limited
|
|
-- with clauses or withs that have pragma Elaborate or
|
|
-- Elaborate_All apllied.
|
|
|
|
if Nkind (Clause) = N_With_Clause
|
|
and then not Implicit_With (Clause)
|
|
and then not Limited_Present (Clause)
|
|
and then not Elaborate_Present (Clause)
|
|
then
|
|
-- Package body-to-spec check
|
|
|
|
if Present (Spec_Context_Items) then
|
|
declare
|
|
Used_In_Body : Boolean := False;
|
|
Used_In_Spec : Boolean := False;
|
|
Used_Type_Or_Elab : Boolean := False;
|
|
Withed_In_Spec : Boolean := False;
|
|
|
|
begin
|
|
Process_Spec_Clauses
|
|
(Context_List => Spec_Context_Items,
|
|
Clause => Clause,
|
|
Used => Used_In_Spec,
|
|
Withed => Withed_In_Spec);
|
|
|
|
Process_Body_Clauses
|
|
(Context_List => Context_Items,
|
|
Clause => Clause,
|
|
Used => Used_In_Body,
|
|
Used_Type_Or_Elab => Used_Type_Or_Elab);
|
|
|
|
-- "Type Elab" refers to the presence of either a use
|
|
-- type clause, pragmas Elaborate or Elaborate_All.
|
|
|
|
-- +---------------+---------------------------+------+
|
|
-- | Spec | Body | Warn |
|
|
-- +--------+------+--------+------+-----------+------+
|
|
-- | Withed | Used | Withed | Used | Type Elab | |
|
|
-- | X | | X | | | X |
|
|
-- | X | | X | X | | |
|
|
-- | X | | X | | X | |
|
|
-- | X | | X | X | X | |
|
|
-- | X | X | X | | | X |
|
|
-- | X | X | X | | X | |
|
|
-- | X | X | X | X | | X |
|
|
-- | X | X | X | X | X | |
|
|
-- +--------+------+--------+------+-----------+------+
|
|
|
|
if (Withed_In_Spec
|
|
and then not Used_Type_Or_Elab)
|
|
and then
|
|
((not Used_In_Spec
|
|
and then not Used_In_Body)
|
|
or else
|
|
Used_In_Spec)
|
|
then
|
|
Error_Msg_N ("?redundant with clause in body", Clause);
|
|
end if;
|
|
|
|
Used_In_Body := False;
|
|
Used_In_Spec := False;
|
|
Used_Type_Or_Elab := False;
|
|
Withed_In_Spec := False;
|
|
end;
|
|
|
|
-- Standalone package spec or body check
|
|
|
|
else
|
|
declare
|
|
Dont_Care : Boolean := False;
|
|
Withed : Boolean := False;
|
|
|
|
begin
|
|
-- The mechanism for examining the context clauses of a
|
|
-- package spec can be applied to package body clauses.
|
|
|
|
Process_Spec_Clauses
|
|
(Context_List => Context_Items,
|
|
Clause => Clause,
|
|
Used => Dont_Care,
|
|
Withed => Withed,
|
|
Exit_On_Self => True);
|
|
|
|
if Withed then
|
|
Error_Msg_N ("?redundant with clause", Clause);
|
|
end if;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
Prev (Clause);
|
|
end loop;
|
|
end Check_Redundant_Withs;
|
|
|
|
--------------------------------
|
|
-- Generate_Parent_References --
|
|
--------------------------------
|
|
|
|
procedure Generate_Parent_References (N : Node_Id; P_Id : Entity_Id) is
|
|
Pref : Node_Id;
|
|
P_Name : Entity_Id := P_Id;
|
|
|
|
begin
|
|
Pref := Name (Parent (Defining_Entity (N)));
|
|
|
|
if Nkind (Pref) = N_Expanded_Name then
|
|
|
|
-- Done already, if the unit has been compiled indirectly as
|
|
-- part of the closure of its context because of inlining.
|
|
|
|
return;
|
|
end if;
|
|
|
|
while Nkind (Pref) = N_Selected_Component loop
|
|
Change_Selected_Component_To_Expanded_Name (Pref);
|
|
Set_Entity (Pref, P_Name);
|
|
Set_Etype (Pref, Etype (P_Name));
|
|
Generate_Reference (P_Name, Pref, 'r');
|
|
Pref := Prefix (Pref);
|
|
P_Name := Scope (P_Name);
|
|
end loop;
|
|
|
|
-- The guard here on P_Name is to handle the error condition where
|
|
-- the parent unit is missing because the file was not found.
|
|
|
|
if Present (P_Name) then
|
|
Set_Entity (Pref, P_Name);
|
|
Set_Etype (Pref, Etype (P_Name));
|
|
Generate_Reference (P_Name, Pref, 'r');
|
|
Style.Check_Identifier (Pref, P_Name);
|
|
end if;
|
|
end Generate_Parent_References;
|
|
|
|
-- Start of processing for Analyze_Compilation_Unit
|
|
|
|
begin
|
|
Process_Compilation_Unit_Pragmas (N);
|
|
|
|
-- If the unit is a subunit whose parent has not been analyzed (which
|
|
-- indicates that the main unit is a subunit, either the current one or
|
|
-- one of its descendents) then the subunit is compiled as part of the
|
|
-- analysis of the parent, which we proceed to do. Basically this gets
|
|
-- handled from the top down and we don't want to do anything at this
|
|
-- level (i.e. this subunit will be handled on the way down from the
|
|
-- parent), so at this level we immediately return. If the subunit
|
|
-- ends up not analyzed, it means that the parent did not contain a
|
|
-- stub for it, or that there errors were dectected in some ancestor.
|
|
|
|
if Nkind (Unit_Node) = N_Subunit
|
|
and then not Analyzed (Lib_Unit)
|
|
then
|
|
Semantics (Lib_Unit);
|
|
|
|
if not Analyzed (Proper_Body (Unit_Node)) then
|
|
if Serious_Errors_Detected > 0 then
|
|
Error_Msg_N ("subunit not analyzed (errors in parent unit)", N);
|
|
else
|
|
Error_Msg_N ("missing stub for subunit", N);
|
|
end if;
|
|
end if;
|
|
|
|
return;
|
|
end if;
|
|
|
|
-- Analyze context (this will call Sem recursively for with'ed units)
|
|
|
|
Analyze_Context (N);
|
|
|
|
-- If the unit is a package body, the spec is already loaded and must
|
|
-- be analyzed first, before we analyze the body.
|
|
|
|
if Nkind (Unit_Node) = N_Package_Body then
|
|
|
|
-- If no Lib_Unit, then there was a serious previous error, so
|
|
-- just ignore the entire analysis effort
|
|
|
|
if No (Lib_Unit) then
|
|
return;
|
|
|
|
else
|
|
Semantics (Lib_Unit);
|
|
Check_Unused_Withs (Get_Cunit_Unit_Number (Lib_Unit));
|
|
|
|
-- Verify that the library unit is a package declaration
|
|
|
|
if Nkind (Unit (Lib_Unit)) /= N_Package_Declaration
|
|
and then
|
|
Nkind (Unit (Lib_Unit)) /= N_Generic_Package_Declaration
|
|
then
|
|
Error_Msg_N
|
|
("no legal package declaration for package body", N);
|
|
return;
|
|
|
|
-- Otherwise, the entity in the declaration is visible. Update
|
|
-- the version to reflect dependence of this body on the spec.
|
|
|
|
else
|
|
Spec_Id := Defining_Entity (Unit (Lib_Unit));
|
|
Set_Is_Immediately_Visible (Spec_Id, True);
|
|
Version_Update (N, Lib_Unit);
|
|
|
|
if Nkind (Defining_Unit_Name (Unit_Node))
|
|
= N_Defining_Program_Unit_Name
|
|
then
|
|
Generate_Parent_References (Unit_Node, Scope (Spec_Id));
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
-- If the unit is a subprogram body, then we similarly need to analyze
|
|
-- its spec. However, things are a little simpler in this case, because
|
|
-- here, this analysis is done only for error checking and consistency
|
|
-- purposes, so there's nothing else to be done.
|
|
|
|
elsif Nkind (Unit_Node) = N_Subprogram_Body then
|
|
if Acts_As_Spec (N) then
|
|
|
|
-- If the subprogram body is a child unit, we must create a
|
|
-- declaration for it, in order to properly load the parent(s).
|
|
-- After this, the original unit does not acts as a spec, because
|
|
-- there is an explicit one. If this unit appears in a context
|
|
-- clause, then an implicit with on the parent will be added when
|
|
-- installing the context. If this is the main unit, there is no
|
|
-- Unit_Table entry for the declaration, (It has the unit number
|
|
-- of the main unit) and code generation is unaffected.
|
|
|
|
Unum := Get_Cunit_Unit_Number (N);
|
|
Par_Spec_Name := Get_Parent_Spec_Name (Unit_Name (Unum));
|
|
|
|
if Par_Spec_Name /= No_Name then
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Par_Spec_Name,
|
|
Required => True,
|
|
Subunit => False,
|
|
Error_Node => N);
|
|
|
|
if Unum /= No_Unit then
|
|
|
|
-- Build subprogram declaration and attach parent unit to it
|
|
-- This subprogram declaration does not come from source,
|
|
-- Nevertheless the backend must generate debugging info for
|
|
-- it, and this must be indicated explicitly.
|
|
|
|
declare
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
SCS : constant Boolean :=
|
|
Get_Comes_From_Source_Default;
|
|
|
|
begin
|
|
Set_Comes_From_Source_Default (False);
|
|
Lib_Unit :=
|
|
Make_Compilation_Unit (Loc,
|
|
Context_Items => New_Copy_List (Context_Items (N)),
|
|
Unit =>
|
|
Make_Subprogram_Declaration (Sloc (N),
|
|
Specification =>
|
|
Copy_Separate_Tree
|
|
(Specification (Unit_Node))),
|
|
Aux_Decls_Node =>
|
|
Make_Compilation_Unit_Aux (Loc));
|
|
|
|
Set_Library_Unit (N, Lib_Unit);
|
|
Set_Parent_Spec (Unit (Lib_Unit), Cunit (Unum));
|
|
Semantics (Lib_Unit);
|
|
Set_Acts_As_Spec (N, False);
|
|
Set_Needs_Debug_Info (Defining_Entity (Unit (Lib_Unit)));
|
|
Set_Comes_From_Source_Default (SCS);
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
-- Here for subprogram with separate declaration
|
|
|
|
else
|
|
Semantics (Lib_Unit);
|
|
Check_Unused_Withs (Get_Cunit_Unit_Number (Lib_Unit));
|
|
Version_Update (N, Lib_Unit);
|
|
end if;
|
|
|
|
if Nkind (Defining_Unit_Name (Specification (Unit_Node))) =
|
|
N_Defining_Program_Unit_Name
|
|
then
|
|
Generate_Parent_References (
|
|
Specification (Unit_Node),
|
|
Scope (Defining_Entity (Unit (Lib_Unit))));
|
|
end if;
|
|
end if;
|
|
|
|
-- If it is a child unit, the parent must be elaborated first
|
|
-- and we update version, since we are dependent on our parent.
|
|
|
|
if Is_Child_Spec (Unit_Node) then
|
|
|
|
-- The analysis of the parent is done with style checks off
|
|
|
|
declare
|
|
Save_Style_Check : constant Boolean := Style_Check;
|
|
Save_C_Restrict : constant Save_Cunit_Boolean_Restrictions :=
|
|
Cunit_Boolean_Restrictions_Save;
|
|
|
|
begin
|
|
if not GNAT_Mode then
|
|
Style_Check := False;
|
|
end if;
|
|
|
|
Semantics (Parent_Spec (Unit_Node));
|
|
Version_Update (N, Parent_Spec (Unit_Node));
|
|
Style_Check := Save_Style_Check;
|
|
Cunit_Boolean_Restrictions_Restore (Save_C_Restrict);
|
|
end;
|
|
end if;
|
|
|
|
-- With the analysis done, install the context. Note that we can't
|
|
-- install the context from the with clauses as we analyze them,
|
|
-- because each with clause must be analyzed in a clean visibility
|
|
-- context, so we have to wait and install them all at once.
|
|
|
|
Install_Context (N);
|
|
|
|
if Is_Child_Spec (Unit_Node) then
|
|
|
|
-- Set the entities of all parents in the program_unit_name
|
|
|
|
Generate_Parent_References (
|
|
Unit_Node, Get_Parent_Entity (Unit (Parent_Spec (Unit_Node))));
|
|
end if;
|
|
|
|
-- All components of the context: with-clauses, library unit, ancestors
|
|
-- if any, (and their context) are analyzed and installed. Now analyze
|
|
-- the unit itself, which is either a package, subprogram spec or body.
|
|
|
|
Analyze (Unit_Node);
|
|
|
|
if Warn_On_Redundant_Constructs then
|
|
Check_Redundant_Withs (Context_Items (N));
|
|
|
|
if Nkind (Unit_Node) = N_Package_Body then
|
|
Check_Redundant_Withs
|
|
(Context_Items => Context_Items (N),
|
|
Spec_Context_Items => Context_Items (Lib_Unit));
|
|
end if;
|
|
end if;
|
|
|
|
-- The above call might have made Unit_Node an N_Subprogram_Body
|
|
-- from something else, so propagate any Acts_As_Spec flag.
|
|
|
|
if Nkind (Unit_Node) = N_Subprogram_Body
|
|
and then Acts_As_Spec (Unit_Node)
|
|
then
|
|
Set_Acts_As_Spec (N);
|
|
end if;
|
|
|
|
-- Register predefined units in Rtsfind
|
|
|
|
declare
|
|
Unum : constant Unit_Number_Type := Get_Source_Unit (Sloc (N));
|
|
begin
|
|
if Is_Predefined_File_Name (Unit_File_Name (Unum)) then
|
|
Set_RTU_Loaded (Unit_Node);
|
|
end if;
|
|
end;
|
|
|
|
-- Treat compilation unit pragmas that appear after the library unit
|
|
|
|
if Present (Pragmas_After (Aux_Decls_Node (N))) then
|
|
declare
|
|
Prag_Node : Node_Id := First (Pragmas_After (Aux_Decls_Node (N)));
|
|
begin
|
|
while Present (Prag_Node) loop
|
|
Analyze (Prag_Node);
|
|
Next (Prag_Node);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
-- Generate distribution stubs if requested and no error
|
|
|
|
if N = Main_Cunit
|
|
and then (Distribution_Stub_Mode = Generate_Receiver_Stub_Body
|
|
or else
|
|
Distribution_Stub_Mode = Generate_Caller_Stub_Body)
|
|
and then not Fatal_Error (Main_Unit)
|
|
then
|
|
if Is_RCI_Pkg_Spec_Or_Body (N) then
|
|
|
|
-- Regular RCI package
|
|
|
|
Add_Stub_Constructs (N);
|
|
|
|
elsif (Nkind (Unit_Node) = N_Package_Declaration
|
|
and then Is_Shared_Passive (Defining_Entity
|
|
(Specification (Unit_Node))))
|
|
or else (Nkind (Unit_Node) = N_Package_Body
|
|
and then
|
|
Is_Shared_Passive (Corresponding_Spec (Unit_Node)))
|
|
then
|
|
-- Shared passive package
|
|
|
|
Add_Stub_Constructs (N);
|
|
|
|
elsif Nkind (Unit_Node) = N_Package_Instantiation
|
|
and then
|
|
Is_Remote_Call_Interface
|
|
(Defining_Entity (Specification (Instance_Spec (Unit_Node))))
|
|
then
|
|
-- Instantiation of a RCI generic package
|
|
|
|
Add_Stub_Constructs (N);
|
|
end if;
|
|
|
|
end if;
|
|
|
|
if Nkind (Unit_Node) = N_Package_Declaration
|
|
or else Nkind (Unit_Node) in N_Generic_Declaration
|
|
or else Nkind (Unit_Node) = N_Package_Renaming_Declaration
|
|
or else Nkind (Unit_Node) = N_Subprogram_Declaration
|
|
then
|
|
Remove_Unit_From_Visibility (Defining_Entity (Unit_Node));
|
|
|
|
-- If the unit is an instantiation whose body will be elaborated
|
|
-- for inlining purposes, use the the proper entity of the instance.
|
|
|
|
elsif Nkind (Unit_Node) = N_Package_Instantiation
|
|
and then not Error_Posted (Unit_Node)
|
|
then
|
|
Remove_Unit_From_Visibility
|
|
(Defining_Entity (Instance_Spec (Unit_Node)));
|
|
|
|
elsif Nkind (Unit_Node) = N_Package_Body
|
|
or else (Nkind (Unit_Node) = N_Subprogram_Body
|
|
and then not Acts_As_Spec (Unit_Node))
|
|
then
|
|
-- Bodies that are not the main unit are compiled if they
|
|
-- are generic or contain generic or inlined units. Their
|
|
-- analysis brings in the context of the corresponding spec
|
|
-- (unit declaration) which must be removed as well, to
|
|
-- return the compilation environment to its proper state.
|
|
|
|
Remove_Context (Lib_Unit);
|
|
Set_Is_Immediately_Visible (Defining_Entity (Unit (Lib_Unit)), False);
|
|
end if;
|
|
|
|
-- Last step is to deinstall the context we just installed
|
|
-- as well as the unit just compiled.
|
|
|
|
Remove_Context (N);
|
|
|
|
-- If this is the main unit and we are generating code, we must
|
|
-- check that all generic units in the context have a body if they
|
|
-- need it, even if they have not been instantiated. In the absence
|
|
-- of .ali files for generic units, we must force the load of the body,
|
|
-- just to produce the proper error if the body is absent. We skip this
|
|
-- verification if the main unit itself is generic.
|
|
|
|
if Get_Cunit_Unit_Number (N) = Main_Unit
|
|
and then Operating_Mode = Generate_Code
|
|
and then Expander_Active
|
|
then
|
|
-- Check whether the source for the body of the unit must be
|
|
-- included in a standalone library.
|
|
|
|
Check_Body_Needed_For_SAL (Cunit_Entity (Main_Unit));
|
|
|
|
-- Indicate that the main unit is now analyzed, to catch possible
|
|
-- circularities between it and generic bodies. Remove main unit
|
|
-- from visibility. This might seem superfluous, but the main unit
|
|
-- must not be visible in the generic body expansions that follow.
|
|
|
|
Set_Analyzed (N, True);
|
|
Set_Is_Immediately_Visible (Cunit_Entity (Main_Unit), False);
|
|
|
|
declare
|
|
Item : Node_Id;
|
|
Nam : Entity_Id;
|
|
Un : Unit_Number_Type;
|
|
|
|
Save_Style_Check : constant Boolean := Style_Check;
|
|
Save_C_Restrict : constant Save_Cunit_Boolean_Restrictions :=
|
|
Cunit_Boolean_Restrictions_Save;
|
|
|
|
begin
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
|
|
-- Check for explicit with clause
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Implicit_With (Item)
|
|
|
|
-- Ada 2005 (AI-50217): Ignore limited-withed units
|
|
|
|
and then not Limited_Present (Item)
|
|
then
|
|
Nam := Entity (Name (Item));
|
|
|
|
if (Is_Generic_Subprogram (Nam)
|
|
and then not Is_Intrinsic_Subprogram (Nam))
|
|
or else (Ekind (Nam) = E_Generic_Package
|
|
and then Unit_Requires_Body (Nam))
|
|
then
|
|
Style_Check := False;
|
|
|
|
if Present (Renamed_Object (Nam)) then
|
|
Un :=
|
|
Load_Unit
|
|
(Load_Name => Get_Body_Name
|
|
(Get_Unit_Name
|
|
(Unit_Declaration_Node
|
|
(Renamed_Object (Nam)))),
|
|
Required => False,
|
|
Subunit => False,
|
|
Error_Node => N,
|
|
Renamings => True);
|
|
else
|
|
Un :=
|
|
Load_Unit
|
|
(Load_Name => Get_Body_Name
|
|
(Get_Unit_Name (Item)),
|
|
Required => False,
|
|
Subunit => False,
|
|
Error_Node => N,
|
|
Renamings => True);
|
|
end if;
|
|
|
|
if Un = No_Unit then
|
|
Error_Msg_NE
|
|
("body of generic unit& not found", Item, Nam);
|
|
exit;
|
|
|
|
elsif not Analyzed (Cunit (Un))
|
|
and then Un /= Main_Unit
|
|
and then not Fatal_Error (Un)
|
|
then
|
|
Style_Check := False;
|
|
Semantics (Cunit (Un));
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
Style_Check := Save_Style_Check;
|
|
Cunit_Boolean_Restrictions_Restore (Save_C_Restrict);
|
|
end;
|
|
end if;
|
|
|
|
-- Deal with creating elaboration Boolean if needed. We create an
|
|
-- elaboration boolean only for units that come from source since
|
|
-- units manufactured by the compiler never need elab checks.
|
|
|
|
if Comes_From_Source (N)
|
|
and then
|
|
(Nkind (Unit (N)) = N_Package_Declaration or else
|
|
Nkind (Unit (N)) = N_Generic_Package_Declaration or else
|
|
Nkind (Unit (N)) = N_Subprogram_Declaration or else
|
|
Nkind (Unit (N)) = N_Generic_Subprogram_Declaration)
|
|
then
|
|
declare
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
Unum : constant Unit_Number_Type := Get_Source_Unit (Loc);
|
|
|
|
begin
|
|
Spec_Id := Defining_Entity (Unit (N));
|
|
Generate_Definition (Spec_Id);
|
|
|
|
-- See if an elaboration entity is required for possible
|
|
-- access before elaboration checking. Note that we must
|
|
-- allow for this even if -gnatE is not set, since a client
|
|
-- may be compiled in -gnatE mode and reference the entity.
|
|
|
|
-- Case of units which do not require elaboration checks
|
|
|
|
if
|
|
-- Pure units do not need checks
|
|
|
|
Is_Pure (Spec_Id)
|
|
|
|
-- Preelaborated units do not need checks
|
|
|
|
or else Is_Preelaborated (Spec_Id)
|
|
|
|
-- No checks needed if pagma Elaborate_Body present
|
|
|
|
or else Has_Pragma_Elaborate_Body (Spec_Id)
|
|
|
|
-- No checks needed if unit does not require a body
|
|
|
|
or else not Unit_Requires_Body (Spec_Id)
|
|
|
|
-- No checks needed for predefined files
|
|
|
|
or else Is_Predefined_File_Name (Unit_File_Name (Unum))
|
|
|
|
-- No checks required if no separate spec
|
|
|
|
or else Acts_As_Spec (N)
|
|
then
|
|
-- This is a case where we only need the entity for
|
|
-- checking to prevent multiple elaboration checks.
|
|
|
|
Set_Elaboration_Entity_Required (Spec_Id, False);
|
|
|
|
-- Case of elaboration entity is required for access before
|
|
-- elaboration checking (so certainly we must build it!)
|
|
|
|
else
|
|
Set_Elaboration_Entity_Required (Spec_Id, True);
|
|
end if;
|
|
|
|
Build_Elaboration_Entity (N, Spec_Id);
|
|
end;
|
|
end if;
|
|
|
|
-- Freeze the compilation unit entity. This for sure is needed because
|
|
-- of some warnings that can be output (see Freeze_Subprogram), but may
|
|
-- in general be required. If freezing actions result, place them in the
|
|
-- compilation unit actions list, and analyze them.
|
|
|
|
declare
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
L : constant List_Id :=
|
|
Freeze_Entity (Cunit_Entity (Current_Sem_Unit), Loc);
|
|
begin
|
|
while Is_Non_Empty_List (L) loop
|
|
Insert_Library_Level_Action (Remove_Head (L));
|
|
end loop;
|
|
end;
|
|
|
|
Set_Analyzed (N);
|
|
|
|
if Nkind (Unit_Node) = N_Package_Declaration
|
|
and then Get_Cunit_Unit_Number (N) /= Main_Unit
|
|
and then Expander_Active
|
|
then
|
|
declare
|
|
Save_Style_Check : constant Boolean := Style_Check;
|
|
Save_Warning : constant Warning_Mode_Type := Warning_Mode;
|
|
Options : Style_Check_Options;
|
|
|
|
begin
|
|
Save_Style_Check_Options (Options);
|
|
Reset_Style_Check_Options;
|
|
Opt.Warning_Mode := Suppress;
|
|
Check_Body_For_Inlining (N, Defining_Entity (Unit_Node));
|
|
|
|
Reset_Style_Check_Options;
|
|
Set_Style_Check_Options (Options);
|
|
Style_Check := Save_Style_Check;
|
|
Warning_Mode := Save_Warning;
|
|
end;
|
|
end if;
|
|
|
|
-- If we are generating obsolescent warnings, then here is where we
|
|
-- generate them for the with'ed items. The reason for this special
|
|
-- processing is that the normal mechanism of generating the warnings
|
|
-- for referenced entities does not work for context clause references.
|
|
-- That's because when we first analyze the context, it is too early to
|
|
-- know if the with'ing unit is itself obsolescent (which suppresses
|
|
-- the warnings).
|
|
|
|
if not GNAT_Mode and then Warn_On_Obsolescent_Feature then
|
|
|
|
-- Push current compilation unit as scope, so that the test for
|
|
-- being within an obsolescent unit will work correctly.
|
|
|
|
New_Scope (Defining_Entity (Unit (N)));
|
|
|
|
-- Loop through context items to deal with with clauses
|
|
|
|
declare
|
|
Item : Node_Id;
|
|
Nam : Node_Id;
|
|
Ent : Entity_Id;
|
|
|
|
begin
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause then
|
|
Nam := Name (Item);
|
|
Ent := Entity (Nam);
|
|
|
|
if Is_Obsolescent (Ent) then
|
|
Output_Obsolescent_Entity_Warnings (Nam, Ent);
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end;
|
|
|
|
-- Remove temporary install of current unit as scope
|
|
|
|
Pop_Scope;
|
|
end if;
|
|
end Analyze_Compilation_Unit;
|
|
|
|
---------------------
|
|
-- Analyze_Context --
|
|
---------------------
|
|
|
|
procedure Analyze_Context (N : Node_Id) is
|
|
Ukind : constant Node_Kind := Nkind (Unit (N));
|
|
Item : Node_Id;
|
|
|
|
begin
|
|
-- First process all configuration pragmas at the start of the context
|
|
-- items. Strictly these are not part of the context clause, but that
|
|
-- is where the parser puts them. In any case for sure we must analyze
|
|
-- these before analyzing the actual context items, since they can have
|
|
-- an effect on that analysis (e.g. pragma Ada_2005 may allow a unit to
|
|
-- be with'ed as a result of changing categorizations in Ada 2005).
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item)
|
|
and then Nkind (Item) = N_Pragma
|
|
and then Chars (Item) in Configuration_Pragma_Names
|
|
loop
|
|
Analyze (Item);
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Loop through actual context items. This is done in two passes:
|
|
|
|
-- a) The first pass analyzes non-limited with-clauses and also any
|
|
-- configuration pragmas (we need to get the latter analyzed right
|
|
-- away, since they can affect processing of subsequent items.
|
|
|
|
-- b) The second pass analyzes limited_with clauses (Ada 2005: AI-50217)
|
|
|
|
while Present (Item) loop
|
|
|
|
-- For with clause, analyze the with clause, and then update
|
|
-- the version, since we are dependent on a unit that we with.
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Limited_Present (Item)
|
|
then
|
|
-- Skip analyzing with clause if no unit, nothing to do (this
|
|
-- happens for a with that references a non-existant unit)
|
|
|
|
if Present (Library_Unit (Item)) then
|
|
Analyze (Item);
|
|
end if;
|
|
|
|
if not Implicit_With (Item) then
|
|
Version_Update (N, Library_Unit (Item));
|
|
end if;
|
|
|
|
-- Skip pragmas. Configuration pragmas at the start were handled in
|
|
-- the loop above, and remaining pragmas are not processed until we
|
|
-- actually install the context (see Install_Context). We delay the
|
|
-- analysis of these pragmas to make sure that we have installed all
|
|
-- the implicit with's on parent units.
|
|
|
|
-- Skip use clauses at this stage, since we don't want to do any
|
|
-- installing of potentially use visible entities until we we
|
|
-- actually install the complete context (in Install_Context).
|
|
-- Otherwise things can get installed in the wrong context.
|
|
|
|
else
|
|
null;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Second pass: examine all limited_with clauses. All other context
|
|
-- items are ignored in this pass.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Limited_Present (Item)
|
|
then
|
|
-- No need to check errors on implicitly generated limited-with
|
|
-- clauses.
|
|
|
|
if not Implicit_With (Item) then
|
|
|
|
-- Check compilation unit containing the limited-with clause
|
|
|
|
if Ukind /= N_Package_Declaration
|
|
and then Ukind /= N_Subprogram_Declaration
|
|
and then Ukind /= N_Package_Renaming_Declaration
|
|
and then Ukind /= N_Subprogram_Renaming_Declaration
|
|
and then Ukind not in N_Generic_Declaration
|
|
and then Ukind not in N_Generic_Renaming_Declaration
|
|
and then Ukind not in N_Generic_Instantiation
|
|
then
|
|
Error_Msg_N ("limited with_clause not allowed here", Item);
|
|
|
|
-- Check wrong use of a limited with clause applied to the
|
|
-- compilation unit containing the limited-with clause.
|
|
|
|
-- limited with P.Q;
|
|
-- package P.Q is ...
|
|
|
|
elsif Unit (Library_Unit (Item)) = Unit (N) then
|
|
Error_Msg_N ("wrong use of limited-with clause", Item);
|
|
|
|
-- Check wrong use of limited-with clause applied to some
|
|
-- immediate ancestor.
|
|
|
|
elsif Is_Child_Spec (Unit (N)) then
|
|
declare
|
|
Lib_U : constant Entity_Id := Unit (Library_Unit (Item));
|
|
P : Node_Id;
|
|
|
|
begin
|
|
P := Parent_Spec (Unit (N));
|
|
loop
|
|
if Unit (P) = Lib_U then
|
|
Error_Msg_N ("limited with_clause of immediate "
|
|
& "ancestor not allowed", Item);
|
|
exit;
|
|
end if;
|
|
|
|
exit when not Is_Child_Spec (Unit (P));
|
|
P := Parent_Spec (Unit (P));
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
-- Check if the limited-withed unit is already visible through
|
|
-- some context clause of the current compilation unit or some
|
|
-- ancestor of the current compilation unit.
|
|
|
|
declare
|
|
Lim_Unit_Name : constant Node_Id := Name (Item);
|
|
Comp_Unit : Node_Id;
|
|
It : Node_Id;
|
|
Unit_Name : Node_Id;
|
|
|
|
begin
|
|
Comp_Unit := N;
|
|
loop
|
|
It := First (Context_Items (Comp_Unit));
|
|
while Present (It) loop
|
|
if Item /= It
|
|
and then Nkind (It) = N_With_Clause
|
|
and then not Limited_Present (It)
|
|
and then
|
|
(Nkind (Unit (Library_Unit (It)))
|
|
= N_Package_Declaration
|
|
or else
|
|
Nkind (Unit (Library_Unit (It)))
|
|
= N_Package_Renaming_Declaration)
|
|
then
|
|
if Nkind (Unit (Library_Unit (It)))
|
|
= N_Package_Declaration
|
|
then
|
|
Unit_Name := Name (It);
|
|
else
|
|
Unit_Name := Name (Unit (Library_Unit (It)));
|
|
end if;
|
|
|
|
-- Check if the named package (or some ancestor)
|
|
-- leaves visible the full-view of the unit given
|
|
-- in the limited-with clause
|
|
|
|
loop
|
|
if Designate_Same_Unit (Lim_Unit_Name,
|
|
Unit_Name)
|
|
then
|
|
Error_Msg_Sloc := Sloc (It);
|
|
Error_Msg_NE
|
|
("unlimited view visible through the"
|
|
& " context clause found #",
|
|
Item, It);
|
|
Error_Msg_N
|
|
("\simultaneous visibility of the limited"
|
|
& " and unlimited views not allowed"
|
|
, Item);
|
|
exit;
|
|
|
|
elsif Nkind (Unit_Name) = N_Identifier then
|
|
exit;
|
|
end if;
|
|
|
|
Unit_Name := Prefix (Unit_Name);
|
|
end loop;
|
|
end if;
|
|
|
|
Next (It);
|
|
end loop;
|
|
|
|
exit when not Is_Child_Spec (Unit (Comp_Unit));
|
|
|
|
Comp_Unit := Parent_Spec (Unit (Comp_Unit));
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
-- Skip analyzing with clause if no unit, see above
|
|
|
|
if Present (Library_Unit (Item)) then
|
|
Analyze (Item);
|
|
end if;
|
|
|
|
-- A limited_with does not impose an elaboration order, but
|
|
-- there is a semantic dependency for recompilation purposes.
|
|
|
|
if not Implicit_With (Item) then
|
|
Version_Update (N, Library_Unit (Item));
|
|
end if;
|
|
|
|
-- Pragmas and use clauses and with clauses other than limited
|
|
-- with's are ignored in this pass through the context items.
|
|
|
|
else
|
|
null;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Analyze_Context;
|
|
|
|
-------------------------------
|
|
-- Analyze_Package_Body_Stub --
|
|
-------------------------------
|
|
|
|
procedure Analyze_Package_Body_Stub (N : Node_Id) is
|
|
Id : constant Entity_Id := Defining_Identifier (N);
|
|
Nam : Entity_Id;
|
|
|
|
begin
|
|
-- The package declaration must be in the current declarative part
|
|
|
|
Check_Stub_Level (N);
|
|
Nam := Current_Entity_In_Scope (Id);
|
|
|
|
if No (Nam) or else not Is_Package_Or_Generic_Package (Nam) then
|
|
Error_Msg_N ("missing specification for package stub", N);
|
|
|
|
elsif Has_Completion (Nam)
|
|
and then Present (Corresponding_Body (Unit_Declaration_Node (Nam)))
|
|
then
|
|
Error_Msg_N ("duplicate or redundant stub for package", N);
|
|
|
|
else
|
|
-- Indicate that the body of the package exists. If we are doing
|
|
-- only semantic analysis, the stub stands for the body. If we are
|
|
-- generating code, the existence of the body will be confirmed
|
|
-- when we load the proper body.
|
|
|
|
Set_Has_Completion (Nam);
|
|
Set_Scope (Defining_Entity (N), Current_Scope);
|
|
Generate_Reference (Nam, Id, 'b');
|
|
Analyze_Proper_Body (N, Nam);
|
|
end if;
|
|
end Analyze_Package_Body_Stub;
|
|
|
|
-------------------------
|
|
-- Analyze_Proper_Body --
|
|
-------------------------
|
|
|
|
procedure Analyze_Proper_Body (N : Node_Id; Nam : Entity_Id) is
|
|
Subunit_Name : constant Unit_Name_Type := Get_Unit_Name (N);
|
|
Unum : Unit_Number_Type;
|
|
|
|
procedure Optional_Subunit;
|
|
-- This procedure is called when the main unit is a stub, or when we
|
|
-- are not generating code. In such a case, we analyze the subunit if
|
|
-- present, which is user-friendly and in fact required for ASIS, but
|
|
-- we don't complain if the subunit is missing.
|
|
|
|
----------------------
|
|
-- Optional_Subunit --
|
|
----------------------
|
|
|
|
procedure Optional_Subunit is
|
|
Comp_Unit : Node_Id;
|
|
|
|
begin
|
|
-- Try to load subunit, but ignore any errors that occur during
|
|
-- the loading of the subunit, by using the special feature in
|
|
-- Errout to ignore all errors. Note that Fatal_Error will still
|
|
-- be set, so we will be able to check for this case below.
|
|
|
|
if not ASIS_Mode then
|
|
Ignore_Errors_Enable := Ignore_Errors_Enable + 1;
|
|
end if;
|
|
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Subunit_Name,
|
|
Required => False,
|
|
Subunit => True,
|
|
Error_Node => N);
|
|
|
|
if not ASIS_Mode then
|
|
Ignore_Errors_Enable := Ignore_Errors_Enable - 1;
|
|
end if;
|
|
|
|
-- All done if we successfully loaded the subunit
|
|
|
|
if Unum /= No_Unit
|
|
and then (not Fatal_Error (Unum) or else Try_Semantics)
|
|
then
|
|
Comp_Unit := Cunit (Unum);
|
|
|
|
-- If the file was empty or seriously mangled, the unit
|
|
-- itself may be missing.
|
|
|
|
if No (Unit (Comp_Unit)) then
|
|
Error_Msg_N
|
|
("subunit does not contain expected proper body", N);
|
|
|
|
elsif Nkind (Unit (Comp_Unit)) /= N_Subunit then
|
|
Error_Msg_N
|
|
("expected SEPARATE subunit, found child unit",
|
|
Cunit_Entity (Unum));
|
|
else
|
|
Set_Corresponding_Stub (Unit (Comp_Unit), N);
|
|
Analyze_Subunit (Comp_Unit);
|
|
Set_Library_Unit (N, Comp_Unit);
|
|
end if;
|
|
|
|
elsif Unum = No_Unit
|
|
and then Present (Nam)
|
|
then
|
|
if Is_Protected_Type (Nam) then
|
|
Set_Corresponding_Body (Parent (Nam), Defining_Identifier (N));
|
|
else
|
|
Set_Corresponding_Body (
|
|
Unit_Declaration_Node (Nam), Defining_Identifier (N));
|
|
end if;
|
|
end if;
|
|
end Optional_Subunit;
|
|
|
|
-- Start of processing for Analyze_Proper_Body
|
|
|
|
begin
|
|
-- If the subunit is already loaded, it means that the main unit
|
|
-- is a subunit, and that the current unit is one of its parents
|
|
-- which was being analyzed to provide the needed context for the
|
|
-- analysis of the subunit. In this case we analyze the subunit and
|
|
-- continue with the parent, without looking a subsequent subunits.
|
|
|
|
if Is_Loaded (Subunit_Name) then
|
|
|
|
-- If the proper body is already linked to the stub node,
|
|
-- the stub is in a generic unit and just needs analyzing.
|
|
|
|
if Present (Library_Unit (N)) then
|
|
Set_Corresponding_Stub (Unit (Library_Unit (N)), N);
|
|
Analyze_Subunit (Library_Unit (N));
|
|
|
|
-- Otherwise we must load the subunit and link to it
|
|
|
|
else
|
|
-- Load the subunit, this must work, since we originally
|
|
-- loaded the subunit earlier on. So this will not really
|
|
-- load it, just give access to it.
|
|
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Subunit_Name,
|
|
Required => True,
|
|
Subunit => False,
|
|
Error_Node => N);
|
|
|
|
-- And analyze the subunit in the parent context (note that we
|
|
-- do not call Semantics, since that would remove the parent
|
|
-- context). Because of this, we have to manually reset the
|
|
-- compiler state to Analyzing since it got destroyed by Load.
|
|
|
|
if Unum /= No_Unit then
|
|
Compiler_State := Analyzing;
|
|
|
|
-- Check that the proper body is a subunit and not a child
|
|
-- unit. If the unit was previously loaded, the error will
|
|
-- have been emitted when copying the generic node, so we
|
|
-- just return to avoid cascaded errors.
|
|
|
|
if Nkind (Unit (Cunit (Unum))) /= N_Subunit then
|
|
return;
|
|
end if;
|
|
|
|
Set_Corresponding_Stub (Unit (Cunit (Unum)), N);
|
|
Analyze_Subunit (Cunit (Unum));
|
|
Set_Library_Unit (N, Cunit (Unum));
|
|
end if;
|
|
end if;
|
|
|
|
-- If the main unit is a subunit, then we are just performing semantic
|
|
-- analysis on that subunit, and any other subunits of any parent unit
|
|
-- should be ignored, except that if we are building trees for ASIS
|
|
-- usage we want to annotate the stub properly.
|
|
|
|
elsif Nkind (Unit (Cunit (Main_Unit))) = N_Subunit
|
|
and then Subunit_Name /= Unit_Name (Main_Unit)
|
|
then
|
|
if ASIS_Mode then
|
|
Optional_Subunit;
|
|
end if;
|
|
|
|
-- But before we return, set the flag for unloaded subunits. This
|
|
-- will suppress junk warnings of variables in the same declarative
|
|
-- part (or a higher level one) that are in danger of looking unused
|
|
-- when in fact there might be a declaration in the subunit that we
|
|
-- do not intend to load.
|
|
|
|
Unloaded_Subunits := True;
|
|
return;
|
|
|
|
-- If the subunit is not already loaded, and we are generating code,
|
|
-- then this is the case where compilation started from the parent,
|
|
-- and we are generating code for an entire subunit tree. In that
|
|
-- case we definitely need to load the subunit.
|
|
|
|
-- In order to continue the analysis with the rest of the parent,
|
|
-- and other subunits, we load the unit without requiring its
|
|
-- presence, and emit a warning if not found, rather than terminating
|
|
-- the compilation abruptly, as for other missing file problems.
|
|
|
|
elsif Original_Operating_Mode = Generate_Code then
|
|
|
|
-- If the proper body is already linked to the stub node,
|
|
-- the stub is in a generic unit and just needs analyzing.
|
|
|
|
-- We update the version. Although we are not technically
|
|
-- semantically dependent on the subunit, given our approach
|
|
-- of macro substitution of subunits, it makes sense to
|
|
-- include it in the version identification.
|
|
|
|
if Present (Library_Unit (N)) then
|
|
Set_Corresponding_Stub (Unit (Library_Unit (N)), N);
|
|
Analyze_Subunit (Library_Unit (N));
|
|
Version_Update (Cunit (Main_Unit), Library_Unit (N));
|
|
|
|
-- Otherwise we must load the subunit and link to it
|
|
|
|
else
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Subunit_Name,
|
|
Required => False,
|
|
Subunit => True,
|
|
Error_Node => N);
|
|
|
|
if Original_Operating_Mode = Generate_Code
|
|
and then Unum = No_Unit
|
|
then
|
|
Error_Msg_Name_1 := Subunit_Name;
|
|
Error_Msg_Name_2 :=
|
|
Get_File_Name (Subunit_Name, Subunit => True);
|
|
Error_Msg_N
|
|
("subunit% in file{ not found?", N);
|
|
Subunits_Missing := True;
|
|
end if;
|
|
|
|
-- Load_Unit may reset Compiler_State, since it may have been
|
|
-- necessary to parse an additional units, so we make sure
|
|
-- that we reset it to the Analyzing state.
|
|
|
|
Compiler_State := Analyzing;
|
|
|
|
if Unum /= No_Unit then
|
|
if Debug_Flag_L then
|
|
Write_Str ("*** Loaded subunit from stub. Analyze");
|
|
Write_Eol;
|
|
end if;
|
|
|
|
declare
|
|
Comp_Unit : constant Node_Id := Cunit (Unum);
|
|
|
|
begin
|
|
-- Check for child unit instead of subunit
|
|
|
|
if Nkind (Unit (Comp_Unit)) /= N_Subunit then
|
|
Error_Msg_N
|
|
("expected SEPARATE subunit, found child unit",
|
|
Cunit_Entity (Unum));
|
|
|
|
-- OK, we have a subunit
|
|
|
|
else
|
|
-- Set corresponding stub (even if errors)
|
|
|
|
Set_Corresponding_Stub (Unit (Comp_Unit), N);
|
|
|
|
-- Analyze the unit if semantics active
|
|
|
|
if not Fatal_Error (Unum) or else Try_Semantics then
|
|
Analyze_Subunit (Comp_Unit);
|
|
end if;
|
|
|
|
-- Set the library unit pointer in any case
|
|
|
|
Set_Library_Unit (N, Comp_Unit);
|
|
|
|
-- We update the version. Although we are not technically
|
|
-- semantically dependent on the subunit, given our
|
|
-- approach of macro substitution of subunits, it makes
|
|
-- sense to include it in the version identification.
|
|
|
|
Version_Update (Cunit (Main_Unit), Comp_Unit);
|
|
end if;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
-- The remaining case is when the subunit is not already loaded and
|
|
-- we are not generating code. In this case we are just performing
|
|
-- semantic analysis on the parent, and we are not interested in
|
|
-- the subunit. For subprograms, analyze the stub as a body. For
|
|
-- other entities the stub has already been marked as completed.
|
|
|
|
else
|
|
Optional_Subunit;
|
|
end if;
|
|
|
|
end Analyze_Proper_Body;
|
|
|
|
----------------------------------
|
|
-- Analyze_Protected_Body_Stub --
|
|
----------------------------------
|
|
|
|
procedure Analyze_Protected_Body_Stub (N : Node_Id) is
|
|
Nam : Entity_Id := Current_Entity_In_Scope (Defining_Identifier (N));
|
|
|
|
begin
|
|
Check_Stub_Level (N);
|
|
|
|
-- First occurence of name may have been as an incomplete type
|
|
|
|
if Present (Nam) and then Ekind (Nam) = E_Incomplete_Type then
|
|
Nam := Full_View (Nam);
|
|
end if;
|
|
|
|
if No (Nam)
|
|
or else not Is_Protected_Type (Etype (Nam))
|
|
then
|
|
Error_Msg_N ("missing specification for Protected body", N);
|
|
else
|
|
Set_Scope (Defining_Entity (N), Current_Scope);
|
|
Set_Has_Completion (Etype (Nam));
|
|
Generate_Reference (Nam, Defining_Identifier (N), 'b');
|
|
Analyze_Proper_Body (N, Etype (Nam));
|
|
end if;
|
|
end Analyze_Protected_Body_Stub;
|
|
|
|
----------------------------------
|
|
-- Analyze_Subprogram_Body_Stub --
|
|
----------------------------------
|
|
|
|
-- A subprogram body stub can appear with or without a previous
|
|
-- specification. If there is one, the analysis of the body will
|
|
-- find it and verify conformance. The formals appearing in the
|
|
-- specification of the stub play no role, except for requiring an
|
|
-- additional conformance check. If there is no previous subprogram
|
|
-- declaration, the stub acts as a spec, and provides the defining
|
|
-- entity for the subprogram.
|
|
|
|
procedure Analyze_Subprogram_Body_Stub (N : Node_Id) is
|
|
Decl : Node_Id;
|
|
|
|
begin
|
|
Check_Stub_Level (N);
|
|
|
|
-- Verify that the identifier for the stub is unique within this
|
|
-- declarative part.
|
|
|
|
if Nkind (Parent (N)) = N_Block_Statement
|
|
or else Nkind (Parent (N)) = N_Package_Body
|
|
or else Nkind (Parent (N)) = N_Subprogram_Body
|
|
then
|
|
Decl := First (Declarations (Parent (N)));
|
|
while Present (Decl)
|
|
and then Decl /= N
|
|
loop
|
|
if Nkind (Decl) = N_Subprogram_Body_Stub
|
|
and then (Chars (Defining_Unit_Name (Specification (Decl)))
|
|
= Chars (Defining_Unit_Name (Specification (N))))
|
|
then
|
|
Error_Msg_N ("identifier for stub is not unique", N);
|
|
end if;
|
|
|
|
Next (Decl);
|
|
end loop;
|
|
end if;
|
|
|
|
-- Treat stub as a body, which checks conformance if there is a previous
|
|
-- declaration, or else introduces entity and its signature.
|
|
|
|
Analyze_Subprogram_Body (N);
|
|
Analyze_Proper_Body (N, Empty);
|
|
end Analyze_Subprogram_Body_Stub;
|
|
|
|
---------------------
|
|
-- Analyze_Subunit --
|
|
---------------------
|
|
|
|
-- A subunit is compiled either by itself (for semantic checking)
|
|
-- or as part of compiling the parent (for code generation). In
|
|
-- either case, by the time we actually process the subunit, the
|
|
-- parent has already been installed and analyzed. The node N is
|
|
-- a compilation unit, whose context needs to be treated here,
|
|
-- because we come directly here from the parent without calling
|
|
-- Analyze_Compilation_Unit.
|
|
|
|
-- The compilation context includes the explicit context of the
|
|
-- subunit, and the context of the parent, together with the parent
|
|
-- itself. In order to compile the current context, we remove the
|
|
-- one inherited from the parent, in order to have a clean visibility
|
|
-- table. We restore the parent context before analyzing the proper
|
|
-- body itself. On exit, we remove only the explicit context of the
|
|
-- subunit.
|
|
|
|
procedure Analyze_Subunit (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Library_Unit (N);
|
|
Par_Unit : constant Entity_Id := Current_Scope;
|
|
|
|
Lib_Spec : Node_Id := Library_Unit (Lib_Unit);
|
|
Num_Scopes : Int := 0;
|
|
Use_Clauses : array (1 .. Scope_Stack.Last) of Node_Id;
|
|
Enclosing_Child : Entity_Id := Empty;
|
|
Svg : constant Suppress_Array := Scope_Suppress;
|
|
|
|
procedure Analyze_Subunit_Context;
|
|
-- Capture names in use clauses of the subunit. This must be done
|
|
-- before re-installing parent declarations, because items in the
|
|
-- context must not be hidden by declarations local to the parent.
|
|
|
|
procedure Re_Install_Parents (L : Node_Id; Scop : Entity_Id);
|
|
-- Recursive procedure to restore scope of all ancestors of subunit,
|
|
-- from outermost in. If parent is not a subunit, the call to install
|
|
-- context installs context of spec and (if parent is a child unit)
|
|
-- the context of its parents as well. It is confusing that parents
|
|
-- should be treated differently in both cases, but the semantics are
|
|
-- just not identical.
|
|
|
|
procedure Re_Install_Use_Clauses;
|
|
-- As part of the removal of the parent scope, the use clauses are
|
|
-- removed, to be reinstalled when the context of the subunit has
|
|
-- been analyzed. Use clauses may also have been affected by the
|
|
-- analysis of the context of the subunit, so they have to be applied
|
|
-- again, to insure that the compilation environment of the rest of
|
|
-- the parent unit is identical.
|
|
|
|
procedure Remove_Scope;
|
|
-- Remove current scope from scope stack, and preserve the list
|
|
-- of use clauses in it, to be reinstalled after context is analyzed.
|
|
|
|
-----------------------------
|
|
-- Analyze_Subunit_Context --
|
|
-----------------------------
|
|
|
|
procedure Analyze_Subunit_Context is
|
|
Item : Node_Id;
|
|
Nam : Node_Id;
|
|
Unit_Name : Entity_Id;
|
|
|
|
begin
|
|
Analyze_Context (N);
|
|
|
|
-- Make withed units immediately visible. If child unit, make the
|
|
-- ultimate parent immediately visible.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause then
|
|
|
|
-- Protect frontend against previous errors in context clauses
|
|
|
|
if Nkind (Name (Item)) /= N_Selected_Component then
|
|
Unit_Name := Entity (Name (Item));
|
|
while Is_Child_Unit (Unit_Name) loop
|
|
Set_Is_Visible_Child_Unit (Unit_Name);
|
|
Unit_Name := Scope (Unit_Name);
|
|
end loop;
|
|
|
|
if not Is_Immediately_Visible (Unit_Name) then
|
|
Set_Is_Immediately_Visible (Unit_Name);
|
|
Set_Context_Installed (Item);
|
|
end if;
|
|
end if;
|
|
|
|
elsif Nkind (Item) = N_Use_Package_Clause then
|
|
Nam := First (Names (Item));
|
|
while Present (Nam) loop
|
|
Analyze (Nam);
|
|
Next (Nam);
|
|
end loop;
|
|
|
|
elsif Nkind (Item) = N_Use_Type_Clause then
|
|
Nam := First (Subtype_Marks (Item));
|
|
while Present (Nam) loop
|
|
Analyze (Nam);
|
|
Next (Nam);
|
|
end loop;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Reset visibility of withed units. They will be made visible
|
|
-- again when we install the subunit context.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
|
|
-- Protect frontend against previous errors in context clauses
|
|
|
|
and then Nkind (Name (Item)) /= N_Selected_Component
|
|
then
|
|
Unit_Name := Entity (Name (Item));
|
|
while Is_Child_Unit (Unit_Name) loop
|
|
Set_Is_Visible_Child_Unit (Unit_Name, False);
|
|
Unit_Name := Scope (Unit_Name);
|
|
end loop;
|
|
|
|
if Context_Installed (Item) then
|
|
Set_Is_Immediately_Visible (Unit_Name, False);
|
|
Set_Context_Installed (Item, False);
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Analyze_Subunit_Context;
|
|
|
|
------------------------
|
|
-- Re_Install_Parents --
|
|
------------------------
|
|
|
|
procedure Re_Install_Parents (L : Node_Id; Scop : Entity_Id) is
|
|
E : Entity_Id;
|
|
|
|
begin
|
|
if Nkind (Unit (L)) = N_Subunit then
|
|
Re_Install_Parents (Library_Unit (L), Scope (Scop));
|
|
end if;
|
|
|
|
Install_Context (L);
|
|
|
|
-- If the subunit occurs within a child unit, we must restore the
|
|
-- immediate visibility of any siblings that may occur in context.
|
|
|
|
if Present (Enclosing_Child) then
|
|
Install_Siblings (Enclosing_Child, L);
|
|
end if;
|
|
|
|
New_Scope (Scop);
|
|
|
|
if Scop /= Par_Unit then
|
|
Set_Is_Immediately_Visible (Scop);
|
|
end if;
|
|
|
|
-- Make entities in scope visible again. For child units, restore
|
|
-- visibility only if they are actually in context.
|
|
|
|
E := First_Entity (Current_Scope);
|
|
while Present (E) loop
|
|
if not Is_Child_Unit (E)
|
|
or else Is_Visible_Child_Unit (E)
|
|
then
|
|
Set_Is_Immediately_Visible (E);
|
|
end if;
|
|
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
-- A subunit appears within a body, and for a nested subunits
|
|
-- all the parents are bodies. Restore full visibility of their
|
|
-- private entities.
|
|
|
|
if Ekind (Scop) = E_Package then
|
|
Set_In_Package_Body (Scop);
|
|
Install_Private_Declarations (Scop);
|
|
end if;
|
|
end Re_Install_Parents;
|
|
|
|
----------------------------
|
|
-- Re_Install_Use_Clauses --
|
|
----------------------------
|
|
|
|
procedure Re_Install_Use_Clauses is
|
|
U : Node_Id;
|
|
begin
|
|
for J in reverse 1 .. Num_Scopes loop
|
|
U := Use_Clauses (J);
|
|
Scope_Stack.Table (Scope_Stack.Last - J + 1).First_Use_Clause := U;
|
|
Install_Use_Clauses (U, Force_Installation => True);
|
|
end loop;
|
|
end Re_Install_Use_Clauses;
|
|
|
|
------------------
|
|
-- Remove_Scope --
|
|
------------------
|
|
|
|
procedure Remove_Scope is
|
|
E : Entity_Id;
|
|
|
|
begin
|
|
Num_Scopes := Num_Scopes + 1;
|
|
Use_Clauses (Num_Scopes) :=
|
|
Scope_Stack.Table (Scope_Stack.Last).First_Use_Clause;
|
|
|
|
E := First_Entity (Current_Scope);
|
|
while Present (E) loop
|
|
Set_Is_Immediately_Visible (E, False);
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
if Is_Child_Unit (Current_Scope) then
|
|
Enclosing_Child := Current_Scope;
|
|
end if;
|
|
|
|
Pop_Scope;
|
|
end Remove_Scope;
|
|
|
|
-- Start of processing for Analyze_Subunit
|
|
|
|
begin
|
|
if not Is_Empty_List (Context_Items (N)) then
|
|
|
|
-- Save current use clauses
|
|
|
|
Remove_Scope;
|
|
Remove_Context (Lib_Unit);
|
|
|
|
-- Now remove parents and their context, including enclosing
|
|
-- subunits and the outer parent body which is not a subunit.
|
|
|
|
if Present (Lib_Spec) then
|
|
Remove_Context (Lib_Spec);
|
|
|
|
while Nkind (Unit (Lib_Spec)) = N_Subunit loop
|
|
Lib_Spec := Library_Unit (Lib_Spec);
|
|
Remove_Scope;
|
|
Remove_Context (Lib_Spec);
|
|
end loop;
|
|
|
|
if Nkind (Unit (Lib_Unit)) = N_Subunit then
|
|
Remove_Scope;
|
|
end if;
|
|
|
|
if Nkind (Unit (Lib_Spec)) = N_Package_Body then
|
|
Remove_Context (Library_Unit (Lib_Spec));
|
|
end if;
|
|
end if;
|
|
|
|
Set_Is_Immediately_Visible (Par_Unit, False);
|
|
|
|
Analyze_Subunit_Context;
|
|
|
|
Re_Install_Parents (Lib_Unit, Par_Unit);
|
|
Set_Is_Immediately_Visible (Par_Unit);
|
|
|
|
-- If the context includes a child unit of the parent of the
|
|
-- subunit, the parent will have been removed from visibility,
|
|
-- after compiling that cousin in the context. The visibility
|
|
-- of the parent must be restored now. This also applies if the
|
|
-- context includes another subunit of the same parent which in
|
|
-- turn includes a child unit in its context.
|
|
|
|
if Ekind (Par_Unit) = E_Package then
|
|
if not Is_Immediately_Visible (Par_Unit)
|
|
or else (Present (First_Entity (Par_Unit))
|
|
and then not Is_Immediately_Visible
|
|
(First_Entity (Par_Unit)))
|
|
then
|
|
Set_Is_Immediately_Visible (Par_Unit);
|
|
Install_Visible_Declarations (Par_Unit);
|
|
Install_Private_Declarations (Par_Unit);
|
|
end if;
|
|
end if;
|
|
|
|
Re_Install_Use_Clauses;
|
|
Install_Context (N);
|
|
|
|
-- Restore state of suppress flags for current body
|
|
|
|
Scope_Suppress := Svg;
|
|
|
|
-- If the subunit is within a child unit, then siblings of any
|
|
-- parent unit that appear in the context clause of the subunit
|
|
-- must also be made immediately visible.
|
|
|
|
if Present (Enclosing_Child) then
|
|
Install_Siblings (Enclosing_Child, N);
|
|
end if;
|
|
|
|
end if;
|
|
|
|
Analyze (Proper_Body (Unit (N)));
|
|
Remove_Context (N);
|
|
|
|
-- The subunit may contain a with_clause on a sibling of some
|
|
-- ancestor. Removing the context will remove from visibility those
|
|
-- ancestor child units, which must be restored to the visibility
|
|
-- they have in the enclosing body.
|
|
|
|
if Present (Enclosing_Child) then
|
|
declare
|
|
C : Entity_Id;
|
|
begin
|
|
C := Current_Scope;
|
|
while Present (C)
|
|
and then Is_Child_Unit (C)
|
|
loop
|
|
Set_Is_Immediately_Visible (C);
|
|
Set_Is_Visible_Child_Unit (C);
|
|
C := Scope (C);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end Analyze_Subunit;
|
|
|
|
----------------------------
|
|
-- Analyze_Task_Body_Stub --
|
|
----------------------------
|
|
|
|
procedure Analyze_Task_Body_Stub (N : Node_Id) is
|
|
Nam : Entity_Id := Current_Entity_In_Scope (Defining_Identifier (N));
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
|
|
begin
|
|
Check_Stub_Level (N);
|
|
|
|
-- First occurence of name may have been as an incomplete type
|
|
|
|
if Present (Nam) and then Ekind (Nam) = E_Incomplete_Type then
|
|
Nam := Full_View (Nam);
|
|
end if;
|
|
|
|
if No (Nam)
|
|
or else not Is_Task_Type (Etype (Nam))
|
|
then
|
|
Error_Msg_N ("missing specification for task body", N);
|
|
else
|
|
Set_Scope (Defining_Entity (N), Current_Scope);
|
|
Generate_Reference (Nam, Defining_Identifier (N), 'b');
|
|
Set_Has_Completion (Etype (Nam));
|
|
Analyze_Proper_Body (N, Etype (Nam));
|
|
|
|
-- Set elaboration flag to indicate that entity is callable.
|
|
-- This cannot be done in the expansion of the body itself,
|
|
-- because the proper body is not in a declarative part. This
|
|
-- is only done if expansion is active, because the context
|
|
-- may be generic and the flag not defined yet.
|
|
|
|
if Expander_Active then
|
|
Insert_After (N,
|
|
Make_Assignment_Statement (Loc,
|
|
Name =>
|
|
Make_Identifier (Loc,
|
|
New_External_Name (Chars (Etype (Nam)), 'E')),
|
|
Expression => New_Reference_To (Standard_True, Loc)));
|
|
end if;
|
|
|
|
end if;
|
|
end Analyze_Task_Body_Stub;
|
|
|
|
-------------------------
|
|
-- Analyze_With_Clause --
|
|
-------------------------
|
|
|
|
-- Analyze the declaration of a unit in a with clause. At end,
|
|
-- label the with clause with the defining entity for the unit.
|
|
|
|
procedure Analyze_With_Clause (N : Node_Id) is
|
|
|
|
-- Retrieve the original kind of the unit node, before analysis.
|
|
-- If it is a subprogram instantiation, its analysis below will
|
|
-- rewrite as the declaration of the wrapper package. If the same
|
|
-- instantiation appears indirectly elsewhere in the context, it
|
|
-- will have been analyzed already.
|
|
|
|
Unit_Kind : constant Node_Kind :=
|
|
Nkind (Original_Node (Unit (Library_Unit (N))));
|
|
|
|
E_Name : Entity_Id;
|
|
Par_Name : Entity_Id;
|
|
Pref : Node_Id;
|
|
U : Node_Id;
|
|
|
|
Intunit : Boolean;
|
|
-- Set True if the unit currently being compiled is an internal unit
|
|
|
|
Save_Style_Check : constant Boolean := Opt.Style_Check;
|
|
Save_C_Restrict : constant Save_Cunit_Boolean_Restrictions :=
|
|
Cunit_Boolean_Restrictions_Save;
|
|
|
|
begin
|
|
if Limited_Present (N) then
|
|
|
|
-- Ada 2005 (AI-50217): Build visibility structures but do not
|
|
-- analyze unit
|
|
|
|
Build_Limited_Views (N);
|
|
return;
|
|
end if;
|
|
|
|
-- We reset ordinary style checking during the analysis of a with'ed
|
|
-- unit, but we do NOT reset GNAT special analysis mode (the latter
|
|
-- definitely *does* apply to with'ed units).
|
|
|
|
if not GNAT_Mode then
|
|
Style_Check := False;
|
|
end if;
|
|
|
|
-- If the library unit is a predefined unit, and we are in high
|
|
-- integrity mode, then temporarily reset Configurable_Run_Time_Mode
|
|
-- for the analysis of the with'ed unit. This mode does not prevent
|
|
-- explicit with'ing of run-time units.
|
|
|
|
if Configurable_Run_Time_Mode
|
|
and then
|
|
Is_Predefined_File_Name
|
|
(Unit_File_Name (Get_Source_Unit (Unit (Library_Unit (N)))))
|
|
then
|
|
Configurable_Run_Time_Mode := False;
|
|
Semantics (Library_Unit (N));
|
|
Configurable_Run_Time_Mode := True;
|
|
|
|
else
|
|
Semantics (Library_Unit (N));
|
|
end if;
|
|
|
|
U := Unit (Library_Unit (N));
|
|
Check_Restriction_No_Dependence (Name (N), N);
|
|
Intunit := Is_Internal_File_Name (Unit_File_Name (Current_Sem_Unit));
|
|
|
|
-- Following checks are skipped for dummy packages (those supplied
|
|
-- for with's where no matching file could be found). Such packages
|
|
-- are identified by the Sloc value being set to No_Location
|
|
|
|
if Sloc (U) /= No_Location then
|
|
|
|
-- Check restrictions, except that we skip the check if this
|
|
-- is an internal unit unless we are compiling the internal
|
|
-- unit as the main unit. We also skip this for dummy packages.
|
|
|
|
if not Intunit or else Current_Sem_Unit = Main_Unit then
|
|
Check_Restricted_Unit (Unit_Name (Get_Source_Unit (U)), N);
|
|
end if;
|
|
|
|
-- Check for inappropriate with of internal implementation unit
|
|
-- if we are currently compiling the main unit and the main unit
|
|
-- is itself not an internal unit. We do not issue this message
|
|
-- for implicit with's generated by the compiler itself.
|
|
|
|
if Implementation_Unit_Warnings
|
|
and then Current_Sem_Unit = Main_Unit
|
|
and then not Intunit
|
|
and then not Implicit_With (N)
|
|
and then not GNAT_Mode
|
|
then
|
|
declare
|
|
U_Kind : constant Kind_Of_Unit :=
|
|
Get_Kind_Of_Unit (Get_Source_Unit (U));
|
|
|
|
begin
|
|
if U_Kind = Implementation_Unit then
|
|
Error_Msg_N ("& is an internal 'G'N'A'T unit?", Name (N));
|
|
Error_Msg_N
|
|
("\use of this unit is non-portable " &
|
|
"and version-dependent?",
|
|
Name (N));
|
|
|
|
elsif U_Kind = Ada_05_Unit
|
|
and then Ada_Version < Ada_05
|
|
and then Warn_On_Ada_2005_Compatibility
|
|
then
|
|
Error_Msg_N ("& is an Ada 2005 unit?", Name (N));
|
|
end if;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
-- Semantic analysis of a generic unit is performed on a copy of
|
|
-- the original tree. Retrieve the entity on which semantic info
|
|
-- actually appears.
|
|
|
|
if Unit_Kind in N_Generic_Declaration then
|
|
E_Name := Defining_Entity (U);
|
|
|
|
-- Note: in the following test, Unit_Kind is the original Nkind, but
|
|
-- in the case of an instantiation, semantic analysis above will
|
|
-- have replaced the unit by its instantiated version. If the instance
|
|
-- body has been generated, the instance now denotes the body entity.
|
|
-- For visibility purposes we need the entity of its spec.
|
|
|
|
elsif (Unit_Kind = N_Package_Instantiation
|
|
or else Nkind (Original_Node (Unit (Library_Unit (N)))) =
|
|
N_Package_Instantiation)
|
|
and then Nkind (U) = N_Package_Body
|
|
then
|
|
E_Name := Corresponding_Spec (U);
|
|
|
|
elsif Unit_Kind = N_Package_Instantiation
|
|
and then Nkind (U) = N_Package_Instantiation
|
|
then
|
|
-- If the instance has not been rewritten as a package declaration,
|
|
-- then it appeared already in a previous with clause. Retrieve
|
|
-- the entity from the previous instance.
|
|
|
|
E_Name := Defining_Entity (Specification (Instance_Spec (U)));
|
|
|
|
elsif Unit_Kind in N_Subprogram_Instantiation then
|
|
|
|
-- Instantiation node is replaced with a wrapper package.
|
|
-- Retrieve the visible subprogram created by the instance from
|
|
-- the corresponding attribute of the wrapper.
|
|
|
|
E_Name := Related_Instance (Defining_Entity (U));
|
|
|
|
elsif Unit_Kind = N_Package_Renaming_Declaration
|
|
or else Unit_Kind in N_Generic_Renaming_Declaration
|
|
then
|
|
E_Name := Defining_Entity (U);
|
|
|
|
elsif Unit_Kind = N_Subprogram_Body
|
|
and then Nkind (Name (N)) = N_Selected_Component
|
|
and then not Acts_As_Spec (Library_Unit (N))
|
|
then
|
|
-- For a child unit that has no spec, one has been created and
|
|
-- analyzed. The entity required is that of the spec.
|
|
|
|
E_Name := Corresponding_Spec (U);
|
|
|
|
else
|
|
E_Name := Defining_Entity (U);
|
|
end if;
|
|
|
|
if Nkind (Name (N)) = N_Selected_Component then
|
|
|
|
-- Child unit in a with clause
|
|
|
|
Change_Selected_Component_To_Expanded_Name (Name (N));
|
|
end if;
|
|
|
|
-- Restore style checks and restrictions
|
|
|
|
Style_Check := Save_Style_Check;
|
|
Cunit_Boolean_Restrictions_Restore (Save_C_Restrict);
|
|
|
|
-- Record the reference, but do NOT set the unit as referenced, we want
|
|
-- to consider the unit as unreferenced if this is the only reference
|
|
-- that occurs.
|
|
|
|
Set_Entity_With_Style_Check (Name (N), E_Name);
|
|
Generate_Reference (E_Name, Name (N), 'w', Set_Ref => False);
|
|
|
|
if Is_Child_Unit (E_Name) then
|
|
Pref := Prefix (Name (N));
|
|
Par_Name := Scope (E_Name);
|
|
while Nkind (Pref) = N_Selected_Component loop
|
|
Change_Selected_Component_To_Expanded_Name (Pref);
|
|
Set_Entity_With_Style_Check (Pref, Par_Name);
|
|
|
|
Generate_Reference (Par_Name, Pref);
|
|
Pref := Prefix (Pref);
|
|
|
|
-- If E_Name is the dummy entity for a nonexistent unit, its scope
|
|
-- is set to Standard_Standard, and no attempt should be made to
|
|
-- further unwind scopes.
|
|
|
|
if Par_Name /= Standard_Standard then
|
|
Par_Name := Scope (Par_Name);
|
|
end if;
|
|
end loop;
|
|
|
|
if Present (Entity (Pref))
|
|
and then not Analyzed (Parent (Parent (Entity (Pref))))
|
|
then
|
|
-- If the entity is set without its unit being compiled, the
|
|
-- original parent is a renaming, and Par_Name is the renamed
|
|
-- entity. For visibility purposes, we need the original entity,
|
|
-- which must be analyzed now because Load_Unit directly retrieves
|
|
-- the renamed unit, and the renaming declaration itself has not
|
|
-- been analyzed.
|
|
|
|
Analyze (Parent (Parent (Entity (Pref))));
|
|
pragma Assert (Renamed_Object (Entity (Pref)) = Par_Name);
|
|
Par_Name := Entity (Pref);
|
|
end if;
|
|
|
|
Set_Entity_With_Style_Check (Pref, Par_Name);
|
|
Generate_Reference (Par_Name, Pref);
|
|
end if;
|
|
|
|
-- If the withed unit is System, and a system extension pragma is
|
|
-- present, compile the extension now, rather than waiting for a
|
|
-- visibility check on a specific entity.
|
|
|
|
if Chars (E_Name) = Name_System
|
|
and then Scope (E_Name) = Standard_Standard
|
|
and then Present (System_Extend_Unit)
|
|
and then Present_System_Aux (N)
|
|
then
|
|
-- If the extension is not present, an error will have been emitted
|
|
|
|
null;
|
|
end if;
|
|
|
|
-- Ada 2005 (AI-262): Remove from visibility the entity corresponding
|
|
-- to private_with units; they will be made visible later (just before
|
|
-- the private part is analyzed)
|
|
|
|
if Private_Present (N) then
|
|
Set_Is_Immediately_Visible (E_Name, False);
|
|
end if;
|
|
end Analyze_With_Clause;
|
|
|
|
------------------------------
|
|
-- Analyze_With_Type_Clause --
|
|
------------------------------
|
|
|
|
procedure Analyze_With_Type_Clause (N : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
Nam : constant Node_Id := Name (N);
|
|
Pack : Node_Id;
|
|
Decl : Node_Id;
|
|
P : Entity_Id;
|
|
Unum : Unit_Number_Type;
|
|
Sel : Node_Id;
|
|
|
|
procedure Decorate_Tagged_Type (T : Entity_Id);
|
|
-- Set basic attributes of type, including its class_wide type
|
|
|
|
function In_Chain (E : Entity_Id) return Boolean;
|
|
-- Check that the imported type is not already in the homonym chain,
|
|
-- for example through a with_type clause in a parent unit.
|
|
|
|
--------------------------
|
|
-- Decorate_Tagged_Type --
|
|
--------------------------
|
|
|
|
procedure Decorate_Tagged_Type (T : Entity_Id) is
|
|
CW : Entity_Id;
|
|
|
|
begin
|
|
Set_Ekind (T, E_Record_Type);
|
|
Set_Is_Tagged_Type (T);
|
|
Set_Etype (T, T);
|
|
Set_From_With_Type (T);
|
|
Set_Scope (T, P);
|
|
|
|
if not In_Chain (T) then
|
|
Set_Homonym (T, Current_Entity (T));
|
|
Set_Current_Entity (T);
|
|
end if;
|
|
|
|
-- Build bogus class_wide type, if not previously done
|
|
|
|
if No (Class_Wide_Type (T)) then
|
|
CW := Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
|
|
|
|
Set_Ekind (CW, E_Class_Wide_Type);
|
|
Set_Etype (CW, T);
|
|
Set_Scope (CW, P);
|
|
Set_Is_Tagged_Type (CW);
|
|
Set_Is_First_Subtype (CW, True);
|
|
Init_Size_Align (CW);
|
|
Set_Has_Unknown_Discriminants
|
|
(CW, True);
|
|
Set_Class_Wide_Type (CW, CW);
|
|
Set_Equivalent_Type (CW, Empty);
|
|
Set_From_With_Type (CW);
|
|
|
|
Set_Class_Wide_Type (T, CW);
|
|
end if;
|
|
end Decorate_Tagged_Type;
|
|
|
|
--------------
|
|
-- In_Chain --
|
|
--------------
|
|
|
|
function In_Chain (E : Entity_Id) return Boolean is
|
|
H : Entity_Id;
|
|
|
|
begin
|
|
H := Current_Entity (E);
|
|
while Present (H) loop
|
|
if H = E then
|
|
return True;
|
|
else
|
|
H := Homonym (H);
|
|
end if;
|
|
end loop;
|
|
|
|
return False;
|
|
end In_Chain;
|
|
|
|
-- Start of processing for Analyze_With_Type_Clause
|
|
|
|
begin
|
|
if Nkind (Nam) = N_Selected_Component then
|
|
Pack := New_Copy_Tree (Prefix (Nam));
|
|
Sel := Selector_Name (Nam);
|
|
|
|
else
|
|
Error_Msg_N ("illegal name for imported type", Nam);
|
|
return;
|
|
end if;
|
|
|
|
Decl :=
|
|
Make_Package_Declaration (Loc,
|
|
Specification =>
|
|
(Make_Package_Specification (Loc,
|
|
Defining_Unit_Name => Pack,
|
|
Visible_Declarations => New_List,
|
|
End_Label => Empty)));
|
|
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Get_Unit_Name (Decl),
|
|
Required => True,
|
|
Subunit => False,
|
|
Error_Node => Nam);
|
|
|
|
if Unum = No_Unit
|
|
or else Nkind (Unit (Cunit (Unum))) /= N_Package_Declaration
|
|
then
|
|
Error_Msg_N ("imported type must be declared in package", Nam);
|
|
return;
|
|
|
|
elsif Unum = Current_Sem_Unit then
|
|
|
|
-- If type is defined in unit being analyzed, then the clause
|
|
-- is redundant.
|
|
|
|
return;
|
|
|
|
else
|
|
P := Cunit_Entity (Unum);
|
|
end if;
|
|
|
|
-- Find declaration for imported type, and set its basic attributes
|
|
-- if it has not been analyzed (which will be the case if there is
|
|
-- circular dependence).
|
|
|
|
declare
|
|
Decl : Node_Id;
|
|
Typ : Entity_Id;
|
|
|
|
begin
|
|
if not Analyzed (Cunit (Unum))
|
|
and then not From_With_Type (P)
|
|
then
|
|
Set_Ekind (P, E_Package);
|
|
Set_Etype (P, Standard_Void_Type);
|
|
Set_From_With_Type (P);
|
|
Set_Scope (P, Standard_Standard);
|
|
Set_Homonym (P, Current_Entity (P));
|
|
Set_Current_Entity (P);
|
|
|
|
elsif Analyzed (Cunit (Unum))
|
|
and then Is_Child_Unit (P)
|
|
then
|
|
-- If the child unit is already in scope, indicate that it is
|
|
-- visible, and remains so after intervening calls to rtsfind.
|
|
|
|
Set_Is_Visible_Child_Unit (P);
|
|
end if;
|
|
|
|
if Nkind (Parent (P)) = N_Defining_Program_Unit_Name then
|
|
|
|
-- Make parent packages visible
|
|
|
|
declare
|
|
Parent_Comp : Node_Id;
|
|
Parent_Id : Entity_Id;
|
|
Child : Entity_Id;
|
|
|
|
begin
|
|
Child := P;
|
|
Parent_Comp := Parent_Spec (Unit (Cunit (Unum)));
|
|
|
|
loop
|
|
Parent_Id := Defining_Entity (Unit (Parent_Comp));
|
|
Set_Scope (Child, Parent_Id);
|
|
|
|
-- The type may be imported from a child unit, in which
|
|
-- case the current compilation appears in the name. Do
|
|
-- not change its visibility here because it will conflict
|
|
-- with the subsequent normal processing.
|
|
|
|
if not Analyzed (Unit_Declaration_Node (Parent_Id))
|
|
and then Parent_Id /= Cunit_Entity (Current_Sem_Unit)
|
|
then
|
|
Set_Ekind (Parent_Id, E_Package);
|
|
Set_Etype (Parent_Id, Standard_Void_Type);
|
|
|
|
-- The same package may appear is several with_type
|
|
-- clauses.
|
|
|
|
if not From_With_Type (Parent_Id) then
|
|
Set_Homonym (Parent_Id, Current_Entity (Parent_Id));
|
|
Set_Current_Entity (Parent_Id);
|
|
Set_From_With_Type (Parent_Id);
|
|
end if;
|
|
end if;
|
|
|
|
Set_Is_Immediately_Visible (Parent_Id);
|
|
|
|
Child := Parent_Id;
|
|
Parent_Comp := Parent_Spec (Unit (Parent_Comp));
|
|
exit when No (Parent_Comp);
|
|
end loop;
|
|
|
|
Set_Scope (Parent_Id, Standard_Standard);
|
|
end;
|
|
end if;
|
|
|
|
-- Even if analyzed, the package may not be currently visible. It
|
|
-- must be while the with_type clause is active.
|
|
|
|
Set_Is_Immediately_Visible (P);
|
|
|
|
Decl :=
|
|
First (Visible_Declarations (Specification (Unit (Cunit (Unum)))));
|
|
while Present (Decl) loop
|
|
if Nkind (Decl) = N_Full_Type_Declaration
|
|
and then Chars (Defining_Identifier (Decl)) = Chars (Sel)
|
|
then
|
|
Typ := Defining_Identifier (Decl);
|
|
|
|
if Tagged_Present (N) then
|
|
|
|
-- The declaration must indicate that this is a tagged
|
|
-- type or a type extension.
|
|
|
|
if (Nkind (Type_Definition (Decl)) = N_Record_Definition
|
|
and then Tagged_Present (Type_Definition (Decl)))
|
|
or else
|
|
(Nkind (Type_Definition (Decl))
|
|
= N_Derived_Type_Definition
|
|
and then Present
|
|
(Record_Extension_Part (Type_Definition (Decl))))
|
|
then
|
|
null;
|
|
else
|
|
Error_Msg_N ("imported type is not a tagged type", Nam);
|
|
return;
|
|
end if;
|
|
|
|
if not Analyzed (Decl) then
|
|
|
|
-- Unit is not currently visible. Add basic attributes
|
|
-- to type and build its class-wide type.
|
|
|
|
Init_Size_Align (Typ);
|
|
Decorate_Tagged_Type (Typ);
|
|
end if;
|
|
|
|
else
|
|
if Nkind (Type_Definition (Decl))
|
|
/= N_Access_To_Object_Definition
|
|
then
|
|
Error_Msg_N
|
|
("imported type is not an access type", Nam);
|
|
|
|
elsif not Analyzed (Decl) then
|
|
Set_Ekind (Typ, E_Access_Type);
|
|
Set_Etype (Typ, Typ);
|
|
Set_Scope (Typ, P);
|
|
Init_Size (Typ, System_Address_Size);
|
|
Init_Alignment (Typ);
|
|
Set_Directly_Designated_Type (Typ, Standard_Integer);
|
|
Set_From_With_Type (Typ);
|
|
|
|
if not In_Chain (Typ) then
|
|
Set_Homonym (Typ, Current_Entity (Typ));
|
|
Set_Current_Entity (Typ);
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
Set_Entity (Sel, Typ);
|
|
return;
|
|
|
|
elsif ((Nkind (Decl) = N_Private_Type_Declaration
|
|
and then Tagged_Present (Decl))
|
|
or else (Nkind (Decl) = N_Private_Extension_Declaration))
|
|
and then Chars (Defining_Identifier (Decl)) = Chars (Sel)
|
|
then
|
|
Typ := Defining_Identifier (Decl);
|
|
|
|
if not Tagged_Present (N) then
|
|
Error_Msg_N ("type must be declared tagged", N);
|
|
|
|
elsif not Analyzed (Decl) then
|
|
Decorate_Tagged_Type (Typ);
|
|
end if;
|
|
|
|
Set_Entity (Sel, Typ);
|
|
Set_From_With_Type (Typ);
|
|
return;
|
|
end if;
|
|
|
|
Decl := Next (Decl);
|
|
end loop;
|
|
|
|
Error_Msg_NE ("not a visible access or tagged type in&", Nam, P);
|
|
end;
|
|
end Analyze_With_Type_Clause;
|
|
|
|
-----------------------------
|
|
-- Check_With_Type_Clauses --
|
|
-----------------------------
|
|
|
|
procedure Check_With_Type_Clauses (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Unit (N);
|
|
|
|
procedure Check_Parent_Context (U : Node_Id);
|
|
-- Examine context items of parent unit to locate with_type clauses
|
|
|
|
--------------------------
|
|
-- Check_Parent_Context --
|
|
--------------------------
|
|
|
|
procedure Check_Parent_Context (U : Node_Id) is
|
|
Item : Node_Id;
|
|
|
|
begin
|
|
Item := First (Context_Items (U));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Type_Clause
|
|
and then not Error_Posted (Item)
|
|
and then
|
|
From_With_Type (Scope (Entity (Selector_Name (Name (Item)))))
|
|
then
|
|
Error_Msg_Sloc := Sloc (Item);
|
|
Error_Msg_N ("missing With_Clause for With_Type_Clause#", N);
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Check_Parent_Context;
|
|
|
|
-- Start of processing for Check_With_Type_Clauses
|
|
|
|
begin
|
|
if Extensions_Allowed
|
|
and then (Nkind (Lib_Unit) = N_Package_Body
|
|
or else Nkind (Lib_Unit) = N_Subprogram_Body)
|
|
then
|
|
Check_Parent_Context (Library_Unit (N));
|
|
|
|
if Is_Child_Spec (Unit (Library_Unit (N))) then
|
|
Check_Parent_Context (Parent_Spec (Unit (Library_Unit (N))));
|
|
end if;
|
|
end if;
|
|
end Check_With_Type_Clauses;
|
|
|
|
------------------------------
|
|
-- Check_Private_Child_Unit --
|
|
------------------------------
|
|
|
|
procedure Check_Private_Child_Unit (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Unit (N);
|
|
Item : Node_Id;
|
|
Curr_Unit : Entity_Id;
|
|
Sub_Parent : Node_Id;
|
|
Priv_Child : Entity_Id;
|
|
Par_Lib : Entity_Id;
|
|
Par_Spec : Node_Id;
|
|
|
|
function Is_Private_Library_Unit (Unit : Entity_Id) return Boolean;
|
|
-- Returns true if and only if the library unit is declared with
|
|
-- an explicit designation of private.
|
|
|
|
function Is_Private_Library_Unit (Unit : Entity_Id) return Boolean is
|
|
Comp_Unit : constant Node_Id := Parent (Unit_Declaration_Node (Unit));
|
|
|
|
begin
|
|
return Private_Present (Comp_Unit);
|
|
end Is_Private_Library_Unit;
|
|
|
|
-- Start of processing for Check_Private_Child_Unit
|
|
|
|
begin
|
|
if Nkind (Lib_Unit) = N_Package_Body
|
|
or else Nkind (Lib_Unit) = N_Subprogram_Body
|
|
then
|
|
Curr_Unit := Defining_Entity (Unit (Library_Unit (N)));
|
|
Par_Lib := Curr_Unit;
|
|
|
|
elsif Nkind (Lib_Unit) = N_Subunit then
|
|
|
|
-- The parent is itself a body. The parent entity is to be found
|
|
-- in the corresponding spec.
|
|
|
|
Sub_Parent := Library_Unit (N);
|
|
Curr_Unit := Defining_Entity (Unit (Library_Unit (Sub_Parent)));
|
|
|
|
-- If the parent itself is a subunit, Curr_Unit is the entity
|
|
-- of the enclosing body, retrieve the spec entity which is
|
|
-- the proper ancestor we need for the following tests.
|
|
|
|
if Ekind (Curr_Unit) = E_Package_Body then
|
|
Curr_Unit := Spec_Entity (Curr_Unit);
|
|
end if;
|
|
|
|
Par_Lib := Curr_Unit;
|
|
|
|
else
|
|
Curr_Unit := Defining_Entity (Lib_Unit);
|
|
|
|
Par_Lib := Curr_Unit;
|
|
Par_Spec := Parent_Spec (Lib_Unit);
|
|
|
|
if No (Par_Spec) then
|
|
Par_Lib := Empty;
|
|
else
|
|
Par_Lib := Defining_Entity (Unit (Par_Spec));
|
|
end if;
|
|
end if;
|
|
|
|
-- Loop through context items
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
|
|
-- Ada 2005 (AI-262): Allow private_with of a private child package
|
|
-- in public siblings
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Implicit_With (Item)
|
|
and then Is_Private_Descendant (Entity (Name (Item)))
|
|
then
|
|
Priv_Child := Entity (Name (Item));
|
|
|
|
declare
|
|
Curr_Parent : Entity_Id := Par_Lib;
|
|
Child_Parent : Entity_Id := Scope (Priv_Child);
|
|
Prv_Ancestor : Entity_Id := Child_Parent;
|
|
Curr_Private : Boolean := Is_Private_Library_Unit (Curr_Unit);
|
|
|
|
begin
|
|
-- If the child unit is a public child then locate
|
|
-- the nearest private ancestor; Child_Parent will
|
|
-- then be set to the parent of that ancestor.
|
|
|
|
if not Is_Private_Library_Unit (Priv_Child) then
|
|
while Present (Prv_Ancestor)
|
|
and then not Is_Private_Library_Unit (Prv_Ancestor)
|
|
loop
|
|
Prv_Ancestor := Scope (Prv_Ancestor);
|
|
end loop;
|
|
|
|
if Present (Prv_Ancestor) then
|
|
Child_Parent := Scope (Prv_Ancestor);
|
|
end if;
|
|
end if;
|
|
|
|
while Present (Curr_Parent)
|
|
and then Curr_Parent /= Standard_Standard
|
|
and then Curr_Parent /= Child_Parent
|
|
loop
|
|
Curr_Private :=
|
|
Curr_Private or else Is_Private_Library_Unit (Curr_Parent);
|
|
Curr_Parent := Scope (Curr_Parent);
|
|
end loop;
|
|
|
|
if No (Curr_Parent) then
|
|
Curr_Parent := Standard_Standard;
|
|
end if;
|
|
|
|
if Curr_Parent /= Child_Parent then
|
|
if Ekind (Priv_Child) = E_Generic_Package
|
|
and then Chars (Priv_Child) in Text_IO_Package_Name
|
|
and then Chars (Scope (Scope (Priv_Child))) = Name_Ada
|
|
then
|
|
Error_Msg_NE
|
|
("& is a nested package, not a compilation unit",
|
|
Name (Item), Priv_Child);
|
|
|
|
else
|
|
Error_Msg_N
|
|
("unit in with clause is private child unit!", Item);
|
|
Error_Msg_NE
|
|
("\current unit must also have parent&!",
|
|
Item, Child_Parent);
|
|
end if;
|
|
|
|
elsif not Curr_Private
|
|
and then not Private_Present (Item)
|
|
and then Nkind (Lib_Unit) /= N_Package_Body
|
|
and then Nkind (Lib_Unit) /= N_Subprogram_Body
|
|
and then Nkind (Lib_Unit) /= N_Subunit
|
|
then
|
|
Error_Msg_NE
|
|
("current unit must also be private descendant of&",
|
|
Item, Child_Parent);
|
|
end if;
|
|
end;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
end Check_Private_Child_Unit;
|
|
|
|
----------------------
|
|
-- Check_Stub_Level --
|
|
----------------------
|
|
|
|
procedure Check_Stub_Level (N : Node_Id) is
|
|
Par : constant Node_Id := Parent (N);
|
|
Kind : constant Node_Kind := Nkind (Par);
|
|
|
|
begin
|
|
if (Kind = N_Package_Body
|
|
or else Kind = N_Subprogram_Body
|
|
or else Kind = N_Task_Body
|
|
or else Kind = N_Protected_Body)
|
|
and then (Nkind (Parent (Par)) = N_Compilation_Unit
|
|
or else Nkind (Parent (Par)) = N_Subunit)
|
|
then
|
|
null;
|
|
|
|
-- In an instance, a missing stub appears at any level. A warning
|
|
-- message will have been emitted already for the missing file.
|
|
|
|
elsif not In_Instance then
|
|
Error_Msg_N ("stub cannot appear in an inner scope", N);
|
|
|
|
elsif Expander_Active then
|
|
Error_Msg_N ("missing proper body", N);
|
|
end if;
|
|
end Check_Stub_Level;
|
|
|
|
------------------------
|
|
-- Expand_With_Clause --
|
|
------------------------
|
|
|
|
procedure Expand_With_Clause (Item : Node_Id; Nam : Node_Id; N : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (Nam);
|
|
Ent : constant Entity_Id := Entity (Nam);
|
|
Withn : Node_Id;
|
|
P : Node_Id;
|
|
|
|
function Build_Unit_Name (Nam : Node_Id) return Node_Id;
|
|
-- Comment requireed here ???
|
|
|
|
---------------------
|
|
-- Build_Unit_Name --
|
|
---------------------
|
|
|
|
function Build_Unit_Name (Nam : Node_Id) return Node_Id is
|
|
Result : Node_Id;
|
|
|
|
begin
|
|
if Nkind (Nam) = N_Identifier then
|
|
return New_Occurrence_Of (Entity (Nam), Loc);
|
|
|
|
else
|
|
Result :=
|
|
Make_Expanded_Name (Loc,
|
|
Chars => Chars (Entity (Nam)),
|
|
Prefix => Build_Unit_Name (Prefix (Nam)),
|
|
Selector_Name => New_Occurrence_Of (Entity (Nam), Loc));
|
|
Set_Entity (Result, Entity (Nam));
|
|
return Result;
|
|
end if;
|
|
end Build_Unit_Name;
|
|
|
|
-- Start of processing for Expand_With_Clause
|
|
|
|
begin
|
|
New_Nodes_OK := New_Nodes_OK + 1;
|
|
Withn :=
|
|
Make_With_Clause (Loc, Name => Build_Unit_Name (Nam));
|
|
|
|
P := Parent (Unit_Declaration_Node (Ent));
|
|
Set_Library_Unit (Withn, P);
|
|
Set_Corresponding_Spec (Withn, Ent);
|
|
Set_First_Name (Withn, True);
|
|
Set_Implicit_With (Withn, True);
|
|
|
|
-- If the unit is a package declaration, a private_with_clause on a
|
|
-- child unit implies that the implicit with on the parent is also
|
|
-- private.
|
|
|
|
if Nkind (Unit (N)) = N_Package_Declaration then
|
|
Set_Private_Present (Withn, Private_Present (Item));
|
|
end if;
|
|
|
|
Prepend (Withn, Context_Items (N));
|
|
Mark_Rewrite_Insertion (Withn);
|
|
Install_Withed_Unit (Withn);
|
|
|
|
if Nkind (Nam) = N_Expanded_Name then
|
|
Expand_With_Clause (Item, Prefix (Nam), N);
|
|
end if;
|
|
|
|
New_Nodes_OK := New_Nodes_OK - 1;
|
|
end Expand_With_Clause;
|
|
|
|
-----------------------
|
|
-- Get_Parent_Entity --
|
|
-----------------------
|
|
|
|
function Get_Parent_Entity (Unit : Node_Id) return Entity_Id is
|
|
begin
|
|
if Nkind (Unit) = N_Package_Body
|
|
and then Nkind (Original_Node (Unit)) = N_Package_Instantiation
|
|
then
|
|
return
|
|
Defining_Entity
|
|
(Specification (Instance_Spec (Original_Node (Unit))));
|
|
|
|
elsif Nkind (Unit) = N_Package_Instantiation then
|
|
return Defining_Entity (Specification (Instance_Spec (Unit)));
|
|
|
|
else
|
|
return Defining_Entity (Unit);
|
|
end if;
|
|
end Get_Parent_Entity;
|
|
|
|
-----------------------------
|
|
-- Implicit_With_On_Parent --
|
|
-----------------------------
|
|
|
|
procedure Implicit_With_On_Parent
|
|
(Child_Unit : Node_Id;
|
|
N : Node_Id)
|
|
is
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
P : constant Node_Id := Parent_Spec (Child_Unit);
|
|
|
|
P_Unit : Node_Id := Unit (P);
|
|
|
|
P_Name : constant Entity_Id := Get_Parent_Entity (P_Unit);
|
|
Withn : Node_Id;
|
|
|
|
function Build_Ancestor_Name (P : Node_Id) return Node_Id;
|
|
-- Build prefix of child unit name. Recurse if needed
|
|
|
|
function Build_Unit_Name return Node_Id;
|
|
-- If the unit is a child unit, build qualified name with all
|
|
-- ancestors.
|
|
|
|
-------------------------
|
|
-- Build_Ancestor_Name --
|
|
-------------------------
|
|
|
|
function Build_Ancestor_Name (P : Node_Id) return Node_Id is
|
|
P_Ref : constant Node_Id :=
|
|
New_Reference_To (Defining_Entity (P), Loc);
|
|
P_Spec : Node_Id := P;
|
|
|
|
begin
|
|
-- Ancestor may have been rewritten as a package body. Retrieve
|
|
-- the original spec to trace earlier ancestors.
|
|
|
|
if Nkind (P) = N_Package_Body
|
|
and then Nkind (Original_Node (P)) = N_Package_Instantiation
|
|
then
|
|
P_Spec := Original_Node (P);
|
|
end if;
|
|
|
|
if No (Parent_Spec (P_Spec)) then
|
|
return P_Ref;
|
|
else
|
|
return
|
|
Make_Selected_Component (Loc,
|
|
Prefix => Build_Ancestor_Name (Unit (Parent_Spec (P_Spec))),
|
|
Selector_Name => P_Ref);
|
|
end if;
|
|
end Build_Ancestor_Name;
|
|
|
|
---------------------
|
|
-- Build_Unit_Name --
|
|
---------------------
|
|
|
|
function Build_Unit_Name return Node_Id is
|
|
Result : Node_Id;
|
|
begin
|
|
if No (Parent_Spec (P_Unit)) then
|
|
return New_Reference_To (P_Name, Loc);
|
|
else
|
|
Result :=
|
|
Make_Expanded_Name (Loc,
|
|
Chars => Chars (P_Name),
|
|
Prefix => Build_Ancestor_Name (Unit (Parent_Spec (P_Unit))),
|
|
Selector_Name => New_Reference_To (P_Name, Loc));
|
|
Set_Entity (Result, P_Name);
|
|
return Result;
|
|
end if;
|
|
end Build_Unit_Name;
|
|
|
|
-- Start of processing for Implicit_With_On_Parent
|
|
|
|
begin
|
|
-- The unit of the current compilation may be a package body
|
|
-- that replaces an instance node. In this case we need the
|
|
-- original instance node to construct the proper parent name.
|
|
|
|
if Nkind (P_Unit) = N_Package_Body
|
|
and then Nkind (Original_Node (P_Unit)) = N_Package_Instantiation
|
|
then
|
|
P_Unit := Original_Node (P_Unit);
|
|
end if;
|
|
|
|
-- We add the implicit with if the child unit is the current unit
|
|
-- being compiled. If the current unit is a body, we do not want
|
|
-- to add an implicit_with a second time to the corresponding spec.
|
|
|
|
if Nkind (Child_Unit) = N_Package_Declaration
|
|
and then Child_Unit /= Unit (Cunit (Current_Sem_Unit))
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
New_Nodes_OK := New_Nodes_OK + 1;
|
|
Withn := Make_With_Clause (Loc, Name => Build_Unit_Name);
|
|
|
|
Set_Library_Unit (Withn, P);
|
|
Set_Corresponding_Spec (Withn, P_Name);
|
|
Set_First_Name (Withn, True);
|
|
Set_Implicit_With (Withn, True);
|
|
|
|
-- Node is placed at the beginning of the context items, so that
|
|
-- subsequent use clauses on the parent can be validated.
|
|
|
|
Prepend (Withn, Context_Items (N));
|
|
Mark_Rewrite_Insertion (Withn);
|
|
Install_Withed_Unit (Withn);
|
|
|
|
if Is_Child_Spec (P_Unit) then
|
|
Implicit_With_On_Parent (P_Unit, N);
|
|
end if;
|
|
|
|
New_Nodes_OK := New_Nodes_OK - 1;
|
|
end Implicit_With_On_Parent;
|
|
|
|
--------------
|
|
-- In_Chain --
|
|
--------------
|
|
|
|
function In_Chain (E : Entity_Id) return Boolean is
|
|
H : Entity_Id;
|
|
|
|
begin
|
|
H := Current_Entity (E);
|
|
while Present (H) loop
|
|
if H = E then
|
|
return True;
|
|
else
|
|
H := Homonym (H);
|
|
end if;
|
|
end loop;
|
|
|
|
return False;
|
|
end In_Chain;
|
|
|
|
---------------------
|
|
-- Install_Context --
|
|
---------------------
|
|
|
|
procedure Install_Context (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Unit (N);
|
|
|
|
begin
|
|
Install_Context_Clauses (N);
|
|
|
|
if Is_Child_Spec (Lib_Unit) then
|
|
Install_Parents (Lib_Unit, Private_Present (Parent (Lib_Unit)));
|
|
end if;
|
|
|
|
Install_Limited_Context_Clauses (N);
|
|
|
|
Check_With_Type_Clauses (N);
|
|
end Install_Context;
|
|
|
|
-----------------------------
|
|
-- Install_Context_Clauses --
|
|
-----------------------------
|
|
|
|
procedure Install_Context_Clauses (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Unit (N);
|
|
Item : Node_Id;
|
|
Uname_Node : Entity_Id;
|
|
Check_Private : Boolean := False;
|
|
Decl_Node : Node_Id;
|
|
Lib_Parent : Entity_Id;
|
|
|
|
begin
|
|
-- First skip configuration pragmas at the start of the context. They
|
|
-- are not technically part of the context clause, but that's where the
|
|
-- parser puts them. Note they were analyzed in Analyze_Context.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item)
|
|
and then Nkind (Item) = N_Pragma
|
|
and then Chars (Item) in Configuration_Pragma_Names
|
|
loop
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Loop through the actual context clause items. We process everything
|
|
-- except Limited_With clauses in this routine. Limited_With clauses
|
|
-- are separately installed (see Install_Limited_Context_Clauses).
|
|
|
|
while Present (Item) loop
|
|
|
|
-- Case of explicit WITH clause
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Implicit_With (Item)
|
|
then
|
|
if Limited_Present (Item) then
|
|
|
|
-- Limited withed units will be installed later
|
|
|
|
goto Continue;
|
|
|
|
-- If Name (Item) is not an entity name, something is wrong, and
|
|
-- this will be detected in due course, for now ignore the item
|
|
|
|
elsif not Is_Entity_Name (Name (Item)) then
|
|
goto Continue;
|
|
|
|
elsif No (Entity (Name (Item))) then
|
|
Set_Entity (Name (Item), Any_Id);
|
|
goto Continue;
|
|
end if;
|
|
|
|
Uname_Node := Entity (Name (Item));
|
|
|
|
if Is_Private_Descendant (Uname_Node) then
|
|
Check_Private := True;
|
|
end if;
|
|
|
|
Install_Withed_Unit (Item);
|
|
|
|
Decl_Node := Unit_Declaration_Node (Uname_Node);
|
|
|
|
-- If the unit is a subprogram instance, it appears nested
|
|
-- within a package that carries the parent information.
|
|
|
|
if Is_Generic_Instance (Uname_Node)
|
|
and then Ekind (Uname_Node) /= E_Package
|
|
then
|
|
Decl_Node := Parent (Parent (Decl_Node));
|
|
end if;
|
|
|
|
if Is_Child_Spec (Decl_Node) then
|
|
if Nkind (Name (Item)) = N_Expanded_Name then
|
|
Expand_With_Clause (Item, Prefix (Name (Item)), N);
|
|
else
|
|
-- if not an expanded name, the child unit must be a
|
|
-- renaming, nothing to do.
|
|
|
|
null;
|
|
end if;
|
|
|
|
elsif Nkind (Decl_Node) = N_Subprogram_Body
|
|
and then not Acts_As_Spec (Parent (Decl_Node))
|
|
and then Is_Child_Spec (Unit (Library_Unit (Parent (Decl_Node))))
|
|
then
|
|
Implicit_With_On_Parent
|
|
(Unit (Library_Unit (Parent (Decl_Node))), N);
|
|
end if;
|
|
|
|
-- Check license conditions unless this is a dummy unit
|
|
|
|
if Sloc (Library_Unit (Item)) /= No_Location then
|
|
License_Check : declare
|
|
|
|
Withu : constant Unit_Number_Type :=
|
|
Get_Source_Unit (Library_Unit (Item));
|
|
|
|
Withl : constant License_Type :=
|
|
License (Source_Index (Withu));
|
|
|
|
Unitl : constant License_Type :=
|
|
License (Source_Index (Current_Sem_Unit));
|
|
|
|
procedure License_Error;
|
|
-- Signal error of bad license
|
|
|
|
-------------------
|
|
-- License_Error --
|
|
-------------------
|
|
|
|
procedure License_Error is
|
|
begin
|
|
Error_Msg_N
|
|
("?license of with'ed unit & may be inconsistent",
|
|
Name (Item));
|
|
end License_Error;
|
|
|
|
-- Start of processing for License_Check
|
|
|
|
begin
|
|
-- Exclude license check if withed unit is an internal unit.
|
|
-- This situation arises e.g. with the GPL version of GNAT.
|
|
|
|
if Is_Internal_File_Name (Unit_File_Name (Withu)) then
|
|
null;
|
|
|
|
-- Otherwise check various cases
|
|
else
|
|
case Unitl is
|
|
when Unknown =>
|
|
null;
|
|
|
|
when Restricted =>
|
|
if Withl = GPL then
|
|
License_Error;
|
|
end if;
|
|
|
|
when GPL =>
|
|
if Withl = Restricted then
|
|
License_Error;
|
|
end if;
|
|
|
|
when Modified_GPL =>
|
|
if Withl = Restricted or else Withl = GPL then
|
|
License_Error;
|
|
end if;
|
|
|
|
when Unrestricted =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
end License_Check;
|
|
end if;
|
|
|
|
-- Case of USE PACKAGE clause
|
|
|
|
elsif Nkind (Item) = N_Use_Package_Clause then
|
|
Analyze_Use_Package (Item);
|
|
|
|
-- Case of USE TYPE clause
|
|
|
|
elsif Nkind (Item) = N_Use_Type_Clause then
|
|
Analyze_Use_Type (Item);
|
|
|
|
-- Case of WITH TYPE clause
|
|
|
|
-- A With_Type_Clause is processed when installing the context,
|
|
-- because it is a visibility mechanism and does not create a
|
|
-- semantic dependence on other units, as a With_Clause does.
|
|
|
|
elsif Nkind (Item) = N_With_Type_Clause then
|
|
Analyze_With_Type_Clause (Item);
|
|
|
|
-- case of PRAGMA
|
|
|
|
elsif Nkind (Item) = N_Pragma then
|
|
Analyze (Item);
|
|
end if;
|
|
|
|
<<Continue>>
|
|
Next (Item);
|
|
end loop;
|
|
|
|
if Is_Child_Spec (Lib_Unit) then
|
|
|
|
-- The unit also has implicit withs on its own parents
|
|
|
|
if No (Context_Items (N)) then
|
|
Set_Context_Items (N, New_List);
|
|
end if;
|
|
|
|
Implicit_With_On_Parent (Lib_Unit, N);
|
|
end if;
|
|
|
|
-- If the unit is a body, the context of the specification must also
|
|
-- be installed.
|
|
|
|
if Nkind (Lib_Unit) = N_Package_Body
|
|
or else (Nkind (Lib_Unit) = N_Subprogram_Body
|
|
and then not Acts_As_Spec (N))
|
|
then
|
|
Install_Context (Library_Unit (N));
|
|
|
|
if Is_Child_Spec (Unit (Library_Unit (N))) then
|
|
|
|
-- If the unit is the body of a public child unit, the private
|
|
-- declarations of the parent must be made visible. If the child
|
|
-- unit is private, the private declarations have been installed
|
|
-- already in the call to Install_Parents for the spec. Installing
|
|
-- private declarations must be done for all ancestors of public
|
|
-- child units. In addition, sibling units mentioned in the
|
|
-- context clause of the body are directly visible.
|
|
|
|
declare
|
|
Lib_Spec : Node_Id;
|
|
P : Node_Id;
|
|
P_Name : Entity_Id;
|
|
|
|
begin
|
|
Lib_Spec := Unit (Library_Unit (N));
|
|
while Is_Child_Spec (Lib_Spec) loop
|
|
P := Unit (Parent_Spec (Lib_Spec));
|
|
P_Name := Defining_Entity (P);
|
|
|
|
if not (Private_Present (Parent (Lib_Spec)))
|
|
and then not In_Private_Part (P_Name)
|
|
then
|
|
Install_Private_Declarations (P_Name);
|
|
Install_Private_With_Clauses (P_Name);
|
|
Set_Use (Private_Declarations (Specification (P)));
|
|
end if;
|
|
|
|
Lib_Spec := P;
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
-- For a package body, children in context are immediately visible
|
|
|
|
Install_Siblings (Defining_Entity (Unit (Library_Unit (N))), N);
|
|
end if;
|
|
|
|
if Nkind (Lib_Unit) = N_Generic_Package_Declaration
|
|
or else Nkind (Lib_Unit) = N_Generic_Subprogram_Declaration
|
|
or else Nkind (Lib_Unit) = N_Package_Declaration
|
|
or else Nkind (Lib_Unit) = N_Subprogram_Declaration
|
|
then
|
|
if Is_Child_Spec (Lib_Unit) then
|
|
Lib_Parent := Defining_Entity (Unit (Parent_Spec (Lib_Unit)));
|
|
Set_Is_Private_Descendant
|
|
(Defining_Entity (Lib_Unit),
|
|
Is_Private_Descendant (Lib_Parent)
|
|
or else Private_Present (Parent (Lib_Unit)));
|
|
|
|
else
|
|
Set_Is_Private_Descendant
|
|
(Defining_Entity (Lib_Unit),
|
|
Private_Present (Parent (Lib_Unit)));
|
|
end if;
|
|
end if;
|
|
|
|
if Check_Private then
|
|
Check_Private_Child_Unit (N);
|
|
end if;
|
|
end Install_Context_Clauses;
|
|
|
|
-------------------------------------
|
|
-- Install_Limited_Context_Clauses --
|
|
-------------------------------------
|
|
|
|
procedure Install_Limited_Context_Clauses (N : Node_Id) is
|
|
Item : Node_Id;
|
|
|
|
procedure Check_Renamings (P : Node_Id; W : Node_Id);
|
|
-- Check that the unlimited view of a given compilation_unit is not
|
|
-- already visible through "use + renamings".
|
|
|
|
procedure Check_Private_Limited_Withed_Unit (Item : Node_Id);
|
|
-- Check that if a limited_with clause of a given compilation_unit
|
|
-- mentions a descendant of a private child of some library unit,
|
|
-- then the given compilation_unit shall be the declaration of a
|
|
-- private descendant of that library unit.
|
|
|
|
procedure Expand_Limited_With_Clause
|
|
(Comp_Unit : Node_Id; Nam : Node_Id; N : Node_Id);
|
|
-- If a child unit appears in a limited_with clause, there are implicit
|
|
-- limited_with clauses on all parents that are not already visible
|
|
-- through a regular with clause. This procedure creates the implicit
|
|
-- limited with_clauses for the parents and loads the corresponding
|
|
-- units. The shadow entities are created when the inserted clause is
|
|
-- analyzed. Implements Ada 2005 (AI-50217).
|
|
|
|
---------------------
|
|
-- Check_Renamings --
|
|
---------------------
|
|
|
|
procedure Check_Renamings (P : Node_Id; W : Node_Id) is
|
|
Item : Node_Id;
|
|
Spec : Node_Id;
|
|
WEnt : Entity_Id;
|
|
Nam : Node_Id;
|
|
E : Entity_Id;
|
|
E2 : Entity_Id;
|
|
|
|
begin
|
|
pragma Assert (Nkind (W) = N_With_Clause);
|
|
|
|
-- Protect the frontend against previous critical errors
|
|
|
|
case Nkind (Unit (Library_Unit (W))) is
|
|
when N_Subprogram_Declaration |
|
|
N_Package_Declaration |
|
|
N_Generic_Subprogram_Declaration |
|
|
N_Generic_Package_Declaration =>
|
|
null;
|
|
|
|
when others =>
|
|
return;
|
|
end case;
|
|
|
|
-- Check "use + renamings"
|
|
|
|
WEnt := Defining_Unit_Name (Specification (Unit (Library_Unit (W))));
|
|
Spec := Specification (Unit (P));
|
|
|
|
Item := First (Visible_Declarations (Spec));
|
|
while Present (Item) loop
|
|
|
|
-- Look only at use package clauses
|
|
|
|
if Nkind (Item) = N_Use_Package_Clause then
|
|
|
|
-- Traverse the list of packages
|
|
|
|
Nam := First (Names (Item));
|
|
while Present (Nam) loop
|
|
E := Entity (Nam);
|
|
|
|
pragma Assert (Present (Parent (E)));
|
|
|
|
if Nkind (Parent (E)) = N_Package_Renaming_Declaration
|
|
and then Renamed_Entity (E) = WEnt
|
|
then
|
|
-- The unlimited view is visible through use clause and
|
|
-- renamings. There is not need to generate the error
|
|
-- message here because Is_Visible_Through_Renamings
|
|
-- takes care of generating the precise error message.
|
|
|
|
return;
|
|
|
|
elsif Nkind (Parent (E)) = N_Package_Specification then
|
|
|
|
-- The use clause may refer to a local package.
|
|
-- Check all the enclosing scopes.
|
|
|
|
E2 := E;
|
|
while E2 /= Standard_Standard
|
|
and then E2 /= WEnt loop
|
|
E2 := Scope (E2);
|
|
end loop;
|
|
|
|
if E2 = WEnt then
|
|
Error_Msg_N
|
|
("unlimited view visible through use clause ", W);
|
|
return;
|
|
end if;
|
|
|
|
end if;
|
|
Next (Nam);
|
|
end loop;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Recursive call to check all the ancestors
|
|
|
|
if Is_Child_Spec (Unit (P)) then
|
|
Check_Renamings (P => Parent_Spec (Unit (P)), W => W);
|
|
end if;
|
|
end Check_Renamings;
|
|
|
|
---------------------------------------
|
|
-- Check_Private_Limited_Withed_Unit --
|
|
---------------------------------------
|
|
|
|
procedure Check_Private_Limited_Withed_Unit (Item : Node_Id) is
|
|
Curr_Parent : Node_Id;
|
|
Child_Parent : Node_Id;
|
|
|
|
begin
|
|
-- Compilation unit of the parent of the withed library unit
|
|
|
|
Child_Parent := Parent_Spec (Unit (Library_Unit (Item)));
|
|
|
|
-- If the child unit is a public child, then locate its nearest
|
|
-- private ancestor, if any; Child_Parent will then be set to
|
|
-- the parent of that ancestor.
|
|
|
|
if not Private_Present (Library_Unit (Item)) then
|
|
while Present (Child_Parent)
|
|
and then not Private_Present (Child_Parent)
|
|
loop
|
|
Child_Parent := Parent_Spec (Unit (Child_Parent));
|
|
end loop;
|
|
|
|
if No (Child_Parent) then
|
|
return;
|
|
end if;
|
|
|
|
Child_Parent := Parent_Spec (Unit (Child_Parent));
|
|
end if;
|
|
|
|
-- Traverse all the ancestors of the current compilation
|
|
-- unit to check if it is a descendant of named library unit.
|
|
|
|
Curr_Parent := Parent (Item);
|
|
|
|
while Present (Parent_Spec (Unit (Curr_Parent)))
|
|
and then Curr_Parent /= Child_Parent
|
|
loop
|
|
Curr_Parent := Parent_Spec (Unit (Curr_Parent));
|
|
end loop;
|
|
|
|
if Curr_Parent /= Child_Parent then
|
|
Error_Msg_N
|
|
("unit in with clause is private child unit!", Item);
|
|
Error_Msg_NE
|
|
("\current unit must also have parent&!",
|
|
Item, Defining_Unit_Name (Specification (Unit (Child_Parent))));
|
|
|
|
elsif not Private_Present (Parent (Item))
|
|
and then not Private_Present (Item)
|
|
and then Nkind (Unit (Parent (Item))) /= N_Package_Body
|
|
and then Nkind (Unit (Parent (Item))) /= N_Subprogram_Body
|
|
and then Nkind (Unit (Parent (Item))) /= N_Subunit
|
|
then
|
|
Error_Msg_NE
|
|
("current unit must also be private descendant of&",
|
|
Item, Defining_Unit_Name (Specification (Unit (Child_Parent))));
|
|
end if;
|
|
end Check_Private_Limited_Withed_Unit;
|
|
|
|
--------------------------------
|
|
-- Expand_Limited_With_Clause --
|
|
--------------------------------
|
|
|
|
procedure Expand_Limited_With_Clause
|
|
(Comp_Unit : Node_Id;
|
|
Nam : Node_Id;
|
|
N : Node_Id)
|
|
is
|
|
Loc : constant Source_Ptr := Sloc (Nam);
|
|
Unum : Unit_Number_Type;
|
|
Withn : Node_Id;
|
|
|
|
function Previous_Withed_Unit (W : Node_Id) return Boolean;
|
|
-- Returns true if the context already includes a with_clause for
|
|
-- this unit. If the with_clause is non-limited, the unit is fully
|
|
-- visible and an implicit limited_with should not be created. If
|
|
-- there is already a limited_with clause for W, a second one is
|
|
-- simply redundant.
|
|
|
|
--------------------------
|
|
-- Previous_Withed_Unit --
|
|
--------------------------
|
|
|
|
function Previous_Withed_Unit (W : Node_Id) return Boolean is
|
|
Item : Node_Id;
|
|
|
|
begin
|
|
-- A limited with_clause cannot appear in the same context_clause
|
|
-- as a nonlimited with_clause which mentions the same library.
|
|
|
|
Item := First (Context_Items (Comp_Unit));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Library_Unit (Item) = Library_Unit (W)
|
|
then
|
|
return True;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
return False;
|
|
end Previous_Withed_Unit;
|
|
|
|
-- Start of processing for Expand_Limited_With_Clause
|
|
|
|
begin
|
|
New_Nodes_OK := New_Nodes_OK + 1;
|
|
|
|
if Nkind (Nam) = N_Identifier then
|
|
|
|
-- Create node for name of withed unit
|
|
|
|
Withn :=
|
|
Make_With_Clause (Loc,
|
|
Name => New_Copy (Nam));
|
|
|
|
else pragma Assert (Nkind (Nam) = N_Selected_Component);
|
|
Withn :=
|
|
Make_With_Clause (Loc,
|
|
Name => Make_Selected_Component (Loc,
|
|
Prefix => New_Copy_Tree (Prefix (Nam)),
|
|
Selector_Name => Selector_Name (Nam)));
|
|
Set_Parent (Withn, Parent (N));
|
|
end if;
|
|
|
|
Set_Limited_Present (Withn);
|
|
Set_First_Name (Withn);
|
|
Set_Implicit_With (Withn);
|
|
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Get_Spec_Name (Get_Unit_Name (Nam)),
|
|
Required => True,
|
|
Subunit => False,
|
|
Error_Node => Nam);
|
|
|
|
-- Do not generate a limited_with_clause on the current unit.
|
|
-- This path is taken when a unit has a limited_with clause on
|
|
-- one of its child units.
|
|
|
|
if Unum = Current_Sem_Unit then
|
|
return;
|
|
end if;
|
|
|
|
Set_Library_Unit (Withn, Cunit (Unum));
|
|
Set_Corresponding_Spec
|
|
(Withn, Specification (Unit (Cunit (Unum))));
|
|
|
|
if not Previous_Withed_Unit (Withn) then
|
|
Prepend (Withn, Context_Items (Parent (N)));
|
|
Mark_Rewrite_Insertion (Withn);
|
|
|
|
-- Add implicit limited_with_clauses for parents of child units
|
|
-- mentioned in limited_with clauses.
|
|
|
|
if Nkind (Nam) = N_Selected_Component then
|
|
Expand_Limited_With_Clause (Comp_Unit, Prefix (Nam), N);
|
|
end if;
|
|
|
|
Analyze (Withn);
|
|
|
|
if not Limited_View_Installed (Withn) then
|
|
Install_Limited_Withed_Unit (Withn);
|
|
end if;
|
|
end if;
|
|
|
|
New_Nodes_OK := New_Nodes_OK - 1;
|
|
end Expand_Limited_With_Clause;
|
|
|
|
-- Start of processing for Install_Limited_Context_Clauses
|
|
|
|
begin
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Limited_Present (Item)
|
|
then
|
|
if Nkind (Name (Item)) = N_Selected_Component then
|
|
Expand_Limited_With_Clause
|
|
(Comp_Unit => N, Nam => Prefix (Name (Item)), N => Item);
|
|
end if;
|
|
|
|
Check_Private_Limited_Withed_Unit (Item);
|
|
|
|
if not Implicit_With (Item)
|
|
and then Is_Child_Spec (Unit (N))
|
|
then
|
|
Check_Renamings (Parent_Spec (Unit (N)), Item);
|
|
end if;
|
|
|
|
-- A unit may have a limited with on itself if it has a
|
|
-- limited with_clause on one of its child units. In that
|
|
-- case it is already being compiled and it makes no sense
|
|
-- to install its limited view.
|
|
|
|
if Library_Unit (Item) /= Cunit (Current_Sem_Unit)
|
|
and then not Limited_View_Installed (Item)
|
|
then
|
|
Install_Limited_Withed_Unit (Item);
|
|
end if;
|
|
|
|
-- All items other than Limited_With clauses are ignored (they were
|
|
-- installed separately early on by Install_Context_Clause).
|
|
|
|
else
|
|
null;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Ada 2005 (AI-412): Examine the visible declarations of a package
|
|
-- spec, looking for incomplete subtype declarations of incomplete
|
|
-- types visible through a limited with clause.
|
|
|
|
if Ada_Version >= Ada_05
|
|
and then Analyzed (N)
|
|
and then Nkind (Unit (N)) = N_Package_Declaration
|
|
then
|
|
declare
|
|
Decl : Node_Id;
|
|
Def_Id : Entity_Id;
|
|
Non_Lim_View : Entity_Id;
|
|
|
|
begin
|
|
Decl := First (Visible_Declarations (Specification (Unit (N))));
|
|
while Present (Decl) loop
|
|
if Nkind (Decl) = N_Subtype_Declaration
|
|
and then
|
|
Ekind (Defining_Identifier (Decl)) = E_Incomplete_Subtype
|
|
and then
|
|
From_With_Type (Defining_Identifier (Decl))
|
|
then
|
|
Def_Id := Defining_Identifier (Decl);
|
|
Non_Lim_View := Non_Limited_View (Def_Id);
|
|
|
|
-- Convert an incomplete subtype declaration into a
|
|
-- corresponding non-limited view subtype declaration.
|
|
|
|
Set_Subtype_Indication (Decl,
|
|
New_Reference_To (Non_Lim_View, Sloc (Def_Id)));
|
|
Set_Etype (Def_Id, Non_Lim_View);
|
|
Set_Ekind (Def_Id, Subtype_Kind (Ekind (Non_Lim_View)));
|
|
Set_Analyzed (Decl, False);
|
|
|
|
-- Reanalyze the declaration, suppressing the call to
|
|
-- Enter_Name to avoid duplicate names.
|
|
|
|
Analyze_Subtype_Declaration
|
|
(N => Decl,
|
|
Skip => True);
|
|
end if;
|
|
|
|
Next (Decl);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end Install_Limited_Context_Clauses;
|
|
|
|
---------------------
|
|
-- Install_Parents --
|
|
---------------------
|
|
|
|
procedure Install_Parents (Lib_Unit : Node_Id; Is_Private : Boolean) is
|
|
P : Node_Id;
|
|
E_Name : Entity_Id;
|
|
P_Name : Entity_Id;
|
|
P_Spec : Node_Id;
|
|
|
|
begin
|
|
P := Unit (Parent_Spec (Lib_Unit));
|
|
P_Name := Get_Parent_Entity (P);
|
|
|
|
if Etype (P_Name) = Any_Type then
|
|
return;
|
|
end if;
|
|
|
|
if Ekind (P_Name) = E_Generic_Package
|
|
and then Nkind (Lib_Unit) /= N_Generic_Subprogram_Declaration
|
|
and then Nkind (Lib_Unit) /= N_Generic_Package_Declaration
|
|
and then Nkind (Lib_Unit) not in N_Generic_Renaming_Declaration
|
|
then
|
|
Error_Msg_N
|
|
("child of a generic package must be a generic unit", Lib_Unit);
|
|
|
|
elsif not Is_Package_Or_Generic_Package (P_Name) then
|
|
Error_Msg_N
|
|
("parent unit must be package or generic package", Lib_Unit);
|
|
raise Unrecoverable_Error;
|
|
|
|
elsif Present (Renamed_Object (P_Name)) then
|
|
Error_Msg_N ("parent unit cannot be a renaming", Lib_Unit);
|
|
raise Unrecoverable_Error;
|
|
|
|
-- Verify that a child of an instance is itself an instance, or
|
|
-- the renaming of one. Given that an instance that is a unit is
|
|
-- replaced with a package declaration, check against the original
|
|
-- node. The parent may be currently being instantiated, in which
|
|
-- case it appears as a declaration, but the generic_parent is
|
|
-- already established indicating that we deal with an instance.
|
|
|
|
elsif Nkind (Original_Node (P)) = N_Package_Instantiation then
|
|
|
|
if Nkind (Lib_Unit) in N_Renaming_Declaration
|
|
or else Nkind (Original_Node (Lib_Unit)) in N_Generic_Instantiation
|
|
or else
|
|
(Nkind (Lib_Unit) = N_Package_Declaration
|
|
and then Present (Generic_Parent (Specification (Lib_Unit))))
|
|
then
|
|
null;
|
|
else
|
|
Error_Msg_N
|
|
("child of an instance must be an instance or renaming",
|
|
Lib_Unit);
|
|
end if;
|
|
end if;
|
|
|
|
-- This is the recursive call that ensures all parents are loaded
|
|
|
|
if Is_Child_Spec (P) then
|
|
Install_Parents (P,
|
|
Is_Private or else Private_Present (Parent (Lib_Unit)));
|
|
end if;
|
|
|
|
-- Now we can install the context for this parent
|
|
|
|
Install_Context_Clauses (Parent_Spec (Lib_Unit));
|
|
Install_Limited_Context_Clauses (Parent_Spec (Lib_Unit));
|
|
Install_Siblings (P_Name, Parent (Lib_Unit));
|
|
|
|
-- The child unit is in the declarative region of the parent. The
|
|
-- parent must therefore appear in the scope stack and be visible,
|
|
-- as when compiling the corresponding body. If the child unit is
|
|
-- private or it is a package body, private declarations must be
|
|
-- accessible as well. Use declarations in the parent must also
|
|
-- be installed. Finally, other child units of the same parent that
|
|
-- are in the context are immediately visible.
|
|
|
|
-- Find entity for compilation unit, and set its private descendant
|
|
-- status as needed.
|
|
|
|
E_Name := Defining_Entity (Lib_Unit);
|
|
|
|
Set_Is_Child_Unit (E_Name);
|
|
|
|
Set_Is_Private_Descendant (E_Name,
|
|
Is_Private_Descendant (P_Name)
|
|
or else Private_Present (Parent (Lib_Unit)));
|
|
|
|
P_Spec := Specification (Unit_Declaration_Node (P_Name));
|
|
New_Scope (P_Name);
|
|
|
|
-- Save current visibility of unit
|
|
|
|
Scope_Stack.Table (Scope_Stack.Last).Previous_Visibility :=
|
|
Is_Immediately_Visible (P_Name);
|
|
Set_Is_Immediately_Visible (P_Name);
|
|
Install_Visible_Declarations (P_Name);
|
|
Set_Use (Visible_Declarations (P_Spec));
|
|
|
|
-- If the parent is a generic unit, its formal part may contain
|
|
-- formal packages and use clauses for them.
|
|
|
|
if Ekind (P_Name) = E_Generic_Package then
|
|
Set_Use (Generic_Formal_Declarations (Parent (P_Spec)));
|
|
end if;
|
|
|
|
if Is_Private
|
|
or else Private_Present (Parent (Lib_Unit))
|
|
then
|
|
Install_Private_Declarations (P_Name);
|
|
Install_Private_With_Clauses (P_Name);
|
|
Set_Use (Private_Declarations (P_Spec));
|
|
end if;
|
|
end Install_Parents;
|
|
|
|
----------------------------------
|
|
-- Install_Private_With_Clauses --
|
|
----------------------------------
|
|
|
|
procedure Install_Private_With_Clauses (P : Entity_Id) is
|
|
Decl : constant Node_Id := Unit_Declaration_Node (P);
|
|
Item : Node_Id;
|
|
|
|
begin
|
|
if Debug_Flag_I then
|
|
Write_Str ("install private with clauses of ");
|
|
Write_Name (Chars (P));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
if Nkind (Parent (Decl)) = N_Compilation_Unit then
|
|
Item := First (Context_Items (Parent (Decl)));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Private_Present (Item)
|
|
then
|
|
if Limited_Present (Item) then
|
|
if not Limited_View_Installed (Item) then
|
|
Install_Limited_Withed_Unit (Item);
|
|
end if;
|
|
else
|
|
Install_Withed_Unit (Item, Private_With_OK => True);
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end if;
|
|
end Install_Private_With_Clauses;
|
|
|
|
----------------------
|
|
-- Install_Siblings --
|
|
----------------------
|
|
|
|
procedure Install_Siblings (U_Name : Entity_Id; N : Node_Id) is
|
|
Item : Node_Id;
|
|
Id : Entity_Id;
|
|
Prev : Entity_Id;
|
|
begin
|
|
-- Iterate over explicit with clauses, and check whether the
|
|
-- scope of each entity is an ancestor of the current unit, in
|
|
-- which case it is immediately visible.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
|
|
-- Do not install private_with_clauses if the unit is a package
|
|
-- declaration, unless it is itself a private child unit.
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Implicit_With (Item)
|
|
and then not Limited_Present (Item)
|
|
and then
|
|
(not Private_Present (Item)
|
|
or else Nkind (Unit (N)) /= N_Package_Declaration
|
|
or else Private_Present (N))
|
|
then
|
|
Id := Entity (Name (Item));
|
|
|
|
if Is_Child_Unit (Id)
|
|
and then Is_Ancestor_Package (Scope (Id), U_Name)
|
|
then
|
|
Set_Is_Immediately_Visible (Id);
|
|
|
|
-- Check for the presence of another unit in the context,
|
|
-- that may be inadvertently hidden by the child.
|
|
|
|
Prev := Current_Entity (Id);
|
|
|
|
if Present (Prev)
|
|
and then Is_Immediately_Visible (Prev)
|
|
and then not Is_Child_Unit (Prev)
|
|
then
|
|
declare
|
|
Clause : Node_Id;
|
|
|
|
begin
|
|
Clause := First (Context_Items (N));
|
|
while Present (Clause) loop
|
|
if Nkind (Clause) = N_With_Clause
|
|
and then Entity (Name (Clause)) = Prev
|
|
then
|
|
Error_Msg_NE
|
|
("child unit& hides compilation unit " &
|
|
"with the same name?",
|
|
Name (Item), Id);
|
|
exit;
|
|
end if;
|
|
|
|
Next (Clause);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
-- The With_Clause may be on a grand-child or one of its
|
|
-- further descendants, which makes a child immediately visible.
|
|
-- Examine ancestry to determine whether such a child exists.
|
|
-- For example, if current unit is A.C, and with_clause is on
|
|
-- A.X.Y.Z, then X is immediately visible.
|
|
|
|
elsif Is_Child_Unit (Id) then
|
|
declare
|
|
Par : Entity_Id;
|
|
|
|
begin
|
|
Par := Scope (Id);
|
|
while Is_Child_Unit (Par) loop
|
|
if Is_Ancestor_Package (Scope (Par), U_Name) then
|
|
Set_Is_Immediately_Visible (Par);
|
|
exit;
|
|
end if;
|
|
|
|
Par := Scope (Par);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Install_Siblings;
|
|
|
|
-------------------------------
|
|
-- Install_Limited_With_Unit --
|
|
-------------------------------
|
|
|
|
procedure Install_Limited_Withed_Unit (N : Node_Id) is
|
|
P_Unit : constant Entity_Id := Unit (Library_Unit (N));
|
|
E : Entity_Id;
|
|
P : Entity_Id;
|
|
Is_Child_Package : Boolean := False;
|
|
|
|
Lim_Header : Entity_Id;
|
|
Lim_Typ : Entity_Id;
|
|
|
|
function Is_Visible_Through_Renamings (P : Entity_Id) return Boolean;
|
|
-- Check if some package installed though normal with-clauses has a
|
|
-- renaming declaration of package P. AARM 10.1.2(21/2).
|
|
|
|
----------------------------------
|
|
-- Is_Visible_Through_Renamings --
|
|
----------------------------------
|
|
|
|
function Is_Visible_Through_Renamings (P : Entity_Id) return Boolean is
|
|
Kind : constant Node_Kind :=
|
|
Nkind (Unit (Cunit (Current_Sem_Unit)));
|
|
Aux_Unit : Node_Id;
|
|
Item : Node_Id;
|
|
Decl : Entity_Id;
|
|
|
|
begin
|
|
-- Example of the error detected by this subprogram:
|
|
|
|
-- package P is
|
|
-- type T is ...
|
|
-- end P;
|
|
|
|
-- with P;
|
|
-- package Q is
|
|
-- package Ren_P renames P;
|
|
-- end Q;
|
|
|
|
-- with Q;
|
|
-- package R is ...
|
|
|
|
-- limited with P; -- ERROR
|
|
-- package R.C is ...
|
|
|
|
Aux_Unit := Cunit (Current_Sem_Unit);
|
|
|
|
loop
|
|
Item := First (Context_Items (Aux_Unit));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then not Limited_Present (Item)
|
|
and then Nkind (Unit (Library_Unit (Item)))
|
|
= N_Package_Declaration
|
|
then
|
|
Decl :=
|
|
First (Visible_Declarations
|
|
(Specification (Unit (Library_Unit (Item)))));
|
|
while Present (Decl) loop
|
|
if Nkind (Decl) = N_Package_Renaming_Declaration
|
|
and then Entity (Name (Decl)) = P
|
|
then
|
|
-- Generate the error message only if the current unit
|
|
-- is a package declaration; in case of subprogram
|
|
-- bodies and package bodies we just return true to
|
|
-- indicate that the limited view must not be
|
|
-- installed.
|
|
|
|
if Kind = N_Package_Declaration then
|
|
Error_Msg_N
|
|
("simultaneous visibility of the limited and" &
|
|
" unlimited views not allowed", N);
|
|
Error_Msg_Sloc := Sloc (Item);
|
|
Error_Msg_NE
|
|
("\unlimited view of & visible through the" &
|
|
" context clause found #", N, P);
|
|
Error_Msg_Sloc := Sloc (Decl);
|
|
Error_Msg_NE ("\and the renaming found #", N, P);
|
|
end if;
|
|
|
|
return True;
|
|
end if;
|
|
|
|
Next (Decl);
|
|
end loop;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
if Present (Library_Unit (Aux_Unit)) then
|
|
if Aux_Unit = Library_Unit (Aux_Unit) then
|
|
|
|
-- Aux_Unit is a body that acts as a spec. Clause has
|
|
-- already been flagged as illegal.
|
|
|
|
return False;
|
|
|
|
else
|
|
Aux_Unit := Library_Unit (Aux_Unit);
|
|
end if;
|
|
else
|
|
Aux_Unit := Parent_Spec (Unit (Aux_Unit));
|
|
end if;
|
|
|
|
exit when No (Aux_Unit);
|
|
end loop;
|
|
|
|
return False;
|
|
end Is_Visible_Through_Renamings;
|
|
|
|
-- Start of processing for Install_Limited_Withed_Unit
|
|
|
|
begin
|
|
pragma Assert (not Limited_View_Installed (N));
|
|
|
|
-- In case of limited with_clause on subprograms, generics, instances,
|
|
-- or renamings, the corresponding error was previously posted and we
|
|
-- have nothing to do here.
|
|
|
|
if Nkind (P_Unit) /= N_Package_Declaration then
|
|
return;
|
|
end if;
|
|
|
|
P := Defining_Unit_Name (Specification (P_Unit));
|
|
|
|
-- Handle child packages
|
|
|
|
if Nkind (P) = N_Defining_Program_Unit_Name then
|
|
Is_Child_Package := True;
|
|
P := Defining_Identifier (P);
|
|
end if;
|
|
|
|
-- Do not install the limited-view if the full-view is already visible
|
|
-- through renaming declarations.
|
|
|
|
if Is_Visible_Through_Renamings (P) then
|
|
return;
|
|
end if;
|
|
|
|
-- A common use of the limited-with is to have a limited-with
|
|
-- in the package spec, and a normal with in its package body.
|
|
-- For example:
|
|
|
|
-- limited with X; -- [1]
|
|
-- package A is ...
|
|
|
|
-- with X; -- [2]
|
|
-- package body A is ...
|
|
|
|
-- The compilation of A's body installs the context clauses found at [2]
|
|
-- and then the context clauses of its specification (found at [1]). As
|
|
-- a consequence, at [1] the specification of X has been analyzed and it
|
|
-- is immediately visible. According to the semantics of limited-with
|
|
-- context clauses we don't install the limited view because the full
|
|
-- view of X supersedes its limited view.
|
|
|
|
if Analyzed (P_Unit)
|
|
and then (Is_Immediately_Visible (P)
|
|
or else (Is_Child_Package
|
|
and then Is_Visible_Child_Unit (P)))
|
|
then
|
|
-- Ada 2005 (AI-262): Install the private declarations of P
|
|
|
|
if Private_Present (N)
|
|
and then not In_Private_Part (P)
|
|
then
|
|
declare
|
|
Id : Entity_Id;
|
|
|
|
begin
|
|
Id := First_Private_Entity (P);
|
|
while Present (Id) loop
|
|
if not Is_Internal (Id)
|
|
and then not Is_Child_Unit (Id)
|
|
then
|
|
if not In_Chain (Id) then
|
|
Set_Homonym (Id, Current_Entity (Id));
|
|
Set_Current_Entity (Id);
|
|
end if;
|
|
|
|
Set_Is_Immediately_Visible (Id);
|
|
end if;
|
|
|
|
Next_Entity (Id);
|
|
end loop;
|
|
|
|
Set_In_Private_Part (P);
|
|
end;
|
|
end if;
|
|
|
|
return;
|
|
end if;
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str ("install limited view of ");
|
|
Write_Name (Chars (P));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
-- If the unit has not been analyzed and the limited view has not been
|
|
-- already installed then we install it.
|
|
|
|
if not Analyzed (P_Unit) then
|
|
if not In_Chain (P) then
|
|
|
|
-- Minimum decoration
|
|
|
|
Set_Ekind (P, E_Package);
|
|
Set_Etype (P, Standard_Void_Type);
|
|
Set_Scope (P, Standard_Standard);
|
|
|
|
if Is_Child_Package then
|
|
Set_Is_Child_Unit (P);
|
|
Set_Is_Visible_Child_Unit (P);
|
|
Set_Scope (P, Defining_Entity (Unit (Parent_Spec (P_Unit))));
|
|
end if;
|
|
|
|
-- Place entity on visibility structure
|
|
|
|
Set_Homonym (P, Current_Entity (P));
|
|
Set_Current_Entity (P);
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str (" (homonym) chain ");
|
|
Write_Name (Chars (P));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
-- Install the incomplete view. The first element of the limited
|
|
-- view is a header (an E_Package entity) used to reference the
|
|
-- first shadow entity in the private part of the package.
|
|
|
|
Lim_Header := Limited_View (P);
|
|
Lim_Typ := First_Entity (Lim_Header);
|
|
|
|
while Present (Lim_Typ)
|
|
and then Lim_Typ /= First_Private_Entity (Lim_Header)
|
|
loop
|
|
Set_Homonym (Lim_Typ, Current_Entity (Lim_Typ));
|
|
Set_Current_Entity (Lim_Typ);
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str (" (homonym) chain ");
|
|
Write_Name (Chars (Lim_Typ));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
Next_Entity (Lim_Typ);
|
|
end loop;
|
|
end if;
|
|
|
|
-- If the unit appears in a previous regular with_clause, the regular
|
|
-- entities of the public part of the withed package must be replaced
|
|
-- by the shadow ones.
|
|
|
|
-- This code must be kept synchronized with the code that replaces the
|
|
-- the shadow entities by the real entities (see body of Remove_Limited
|
|
-- With_Clause); otherwise the contents of the homonym chains are not
|
|
-- consistent.
|
|
|
|
else
|
|
-- Hide all the type entities of the public part of the package to
|
|
-- avoid its usage. This is needed to cover all the subtype decla-
|
|
-- rations because we do not remove them from the homonym chain.
|
|
|
|
E := First_Entity (P);
|
|
while Present (E) and then E /= First_Private_Entity (P) loop
|
|
if Is_Type (E) then
|
|
Set_Was_Hidden (E, Is_Hidden (E));
|
|
Set_Is_Hidden (E);
|
|
end if;
|
|
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
-- Replace the real entities by the shadow entities of the limited
|
|
-- view. The first element of the limited view is a header that is
|
|
-- used to reference the first shadow entity in the private part
|
|
-- of the package.
|
|
|
|
Lim_Header := Limited_View (P);
|
|
|
|
Lim_Typ := First_Entity (Lim_Header);
|
|
while Present (Lim_Typ)
|
|
and then Lim_Typ /= First_Private_Entity (Lim_Header)
|
|
loop
|
|
pragma Assert (not In_Chain (Lim_Typ));
|
|
|
|
-- Do not unchain nested packages and child units
|
|
|
|
if Ekind (Lim_Typ) /= E_Package
|
|
and then not Is_Child_Unit (Lim_Typ)
|
|
then
|
|
declare
|
|
Prev : Entity_Id;
|
|
|
|
begin
|
|
Prev := Current_Entity (Lim_Typ);
|
|
|
|
-- Handle incomplete types
|
|
|
|
if Ekind (Prev) = E_Incomplete_Type then
|
|
E := Full_View (Prev);
|
|
else
|
|
E := Prev;
|
|
end if;
|
|
|
|
-- Replace E in the homonyms list
|
|
|
|
if E = Non_Limited_View (Lim_Typ) then
|
|
Set_Homonym (Lim_Typ, Homonym (Prev));
|
|
Set_Current_Entity (Lim_Typ);
|
|
|
|
else
|
|
loop
|
|
E := Homonym (Prev);
|
|
pragma Assert (Present (E));
|
|
|
|
-- Handle incomplete types
|
|
|
|
if Ekind (E) = E_Incomplete_Type then
|
|
E := Full_View (E);
|
|
end if;
|
|
|
|
exit when E = Non_Limited_View (Lim_Typ);
|
|
|
|
Prev := Homonym (Prev);
|
|
end loop;
|
|
|
|
Set_Homonym (Lim_Typ, Homonym (Homonym (Prev)));
|
|
Set_Homonym (Prev, Lim_Typ);
|
|
end if;
|
|
end;
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str (" (homonym) chain ");
|
|
Write_Name (Chars (Lim_Typ));
|
|
Write_Eol;
|
|
end if;
|
|
end if;
|
|
|
|
Next_Entity (Lim_Typ);
|
|
end loop;
|
|
end if;
|
|
|
|
-- The package must be visible while the limited-with clause is active
|
|
-- because references to the type P.T must resolve in the usual way.
|
|
-- In addition, we remember that the limited-view has been installed to
|
|
-- uninstall it at the point of context removal.
|
|
|
|
Set_Is_Immediately_Visible (P);
|
|
Set_Limited_View_Installed (N);
|
|
|
|
-- If the package in the limited_with clause is a child unit, the
|
|
-- clause is unanalyzed and appears as a selected component. Recast
|
|
-- it as an expanded name so that the entity can be properly set. Use
|
|
-- entity of parent, if available, for higher ancestors in the name.
|
|
|
|
if Nkind (Name (N)) = N_Selected_Component then
|
|
declare
|
|
Nam : Node_Id;
|
|
Ent : Entity_Id;
|
|
|
|
begin
|
|
Nam := Name (N);
|
|
Ent := P;
|
|
while Nkind (Nam) = N_Selected_Component
|
|
and then Present (Ent)
|
|
loop
|
|
Change_Selected_Component_To_Expanded_Name (Nam);
|
|
|
|
-- Set entity of parent identifiers if the unit is a child
|
|
-- unit. This ensures that the tree is properly formed from
|
|
-- semantic point of view (e.g. for ASIS queries).
|
|
|
|
Set_Entity (Nam, Ent);
|
|
|
|
Nam := Prefix (Nam);
|
|
Ent := Scope (Ent);
|
|
|
|
-- Set entity of last ancestor
|
|
|
|
if Nkind (Nam) = N_Identifier then
|
|
Set_Entity (Nam, Ent);
|
|
end if;
|
|
end loop;
|
|
end;
|
|
end if;
|
|
|
|
Set_Entity (Name (N), P);
|
|
Set_From_With_Type (P);
|
|
end Install_Limited_Withed_Unit;
|
|
|
|
-------------------------
|
|
-- Install_Withed_Unit --
|
|
-------------------------
|
|
|
|
procedure Install_Withed_Unit
|
|
(With_Clause : Node_Id;
|
|
Private_With_OK : Boolean := False)
|
|
is
|
|
Uname : constant Entity_Id := Entity (Name (With_Clause));
|
|
P : constant Entity_Id := Scope (Uname);
|
|
|
|
begin
|
|
-- Ada 2005 (AI-262): Do not install the private withed unit if we are
|
|
-- compiling a package declaration and the Private_With_OK flag was not
|
|
-- set by the caller. These declarations will be installed later (before
|
|
-- analyzing the private part of the package).
|
|
|
|
if Private_Present (With_Clause)
|
|
and then Nkind (Unit (Parent (With_Clause))) = N_Package_Declaration
|
|
and then not (Private_With_OK)
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
if Debug_Flag_I then
|
|
if Private_Present (With_Clause) then
|
|
Write_Str ("install private withed unit ");
|
|
else
|
|
Write_Str ("install withed unit ");
|
|
end if;
|
|
|
|
Write_Name (Chars (Uname));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
-- We do not apply the restrictions to an internal unit unless
|
|
-- we are compiling the internal unit as a main unit. This check
|
|
-- is also skipped for dummy units (for missing packages).
|
|
|
|
if Sloc (Uname) /= No_Location
|
|
and then (not Is_Internal_File_Name (Unit_File_Name (Current_Sem_Unit))
|
|
or else Current_Sem_Unit = Main_Unit)
|
|
then
|
|
Check_Restricted_Unit
|
|
(Unit_Name (Get_Source_Unit (Uname)), With_Clause);
|
|
end if;
|
|
|
|
if P /= Standard_Standard then
|
|
|
|
-- If the unit is not analyzed after analysis of the with clause and
|
|
-- it is an instantiation then it awaits a body and is the main unit.
|
|
-- Its appearance in the context of some other unit indicates a
|
|
-- circular dependency (DEC suite perversity).
|
|
|
|
if not Analyzed (Uname)
|
|
and then Nkind (Parent (Uname)) = N_Package_Instantiation
|
|
then
|
|
Error_Msg_N
|
|
("instantiation depends on itself", Name (With_Clause));
|
|
|
|
elsif not Is_Visible_Child_Unit (Uname) then
|
|
Set_Is_Visible_Child_Unit (Uname);
|
|
|
|
-- If the child unit appears in the context of its parent, it is
|
|
-- immediately visible.
|
|
|
|
if In_Open_Scopes (Scope (Uname)) then
|
|
Set_Is_Immediately_Visible (Uname);
|
|
end if;
|
|
|
|
if Is_Generic_Instance (Uname)
|
|
and then Ekind (Uname) in Subprogram_Kind
|
|
then
|
|
-- Set flag as well on the visible entity that denotes the
|
|
-- instance, which renames the current one.
|
|
|
|
Set_Is_Visible_Child_Unit
|
|
(Related_Instance
|
|
(Defining_Entity (Unit (Library_Unit (With_Clause)))));
|
|
end if;
|
|
|
|
-- The parent unit may have been installed already, and may have
|
|
-- appeared in a use clause.
|
|
|
|
if In_Use (Scope (Uname)) then
|
|
Set_Is_Potentially_Use_Visible (Uname);
|
|
end if;
|
|
|
|
Set_Context_Installed (With_Clause);
|
|
end if;
|
|
|
|
elsif not Is_Immediately_Visible (Uname) then
|
|
if not Private_Present (With_Clause)
|
|
or else Private_With_OK
|
|
then
|
|
Set_Is_Immediately_Visible (Uname);
|
|
end if;
|
|
|
|
Set_Context_Installed (With_Clause);
|
|
end if;
|
|
|
|
-- A with-clause overrides a with-type clause: there are no restric-
|
|
-- tions on the use of package entities.
|
|
|
|
if Ekind (Uname) = E_Package then
|
|
Set_From_With_Type (Uname, False);
|
|
end if;
|
|
|
|
-- Ada 2005 (AI-377): it is illegal for a with_clause to name a child
|
|
-- unit if there is a visible homograph for it declared in the same
|
|
-- declarative region. This pathological case can only arise when an
|
|
-- instance I1 of a generic unit G1 has an explicit child unit I1.G2,
|
|
-- G1 has a generic child also named G2, and the context includes with_
|
|
-- clauses for both I1.G2 and for G1.G2, making an implicit declaration
|
|
-- of I1.G2 visible as well. If the child unit is named Standard, do
|
|
-- not apply the check to the Standard package itself.
|
|
|
|
if Is_Child_Unit (Uname)
|
|
and then Is_Visible_Child_Unit (Uname)
|
|
and then Ada_Version >= Ada_05
|
|
then
|
|
declare
|
|
Decl1 : constant Node_Id := Unit_Declaration_Node (P);
|
|
Decl2 : Node_Id;
|
|
P2 : Entity_Id;
|
|
U2 : Entity_Id;
|
|
|
|
begin
|
|
U2 := Homonym (Uname);
|
|
while Present (U2)
|
|
and U2 /= Standard_Standard
|
|
loop
|
|
P2 := Scope (U2);
|
|
Decl2 := Unit_Declaration_Node (P2);
|
|
|
|
if Is_Child_Unit (U2)
|
|
and then Is_Visible_Child_Unit (U2)
|
|
then
|
|
if Is_Generic_Instance (P)
|
|
and then Nkind (Decl1) = N_Package_Declaration
|
|
and then Generic_Parent (Specification (Decl1)) = P2
|
|
then
|
|
Error_Msg_N ("illegal with_clause", With_Clause);
|
|
Error_Msg_N
|
|
("\child unit has visible homograph" &
|
|
" ('R'M 8.3(26), 10.1.1(19))",
|
|
With_Clause);
|
|
exit;
|
|
|
|
elsif Is_Generic_Instance (P2)
|
|
and then Nkind (Decl2) = N_Package_Declaration
|
|
and then Generic_Parent (Specification (Decl2)) = P
|
|
then
|
|
-- With_clause for child unit of instance appears before
|
|
-- in the context. We want to place the error message on
|
|
-- it, not on the generic child unit itself.
|
|
|
|
declare
|
|
Prev_Clause : Node_Id;
|
|
|
|
begin
|
|
Prev_Clause := First (List_Containing (With_Clause));
|
|
while Entity (Name (Prev_Clause)) /= U2 loop
|
|
Next (Prev_Clause);
|
|
end loop;
|
|
|
|
pragma Assert (Present (Prev_Clause));
|
|
Error_Msg_N ("illegal with_clause", Prev_Clause);
|
|
Error_Msg_N
|
|
("\child unit has visible homograph" &
|
|
" ('R'M 8.3(26), 10.1.1(19))",
|
|
Prev_Clause);
|
|
exit;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
U2 := Homonym (U2);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end Install_Withed_Unit;
|
|
|
|
-------------------
|
|
-- Is_Child_Spec --
|
|
-------------------
|
|
|
|
function Is_Child_Spec (Lib_Unit : Node_Id) return Boolean is
|
|
K : constant Node_Kind := Nkind (Lib_Unit);
|
|
|
|
begin
|
|
return (K in N_Generic_Declaration or else
|
|
K in N_Generic_Instantiation or else
|
|
K in N_Generic_Renaming_Declaration or else
|
|
K = N_Package_Declaration or else
|
|
K = N_Package_Renaming_Declaration or else
|
|
K = N_Subprogram_Declaration or else
|
|
K = N_Subprogram_Renaming_Declaration)
|
|
and then Present (Parent_Spec (Lib_Unit));
|
|
end Is_Child_Spec;
|
|
|
|
-----------------------
|
|
-- Load_Needed_Body --
|
|
-----------------------
|
|
|
|
-- N is a generic unit named in a with clause, or else it is
|
|
-- a unit that contains a generic unit or an inlined function.
|
|
-- In order to perform an instantiation, the body of the unit
|
|
-- must be present. If the unit itself is generic, we assume
|
|
-- that an instantiation follows, and load and analyze the body
|
|
-- unconditionally. This forces analysis of the spec as well.
|
|
|
|
-- If the unit is not generic, but contains a generic unit, it
|
|
-- is loaded on demand, at the point of instantiation (see ch12).
|
|
|
|
procedure Load_Needed_Body (N : Node_Id; OK : out Boolean) is
|
|
Body_Name : Unit_Name_Type;
|
|
Unum : Unit_Number_Type;
|
|
|
|
Save_Style_Check : constant Boolean := Opt.Style_Check;
|
|
-- The loading and analysis is done with style checks off
|
|
|
|
begin
|
|
if not GNAT_Mode then
|
|
Style_Check := False;
|
|
end if;
|
|
|
|
Body_Name := Get_Body_Name (Get_Unit_Name (Unit (N)));
|
|
Unum :=
|
|
Load_Unit
|
|
(Load_Name => Body_Name,
|
|
Required => False,
|
|
Subunit => False,
|
|
Error_Node => N,
|
|
Renamings => True);
|
|
|
|
if Unum = No_Unit then
|
|
OK := False;
|
|
|
|
else
|
|
Compiler_State := Analyzing; -- reset after load
|
|
|
|
if not Fatal_Error (Unum) or else Try_Semantics then
|
|
if Debug_Flag_L then
|
|
Write_Str ("*** Loaded generic body");
|
|
Write_Eol;
|
|
end if;
|
|
|
|
Semantics (Cunit (Unum));
|
|
end if;
|
|
|
|
OK := True;
|
|
end if;
|
|
|
|
Style_Check := Save_Style_Check;
|
|
end Load_Needed_Body;
|
|
|
|
-------------------------
|
|
-- Build_Limited_Views --
|
|
-------------------------
|
|
|
|
procedure Build_Limited_Views (N : Node_Id) is
|
|
Unum : constant Unit_Number_Type := Get_Source_Unit (Library_Unit (N));
|
|
P : constant Entity_Id := Cunit_Entity (Unum);
|
|
|
|
Spec : Node_Id; -- To denote a package specification
|
|
Lim_Typ : Entity_Id; -- To denote shadow entities
|
|
Comp_Typ : Entity_Id; -- To denote real entities
|
|
|
|
Lim_Header : Entity_Id; -- Package entity
|
|
Last_Lim_E : Entity_Id := Empty; -- Last limited entity built
|
|
Last_Pub_Lim_E : Entity_Id; -- To set the first private entity
|
|
|
|
procedure Decorate_Incomplete_Type
|
|
(E : Entity_Id;
|
|
Scop : Entity_Id);
|
|
-- Add attributes of an incomplete type to a shadow entity. The same
|
|
-- attributes are placed on the real entity, so that gigi receives
|
|
-- a consistent view.
|
|
|
|
procedure Decorate_Package_Specification (P : Entity_Id);
|
|
-- Add attributes of a package entity to the entity in a package
|
|
-- declaration
|
|
|
|
procedure Decorate_Tagged_Type
|
|
(Loc : Source_Ptr;
|
|
T : Entity_Id;
|
|
Scop : Entity_Id);
|
|
-- Set basic attributes of tagged type T, including its class_wide type.
|
|
-- The parameters Loc, Scope are used to decorate the class_wide type.
|
|
|
|
procedure Build_Chain
|
|
(Scope : Entity_Id;
|
|
First_Decl : Node_Id);
|
|
-- Construct list of shadow entities and attach it to entity of
|
|
-- package that is mentioned in a limited_with clause.
|
|
|
|
function New_Internal_Shadow_Entity
|
|
(Kind : Entity_Kind;
|
|
Sloc_Value : Source_Ptr;
|
|
Id_Char : Character) return Entity_Id;
|
|
-- Build a new internal entity and append it to the list of shadow
|
|
-- entities available through the limited-header
|
|
|
|
------------------------------
|
|
-- Decorate_Incomplete_Type --
|
|
------------------------------
|
|
|
|
procedure Decorate_Incomplete_Type
|
|
(E : Entity_Id;
|
|
Scop : Entity_Id)
|
|
is
|
|
begin
|
|
Set_Ekind (E, E_Incomplete_Type);
|
|
Set_Scope (E, Scop);
|
|
Set_Etype (E, E);
|
|
Set_Is_First_Subtype (E, True);
|
|
Set_Stored_Constraint (E, No_Elist);
|
|
Set_Full_View (E, Empty);
|
|
Init_Size_Align (E);
|
|
end Decorate_Incomplete_Type;
|
|
|
|
--------------------------
|
|
-- Decorate_Tagged_Type --
|
|
--------------------------
|
|
|
|
procedure Decorate_Tagged_Type
|
|
(Loc : Source_Ptr;
|
|
T : Entity_Id;
|
|
Scop : Entity_Id)
|
|
is
|
|
CW : Entity_Id;
|
|
|
|
begin
|
|
Decorate_Incomplete_Type (T, Scop);
|
|
Set_Is_Tagged_Type (T);
|
|
|
|
-- Build corresponding class_wide type, if not previously done
|
|
|
|
if No (Class_Wide_Type (T)) then
|
|
CW := Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
|
|
|
|
Set_Ekind (CW, E_Class_Wide_Type);
|
|
Set_Etype (CW, T);
|
|
Set_Scope (CW, Scop);
|
|
Set_Is_Tagged_Type (CW);
|
|
Set_Is_First_Subtype (CW, True);
|
|
Init_Size_Align (CW);
|
|
Set_Has_Unknown_Discriminants (CW, True);
|
|
Set_Class_Wide_Type (CW, CW);
|
|
Set_Equivalent_Type (CW, Empty);
|
|
Set_From_With_Type (CW, From_With_Type (T));
|
|
|
|
Set_Class_Wide_Type (T, CW);
|
|
end if;
|
|
end Decorate_Tagged_Type;
|
|
|
|
------------------------------------
|
|
-- Decorate_Package_Specification --
|
|
------------------------------------
|
|
|
|
procedure Decorate_Package_Specification (P : Entity_Id) is
|
|
begin
|
|
-- Place only the most basic attributes
|
|
|
|
Set_Ekind (P, E_Package);
|
|
Set_Etype (P, Standard_Void_Type);
|
|
end Decorate_Package_Specification;
|
|
|
|
--------------------------------
|
|
-- New_Internal_Shadow_Entity --
|
|
--------------------------------
|
|
|
|
function New_Internal_Shadow_Entity
|
|
(Kind : Entity_Kind;
|
|
Sloc_Value : Source_Ptr;
|
|
Id_Char : Character) return Entity_Id
|
|
is
|
|
E : constant Entity_Id :=
|
|
Make_Defining_Identifier (Sloc_Value,
|
|
Chars => New_Internal_Name (Id_Char));
|
|
|
|
begin
|
|
Set_Ekind (E, Kind);
|
|
Set_Is_Internal (E, True);
|
|
|
|
if Kind in Type_Kind then
|
|
Init_Size_Align (E);
|
|
end if;
|
|
|
|
Append_Entity (E, Lim_Header);
|
|
Last_Lim_E := E;
|
|
return E;
|
|
end New_Internal_Shadow_Entity;
|
|
|
|
-----------------
|
|
-- Build_Chain --
|
|
-----------------
|
|
|
|
procedure Build_Chain
|
|
(Scope : Entity_Id;
|
|
First_Decl : Node_Id)
|
|
is
|
|
Analyzed_Unit : constant Boolean := Analyzed (Cunit (Unum));
|
|
Is_Tagged : Boolean;
|
|
Decl : Node_Id;
|
|
|
|
begin
|
|
Decl := First_Decl;
|
|
while Present (Decl) loop
|
|
|
|
-- For each library_package_declaration in the environment, there
|
|
-- is an implicit declaration of a *limited view* of that library
|
|
-- package. The limited view of a package contains:
|
|
--
|
|
-- * For each nested package_declaration, a declaration of the
|
|
-- limited view of that package, with the same defining-
|
|
-- program-unit name.
|
|
--
|
|
-- * For each type_declaration in the visible part, an incomplete
|
|
-- type-declaration with the same defining_identifier, whose
|
|
-- completion is the type_declaration. If the type_declaration
|
|
-- is tagged, then the incomplete_type_declaration is tagged
|
|
-- incomplete.
|
|
-- The partial view is tagged if the declaration has the
|
|
-- explicit keyword, or else if it is a type extension, both
|
|
-- of which can be ascertained syntactically.
|
|
|
|
if Nkind (Decl) = N_Full_Type_Declaration then
|
|
Is_Tagged :=
|
|
(Nkind (Type_Definition (Decl)) = N_Record_Definition
|
|
and then Tagged_Present (Type_Definition (Decl)))
|
|
or else
|
|
(Nkind (Type_Definition (Decl)) = N_Derived_Type_Definition
|
|
and then
|
|
Present
|
|
(Record_Extension_Part (Type_Definition (Decl))));
|
|
|
|
Comp_Typ := Defining_Identifier (Decl);
|
|
|
|
if not Analyzed_Unit then
|
|
if Is_Tagged then
|
|
Decorate_Tagged_Type (Sloc (Decl), Comp_Typ, Scope);
|
|
else
|
|
Decorate_Incomplete_Type (Comp_Typ, Scope);
|
|
end if;
|
|
end if;
|
|
|
|
-- Create shadow entity for type
|
|
|
|
Lim_Typ := New_Internal_Shadow_Entity
|
|
(Kind => Ekind (Comp_Typ),
|
|
Sloc_Value => Sloc (Comp_Typ),
|
|
Id_Char => 'Z');
|
|
|
|
Set_Chars (Lim_Typ, Chars (Comp_Typ));
|
|
Set_Parent (Lim_Typ, Parent (Comp_Typ));
|
|
Set_From_With_Type (Lim_Typ);
|
|
|
|
if Is_Tagged then
|
|
Decorate_Tagged_Type (Sloc (Decl), Lim_Typ, Scope);
|
|
else
|
|
Decorate_Incomplete_Type (Lim_Typ, Scope);
|
|
end if;
|
|
|
|
Set_Non_Limited_View (Lim_Typ, Comp_Typ);
|
|
|
|
elsif Nkind (Decl) = N_Private_Type_Declaration then
|
|
Comp_Typ := Defining_Identifier (Decl);
|
|
|
|
if not Analyzed_Unit then
|
|
if Tagged_Present (Decl) then
|
|
Decorate_Tagged_Type (Sloc (Decl), Comp_Typ, Scope);
|
|
else
|
|
Decorate_Incomplete_Type (Comp_Typ, Scope);
|
|
end if;
|
|
end if;
|
|
|
|
Lim_Typ := New_Internal_Shadow_Entity
|
|
(Kind => Ekind (Comp_Typ),
|
|
Sloc_Value => Sloc (Comp_Typ),
|
|
Id_Char => 'Z');
|
|
|
|
Set_Chars (Lim_Typ, Chars (Comp_Typ));
|
|
Set_Parent (Lim_Typ, Parent (Comp_Typ));
|
|
Set_From_With_Type (Lim_Typ);
|
|
|
|
if Tagged_Present (Decl) then
|
|
Decorate_Tagged_Type (Sloc (Decl), Lim_Typ, Scope);
|
|
else
|
|
Decorate_Incomplete_Type (Lim_Typ, Scope);
|
|
end if;
|
|
|
|
Set_Non_Limited_View (Lim_Typ, Comp_Typ);
|
|
|
|
elsif Nkind (Decl) = N_Private_Extension_Declaration then
|
|
Comp_Typ := Defining_Identifier (Decl);
|
|
|
|
if not Analyzed_Unit then
|
|
Decorate_Tagged_Type (Sloc (Decl), Comp_Typ, Scope);
|
|
end if;
|
|
|
|
-- Create shadow entity for type
|
|
|
|
Lim_Typ := New_Internal_Shadow_Entity
|
|
(Kind => Ekind (Comp_Typ),
|
|
Sloc_Value => Sloc (Comp_Typ),
|
|
Id_Char => 'Z');
|
|
|
|
Set_Chars (Lim_Typ, Chars (Comp_Typ));
|
|
Set_Parent (Lim_Typ, Parent (Comp_Typ));
|
|
Set_From_With_Type (Lim_Typ);
|
|
|
|
Decorate_Tagged_Type (Sloc (Decl), Lim_Typ, Scope);
|
|
Set_Non_Limited_View (Lim_Typ, Comp_Typ);
|
|
|
|
elsif Nkind (Decl) = N_Package_Declaration then
|
|
|
|
-- Local package
|
|
|
|
declare
|
|
Spec : constant Node_Id := Specification (Decl);
|
|
|
|
begin
|
|
Comp_Typ := Defining_Unit_Name (Spec);
|
|
|
|
if not Analyzed (Cunit (Unum)) then
|
|
Decorate_Package_Specification (Comp_Typ);
|
|
Set_Scope (Comp_Typ, Scope);
|
|
end if;
|
|
|
|
Lim_Typ := New_Internal_Shadow_Entity
|
|
(Kind => Ekind (Comp_Typ),
|
|
Sloc_Value => Sloc (Comp_Typ),
|
|
Id_Char => 'Z');
|
|
|
|
Decorate_Package_Specification (Lim_Typ);
|
|
Set_Scope (Lim_Typ, Scope);
|
|
|
|
Set_Chars (Lim_Typ, Chars (Comp_Typ));
|
|
Set_Parent (Lim_Typ, Parent (Comp_Typ));
|
|
Set_From_With_Type (Lim_Typ);
|
|
|
|
-- Note: The non_limited_view attribute is not used
|
|
-- for local packages.
|
|
|
|
Build_Chain
|
|
(Scope => Lim_Typ,
|
|
First_Decl => First (Visible_Declarations (Spec)));
|
|
end;
|
|
end if;
|
|
|
|
Next (Decl);
|
|
end loop;
|
|
end Build_Chain;
|
|
|
|
-- Start of processing for Build_Limited_Views
|
|
|
|
begin
|
|
pragma Assert (Limited_Present (N));
|
|
|
|
-- A library_item mentioned in a limited_with_clause shall be
|
|
-- a package_declaration, not a subprogram_declaration,
|
|
-- generic_declaration, generic_instantiation, or
|
|
-- package_renaming_declaration
|
|
|
|
case Nkind (Unit (Library_Unit (N))) is
|
|
|
|
when N_Package_Declaration =>
|
|
null;
|
|
|
|
when N_Subprogram_Declaration =>
|
|
Error_Msg_N ("subprograms not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when N_Generic_Package_Declaration |
|
|
N_Generic_Subprogram_Declaration =>
|
|
Error_Msg_N ("generics not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when N_Generic_Instantiation =>
|
|
Error_Msg_N ("generic instantiations not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when N_Generic_Renaming_Declaration =>
|
|
Error_Msg_N ("generic renamings not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when N_Subprogram_Renaming_Declaration =>
|
|
Error_Msg_N ("renamed subprograms not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when N_Package_Renaming_Declaration =>
|
|
Error_Msg_N ("renamed packages not allowed in "
|
|
& "limited with_clauses", N);
|
|
return;
|
|
|
|
when others =>
|
|
raise Program_Error;
|
|
end case;
|
|
|
|
-- Check if the chain is already built
|
|
|
|
Spec := Specification (Unit (Library_Unit (N)));
|
|
|
|
if Limited_View_Installed (Spec) then
|
|
return;
|
|
end if;
|
|
|
|
Set_Ekind (P, E_Package);
|
|
|
|
-- Build the header of the limited_view
|
|
|
|
Lim_Header := Make_Defining_Identifier (Sloc (N),
|
|
Chars => New_Internal_Name (Id_Char => 'Z'));
|
|
Set_Ekind (Lim_Header, E_Package);
|
|
Set_Is_Internal (Lim_Header);
|
|
Set_Limited_View (P, Lim_Header);
|
|
|
|
-- Create the auxiliary chain. All the shadow entities are appended
|
|
-- to the list of entities of the limited-view header
|
|
|
|
Build_Chain
|
|
(Scope => P,
|
|
First_Decl => First (Visible_Declarations (Spec)));
|
|
|
|
-- Save the last built shadow entity. It is needed later to set the
|
|
-- reference to the first shadow entity in the private part
|
|
|
|
Last_Pub_Lim_E := Last_Lim_E;
|
|
|
|
-- Ada 2005 (AI-262): Add the limited view of the private declarations
|
|
-- Required to give support to limited-private-with clauses
|
|
|
|
Build_Chain (Scope => P,
|
|
First_Decl => First (Private_Declarations (Spec)));
|
|
|
|
if Last_Pub_Lim_E /= Empty then
|
|
Set_First_Private_Entity (Lim_Header,
|
|
Next_Entity (Last_Pub_Lim_E));
|
|
else
|
|
Set_First_Private_Entity (Lim_Header,
|
|
First_Entity (P));
|
|
end if;
|
|
|
|
Set_Limited_View_Installed (Spec);
|
|
end Build_Limited_Views;
|
|
|
|
-------------------------------
|
|
-- Check_Body_Needed_For_SAL --
|
|
-------------------------------
|
|
|
|
procedure Check_Body_Needed_For_SAL (Unit_Name : Entity_Id) is
|
|
|
|
function Entity_Needs_Body (E : Entity_Id) return Boolean;
|
|
-- Determine whether use of entity E might require the presence
|
|
-- of its body. For a package this requires a recursive traversal
|
|
-- of all nested declarations.
|
|
|
|
---------------------------
|
|
-- Entity_Needed_For_SAL --
|
|
---------------------------
|
|
|
|
function Entity_Needs_Body (E : Entity_Id) return Boolean is
|
|
Ent : Entity_Id;
|
|
|
|
begin
|
|
if Is_Subprogram (E)
|
|
and then Has_Pragma_Inline (E)
|
|
then
|
|
return True;
|
|
|
|
elsif Ekind (E) = E_Generic_Function
|
|
or else Ekind (E) = E_Generic_Procedure
|
|
then
|
|
return True;
|
|
|
|
elsif Ekind (E) = E_Generic_Package
|
|
and then
|
|
Nkind (Unit_Declaration_Node (E)) = N_Generic_Package_Declaration
|
|
and then Present (Corresponding_Body (Unit_Declaration_Node (E)))
|
|
then
|
|
return True;
|
|
|
|
elsif Ekind (E) = E_Package
|
|
and then
|
|
Nkind (Unit_Declaration_Node (E)) = N_Package_Declaration
|
|
and then Present (Corresponding_Body (Unit_Declaration_Node (E)))
|
|
then
|
|
Ent := First_Entity (E);
|
|
while Present (Ent) loop
|
|
if Entity_Needs_Body (Ent) then
|
|
return True;
|
|
end if;
|
|
|
|
Next_Entity (Ent);
|
|
end loop;
|
|
|
|
return False;
|
|
|
|
else
|
|
return False;
|
|
end if;
|
|
end Entity_Needs_Body;
|
|
|
|
-- Start of processing for Check_Body_Needed_For_SAL
|
|
|
|
begin
|
|
if Ekind (Unit_Name) = E_Generic_Package
|
|
and then
|
|
Nkind (Unit_Declaration_Node (Unit_Name)) =
|
|
N_Generic_Package_Declaration
|
|
and then
|
|
Present (Corresponding_Body (Unit_Declaration_Node (Unit_Name)))
|
|
then
|
|
Set_Body_Needed_For_SAL (Unit_Name);
|
|
|
|
elsif Ekind (Unit_Name) = E_Generic_Procedure
|
|
or else Ekind (Unit_Name) = E_Generic_Function
|
|
then
|
|
Set_Body_Needed_For_SAL (Unit_Name);
|
|
|
|
elsif Is_Subprogram (Unit_Name)
|
|
and then Nkind (Unit_Declaration_Node (Unit_Name)) =
|
|
N_Subprogram_Declaration
|
|
and then Has_Pragma_Inline (Unit_Name)
|
|
then
|
|
Set_Body_Needed_For_SAL (Unit_Name);
|
|
|
|
elsif Ekind (Unit_Name) = E_Subprogram_Body then
|
|
Check_Body_Needed_For_SAL
|
|
(Corresponding_Spec (Unit_Declaration_Node (Unit_Name)));
|
|
|
|
elsif Ekind (Unit_Name) = E_Package
|
|
and then Entity_Needs_Body (Unit_Name)
|
|
then
|
|
Set_Body_Needed_For_SAL (Unit_Name);
|
|
|
|
elsif Ekind (Unit_Name) = E_Package_Body
|
|
and then Nkind (Unit_Declaration_Node (Unit_Name)) = N_Package_Body
|
|
then
|
|
Check_Body_Needed_For_SAL
|
|
(Corresponding_Spec (Unit_Declaration_Node (Unit_Name)));
|
|
end if;
|
|
end Check_Body_Needed_For_SAL;
|
|
|
|
--------------------
|
|
-- Remove_Context --
|
|
--------------------
|
|
|
|
procedure Remove_Context (N : Node_Id) is
|
|
Lib_Unit : constant Node_Id := Unit (N);
|
|
|
|
begin
|
|
-- If this is a child unit, first remove the parent units
|
|
|
|
if Is_Child_Spec (Lib_Unit) then
|
|
Remove_Parents (Lib_Unit);
|
|
end if;
|
|
|
|
Remove_Context_Clauses (N);
|
|
end Remove_Context;
|
|
|
|
----------------------------
|
|
-- Remove_Context_Clauses --
|
|
----------------------------
|
|
|
|
procedure Remove_Context_Clauses (N : Node_Id) is
|
|
Item : Node_Id;
|
|
Unit_Name : Entity_Id;
|
|
|
|
begin
|
|
-- Ada 2005 (AI-50217): We remove the context clauses in two phases:
|
|
-- limited-views first and regular-views later (to maintain the
|
|
-- stack model).
|
|
|
|
-- First Phase: Remove limited_with context clauses
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
|
|
-- We are interested only in with clauses which got installed
|
|
-- on entry.
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Limited_Present (Item)
|
|
and then Limited_View_Installed (Item)
|
|
then
|
|
Remove_Limited_With_Clause (Item);
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
|
|
-- Second Phase: Loop through context items and undo regular
|
|
-- with_clauses and use_clauses.
|
|
|
|
Item := First (Context_Items (N));
|
|
while Present (Item) loop
|
|
|
|
-- We are interested only in with clauses which got installed
|
|
-- on entry, as indicated by their Context_Installed flag set
|
|
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Limited_Present (Item)
|
|
and then Limited_View_Installed (Item)
|
|
then
|
|
null;
|
|
|
|
elsif Nkind (Item) = N_With_Clause
|
|
and then Context_Installed (Item)
|
|
then
|
|
-- Remove items from one with'ed unit
|
|
|
|
Unit_Name := Entity (Name (Item));
|
|
Remove_Unit_From_Visibility (Unit_Name);
|
|
Set_Context_Installed (Item, False);
|
|
|
|
elsif Nkind (Item) = N_Use_Package_Clause then
|
|
End_Use_Package (Item);
|
|
|
|
elsif Nkind (Item) = N_Use_Type_Clause then
|
|
End_Use_Type (Item);
|
|
|
|
elsif Nkind (Item) = N_With_Type_Clause then
|
|
Remove_With_Type_Clause (Name (Item));
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Remove_Context_Clauses;
|
|
|
|
--------------------------------
|
|
-- Remove_Limited_With_Clause --
|
|
--------------------------------
|
|
|
|
procedure Remove_Limited_With_Clause (N : Node_Id) is
|
|
P_Unit : constant Entity_Id := Unit (Library_Unit (N));
|
|
E : Entity_Id;
|
|
P : Entity_Id;
|
|
Lim_Header : Entity_Id;
|
|
Lim_Typ : Entity_Id;
|
|
Prev : Entity_Id;
|
|
|
|
begin
|
|
pragma Assert (Limited_View_Installed (N));
|
|
|
|
-- In case of limited with_clause on subprograms, generics, instances,
|
|
-- or renamings, the corresponding error was previously posted and we
|
|
-- have nothing to do here.
|
|
|
|
if Nkind (P_Unit) /= N_Package_Declaration then
|
|
return;
|
|
end if;
|
|
|
|
P := Defining_Unit_Name (Specification (P_Unit));
|
|
|
|
-- Handle child packages
|
|
|
|
if Nkind (P) = N_Defining_Program_Unit_Name then
|
|
P := Defining_Identifier (P);
|
|
end if;
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str ("remove limited view of ");
|
|
Write_Name (Chars (P));
|
|
Write_Str (" from visibility");
|
|
Write_Eol;
|
|
end if;
|
|
|
|
-- Prepare the removal of the shadow entities from visibility. The
|
|
-- first element of the limited view is a header (an E_Package
|
|
-- entity) that is used to reference the first shadow entity in the
|
|
-- private part of the package
|
|
|
|
Lim_Header := Limited_View (P);
|
|
Lim_Typ := First_Entity (Lim_Header);
|
|
|
|
-- Remove package and shadow entities from visibility if it has not
|
|
-- been analyzed
|
|
|
|
if not Analyzed (P_Unit) then
|
|
Unchain (P);
|
|
Set_Is_Immediately_Visible (P, False);
|
|
|
|
while Present (Lim_Typ) loop
|
|
Unchain (Lim_Typ);
|
|
Next_Entity (Lim_Typ);
|
|
end loop;
|
|
|
|
-- Otherwise this package has already appeared in the closure and its
|
|
-- shadow entities must be replaced by its real entities. This code
|
|
-- must be kept synchronized with the complementary code in Install
|
|
-- Limited_Withed_Unit.
|
|
|
|
else
|
|
-- Real entities that are type or subtype declarations were hidden
|
|
-- from visibility at the point of installation of the limited-view.
|
|
-- Now we recover the previous value of the hidden attribute.
|
|
|
|
E := First_Entity (P);
|
|
while Present (E) and then E /= First_Private_Entity (P) loop
|
|
if Is_Type (E) then
|
|
Set_Is_Hidden (E, Was_Hidden (E));
|
|
end if;
|
|
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
while Present (Lim_Typ)
|
|
and then Lim_Typ /= First_Private_Entity (Lim_Header)
|
|
loop
|
|
-- Nested packages and child units were not unchained
|
|
|
|
if Ekind (Lim_Typ) /= E_Package
|
|
and then not Is_Child_Unit (Non_Limited_View (Lim_Typ))
|
|
then
|
|
-- Handle incomplete types of the real view. For this purpose
|
|
-- we traverse the list of visible entities to look for an
|
|
-- incomplete type in the real-view associated with Lim_Typ.
|
|
|
|
E := First_Entity (P);
|
|
while Present (E) and then E /= First_Private_Entity (P) loop
|
|
exit when Ekind (E) = E_Incomplete_Type
|
|
and then Present (Full_View (E))
|
|
and then Full_View (E) = Lim_Typ;
|
|
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
-- If the previous search was not sucessful then the entity
|
|
-- to be restored in the homonym list is the non-limited view
|
|
|
|
if E = First_Private_Entity (P) then
|
|
E := Non_Limited_View (Lim_Typ);
|
|
end if;
|
|
|
|
pragma Assert (not In_Chain (E));
|
|
|
|
Prev := Current_Entity (Lim_Typ);
|
|
|
|
if Prev = Lim_Typ then
|
|
Set_Current_Entity (E);
|
|
|
|
else
|
|
while Present (Prev)
|
|
and then Homonym (Prev) /= Lim_Typ
|
|
loop
|
|
Prev := Homonym (Prev);
|
|
end loop;
|
|
pragma Assert (Present (Prev));
|
|
|
|
Set_Homonym (Prev, E);
|
|
end if;
|
|
|
|
-- We must also set the next homonym entity of the real entity
|
|
-- to handle the case in which the next homonym was a shadow
|
|
-- entity.
|
|
|
|
Set_Homonym (E, Homonym (Lim_Typ));
|
|
end if;
|
|
|
|
Next_Entity (Lim_Typ);
|
|
end loop;
|
|
end if;
|
|
|
|
-- Indicate that the limited view of the package is not installed
|
|
|
|
Set_From_With_Type (P, False);
|
|
Set_Limited_View_Installed (N, False);
|
|
end Remove_Limited_With_Clause;
|
|
|
|
--------------------
|
|
-- Remove_Parents --
|
|
--------------------
|
|
|
|
procedure Remove_Parents (Lib_Unit : Node_Id) is
|
|
P : Node_Id;
|
|
P_Name : Entity_Id;
|
|
P_Spec : Node_Id := Empty;
|
|
E : Entity_Id;
|
|
Vis : constant Boolean :=
|
|
Scope_Stack.Table (Scope_Stack.Last).Previous_Visibility;
|
|
|
|
begin
|
|
if Is_Child_Spec (Lib_Unit) then
|
|
P_Spec := Parent_Spec (Lib_Unit);
|
|
|
|
elsif Nkind (Lib_Unit) = N_Package_Body
|
|
and then Nkind (Original_Node (Lib_Unit)) = N_Package_Instantiation
|
|
then
|
|
P_Spec := Parent_Spec (Original_Node (Lib_Unit));
|
|
end if;
|
|
|
|
if Present (P_Spec) then
|
|
|
|
P := Unit (P_Spec);
|
|
P_Name := Get_Parent_Entity (P);
|
|
Remove_Context_Clauses (P_Spec);
|
|
End_Package_Scope (P_Name);
|
|
Set_Is_Immediately_Visible (P_Name, Vis);
|
|
|
|
-- Remove from visibility the siblings as well, which are directly
|
|
-- visible while the parent is in scope.
|
|
|
|
E := First_Entity (P_Name);
|
|
while Present (E) loop
|
|
if Is_Child_Unit (E) then
|
|
Set_Is_Immediately_Visible (E, False);
|
|
end if;
|
|
|
|
Next_Entity (E);
|
|
end loop;
|
|
|
|
Set_In_Package_Body (P_Name, False);
|
|
|
|
-- This is the recursive call to remove the context of any
|
|
-- higher level parent. This recursion ensures that all parents
|
|
-- are removed in the reverse order of their installation.
|
|
|
|
Remove_Parents (P);
|
|
end if;
|
|
end Remove_Parents;
|
|
|
|
---------------------------------
|
|
-- Remove_Private_With_Clauses --
|
|
---------------------------------
|
|
|
|
procedure Remove_Private_With_Clauses (Comp_Unit : Node_Id) is
|
|
Item : Node_Id;
|
|
|
|
begin
|
|
Item := First (Context_Items (Comp_Unit));
|
|
while Present (Item) loop
|
|
if Nkind (Item) = N_With_Clause
|
|
and then Private_Present (Item)
|
|
then
|
|
if Limited_Present (Item) then
|
|
if not Limited_View_Installed (Item) then
|
|
Remove_Limited_With_Clause (Item);
|
|
end if;
|
|
else
|
|
Remove_Unit_From_Visibility (Entity (Name (Item)));
|
|
Set_Context_Installed (Item, False);
|
|
end if;
|
|
end if;
|
|
|
|
Next (Item);
|
|
end loop;
|
|
end Remove_Private_With_Clauses;
|
|
|
|
-----------------------------
|
|
-- Remove_With_Type_Clause --
|
|
-----------------------------
|
|
|
|
procedure Remove_With_Type_Clause (Name : Node_Id) is
|
|
Typ : Entity_Id;
|
|
P : Entity_Id;
|
|
|
|
procedure Unchain (E : Entity_Id);
|
|
-- Remove entity from visibility list
|
|
|
|
-------------
|
|
-- Unchain --
|
|
-------------
|
|
|
|
procedure Unchain (E : Entity_Id) is
|
|
Prev : Entity_Id;
|
|
|
|
begin
|
|
Prev := Current_Entity (E);
|
|
|
|
-- Package entity may appear is several with_type_clauses, and
|
|
-- may have been removed already.
|
|
|
|
if No (Prev) then
|
|
return;
|
|
|
|
elsif Prev = E then
|
|
Set_Name_Entity_Id (Chars (E), Homonym (E));
|
|
|
|
else
|
|
while Present (Prev)
|
|
and then Homonym (Prev) /= E
|
|
loop
|
|
Prev := Homonym (Prev);
|
|
end loop;
|
|
|
|
if Present (Prev) then
|
|
Set_Homonym (Prev, Homonym (E));
|
|
end if;
|
|
end if;
|
|
end Unchain;
|
|
|
|
-- Start of processing for Remove_With_Type_Clause
|
|
|
|
begin
|
|
if Nkind (Name) = N_Selected_Component then
|
|
Typ := Entity (Selector_Name (Name));
|
|
|
|
-- If no Typ, then error in declaration, ignore
|
|
|
|
if No (Typ) then
|
|
return;
|
|
end if;
|
|
else
|
|
return;
|
|
end if;
|
|
|
|
P := Scope (Typ);
|
|
|
|
-- If the exporting package has been analyzed, it has appeared in the
|
|
-- context already and should be left alone. Otherwise, remove from
|
|
-- visibility.
|
|
|
|
if not Analyzed (Unit_Declaration_Node (P)) then
|
|
Unchain (P);
|
|
Unchain (Typ);
|
|
Set_Is_Frozen (Typ, False);
|
|
end if;
|
|
|
|
if Ekind (Typ) = E_Record_Type then
|
|
Set_From_With_Type (Class_Wide_Type (Typ), False);
|
|
Set_From_With_Type (Typ, False);
|
|
end if;
|
|
|
|
Set_From_With_Type (P, False);
|
|
|
|
-- If P is a child unit, remove parents as well
|
|
|
|
P := Scope (P);
|
|
while Present (P)
|
|
and then P /= Standard_Standard
|
|
loop
|
|
Set_From_With_Type (P, False);
|
|
|
|
if not Analyzed (Unit_Declaration_Node (P)) then
|
|
Unchain (P);
|
|
end if;
|
|
|
|
P := Scope (P);
|
|
end loop;
|
|
|
|
-- The back-end needs to know that an access type is imported, so it
|
|
-- does not need elaboration and can appear in a mutually recursive
|
|
-- record definition, so the imported flag on an access type is
|
|
-- preserved.
|
|
|
|
end Remove_With_Type_Clause;
|
|
|
|
---------------------------------
|
|
-- Remove_Unit_From_Visibility --
|
|
---------------------------------
|
|
|
|
procedure Remove_Unit_From_Visibility (Unit_Name : Entity_Id) is
|
|
P : constant Entity_Id := Scope (Unit_Name);
|
|
|
|
begin
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str ("remove unit ");
|
|
Write_Name (Chars (Unit_Name));
|
|
Write_Str (" from visibility");
|
|
Write_Eol;
|
|
end if;
|
|
|
|
if P /= Standard_Standard then
|
|
Set_Is_Visible_Child_Unit (Unit_Name, False);
|
|
end if;
|
|
|
|
Set_Is_Potentially_Use_Visible (Unit_Name, False);
|
|
Set_Is_Immediately_Visible (Unit_Name, False);
|
|
|
|
end Remove_Unit_From_Visibility;
|
|
|
|
-------------
|
|
-- Unchain --
|
|
-------------
|
|
|
|
procedure Unchain (E : Entity_Id) is
|
|
Prev : Entity_Id;
|
|
|
|
begin
|
|
Prev := Current_Entity (E);
|
|
|
|
if No (Prev) then
|
|
return;
|
|
|
|
elsif Prev = E then
|
|
Set_Name_Entity_Id (Chars (E), Homonym (E));
|
|
|
|
else
|
|
while Present (Prev)
|
|
and then Homonym (Prev) /= E
|
|
loop
|
|
Prev := Homonym (Prev);
|
|
end loop;
|
|
|
|
if Present (Prev) then
|
|
Set_Homonym (Prev, Homonym (E));
|
|
end if;
|
|
end if;
|
|
|
|
if Debug_Flag_I then
|
|
Write_Str (" (homonym) unchain ");
|
|
Write_Name (Chars (E));
|
|
Write_Eol;
|
|
end if;
|
|
|
|
end Unchain;
|
|
|
|
end Sem_Ch10;
|