home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
gnat-2.06-src.tgz
/
tar.out
/
fsf
/
gnat
/
ada
/
sem_ch10.adb
< prev
next >
Wrap
Text File
|
1996-09-28
|
48KB
|
1,370 lines
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ C H 1 0 --
-- --
-- B o d y --
-- --
-- $Revision: 1.183 $ --
-- --
-- Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved --
-- --
-- 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, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
with Atree; use Atree;
with Debug; use Debug;
with Einfo; use Einfo;
with Errout; use Errout;
with Expander; use Expander;
with Exp_Dist; use Exp_Dist;
with Fname; use Fname;
with Lib; use Lib;
with Lib.Load; use Lib.Load;
with Lib.Writ; use Lib.Writ;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Output; use Output;
with Sem; use Sem;
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_Util; use Sem_Util;
with Stand; use Stand;
with Sinfo; use Sinfo;
with Sinfo.CN; use Sinfo.CN;
with Sinput; use Sinput;
with Snames; use Snames;
with Stringt; use Stringt;
with Tbuild; use Tbuild;
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
function Ancestor (Lib_Unit : Node_Id) return Entity_Id;
-- Return the root ancestor of a child unit.
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).
function Find_Lib_Unit_Entity (Lib_Unit : Node_Id) return Entity_Id;
-- Retrieve the entity for various kinds of library unit nodes that
-- have different structure.
procedure Implicit_With_On_Parent (Child_Unit : Node_Id; N : Node_Id);
-- When a child unit appears in a context clause, the implicit with on
-- parents is made explicit, and with clauses are inserted in the context
-- clause after the one for the child. In addition, if the main unit is a
-- child unit, implicit withs are also added for all its ancestors. N is
-- the compilation unit whose list of context items receives the implicit
-- with clauses.
procedure Install_Context (N : Node_Id);
-- Installs the entities from the context clause of the given compilation
-- unit into the visibility chains. This is done before analyzing a unit.
procedure Install_Withed_Unit (Unit_Name : Entity_Id);
-- If the unit is not a child unit, make unit immediately visible.
-- The caller ensures that the unit is not already currently installed.
procedure Install_Parents (Lib_Unit : Node_Id);
-- 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.
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_Context (N : Node_Id);
-- Removes the entities from the context clause of the given compilation
-- unit from the visibility chains. This is done on exit from a unit as
-- part of cleaning up the visibility chains for the caller. A special
-- case is that the call from the Main_Unit can be ignored, since at the
-- end of the main unit the visibility table won't be needed in any case.
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_Withed_Unit (Unit_Name : Entity_Id);
-- This procedure makes the given unit not visible.
procedure Analyze_Proper_Body (N : Node_Id);
-- Common processing for subprogram stubs and package stubs. Once the
-- subunit name is established, load and analyze.
------------------------------
-- Analyze_Compilation_Unit --
------------------------------
procedure Analyze_Compilation_Unit (N : Node_Id) is
Lib_Unit : constant Node_Id := Unit (N);
Spec_Id : Node_Id;
Stub_Gen_Ok : Boolean := False;
begin
-- 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 N = Cunit (Main_Unit)
and then Is_RCI_Pkg_Spec_Or_Body (N)
and then (Stub_Mode = Generate_Receiver_Stub_Body
or else Stub_Mode = Generate_Caller_Stub_Body)
then
Stub_Gen_Ok := True;
end if;
if Nkind (Lib_Unit) = N_Subunit
and then not Analyzed (Library_Unit (N))
then
Semantics (Library_Unit (N));
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 (Lib_Unit) = N_Package_Body then
-- If the package body is a stub package body, then we perform
-- appropriate changes on the spec compilation unit before analyzing
-- it.
if Stub_Mode = Compile_Caller_Stub_Spec then
To_Calling_Stubs_Decls_Cunit (Library_Unit (N));
elsif Stub_Mode = Compile_Receiver_Stub_Spec then
To_Receiving_Stubs_Decls_Cunit (Library_Unit (N));
end if;
Semantics (Library_Unit (N));
Spec_Id :=
Defining_Unit_Simple_Name (Specification (Unit (Library_Unit (N))));
-- The following check is an error defense, get out if as a result
-- of errors we do not have a proper package spec around!
if No (Spec_Id)
or else (Ekind (Spec_Id) /= E_Package
and then Ekind (Spec_Id) /= E_Generic_Package)
then
return;
-- If we have a proper package spec, then set it visible and
-- update the version to reflect our dependence on the spec.
else
Set_Is_Immediately_Visible (Spec_Id, True);
Version_Update (N, Library_Unit (N));
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 (Lib_Unit) = N_Subprogram_Body
and then not Acts_As_Spec (N)
then
Semantics (Library_Unit (N));
Version_Update (N, Library_Unit (N));
-- If it is a subprogram declaration it does not need an elaboration
-- procedure. A renamed package also needs no elaboration procedure.
elsif Nkind (Lib_Unit) = N_Subprogram_Declaration
or else Nkind (Lib_Unit) = N_Package_Renaming_Declaration
then
Set_Has_No_Elab_Code (N, True);
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 (Lib_Unit) then
Semantics (Parent_Spec (Lib_Unit));
Version_Update (N, Parent_Spec (Lib_Unit));
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);
-- 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 (Lib_Unit);
-- Treat compilation unit pragmas that appear after the library unit
if Present (Following_Pragmas (N)) then
declare
Prag_Node : Node_Id := First (Following_Pragmas (N));
begin
while Present (Prag_Node) loop
Analyze (Prag_Node);
Prag_Node := Next (Prag_Node);
end loop;
end;
end if;
if Stub_Gen_Ok
and then not Fatal_Error (Main_Unit)
then
Generate_Stubs_Files (N);
end if;
-- Last step is to deinstall the context we just installed
-- as well as the unit just compiled.
Remove_Context (N);
if Nkind (Lib_Unit) = N_Package_Declaration
or else Nkind (Lib_Unit) = N_Generic_Package_Declaration
then
Remove_Withed_Unit
(Defining_Unit_Simple_Name (Specification (Lib_Unit)));
elsif Nkind (Lib_Unit) = N_Package_Renaming_Declaration then
Remove_Withed_Unit
(Defining_Unit_Simple_Name (Lib_Unit));
elsif Nkind (Lib_Unit) = N_Package_Body
or else (Nkind (Lib_Unit) = N_Subprogram_Body
and then not Acts_As_Spec (N))
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 (Library_Unit (N));
end if;
end Analyze_Compilation_Unit;
----------------------------
-- 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
-- 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_Has_Completion (Nam);
Analyze_Proper_Body (N);
-- 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_Context --
---------------------
procedure Analyze_Context (N : Node_Id) is
Item : Node_Id;
begin
-- Loop through context items
Item := First (Context_Items (N));
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 then
Analyze (Item);
Version_Update (N, Library_Unit (N));
-- Analyze pragmas
elsif Nkind (Item) = N_Pragma then
Analyze (Item);
-- But 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;
Item := 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
Nam := Current_Entity_In_Scope (Id);
if No (Nam)
or else
(Ekind (Nam) /= E_Package and then Ekind (Nam) /= E_Generic_Package)
then
Error_Msg_N ("missing specification for package stub", 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);
Analyze_Proper_Body (N);
end if;
end Analyze_Package_Body_Stub;
-------------------------
-- Analyze_Proper_Body --
-------------------------
-- If the subunit is already loaded, it means that the main unit
-- was 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 then raise Subunit_Found, since we don't need to analyze
-- any more of the parent (only the part up to here is relevant
-- to the desired analysis of the subunit).
procedure Analyze_Proper_Body (N : Node_Id) is
Subunit_Name : constant Unit_Name_Type := Get_Unit_Name (N);
Unum : Unit_Number_Type;
begin
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 (Subunit_Name, True, 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.
Compiler_State := Analyzing;
Set_Corresponding_Stub (Unit (Cunit (Unum)), N);
Analyze_Subunit (Cunit (Unum));
Set_Library_Unit (N, Cunit (Unum));
raise Subunit_Found;
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 a stub may provide a declaration.
elsif Nkind (Unit (Cunit (Main_Unit))) = N_Subunit
and then Subunit_Name /= Unit_Name (Main_Unit)
and then not Xref_Analyze
then
if Nkind (N) = N_Subprogram_Body_Stub then
Analyze_Subprogram_Body (N);
end if;
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.
-- If the semantic analysis is done for gnatf, we try to load
-- subunit corresponding to the stub without requiring it to
-- avoid messages about files not found.
elsif Operating_Mode = Generate_Code or else Xref_Analyze 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
if Operating_Mode = Generate_Code then
Unum := Load_Unit (Subunit_Name, True, N);
else
Unum := Load_Unit (Subunit_Name, False, N);
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 and then not Fatal_Error (Unum) then
if Debug_Flag_L then
Write_Str ("*** Loaded subunit from stub. Analyze");
Write_Eol;
end if;
Set_Corresponding_Stub (Unit (Cunit (Unum)), N);
Analyze_Subunit (Cunit (Unum));
Set_Library_Unit (N, Cunit (Unum));
-- 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), Cunit (Unum));
else
-- If the subunit corresponding to the stub has not
-- been found, then in an analyze called by gnatf, we
-- avoid messages about missing bodies for procedures
-- and functions
if Xref_Analyze then
case Nkind (N) is
when N_Subprogram_Body_Stub =>
declare
Spec : constant Node_Id := Specification (N);
Spec_Node : Entity_Id;
Subp : Entity_Id;
begin
Subp := Analyze_Spec (Spec);
Spec_Node := Find_Corresponding_Spec (N);
end;
when others =>
null;
end case;
end if;
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. The caller has already processed the stub as a
-- declaration, if necessary.
else
null;
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));
Loc : constant Source_Ptr := Sloc (N);
begin
-- 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_Has_Completion (Nam);
Analyze_Proper_Body (N);
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. However, if we are performing
-- semantic checks only, the stub must be analyzed like a body,
-- because it may be the declaration of the subprogram.
procedure Analyze_Subprogram_Body_Stub (N : Node_Id) is
begin
if Operating_Mode /= Generate_Code and then not Xref_Analyze then
Analyze_Subprogram_Body (N);
else
Analyze_Proper_Body (N);
end if;
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 : constant Node_Id := Library_Unit (N);
Lib_Spec : Node_Id := Library_Unit (Lib);
Par_Unit : constant Entity_Id := Current_Scope;
Use_Clause : Node_Id;
procedure Re_Install_Parents (L : Node_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.
procedure Re_Install_Parents (L : Node_Id) is
begin
if Nkind (Unit (L)) = N_Subunit then
Re_Install_Parents (Library_Unit (L));
end if;
Install_Context (L);
end Re_Install_Parents;
procedure Re_Install_Use_Clauses is
U : Node_Id;
begin
while Present (Use_Clause) loop
U := Use_Clause;
Use_Clause := Next_Use_Clause (U);
if Nkind (U) = N_Use_Package_Clause then
Analyze_Use_Package (U);
else
Analyze_Use_Type (U);
end if;
end loop;
end Re_Install_Use_Clauses;
begin
if not Is_Empty_List (Context_Items (N)) then
-- Save current use clauses.
Use_Clause := Scope_Stack.Table (Scope_Stack.Last).First_Use_Clause;
Pop_Scope;
Remove_Context (Lib);
-- If the parent is a package body, remove the context of the spec
-- as well. If it is a subprogram body, verify first that there is
-- a spec for it. If the parent is a subunit, Lib_Spec is its
-- parent, whose context must also be removed, together with that
-- of further ancestors.
if Present (Lib_Spec) then
Remove_Context (Lib_Spec);
while Nkind (Unit (Lib_Spec)) = N_Subunit loop
Lib_Spec := Library_Unit (Lib_Spec);
Remove_Context (Lib_Spec);
end loop;
end if;
Analyze_Context (N);
Re_Install_Parents (Lib);
New_Scope (Par_Unit);
Re_Install_Use_Clauses;
Install_Context (N);
end if;
Analyze (Proper_Body (Unit (N)));
Remove_Context (N);
end Analyze_Subunit;
-------------------------
-- 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
Unit_Kind : constant Node_Kind := Nkind (Unit (Library_Unit (N)));
E_Name : Entity_Id;
begin
Semantics (Library_Unit (N));
if Unit_Kind in N_Generic_Declaration then
-- Semantic analysis of a generic unit is performed on a copy of
-- the original tree. Retrieve the entity on which semantic info
-- actually appears.
E_Name :=
Defining_Unit_Simple_Name (Specification (Unit (Library_Unit (N))));
elsif Unit_Kind = N_Package_Instantiation
and then Nkind (Unit (Library_Unit (N))) = N_Package_Body
then
-- Instantiation node is replaced with body of instance.
-- Unit name is defining unit name in corresponding spec.
E_Name := Corresponding_Spec (Unit (Library_Unit (N)));
elsif Unit_Kind = N_Procedure_Instantiation
or else Unit_Kind = N_Function_Instantiation
then
-- Instantiation node is replaced with a package that contains
-- renaming declarations and instance itself. The subprogram
-- specification is the last declaration in the package spec.
E_Name := Defining_Unit_Simple_Name (Specification (
Last (Visible_Declarations (Specification (
Unit (Library_Unit (N)))))));
elsif Unit_Kind = N_Package_Renaming_Declaration then
E_Name := Defining_Unit_Simple_Name (Unit (Library_Unit (N)));
elsif Unit_Kind in N_Generic_Renaming_Declaration then
E_Name := Defining_Unit_Simple_Name (Unit (Library_Unit (N)));
else
E_Name := Defining_Unit_Simple_Name
(Specification (Unit (Library_Unit (N))));
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;
Set_Entity_With_Style_Check (Name (N), E_Name);
end Analyze_With_Clause;
--------------
-- Ancestor --
--------------
function Ancestor (Lib_Unit : Node_Id) return Entity_Id is
P : constant Node_Id := Parent_Spec (Lib_Unit);
P_Name : Entity_Id;
begin
if No (P) then
return Empty;
else
P_Name := Defining_Unit_Simple_Name (Specification (Unit (P)));
while Scope (P_Name) /= Standard_Standard loop
P_Name := Scope (P_Name);
end loop;
return P_Name;
end if;
end Ancestor;
------------------------------
-- Check_Private_Child_Unit --
------------------------------
procedure Check_Private_Child_Unit (N : Node_Id) is
Lib_Unit : Node_Id := Unit (N);
Item : Node_Id;
Curr_Unit : Entity_Id;
Parent : Node_Id;
Priv_Child : Entity_Id;
Par_Lib : Entity_Id;
function Parent_Lib_Unit (E : Entity_Id) return Entity_Id;
-- Find ultimate ancestor of analyzed unit.
function Parent_Lib_Unit (E : Entity_Id) return Entity_Id is
Par : Entity_Id := E;
begin
while Present (Par)
and then Is_Child_Unit (Par)
loop
Par := Scope (Par);
end loop;
return Par;
end Parent_Lib_Unit;
begin
if Nkind (Lib_Unit) = N_Package_Body
or else Nkind (Lib_Unit) = N_Subprogram_Body
then
Curr_Unit := Find_Lib_Unit_Entity (Unit (Library_Unit (N)));
Par_Lib := Parent_Lib_Unit (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.
Parent := Library_Unit (N);
Curr_Unit := Find_Lib_Unit_Entity (Unit (Library_Unit (Parent)));
Par_Lib := Parent_Lib_Unit (Curr_Unit);
else
Curr_Unit := Find_Lib_Unit_Entity (Lib_Unit);
Par_Lib := Ancestor (Lib_Unit);
end if;
Item := First (Context_Items (N));
while Present (Item) loop
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));
if not Is_Child_Unit (Curr_Unit)
or else Parent_Lib_Unit (Priv_Child) /= Par_Lib
then
Error_Msg_N
("?unit in with clause is private child unit", Item);
Error_Msg_N
("?current unit must have same ancestor!", Item);
Temporary_Msg_N
("?this will be a fatal error in the next release!",
Item);
Temporary_Msg_N ("?see gnatinfo.txt for details!", Item);
elsif not Is_Private_Descendant (Curr_Unit)
and then Nkind (Lib_Unit) /= N_Package_Body
and then Nkind (Lib_Unit) /= N_Subprogram_Body
then
Error_Msg_NE
("?current unit must also be private child of &",
Item, Parent_Lib_Unit (Priv_Child));
Temporary_Msg_N
("?this will be a fatal error in 2.06, see gnatinfo.txt!",
Item);
end if;
end if;
Item := Next (Item);
end loop;
end Check_Private_Child_Unit;
--------------------------
-- Find_Lib_Unit_Entity --
--------------------------
function Find_Lib_Unit_Entity (Lib_Unit : Node_Id) return Entity_Id is
begin
if Nkind (Lib_Unit) in N_Generic_Instantiation
or else Nkind (Lib_Unit) = N_Package_Renaming_Declaration
or else Nkind (Lib_Unit) in N_Generic_Renaming_Declaration
then
return Defining_Unit_Simple_Name (Lib_Unit);
else
return Defining_Unit_Simple_Name (Specification (Lib_Unit));
end if;
end Find_Lib_Unit_Entity;
---------------------
-- Install_Context --
---------------------
procedure Install_Context (N : Node_Id) is
Lib_Unit : Node_Id := Unit (N);
Item : Node_Id;
Uname_Node : Entity_Id;
Unit_Num : constant Unit_Number_Type := Get_Cunit_Unit_Number (N);
Check_Private : Boolean := False;
begin
-- Loop through context clauses to find the with clauses
Item := First (Context_Items (N));
while Present (Item) loop
if Nkind (Item) = N_With_Clause
and then not Implicit_With (Item)
then
Uname_Node := Entity (Name (Item));
if Is_Private_Descendant (Uname_Node) then
Check_Private := True;
end if;
if not Is_Immediately_Visible (Uname_Node) then
Install_Withed_Unit (Uname_Node);
Set_Context_Installed (Item, True);
else
-- Unit has already been installed for an earlier context.
null;
end if;
if Is_Child_Spec (Get_Declaration_Node (Uname_Node)) then
Implicit_With_On_Parent (Get_Declaration_Node (Uname_Node), N);
end if;
elsif Nkind (Item) = N_Use_Package_Clause
or else Nkind (Item) = N_Use_Type_Clause
then
-- Use clauses are not allowed in the context clause of specs
-- of predefined packages (this ensures meeting the rule that
-- nothing with'ed by rtsfind is allowed to have use clauses)
if Is_Language_Defined_Unit (Unit_File_Name (Unit_Num))
and then Is_Spec_Name (Unit_Name (Unit_Num))
then
Error_Msg_N
("use clause not allowed in predefined spec", Item);
raise Unrecoverable_Error;
elsif Nkind (Item) = N_Use_Package_Clause then
Analyze_Use_Package (Item);
else
Analyze_Use_Type (Item);
end if;
end if;
Item := 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.
declare
Lib_Spec : Node_Id := Unit (Library_Unit (N));
P : Node_Id;
P_Name : Entity_Id;
begin
while Is_Child_Spec (Lib_Spec) loop
P := Unit (Parent_Spec (Lib_Spec));
if not (Private_Present (Parent (Lib_Spec))) then
P_Name := Defining_Unit_Simple_Name (Specification (P));
Install_Private_Declarations (P_Name);
Set_Use (Private_Declarations (Specification (P)));
end if;
Lib_Spec := P;
end loop;
end;
end if;
end if;
Install_Parents (Lib_Unit);
if Check_Private then
Check_Private_Child_Unit (N);
end if;
end Install_Context;
-----------------------------
-- 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 : constant Node_Id := Unit (P);
P_Name : Entity_Id := Find_Lib_Unit_Entity (P_Unit);
Withn : Node_Id;
function Build_Unit_Name return Node_Id;
-- If the unit is a child unit, build qualified name with all
-- ancestors.
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 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;
function Build_Ancestor_Name (P : Node_Id) return Node_Id is
P_Ref : Node_Id := New_Reference_To (Find_Lib_Unit_Entity (P), Loc);
begin
if No (Parent_Spec (P)) then
return P_Ref;
else
return
Make_Selected_Component (Loc,
Prefix => Build_Ancestor_Name (Unit (Parent_Spec (P))),
Selector_Name => P_Ref);
end if;
end Build_Ancestor_Name;
begin
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);
if not Is_Immediately_Visible (P_Name) then
Install_Withed_Unit (P_Name);
Set_Context_Installed (Withn, True);
end if;
if Is_Child_Spec (P_Unit) then
Implicit_With_On_Parent (P_Unit, N);
end if;
end Implicit_With_On_Parent;
-------------------------
-- Install_Withed_Unit --
-------------------------
procedure Install_Withed_Unit (Unit_Name : Entity_Id) is
P : Entity_Id := Scope (Unit_Name);
begin
if P /= Standard_Standard then
-- Unit is child unit, only ultimate ancestor is immediately visible
while Scope (P) /= Standard_Standard loop
P := Scope (P);
end loop;
Set_Is_Immediately_Visible (P);
else
Set_Is_Immediately_Visible (Unit_Name);
end if;
end Install_Withed_Unit;
-----------------------
-- 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) is
Body_Name : Unit_Name_Type;
Unum : Unit_Number_Type;
begin
Body_Name := Get_Body_Name (Get_Unit_Name (Unit (N)));
Unum := Load_Unit (Body_Name, True, N);
Compiler_State := Analyzing; -- reset after load
if Unum /= No_Unit
and then not Fatal_Error (Unum)
then
if Debug_Flag_L then
Write_Str ("*** Loaded generic body");
Write_Eol;
end if;
Semantics (Cunit (Unum));
end if;
end Load_Needed_Body;
----------------------
-- Install_Parents --
----------------------
procedure Install_Parents (Lib_Unit : Node_Id) is
P : Node_Id;
E_Name : Entity_Id;
P_Name : Entity_Id;
P_Spec : Node_Id;
begin
if Is_Child_Spec (Lib_Unit) then
P := Unit (Parent_Spec (Lib_Unit));
P_Name := Find_Lib_Unit_Entity (P);
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
then
Error_Msg_N
("child of a generic package must be generic unit", Lib_Unit);
elsif Ekind (P_Name) /= E_Generic_Package
and then Ekind (P_Name) /= E_Package
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;
end if;
-- This is the recursive call that ensures all parents are loaded
Install_Parents (P);
-- Now we can install the context for this parent
Install_Context (Parent_Spec (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.
Set_Is_Immediately_Visible (P_Name, True);
-- Find entity for compilation unit, and set its private descendant
-- status as needed.
E_Name := Find_Lib_Unit_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 (Get_Declaration_Node (P_Name));
New_Scope (P_Name);
Install_Visible_Declarations (P_Name);
Set_Use (Visible_Declarations (P_Spec));
if Private_Present (Parent (Lib_Unit)) then
Install_Private_Declarations (P_Name);
Set_Use (Private_Declarations (P_Spec));
end if;
-- If the unit is not a child unit, or is a body, nothing to do.
else
null;
end if;
end Install_Parents;
-------------------
-- 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;
--------------------
-- Remove_Parents --
--------------------
procedure Remove_Parents (Lib_Unit : Node_Id) is
P : Node_Id;
P_Name : Entity_Id;
P_Spec : Node_Id;
begin
if Is_Child_Spec (Lib_Unit) then
P := Unit (Parent_Spec (Lib_Unit));
P_Name := Find_Lib_Unit_Entity (P);
P_Spec := Specification (Get_Declaration_Node (P_Name));
Remove_Context (Parent_Spec (Lib_Unit));
End_Package_Scope (P_Name);
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_Context --
--------------------
procedure Remove_Context (N : Node_Id) is
Lib_Unit : constant Node_Id := Unit (N);
Item : Node_Id;
Unit_Name : Entity_Id;
begin
-- Loop through context items looking for with 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 Context_Installed (Item)
then
-- Remove items from one with'ed unit
Unit_Name := Entity (Name (Item));
Remove_Withed_Unit (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);
end if;
Item := Next (Item);
end loop;
Remove_Parents (Lib_Unit);
end Remove_Context;
------------------------
-- Remove_Withed_Unit --
------------------------
procedure Remove_Withed_Unit (Unit_Name : Entity_Id) is
P : Entity_Id := Scope (Unit_Name);
begin
if Debug_Flag_I then
Write_Str ("remove withed unit ");
Write_Name (Chars (Unit_Name));
Write_Eol;
end if;
if P /= Standard_Standard then
-- Ultimate ancestor is not immediately visible any longer.
while Scope (P) /= Standard_Standard loop
P := Scope (P);
end loop;
-- Set_Is_Immediately_Visible (P, False);
-- This cannot be done unconditionally, because the unit may
-- be otherwise visible. It is necessary to know whether this
-- withed unit was the one installed, or whether there is a
-- separate with-clause that installed the ancestor. ???
end if;
Set_Is_Potentially_Use_Visible (Unit_Name, False);
Set_Is_Immediately_Visible (Unit_Name, False);
end Remove_Withed_Unit;
end Sem_Ch10;