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_ch6.adb
< prev
next >
Wrap
Text File
|
1996-09-28
|
69KB
|
2,090 lines
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M _ C H 6 --
-- --
-- B o d y --
-- --
-- $Revision: 1.235 $ --
-- --
-- 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 Casing; use Casing;
with Checks; use Checks;
with Debug; use Debug;
with Einfo; use Einfo;
with Errout; use Errout;
with Expander; use Expander;
with Lib; use Lib;
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_Ch3; use Sem_Ch3;
with Sem_Ch4; use Sem_Ch4;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch12; use Sem_Ch12;
with Sem_Disp; use Sem_Disp;
with Sem_Dist; use Sem_Dist;
with Sem_Eval; use Sem_Eval;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinput; use Sinput;
with Stand; use Stand;
with Sinfo; use Sinfo;
with Sinfo.CN; use Sinfo.CN;
with Snames; use Snames;
with Stringt; use Stringt;
with Style;
with Tbuild; use Tbuild;
with Uintp; use Uintp;
with Urealp; use Urealp;
package body Sem_Ch6 is
-----------------------
-- Local Subprograms --
-----------------------
procedure Analyze_Generic_Subprogram_Body (N : Node_Id; Gen_Id : Entity_Id);
-- Analyze a generic subprogram body
type Conformance_Type is
(Type_Conformant, Mode_Conformant, Subtype_Conformant, Fully_Conformant);
procedure Check_Conformance
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Ctype : Conformance_Type;
Errmsg : Boolean;
Conforms : out Boolean;
Err_Loc : Node_Id := Empty);
-- GIven two entities, this procedure checks that the profiles associated
-- with these entities meet the conformance criterion given by the third
-- parameter. If they conform, Conforms is set True and control returns
-- to the caller. If they do not conform, Conforms is set to False, and
-- in addition, if Errmsg is True on the call, proper messages are output
-- to complain about the conformance failure. If Err_Loc is non_Empty
-- the error messages are placed on Err_Loc, if Err_Loc is empty, then
-- error messages are placed on the appropriate part of the construct
-- denoted by New_Id.
procedure Enter_Overloaded_Entity (S : Entity_Id);
-- This procedure makes S, a new overloaded entity, into the first
-- visible entity with that name.
function Fully_Conformant_Expressions (E1, E2 : Node_Id) return Boolean;
-- Determines if two expressions are fully conformant (RM 6.3.1(18-21))
procedure Install_Entity (E : Entity_Id);
-- Make single entity visible. Used for generic formals as well.
procedure Install_Formals (Id : Entity_Id);
-- On entry to a subprogram body, make the formals visible. Note
-- that simply placing the subprogram on the scope stack is not
-- sufficient: the formals must become the current entities for
-- their names.
procedure Make_Inequality_Operator (S : Entity_Id);
-- Create the declaration for an inequality operator that is implicitly
-- created by a user-defined equality operator that yields a boolean.
procedure May_Need_Actuals (Fun : Entity_Id);
-- Flag functions that can be called without parameters, i.e. those that
-- have no parameters, or those for which defaults exist for all parameters
procedure Valid_Operator_Definition (Designator : Entity_Id);
-- Verify that an operator definition has the proper number of formals
---------------------------------------------
-- Analyze_Abstract_Subprogram_Declaration --
---------------------------------------------
procedure Analyze_Abstract_Subprogram_Declaration (N : Node_Id) is
Designator : constant Entity_Id := Analyze_Spec (Specification (N));
ELU : constant Entity_Id := Current_Scope;
Pure_Flag : constant Boolean := Is_Pure (ELU);
RCI_Flag : constant Boolean := Is_Remote_Call_Interface (ELU);
RT_Flag : constant Boolean := Is_Remote_Types (ELU);
begin
New_Overloaded_Entity (Designator);
Set_Is_Abstract (Designator);
Check_Delayed_Subprogram (Designator);
-- Entities declared in Pure unit should be set Is_Pure
-- Since 'Partition_ID cannot be applied to such an entity
-- Subprogram declared in RCI unit should be set
-- Is_Remote_Call_Interface, used to verify remote call.
Set_Is_Pure (Designator, Pure_Flag);
Set_Is_Remote_Call_Interface (Designator, RCI_Flag);
Set_Is_Remote_Types (Designator, RT_Flag);
end Analyze_Abstract_Subprogram_Declaration;
----------------------------
-- Analyze_Function_Call --
----------------------------
procedure Analyze_Function_Call (N : Node_Id) is
P : constant Node_Id := Name (N);
L : constant List_Id := Parameter_Associations (N);
Actual : Node_Id;
begin
Analyze (P);
-- If error analyzing name, then set Any_Type as result type and return
if Etype (P) = Any_Type then
Set_Etype (N, Any_Type);
return;
end if;
-- Otherwise analyze the parameters
if Present (L) then
Actual := First (L);
while Present (Actual) loop
Analyze (Actual);
Actual := Next (Actual);
end loop;
end if;
Analyze_Call (N);
end Analyze_Function_Call;
-------------------------------------
-- Analyze_Generic_Subprogram_Body --
-------------------------------------
procedure Analyze_Generic_Subprogram_Body
(N : Node_Id;
Gen_Id : Entity_Id)
is
Gen_Decl : constant Node_Id := Get_Declaration_Node (Gen_Id);
Spec : Node_Id;
Kind : constant Entity_Kind := Ekind (Gen_Id);
Nam : Entity_Id;
New_N : Node_Id;
begin
-- Copy body, and disable expansion while analyzing the generic.
New_N := Copy_Generic_Node (N, Empty, Instantiating => False);
Rewrite_Substitute_Tree (N, New_N);
Expander_Mode_Save_And_Set (False);
Spec := Specification (N);
-- Within the body of the generic, the subprogram is callable, and
-- behaves like the corresponding non-generic unit.
Nam := Defining_Unit_Simple_Name (Spec);
if Kind = E_Generic_Procedure
and then Nkind (Spec) /= N_Procedure_Specification
then
Error_Msg_N ("invalid body for generic procedure ", Nam);
return;
elsif Kind = E_Generic_Function
and then Nkind (Spec) /= N_Function_Specification
then
Error_Msg_N ("invalid body for generic function ", Nam);
return;
end if;
Set_Corresponding_Body (Gen_Decl, Nam);
Set_Corresponding_Spec (N, Gen_Id);
Set_Has_Completion (Gen_Id);
if Nkind (N) = N_Subprogram_Body_Stub then
return;
end if;
-- Make generic parameters immediately visible in the body. They are
-- needed to process the formals declarations. Then make the formals
-- visible in a separate step.
New_Scope (Gen_Id);
declare
E : Entity_Id;
begin
E := First_Entity (Gen_Id);
while Present (E) and then Ekind (E) not in Formal_Kind loop
Install_Entity (E);
E := Next_Entity (E);
end loop;
Set_Use (Generic_Formal_Declarations (Gen_Decl));
-- Now generic formals are visible, and the specification can be
-- analyzed, for subsequent conformance check.
Nam := Analyze_Spec (Spec);
if Present (E) then
-- E is the first formal parameter, which must be the first
-- entity in the subprogram body.
Set_First_Entity (Gen_Id, E);
-- Now make formal parameters visible
while Present (E) loop
Install_Entity (E);
E := Next_Formal (E);
end loop;
end if;
end;
-- Visible generic entity is callable within its own body.
Set_Ekind (Gen_Id, Ekind (Nam));
Set_Convention (Nam, Convention (Gen_Id));
Check_Fully_Conformant (Nam, Gen_Id, Nam);
Set_Actual_Subtypes (N, Current_Scope);
Analyze_Declarations (Declarations (N));
Check_Completion;
Analyze (Handled_Statement_Sequence (N));
Save_Global_References (Original_Node (N));
-- Prior to exiting the scope, include generic formals again
-- in the set of local entities.
Set_First_Entity (Gen_Id, First_Entity (Gen_Id));
End_Scope;
-- Outside of its body, unit is generic again.
Set_Ekind (Gen_Id, Kind);
Expander_Mode_Restore;
end Analyze_Generic_Subprogram_Body;
-----------------------------
-- Analyze_Operator_Symbol --
-----------------------------
-- An operator symbol such as "+" or "and" may appear in context where
-- the literal denotes an entity name, such as "+"(x, y) or in a
-- context when it is just a string, as in (conjunction = "or"). In
-- these cases the parser generates this node, and the semantics does
-- the disambiguation. Other such case are actuals in an instantiation,
-- the generic unit in an instantiation, and pragma arguments.
procedure Analyze_Operator_Symbol (N : Node_Id) is
Par : Node_Id := Parent (N);
begin
if (Nkind (Par) = N_Function_Call and then N = Name (Par))
or else Nkind (Par) = N_Function_Instantiation
or else (Nkind (Par) = N_Indexed_Component and then N = Prefix (Par))
or else (Nkind (Par) = N_Pragma_Argument_Association
and then not Is_Pragma_String_Literal (Par))
or else Nkind (Par) = N_Subprogram_Renaming_Declaration
then
Find_Direct_Name (N);
else
Change_Operator_Symbol_To_String_Literal (N);
Analyze (N);
end if;
end Analyze_Operator_Symbol;
-----------------------------------
-- Analyze_Parameter_Association --
-----------------------------------
procedure Analyze_Parameter_Association (N : Node_Id) is
begin
Analyze (Explicit_Actual_Parameter (N));
end Analyze_Parameter_Association;
----------------------------
-- Analyze_Procedure_Call --
----------------------------
procedure Analyze_Procedure_Call (N : Node_Id) is
P : constant Node_Id := Name (N);
Actuals : constant List_Id := Parameter_Associations (N);
Actual : Node_Id;
Loc : Source_Ptr := Sloc (N);
New_N : Node_Id;
S : Entity_Id;
procedure Analyze_And_Resolve;
-- Do Analyze and Resolve calls for procedure call
procedure Analyze_And_Resolve is
begin
Analyze_Call (N);
Resolve (N, Standard_Void_Type);
end Analyze_And_Resolve;
-- Start of processing for Analyze_Procedure_Call
begin
-- The syntactic construct: PREFIX ACTUAL_PARAMETER_PART can denote
-- a procedure call or an entry call. The prefix may denote an access
-- to subprogram type, in which case an implicit dereference applies.
-- If the prefix is an indexed component (without implicit defererence)
-- then the construct denotes a call to a member of an entire family.
-- If the prefix is a simple name, it may still denote a call to a
-- parameterless member of an entry family. Resolution of these various
-- interpretations is delicate.
Analyze (P);
-- If error analyzing prefix, then set Any_Type as result and return
if Etype (P) = Any_Type then
Set_Etype (N, Any_Type);
return;
end if;
-- Otherwise analyze the parameters
if Present (Actuals) then
Actual := First (Actuals);
while Present (Actual) loop
Analyze (Actual);
Actual := Next (Actual);
end loop;
end if;
-- Special processing for Elab_Spec and Elab_Body calls
if Nkind (P) = N_Attribute_Reference
and then (Attribute_Name (P) = Name_Elab_Spec
or else Attribute_Name (P) = Name_Elab_Body)
then
if Present (Actuals) then
Error_Msg_N
("no parameters allowed for this call", First (Actuals));
return;
end if;
Set_Etype (N, Standard_Void_Type);
Set_Analyzed (N);
elsif Is_Entity_Name (P)
and then Ekind (Entity (P)) /= E_Entry_Family
then
Analyze_And_Resolve;
-- If the prefix is the simple name of an entry family, this is
-- a parameterless call from within the task body itself.
elsif Is_Entity_Name (P)
and then Nkind (P) = N_Identifier
and then Ekind (Entity (P)) = E_Entry_Family
and then Present (Actuals)
and then No (Next (First (Actuals)))
then
-- Can be call to parameterless entry family. What appears to be
-- the sole argument is in fact the entry index. Rewrite prefix
-- of node accordingly. Source representation is unchanged by this
-- transformation.
New_N :=
Make_Indexed_Component (Loc,
Prefix =>
Make_Selected_Component (Loc,
Prefix => New_Occurrence_Of (Scope (Entity (P)), Loc),
Selector_Name => New_Occurrence_Of (Entity (P), Loc)),
Expressions => Actuals);
Set_Name (N, New_N);
Set_Etype (New_N, Standard_Void_Type);
Set_Parameter_Associations (N, No_List);
Analyze_And_Resolve;
elsif Nkind (P) = N_Explicit_Dereference then
if Ekind (Etype (P)) = E_Subprogram_Type then
Analyze_And_Resolve;
else
Error_Msg_N ("expect access to procedure in call", P);
end if;
-- The name can be a selected component or an indexed component
-- that yields an access to subprogram. Such a prefix is legal if
-- the call has parameter associations.
elsif Is_Access_Type (Etype (P))
and then Ekind (Designated_Type (Etype (P))) = E_Subprogram_Type
then
if Present (Actuals) then
Analyze_And_Resolve;
else
Error_Msg_N ("missing explicit dereference in call ", N);
end if;
-- If not an access to subprogram, then the prefix must resolve to
-- the name of an entry, entry family, or protected operation.
-- For the case of a simple entry call, P is a selected component
-- where the prefix is the task and the selector name is the entry.
-- A call to a protected procedure will have the same syntax.
elsif Nkind (P) = N_Selected_Component
and then (Ekind (Entity (Selector_Name (P))) = E_Entry
or else
Ekind (Entity (Selector_Name (P))) = E_Procedure)
then
Analyze_And_Resolve;
elsif Nkind (P) = N_Selected_Component
and then Ekind (Entity (Selector_Name (P))) = E_Entry_Family
and then Present (Actuals)
and then No (Next (First (Actuals)))
then
-- Can be call to parameterless entry family. What appears to be
-- the sole argument is in fact the entry index. Rewrite prefix
-- of node accordingly. Source representation is unchanged by this
-- transformation.
New_N :=
Make_Indexed_Component (Loc,
Prefix => New_Copy (P),
Expressions => Actuals);
Set_Name (N, New_N);
Set_Etype (New_N, Standard_Void_Type);
Set_Parameter_Associations (N, No_List);
Analyze_And_Resolve;
-- For the case of a reference to an element of an entry family, P is
-- an indexed component whose prefix is a selected component (task and
-- entry family), and whose index is the entry family index.
elsif Nkind (P) = N_Indexed_Component
and then Nkind (Prefix (P)) = N_Selected_Component
and then Ekind (Entity (Selector_Name (Prefix (P)))) = E_Entry_Family
then
Analyze_And_Resolve;
-- If the prefix is the name of an entry family, it is a call from
-- within the task body itself.
elsif Nkind (P) = N_Indexed_Component
and then Nkind (Prefix (P)) = N_Identifier
and then Ekind (Entity (Prefix (P))) = E_Entry_Family
then
New_N :=
Make_Selected_Component (Loc,
Prefix => New_Occurrence_Of (Scope (Entity (Prefix (P))), Loc),
Selector_Name => New_Occurrence_Of (Entity (Prefix (P)), Loc));
Rewrite_Substitute_Tree (Prefix (P), New_N);
Analyze (P);
Analyze_And_Resolve;
-- Anything else is an error.
else
Error_Msg_N ("Invalid procedure or entry call", N);
end if;
end Analyze_Procedure_Call;
------------------
-- Analyze_Spec --
------------------
function Analyze_Spec (N : Node_Id) return Entity_Id is
Designator : constant Entity_Id := Defining_Unit_Simple_Name (N);
Formals : constant List_Id := Parameter_Specifications (N);
begin
if Nkind (N) = N_Function_Specification then
Set_Ekind (Designator, E_Function);
Find_Type (Subtype_Mark (N));
Set_Etype (Designator, Entity (Subtype_Mark (N)));
else
Set_Ekind (Designator, E_Procedure);
Set_Etype (Designator, Standard_Void_Type);
end if;
if Present (Formals) then
Set_Scope (Designator, Current_Scope);
New_Scope (Designator);
Process_Formals (Designator, Formals, N);
End_Scope;
end if;
if Nkind (N) = N_Function_Specification then
if Nkind (Designator) = N_Defining_Operator_Symbol then
Valid_Operator_Definition (Designator);
end if;
May_Need_Actuals (Designator);
if Is_Abstract (Etype (Designator))
and then Nkind (Parent (N)) /= N_Abstract_Subprogram_Declaration
then
Error_Msg_N
("function that returns abstract type must be abstract", N);
end if;
end if;
return Designator;
end Analyze_Spec;
-----------------------------
-- Analyze_Subprogram_Body --
-----------------------------
-- This procedure is called for regular subprogram bodies, generic bodies,
-- and for subprogram stubs of both kinds. In the case of stubs, only the
-- specification matters, and is used to create a proper declaration for
-- the subprogram, or to perform conformance checks.
procedure Analyze_Subprogram_Body (N : Node_Id) is
Spec : constant Node_Id := Specification (N);
Nam : constant Entity_Id := Defining_Unit_Simple_Name (Spec);
Gen_Id : constant Entity_Id := Current_Entity_In_Scope (Nam);
Decls : List_Id;
Loc : Source_Ptr;
Subp : Entity_Id;
Prev : Entity_Id;
Last_Formal : Entity_Id;
Vsn_Name : Name_Id;
begin
if Debug_Flag_C then
Write_Str ("==== Compiling subprogram body ");
Write_Name (Chars (Nam));
Write_Str (" from ");
Write_Location (Sloc (N));
Write_Eol;
end if;
Trace_Scope (N, Nam, " Analyze subprogram");
Set_Ekind (Nam, E_Subprogram_Body);
-- Generic subprograms are handled separately. They always have
-- a generic specification. Determine whether current scope has
-- a previous declaration.
if Present (Gen_Id)
and then not Is_Overloadable (Gen_Id)
then
if Ekind (Gen_Id) = E_Generic_Procedure
or else Ekind (Gen_Id) = E_Generic_Function
then
Analyze_Generic_Subprogram_Body (N, Gen_Id);
return;
else
-- Previous entity conflicts with subprogram name.
-- Attempting to enter name will post error.
Enter_Name (Nam);
return;
end if;
-- Non-generic case, find the subprogram declaration, if one was
-- seen, or enter new overloaded entity in the current scope.
else
Subp := Analyze_Spec (Spec);
-- Get corresponding spec if not already set (the latter happens
-- in the case of a subprogram instantiation, where the field
-- was set during the instantiation)
if Nkind (N) = N_Subprogram_Body_Stub
or else No (Corresponding_Spec (N))
then
Prev := Find_Corresponding_Spec (N);
else
Prev := Corresponding_Spec (N);
end if;
end if;
-- Place subprogram on scope stack, and make formals visible. If there
-- is a spec, the visible entity remains that of the spec. The defining
-- entity for the body is entered in the chain of entities in that case,
-- to insure that it is instantiated if it appears in a generic unit.
if Present (Prev) then
if Is_Abstract (Prev) then
Error_Msg_N ("an abstract subprogram cannot have a body", N);
return;
else
Set_Convention (Subp, Convention (Prev));
Check_Fully_Conformant (Subp, Prev, Subp);
end if;
if Nkind (N) /= N_Subprogram_Body_Stub then
Set_Corresponding_Spec (N, Prev);
Install_Formals (Prev);
Last_Formal := Last_Entity (Prev);
New_Scope (Prev);
end if;
Set_Corresponding_Body (Get_Declaration_Node (Prev), Subp);
else
if Style_Check and then Comes_From_Source (Nam) then
Style.Body_With_No_Spec (N);
end if;
New_Overloaded_Entity (Subp);
if Nkind (N) /= N_Subprogram_Body_Stub then
Set_Acts_As_Spec (N);
Install_Formals (Subp);
New_Scope (Subp);
end if;
end if;
Set_Has_Completion (Subp);
if Nkind (N) = N_Subprogram_Body_Stub then
return;
else
Set_Actual_Subtypes (N, Current_Scope);
Analyze_Declarations (Declarations (N));
Check_Completion;
-- Expand cleanup actions if necessary
Analyze (Handled_Statement_Sequence (N));
End_Scope;
if Present (Prev) then
-- Chain the declared entities on the id for the body.
-- The id for the spec only holds the formals.
if Present (Last_Formal) then
Set_Next_Entity
(Last_Entity (Subp), Next_Entity (Last_Formal));
Set_Next_Entity (Last_Formal, Empty);
else
Set_First_Entity (Subp, First_Entity (Prev));
Set_First_Entity (Prev, Empty);
end if;
end if;
end if;
-- If function, make sure we had at least one return statement
if Ekind (Nam) = E_Function
or else Ekind (Nam) = E_Generic_Function
then
if (Present (Prev) and then Return_Present (Prev))
or else (No (Prev) and then Return_Present (Subp))
then
null;
else
Error_Msg_N ("missing RETURN statement in function body", N);
end if;
end if;
end Analyze_Subprogram_Body;
-------------------------
-- Set_Actual_Subtypes --
-------------------------
procedure Set_Actual_Subtypes (N : Node_Id; Subp : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
Decl : Node_Id;
Formal : Entity_Id;
T : Entity_Id;
begin
Formal := First_Formal (Subp);
-- Expansion does not apply to initialization procedures, where
-- discriminants are handled specially.
if Chars (Formal) = Name_uInit then
return;
end if;
while Present (Formal) loop
T := Etype (Formal);
if (Is_Array_Type (T)
and then not Is_Constrained (T))
or else (Ekind (T) = E_Record_Type
and then Has_Discriminants (T))
then
Decl := Build_Actual_Subtype (T, Formal);
if Nkind (N) = N_Accept_Statement then
if Present (Handled_Statement_Sequence (N)) then
Prepend (Decl, Statements (Handled_Statement_Sequence (N)));
Mark_Rewrite_Insertion (Decl);
else
-- If the accept statement has no body, there will be
-- no reference to the actuals, so no need to compute
-- actual subtypes.
return;
end if;
else
Prepend (Decl, Declarations (N));
Mark_Rewrite_Insertion (Decl);
end if;
Analyze (Decl);
Set_Actual_Subtype (Formal, Defining_Identifier (Decl));
else
Set_Actual_Subtype (Formal, T);
end if;
Formal := Next_Formal (Formal);
end loop;
end Set_Actual_Subtypes;
------------------------------------
-- Analyze_Subprogram_Declaration --
------------------------------------
procedure Analyze_Subprogram_Declaration (N : Node_Id) is
Designator : constant Entity_Id := Analyze_Spec (Specification (N));
ELU : constant Entity_Id := Current_Scope;
Pure_Flag : Boolean;
RCI_Flag : Boolean;
RT_Flag : Boolean;
Param_Spec : Node_Id;
begin
-- Check for RCI unit subprogram declarations against in-lined
-- subprograms and subprograms having access parameter or limited
-- parameter without Read and Write (RM E.2.3(12-13)).
Validate_RCI_Subprogram_Declaration (N);
Trace_Scope
(N,
Defining_Unit_Simple_Name (Specification (N)),
" Analyze subprogram spec. ");
if Debug_Flag_C then
Write_Str ("==== Compiling subprogram spec ");
Write_Name (Chars (Designator));
Write_Str (" from ");
Write_Location (Sloc (N));
Write_Eol;
end if;
New_Overloaded_Entity (Designator);
Check_Delayed_Subprogram (Designator);
Set_Suppress_Elaboration_Checks (Designator,
Elaboration_Checks_Suppressed (Designator));
-- Entities declared in Pure unit should be set Is_Pure
-- Since 'Partition_ID cannot be applied to such an entity
-- Subprogram declared in RCI unit should be set
-- Is_Remote_Call_Interface, used to verify remote call.
if ELU /= Standard_Standard then
Pure_Flag := Is_Pure (ELU);
Set_Is_Pure (Designator, Pure_Flag);
RCI_Flag := Is_Remote_Call_Interface (ELU);
Set_Is_Remote_Call_Interface (Designator, RCI_Flag);
RT_Flag := Is_Remote_Types (ELU);
Set_Is_Remote_Types (Designator, RT_Flag);
end if;
end Analyze_Subprogram_Declaration;
-----------------------
-- Check_Conformance --
-----------------------
procedure Check_Conformance
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Ctype : Conformance_Type;
Errmsg : Boolean;
Conforms : out Boolean;
Err_Loc : Node_Id := Empty)
is
Old_Type : constant Entity_Id := Etype (Old_Id);
New_Type : constant Entity_Id := Etype (New_Id);
Old_Formal : Entity_Id;
New_Formal : Entity_Id;
function Base_Types_Match (T1, T2 : Entity_Id) return Boolean;
-- If neither T1 nor T2 are generic actual types, then verify
-- that the base types are equal. Otherwise T1 and T2 must be
-- on the same subtype chain. The whole purpose of this procedure
-- is to prevent spurious ambiguities in an instantiation that may
-- arise if two distinct generic types are instantiated with the
-- same actual.
procedure Conformance_Error (Msg : String; N : Node_Id);
-- Post error message for conformance error on given node.
-- Two messages are output. The first points to the previous
-- declaration with a general "no conformance" message.
-- The second is the detailed reason, supplied as Msg. The
-- parameter N provide information for a possible & insertion
-- in the message, and also provides the location for posting
-- the message in the absence of a specified Err_Loc location.
function Conforming_Types (Oldt, Newt : Entity_Id) return Boolean;
-- Check that two formal parameter types conform, checking both
-- for equality of base types, and where required statically
-- matching subtypes, depending on the setting of Ctype.
function Base_Types_Match (T1, T2 : Entity_Id) return Boolean is
begin
if T1 = T2 then
return True;
elsif Base_Type (T1) = Base_Type (T2) then
-- The following is too permissive. A more precise test must
-- check that the generic actual is an ancestor subtype of the
-- other.
return not Is_Generic_Actual_Type (T1)
or else not Is_Generic_Actual_Type (T2);
else
return False;
end if;
end Base_Types_Match;
procedure Conformance_Error (Msg : String; N : Node_Id) is
Enode : Node_Id;
begin
Conforms := False;
if Errmsg then
if No (Err_Loc) then
Enode := N;
else
Enode := Err_Loc;
end if;
Error_Msg_Sloc := Sloc (Old_Id);
case Ctype is
when Type_Conformant =>
Error_Msg_N
("not type conformant with declaration#!", Enode);
when Mode_Conformant =>
Error_Msg_N
("not mode conformant with declaration#!", Enode);
when Subtype_Conformant =>
Error_Msg_N
("not subtype conformant with declaration#!", Enode);
when Fully_Conformant =>
Error_Msg_N
("not fully conformant with declaration#!", Enode);
end case;
Error_Msg_NE (Msg, Enode, N);
end if;
end Conformance_Error;
function Conforming_Types (Oldt, Newt : Entity_Id) return Boolean is
begin
-- First see if base types match
if Base_Types_Match (Oldt, Newt) then
return Ctype <= Mode_Conformant
or else Subtypes_Statically_Match (Oldt, Newt);
elsif Is_Incomplete_Or_Private_Type (Oldt)
and then Present (Full_View (Oldt))
and then Base_Types_Match (Full_View (Oldt), Newt)
then
return Ctype <= Mode_Conformant
or else Subtypes_Statically_Match (Full_View (Oldt), Newt);
end if;
-- Test anonymous access type case. For this case, static subtype
-- matching is required for mode conformance (RM 6.3.1(15))
if Ekind (Oldt) = E_Anonymous_Access_Type
and then Ekind (Newt) = E_Anonymous_Access_Type
then
declare
Old_Desig : Entity_Id;
New_Desig : Entity_Id;
begin
Old_Desig := Directly_Designated_Type (Oldt);
if Is_Incomplete_Or_Private_Type (Old_Desig)
and then Present (Full_View (Old_Desig))
then
Old_Desig := Full_View (Old_Desig);
end if;
New_Desig := Directly_Designated_Type (Newt);
if Is_Incomplete_Or_Private_Type (New_Desig)
and then Present (Full_View (New_Desig))
then
New_Desig := Full_View (New_Desig);
end if;
return Base_Type (Old_Desig) = Base_Type (New_Desig)
and then (Ctype = Type_Conformant
or else
Subtypes_Statically_Match (Old_Desig, New_Desig));
end;
-- Otherwise definitely no match
else
return False;
end if;
end Conforming_Types;
-- Start of processing for Check_Conformance
begin
Conforms := True;
-- If both are functions/operators, check return types conform
if Old_Type /= Standard_Void_Type
and then New_Type /= Standard_Void_Type
then
if not Conforming_Types (Old_Type, New_Type) then
Conformance_Error ("return type does not match!", New_Id);
return;
end if;
-- If either is a function/operator and the other isn't, error
elsif Old_Type /= Standard_Void_Type
or else New_Type /= Standard_Void_Type
then
Conformance_Error ("functions can only match functions!", New_Id);
return;
end if;
-- In subtype conformant case, conventions must match (RM 6.3.1(16))
if Ctype >= Subtype_Conformant then
if Convention (Old_Id) /= Convention (New_Id) then
Conformance_Error ("calling conventions do not match!", New_Id);
return;
end if;
end if;
-- Deal with parameters
-- Note: we use the entity information, rather than going directly
-- to the specification in the tree. This is not only simpler, but
-- absolutely necessary for some cases of conformance tests between
-- operators, where the declaration tree simply does not exist!
Old_Formal := First_Formal (Old_Id);
New_Formal := First_Formal (New_Id);
while Present (Old_Formal) and then Present (New_Formal) loop
-- Types must always match
if not
Conforming_Types (Etype (Old_Formal), Etype (New_Formal))
then
Conformance_Error ("type of & does not match!", New_Formal);
return;
end if;
-- For mode conformance, mode must match
if Ctype >= Mode_Conformant
and then Parameter_Mode (Old_Formal) /= Parameter_Mode (New_Formal)
then
Conformance_Error ("mode of & does not match!", New_Formal);
return;
end if;
-- Full conformance checks
if Ctype = Fully_Conformant then
-- Names must match
if Chars (Old_Formal) /= Chars (New_Formal) then
Conformance_Error ("name & does not match!", New_Formal);
return;
-- And default expressions for in parameters
elsif Parameter_Mode (Old_Formal) = E_In_Parameter then
-- Make sure both expressions are analyzed and resolved.
-- As a result of our decision to delay the analyze/resolve
-- until the Freeze_All, we can encounter unanalyzed cases
-- at this stage.
if Present (Default_Value (Old_Formal)) then
Analyze (Default_Value (Old_Formal));
Resolve (Default_Value (Old_Formal), Etype (Old_Formal));
end if;
if Present (Default_Value (New_Formal)) then
Analyze (Default_Value (New_Formal));
Resolve (Default_Value (New_Formal), Etype (New_Formal));
end if;
if not
Fully_Conformant_Expressions
(Default_Value (Old_Formal), Default_Value (New_Formal))
then
Conformance_Error
("default expression for & does not match!", New_Formal);
return;
end if;
end if;
end if;
-- A couple of special checks for Ada 83 mode. These checks are
-- skipped if either entity is an operator in package Standard.
-- or if either old or new instance is not from the source program.
if Ada_83
and then Sloc (Old_Id) > Standard_Location
and then Sloc (New_Id) > Standard_Location
and then Comes_From_Source (Old_Id)
and then Comes_From_Source (New_Id)
then
declare
Old_Param : constant Node_Id := Declaration_Node (Old_Formal);
New_Param : constant Node_Id := Declaration_Node (New_Formal);
begin
-- Explicit IN must be present or absent in both cases. This
-- test is required only in the full conformance case.
if In_Present (Old_Param) /= In_Present (New_Param)
and then Ctype = Fully_Conformant
then
Conformance_Error
("(Ada 83) IN must appear in both declarations",
New_Formal);
return;
end if;
-- Grouping (use of comma in param lists) must be the same
-- This is where we catch a misconformance like:
-- A,B : Integer
-- A : Integer; B : Integer
-- which are represented identically in the tree except
-- for the setting of the flags More_Ids and Prev_Ids.
if More_Ids (Old_Param) /= More_Ids (New_Param)
or else Prev_Ids (Old_Param) /= Prev_Ids (New_Param)
then
Conformance_Error
("grouping of & does not match!", New_Formal);
return;
end if;
end;
end if;
Old_Formal := Next_Formal (Old_Formal);
New_Formal := Next_Formal (New_Formal);
end loop;
if Present (Old_Formal) then
Conformance_Error ("too few parameters!", New_Id);
return;
elsif Present (New_Formal) then
Conformance_Error ("too many parameters!", New_Formal);
return;
end if;
end Check_Conformance;
------------------------------
-- Check_Delayed_Subprogram --
------------------------------
procedure Check_Delayed_Subprogram (Designator : Entity_Id) is
F : Entity_Id;
procedure Possible_Freeze (T : Entity_Id);
-- T is the type of either a formal parameter or of the return type.
-- If T is not yet frozen and needs a delayed freeze, then the
-- subprogram itself must be delayed.
procedure Possible_Freeze (T : Entity_Id) is
begin
if Has_Delayed_Freeze (T)
and then not Is_Frozen (T)
then
Set_Has_Delayed_Freeze (Designator);
elsif Is_Access_Type (T)
and then Has_Delayed_Freeze (Designated_Type (T))
and then not Is_Frozen (Designated_Type (T))
then
Set_Has_Delayed_Freeze (Designator);
end if;
end Possible_Freeze;
-- Start of processing for Check_Delayed_Subprogram
begin
-- Never need to freeze abstract subprogram
if Is_Abstract (Designator) then
return;
end if;
-- Need delayed freeze if return type itself needs a delayed
-- freeze and is not yet frozen.
Possible_Freeze (Etype (Designator));
Possible_Freeze (Base_Type (Etype (Designator))); -- needed ???
-- Need delayed freeze if any of the formal types themselves need
-- a delayed freeze and are not yet frozen.
F := First_Formal (Designator);
while Present (F) loop
Possible_Freeze (Etype (F));
Possible_Freeze (Base_Type (Etype (F))); -- needed ???
F := Next_Formal (F);
end loop;
end Check_Delayed_Subprogram;
----------------------------
-- Check_Fully_Conformant --
----------------------------
procedure Check_Fully_Conformant
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Err_Loc : Node_Id := Empty)
is
Result : Boolean;
begin
Check_Conformance
(New_Id, Old_Id, Fully_Conformant, True, Result, Err_Loc);
end Check_Fully_Conformant;
---------------------------
-- Check_Mode_Conformant --
---------------------------
procedure Check_Mode_Conformant
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Err_Loc : Node_Id := Empty)
is
Result : Boolean;
begin
Check_Conformance
(New_Id, Old_Id, Mode_Conformant, True, Result, Err_Loc);
end Check_Mode_Conformant;
------------------------------
-- Check_Subtype_Conformant --
------------------------------
procedure Check_Subtype_Conformant
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Err_Loc : Node_Id := Empty)
is
Result : Boolean;
begin
Check_Conformance
(New_Id, Old_Id, Subtype_Conformant, True, Result, Err_Loc);
end Check_Subtype_Conformant;
---------------------------
-- Check_Type_Conformant --
---------------------------
procedure Check_Type_Conformant
(New_Id : Entity_Id;
Old_Id : Entity_Id;
Err_Loc : Node_Id := Empty)
is
Result : Boolean;
begin
Check_Conformance
(New_Id, Old_Id, Type_Conformant, True, Result, Err_Loc);
end Check_Type_Conformant;
-----------------------------
-- Enter_Overloaded_Entity --
-----------------------------
procedure Enter_Overloaded_Entity (S : Entity_Id) is
E : Entity_Id;
begin
E := Current_Entity_In_Scope (S);
if Present (E) then
Set_Has_Homonym (E);
Set_Has_Homonym (S);
end if;
E := Current_Entity (S);
Set_Is_Immediately_Visible (S);
Set_Current_Entity (S);
Set_Scope (S, Current_Scope);
Set_Homonym (S, E);
Append_Entity (S, Current_Scope);
Set_Public_Status (S);
if Debug_Flag_E then
Write_Str ("New overloaded entity chain: ");
Write_Name (Chars (S));
E := S;
while Present (E) loop
Write_Str (" "); Write_Int (Int (E));
E := Homonym (E);
end loop;
Write_Eol;
end if;
-- If this is a user-defined equality operator that is not
-- a derived subprogram, create the corresponding inequality.
if Chars (S) = Name_Op_Eq
and then Etype (S) = Standard_Boolean
and then Present (Parent (S))
and then not Is_Tagged_Type (Etype (First_Formal (S)))
then
Make_Inequality_Operator (S);
end if;
end Enter_Overloaded_Entity;
-----------------------------
-- Find_Corresponding_Spec --
-----------------------------
function Find_Corresponding_Spec (N : Node_Id) return Entity_Id is
Spec : constant Node_Id := Specification (N);
Designator : constant Entity_Id := Defining_Unit_Simple_Name (Spec);
E : Entity_Id;
begin
E := Current_Entity (Designator);
while Present (E) loop
if Scope (E) = Current_Scope
and then Ekind (E) = Ekind (Designator)
and then Type_Conformant (E, Designator)
then
if not Has_Completion (E) then
if Nkind (N) /= N_Subprogram_Body_Stub then
Set_Corresponding_Spec (N, E);
end if;
Set_Has_Completion (E);
return E;
-- If body already exists, this is an error unless the
-- previous declaration is the implicit declaration of
-- a derived subprogram.
elsif No (Alias (E)) and then not Is_Internal (E) then
Error_Msg_N ("duplicate subprogram body", N);
end if;
end if;
E := Homonym (E);
end loop;
-- On exit, we know that no previous declaration of subprogram exists
return Empty;
end Find_Corresponding_Spec;
----------------------
-- Fully_Conformant --
----------------------
function Fully_Conformant (New_Id, Old_Id : Entity_Id) return Boolean is
Result : Boolean;
begin
Check_Conformance (New_Id, Old_Id, Fully_Conformant, False, Result);
return Result;
end Fully_Conformant;
----------------------------------
-- Fully_Conformant_Expressions --
----------------------------------
function Fully_Conformant_Expressions (E1, E2 : Node_Id) return Boolean is
function FCE (E1, E2 : Node_Id) return Boolean
renames Fully_Conformant_Expressions;
function FCL (L1, L2 : List_Id) return Boolean;
-- Compare elements of two lists for conformance
function FCL (L1, L2 : List_Id) return Boolean is
N1, N2 : Node_Id;
begin
if L1 = No_List then
N1 := Empty;
else
N1 := First (L1);
end if;
if L2 = No_List then
N2 := Empty;
else
N2 := First (L2);
end if;
while Present (N1) and then Present (N2) loop
if not FCE (N1, N2) then
return False;
end if;
N1 := Next (N1);
N2 := Next (N2);
end loop;
return No (N1) and then No (N2);
end FCL;
-- Start of processing for Fully_Conformant_Expressions
begin
-- Trivially conformant if both expressions are empty
if No (E1) and No (E2) then
return True;
-- Non-conformant if paren count does not match. Note: if some idiot
-- complains that we don't do this right for more than 15 levels of
-- parentheses, they will be treated with the respect they deserve!
elsif Paren_Count (E1) /= Paren_Count (E2) then
return False;
-- If same entities are referenced, then they are conformant
-- even if they have different forms (RM 8.3.1(19-20)).
elsif Is_Entity_Name (E1) and then Is_Entity_Name (E2) then
return Entity (E1) = Entity (E2);
-- Otherwise we must have the same syntactic entity
elsif Nkind (E1) /= Nkind (E2) then
return False;
-- Both expressions must be rewritten or not to be conformant
elsif Is_Rewrite_Substitution (E1) then
if not Is_Rewrite_Substitution (E2) then
return False;
-- If both nodes are rewritten compare trees before rewrite
else
return FCE (Original_Node (E1), Original_Node (E2));
end if;
-- At this point, we specialize by node type
else
case Nkind (E1) is
when N_Aggregate =>
return
FCL (Expressions (E1), Expressions (E2))
and then FCL (Component_Associations (E1),
Component_Associations (E2));
when N_Allocator =>
return
FCE (Expression (E1), Expression (E2));
when N_Attribute_Reference =>
return
Attribute_Name (E1) = Attribute_Name (E2)
and then FCL (Expressions (E1), Expressions (E2));
when N_Binary_Op =>
return
Entity (E1) = Entity (E2)
and then FCE (Left_Opnd (E1), Left_Opnd (E2))
and then FCE (Right_Opnd (E1), Right_Opnd (E2));
when N_And_Then | N_Or_Else | N_In | N_Not_In =>
return
FCE (Left_Opnd (E1), Left_Opnd (E2))
and then
FCE (Right_Opnd (E1), Right_Opnd (E2));
when N_Character_Literal =>
return
Char_Literal_Value (E1) = Char_Literal_Value (E2);
when N_Component_Association =>
return
FCL (Choices (E1), Choices (E2))
and then FCE (Expression (E1), Expression (E2));
when N_Concat_Multiple =>
return
FCL (Expressions (E1), Expressions (E2));
when N_Conditional_Expression =>
return
FCL (Expressions (E1), Expressions (E2));
when N_Explicit_Dereference =>
return
FCE (Prefix (E1), Prefix (E2));
when N_Extension_Aggregate =>
return
FCL (Expressions (E1), Expressions (E2))
and then Null_Record_Present (E1) =
Null_Record_Present (E2)
and then FCL (Component_Associations (E1),
Component_Associations (E2));
when N_Function_Call =>
return
FCE (Name (E1), Name (E2))
and then FCL (Parameter_Associations (E1),
Parameter_Associations (E2));
when N_Indexed_Component =>
return
FCE (Prefix (E1), Prefix (E2))
and then FCL (Expressions (E1), Expressions (E2));
when N_Integer_Literal =>
return (Intval (E1) = Intval (E2));
when N_Null =>
return True;
when N_Operator_Symbol =>
return
Chars (E1) = Chars (E2);
when N_Others_Choice =>
return True;
when N_Parameter_Association =>
return
FCE (Selector_Name (E1), Selector_Name (E2))
and then FCE (Explicit_Actual_Parameter (E1),
Explicit_Actual_Parameter (E2));
when N_Qualified_Expression =>
return
FCE (Subtype_Mark (E1), Subtype_Mark (E2))
and then FCE (Expression (E1), Expression (E2));
when N_Range =>
return
FCE (Low_Bound (E1), Low_Bound (E2))
and then FCE (High_Bound (E1), High_Bound (E2));
when N_Real_Literal =>
return (Realval (E1) = Realval (E2));
when N_Selected_Component =>
return
FCE (Prefix (E1), Prefix (E2))
and then FCE (Selector_Name (E1), Selector_Name (E2));
when N_Slice =>
return
FCE (Prefix (E1), Prefix (E2))
and then FCE (Discrete_Range (E1), Discrete_Range (E2));
when N_String_Literal =>
declare
S1 : constant String_Id := Strval (E1);
S2 : constant String_Id := Strval (E2);
L1 : constant Nat := String_Length (S1);
L2 : constant Nat := String_Length (S2);
begin
if L1 /= L2 then
return False;
else
for J in 1 .. L1 loop
if Get_String_Char (S1, J) /=
Get_String_Char (S2, J)
then
return False;
end if;
end loop;
return True;
end if;
end;
when N_Type_Conversion =>
return
FCE (Subtype_Mark (E1), Subtype_Mark (E2))
and then FCE (Expression (E1), Expression (E2));
when N_Unary_Op =>
return
Entity (E1) = Entity (E2)
and then FCE (Right_Opnd (E1), Right_Opnd (E2));
when N_Unchecked_Type_Conversion =>
return
FCE (Subtype_Mark (E1), Subtype_Mark (E2))
and then FCE (Expression (E1), Expression (E2));
-- All other node types cannot appear in this context. Strictly
-- we should do a pragma Assert (False). Instead we just ignore
-- the nodes. This means that if anyone makes a mistake in the
-- expander and mucks an expression tree irretrievably, the
-- result will be a failure to detect a (probably very obscure)
-- case of non-conformance, which is better than bombing on some
-- case where two expressions do in fact conform.
when others =>
return True;
end case;
end if;
end Fully_Conformant_Expressions;
--------------------
-- Install_Entity --
--------------------
procedure Install_Entity (E : Entity_Id) is
Prev : constant Entity_Id := Current_Entity (E);
begin
Set_Is_Immediately_Visible (E);
Set_Current_Entity (E);
Set_Homonym (E, Prev);
end Install_Entity;
---------------------
-- Install_Formals --
---------------------
procedure Install_Formals (Id : Entity_Id) is
F : Entity_Id;
begin
F := First_Formal (Id);
while Present (F) loop
Install_Entity (F);
F := Next_Formal (F);
end loop;
end Install_Formals;
------------------------------
-- Make_Inequality_Operator --
------------------------------
-- S is the defining identifier of an equality operator. We build a
-- subprogram declaration with the rignt signature. This operation is
-- intrinsic, because it is always expanded as the negation of the
-- call to the equality function.
procedure Make_Inequality_Operator (S : Entity_Id) is
Loc : constant Source_Ptr := Sloc (S);
Decl : Node_Id;
Formals : List_Id;
Op_Name : Entity_Id;
Stat : Node_Id;
Typ : constant Entity_Id := Etype (First_Formal (S));
A : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA);
B : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uB);
begin
Op_Name := Make_Defining_Operator_Symbol (Loc, Name_Op_Ne);
Formals := New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => A,
Parameter_Type =>
New_Reference_To (Etype (First_Formal (S)), Loc)),
Make_Parameter_Specification (Loc,
Defining_Identifier => B,
Parameter_Type =>
New_Reference_To (Etype (Next_Formal (First_Formal (S))), Loc)));
Decl :=
Make_Subprogram_Declaration (Loc,
Specification => Make_Function_Specification (Loc,
Defining_Unit_Name => Op_Name,
Parameter_Specifications => Formals,
Subtype_Mark => New_Reference_To (Standard_Boolean, Loc)));
Insert_After (Get_Declaration_Node (S), Decl);
Mark_Rewrite_Insertion (Decl);
Analyze (Decl);
Set_Has_Completion (Op_Name);
Set_Is_Intrinsic_Subprogram (Op_Name);
end Make_Inequality_Operator;
----------------------
-- May_Need_Actuals --
----------------------
procedure May_Need_Actuals (Fun : Entity_Id) is
F : Entity_Id;
B : Boolean;
begin
F := First_Formal (Fun);
B := True;
while Present (F) loop
if No (Default_Value (F)) then
B := False;
exit;
end if;
F := Next_Formal (F);
end loop;
Set_Needs_No_Actuals (Fun, B);
end May_Need_Actuals;
---------------------
-- Mode_Conformant --
---------------------
function Mode_Conformant (New_Id, Old_Id : Entity_Id) return Boolean is
Result : Boolean;
begin
Check_Conformance (New_Id, Old_Id, Mode_Conformant, False, Result);
return Result;
end Mode_Conformant;
---------------------------
-- New_Overloaded_Entity --
---------------------------
procedure New_Overloaded_Entity (S : Entity_Id) is
E : Entity_Id := Current_Entity_In_Scope (S);
Prev_Vis : Entity_Id := Empty;
begin
if No (E) then
Enter_Overloaded_Entity (S);
Check_Dispatching_Operation (S, Empty);
elsif not Is_Overloadable (E) then
-- Check for spurious conflict produced by a subprogram that has the
-- same name as that of the enclosing generic package. The conflict
-- occurs within an instance, between the subprogram and the renaming
-- declaration for the package. After the subprogram, the package
-- renaming declaration becomes hidden.
if Ekind (E) = E_Package
and then Present (Renamed_Object (E))
and then Renamed_Object (E) = Current_Scope
and then Nkind (Parent (Renamed_Object (E))) =
N_Package_Specification
and then Present (Generic_Parent (Parent (Renamed_Object (E))))
then
Set_Is_Private (E);
Set_Is_Immediately_Visible (E, False);
Enter_Overloaded_Entity (S);
Set_Homonym (S, Homonym (E));
Check_Dispatching_Operation (S, Empty);
else
Error_Msg_N ("duplicate identifier:&", S);
end if;
else
-- E exists and is overloadable. Determine whether S is the body
-- of E, a new overloaded entity with a different signature, or
-- an error altogether.
while Present (E) and then Scope (E) = Current_Scope loop
if Type_Conformant (E, S) then
-- If the old and new entities have the same profile and
-- one is not the body of the other, then this is an error,
-- unless one of them is implicitly declared.
if Present (Alias (S)) then
-- When an derived operation is overloaded it may be
-- due to the fact that the full view of a private extension
-- re-inherits. It has to be dealt with.
Check_Operation_From_Private_View (S, E);
-- In any case the derived operation remains hidden by
-- the existing declaration.
return;
elsif Present (Alias (E)) or else Is_Internal (E) then
-- E is a derived operation or an internal operator which
-- is being overridden. Remove E from further visibility.
-- Furthermore, if E is a dispatching operation, it must be
-- replaced in the list of primitive operations of its type
declare
Prev : Entity_Id;
begin
Prev := First_Entity (Current_Scope);
while Next_Entity (Prev) /= E loop
Prev := Next_Entity (Prev);
end loop;
-- E must be removed both from the entity_list of the
-- current scope, and from the visibility chain
if Debug_Flag_E then
Write_Str ("Override implicit operation ");
Write_Int (Int (E));
Write_Eol;
end if;
-- If E is a predefined concatenation, it stands for four
-- different operations. As a result, a single explicit
-- declaration does not hide it. In a possible ambiguous
-- situation, Disambiguate chooses the user-defined op,
-- so it is correct to retain the previous internal one.
if Chars (E) /= Name_Op_Concat then
-- Find predecessor of E in Homonym chain.
if E = Current_Entity (E) then
Prev_Vis := Empty;
else
Prev_Vis := Current_Entity (E);
while Homonym (Prev_Vis) /= E loop
Prev_Vis := Homonym (Prev_Vis);
end loop;
end if;
if Prev_Vis /= Empty then
-- Skip E in the visibility chain
Set_Homonym (Prev_Vis, Homonym (E));
else
Set_Name_Entity_Id (Chars (E), Homonym (E));
end if;
Set_Next_Entity (Prev, Next_Entity (E));
if No (Next_Entity (Prev)) then
Set_Last_Entity (Current_Scope, Prev);
end if;
end if;
Enter_Overloaded_Entity (S);
if Is_Dispatching_Operation (E) then
Check_Dispatching_Operation (S, E);
else
Check_Dispatching_Operation (S, Empty);
end if;
return;
end;
-- Here we have a real error (identical profile)
else
Error_Msg_Sloc := Sloc (E);
Error_Msg_N ("& conflicts with declaration#", S);
return;
end if;
else
null;
end if;
Prev_Vis := E;
E := Homonym (E);
end loop;
-- On exit, we know that S is a new entity
Enter_Overloaded_Entity (S);
Check_Dispatching_Operation (S, Empty);
end if;
end New_Overloaded_Entity;
---------------------
-- Process_Formals --
---------------------
procedure Process_Formals
(S : Entity_Id;
T : List_Id;
Related_Nod : Node_Id)
is
Param_Spec : Node_Id;
Formal : Entity_Id;
Formal_Type : Entity_Id;
Default : Node_Id;
begin
-- In order to prevent premature use of the formals in the same formal
-- part, the Ekind is left undefined until all default expressions are
-- analyzed. The Ekind is established in a separate loop at the end.
Param_Spec := First (T);
while Present (Param_Spec) loop
-- Case of ordinary parameters
if Nkind (Parameter_Type (Param_Spec)) /= N_Access_Definition then
Find_Type (Parameter_Type (Param_Spec));
Formal_Type := Entity (Parameter_Type (Param_Spec));
if Ekind (Formal_Type) = E_Incomplete_Type
or else (Is_Class_Wide_Type (Formal_Type)
and then Ekind (Root_Type (Formal_Type)) =
E_Incomplete_Type)
then
if Nkind (Parent (T)) /= N_Access_Function_Definition
and then Nkind (Parent (T)) /= N_Access_Procedure_Definition
then
Error_Msg_N ("invalid use of incomplete type", Param_Spec);
end if;
end if;
else
-- An access formal type
Formal_Type :=
Access_Definition (Related_Nod, Parameter_Type (Param_Spec));
end if;
Formal := Defining_Identifier (Param_Spec);
Enter_Name (Formal);
Set_Etype (Formal, Formal_Type);
Default := Expression (Param_Spec);
if Present (Default) then
if Out_Present (Param_Spec) then
Error_Msg_N
("default initialization only allowed for IN parameters",
Param_Spec);
end if;
-- Do the special preanalysis of the expression (see section on
-- "Handling of Default Expressions" in the spec of package Sem).
Analyze_Default_Expression (Default, Formal_Type);
end if;
Param_Spec := Next (Param_Spec);
end loop;
-- Now set the kind (mode) of each formal
Param_Spec := First (T);
while Present (Param_Spec) loop
Formal := Defining_Identifier (Param_Spec);
Set_Formal_Mode (Formal);
if Ekind (Formal) = E_In_Parameter then
Set_Default_Value (Formal, Expression (Param_Spec));
else
-- Set default value of Actual_Subtype. Will be recomputed
-- within body if type is unconstrained.
Set_Actual_Subtype (Formal, Etype (Formal));
end if;
Param_Spec := Next (Param_Spec);
end loop;
end Process_Formals;
---------------------
-- Set_Formal_Mode --
---------------------
procedure Set_Formal_Mode (Formal_Id : Entity_Id) is
Spec : constant Node_Id := Parent (Formal_Id);
begin
if Out_Present (Spec) then
if Ekind (Scope (Formal_Id)) = E_Function
or else Ekind (Scope (Formal_Id)) = E_Generic_Function
then
Error_Msg_N ("functions can only have IN parameters", Spec);
Set_Ekind (Formal_Id, E_In_Parameter);
elsif In_Present (Spec) then
Set_Ekind (Formal_Id, E_In_Out_Parameter);
else
Set_Ekind (Formal_Id, E_Out_Parameter);
end if;
else
Set_Ekind (Formal_Id, E_In_Parameter);
end if;
end Set_Formal_Mode;
------------------------
-- Subtype_Conformant --
------------------------
function Subtype_Conformant (New_Id, Old_Id : Entity_Id) return Boolean is
Result : Boolean;
begin
Check_Conformance (New_Id, Old_Id, Subtype_Conformant, False, Result);
return Result;
end Subtype_Conformant;
---------------------
-- Type_Conformant --
---------------------
function Type_Conformant (New_Id, Old_Id : Entity_Id) return Boolean is
Result : Boolean;
begin
Check_Conformance (New_Id, Old_Id, Type_Conformant, False, Result);
return Result;
end Type_Conformant;
-------------------------------
-- Valid_Operator_Definition --
-------------------------------
procedure Valid_Operator_Definition (Designator : Entity_Id) is
N : Integer := 0;
F : Entity_Id;
Id : constant Name_Id := Chars (Designator);
N_OK : Boolean;
begin
F := First_Formal (Designator);
while Present (F) loop
N := N + 1;
if Present (Default_Value (F)) then
Error_Msg_N
("default values not allowed for operator parameters",
Parent (F));
end if;
F := Next_Formal (F);
end loop;
-- Verify that user-defined operators have proper number of arguments
-- First case of operators which can only be unary
if Id = Name_Op_Not
or else Id = Name_Op_Abs
then
N_OK := (N = 1);
-- Case of operators which can be unary or binary
elsif Id = Name_Op_Add
or Id = Name_Op_Subtract
then
N_OK := (N in 1 .. 2);
-- All other operators can only be binary
else
N_OK := (N = 2);
end if;
if not N_OK then
Error_Msg_N
("incorrect number of arguments for operator", Designator);
end if;
if Id = Name_Op_Ne
and then Comes_From_Source (Designator)
and then Etype (Designator) = Standard_Boolean then
Error_Msg_N
("explicit definition of inequality not allowed", Designator);
end if;
end Valid_Operator_Definition;
end Sem_Ch6;