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
/
exp_ch6.adb
< prev
next >
Wrap
Text File
|
1996-09-28
|
25KB
|
698 lines
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- E X P _ C H 6 --
-- --
-- B o d y --
-- --
-- $Revision: 1.122 $ --
-- --
-- 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 Checks; use Checks;
with Einfo; use Einfo;
with Exp_Ch7; use Exp_Ch7;
with Exp_Ch9; use Exp_Ch9;
with Exp_Disp; use Exp_Disp;
with Exp_Intr; use Exp_Intr;
with Inline; use Inline;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Sem; use Sem;
with Sem_Ch8; use Sem_Ch8;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Snames; use Snames;
with Stand; use Stand;
with Tbuild; use Tbuild;
package body Exp_Ch6 is
procedure Expand_Actual_Conversions (N : Node_Id; Subp : Entity_Id);
-- For each actual of an in-out parameter which is a numeric conversion
-- of the form T(A), where A denotes a variable, we insert the declaration:
--
-- Temp : T := T(A);
--
-- prior to the call. Then we replace the actual with a reference to Temp,
-- and append the assignment:
--
-- A := T' (Temp);
--
-- after the call. Here T' is the actual type of variable A.
-- For out parameters, the initial declaration has no expression.
-- If A is not an entity name, we generate instead:
--
-- Var : T' renames A;
-- Temp : T := Var; -- omitting expression for out parameter.
-- ...
-- Var := T' (Temp);
-------------------------------
-- Expand_Actual_Conversions --
-------------------------------
procedure Expand_Actual_Conversions (N : Node_Id; Subp : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
Actual : Node_Id;
Formal : Entity_Id;
Init : Node_Id;
N_Node : Node_Id;
Post_Call : List_Id := New_List;
Temp : Entity_Id;
Var : Node_Id;
V_Typ : Entity_Id;
begin
Formal := First_Formal (Subp);
Actual := First_Actual (N);
while Present (Formal) loop
if Is_Array_Type (Etype (Formal)) and then
Is_Constrained (Etype (Formal))
then
Apply_Length_Check (Actual, Etype (Formal));
end if;
if Nkind (Actual) = N_Type_Conversion
and then Is_Numeric_Type (Etype (Formal))
and then Ekind (Formal) /= E_In_Parameter
then
Temp := Make_Defining_Identifier (Loc, New_Internal_Name ('T'));
V_Typ := Etype (Expression (Actual));
if Is_Entity_Name (Expression (Actual)) then
Var := Entity (Expression (Actual));
else
Var :=
Make_Defining_Identifier (Loc, New_Internal_Name ('T'));
N_Node :=
Make_Object_Renaming_Declaration (Loc,
Defining_Identifier => Var,
Subtype_Mark => New_Occurrence_Of (V_Typ, Loc),
Name => Expression (Actual));
Insert_Before_And_Analyze (N, N_Node);
end if;
if Ekind (Formal) = E_In_Out_Parameter then
Init :=
Make_Type_Conversion (Loc,
Subtype_Mark => New_Occurrence_Of (Etype (Formal), Loc),
Expression => New_Occurrence_Of (Var, Loc));
else
Init := Empty;
end if;
N_Node :=
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
Object_Definition =>
New_Occurrence_Of (Etype (Formal), Loc),
Expression => Init);
Insert_Before_And_Analyze (N, N_Node);
Rewrite_Substitute_Tree
(Actual, New_Reference_To
(Defining_Identifier (N_Node), Loc));
Analyze (Actual);
Append_To (Post_Call,
Make_Assignment_Statement (Loc,
Name => New_Occurrence_Of (Var, Loc),
Expression => Make_Type_Conversion (Loc,
Subtype_Mark => New_Occurrence_Of (V_Typ, Loc),
Expression => New_Occurrence_Of (Temp, Loc))));
end if;
Formal := Next_Formal (Formal);
Actual := Next_Actual (Actual);
end loop;
-- Note: the following code is wrong! N may be the action of a
-- triggering statement, and hence not be a list member at all???
if not Is_Empty_List (Post_Call) then
Insert_List_After (N, Post_Call);
end if;
-- The call node itself is re-analyzed in Expand_Call.
end Expand_Actual_Conversions;
-----------------
-- Expand_Call --
-----------------
-- This procedure handles expansion of function calls and procedure call
-- statements (i.e. it serves as the body for Expand_N_Function_Call and
-- Expand_N_Procedure_Call_Statement. Processing for calls includes:
-- Supply default expressions for missing arguments
-- Replace "call" to enumeration literal function by literal itself
-- Rewrite call to predefined operator as operator
-- Replace actuals to in-out parameters that are numeric conversions,
-- with explicit assignment to temporaries before and after the call.
procedure Expand_Call (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Subp : Entity_Id;
Parent_Subp : Entity_Id;
Parent_Formal : Entity_Id;
Actual : Node_Id;
Formal : Entity_Id;
Prev : Node_Id := Empty;
Scop : Entity_Id;
procedure Insert_Default;
-- Internal procedure to insert argument corresponding to Formal.
-- The value is inserted immediately after Prev, or if Prev is Empty,
-- (case of empty argument list), then into a new list. In both cases
-- Prev is set to the inserted default for the next call.
procedure Insert_Default is
Default : Node_Id;
Insert : Node_Id;
F_Name : Node_Id;
begin
Insert := New_Node (N_Parameter_Association, Loc);
F_Name := New_Node (N_Identifier, Loc);
-- Copy the complete expression tree for each default parameter.
-- This will ensure that a new Itype is generated (if applicable)
-- for each such insertion of the expression in the subprogram call.
Default := New_Copy_Tree (Default_Value (Formal));
Set_Chars (F_Name, Chars (Formal));
Set_Explicit_Actual_Parameter (Insert, Default);
Set_Selector_Name (Insert, F_Name);
-- Case of insertion is first named actual
if No (Prev) or else
Nkind (Parent (Prev)) /= N_Parameter_Association
then
Set_Next_Named_Actual (Insert, First_Named_Actual (N));
Set_First_Named_Actual (N, Default);
if No (Prev) then
if not Present (Parameter_Associations (N)) then
Set_Parameter_Associations (N, New_List);
Append (Insert, Parameter_Associations (N));
end if;
else
Insert_After (Prev, Insert);
end if;
-- Case of insertion is not first named actual
else
Set_Next_Named_Actual (Insert, Next_Named_Actual (Parent (Prev)));
Set_Next_Named_Actual (Parent (Prev), Default);
Append (Insert, Parameter_Associations (N));
end if;
Prev := Default;
end Insert_Default;
-- Start of processing for Expand_Call
begin
-- Case of access to subprogram, where the Name is an explicit
-- dereference. The type of the name node is a subprogram type,
-- from which we can retrieve the required signature.
if Nkind (Name (N)) = N_Explicit_Dereference then
Subp := Etype (Name (N));
Parent_Subp := Empty;
-- Case of call to simple entry, where the Name is a selected component
-- whose prefix is the task, and whose selector name is the entry name
elsif Nkind (Name (N)) = N_Selected_Component then
Subp := Entity (Selector_Name (Name (N)));
Parent_Subp := Empty;
-- Case of call to member of entry family, where Name is an indexed
-- component, with the prefix being a selected component giving the
-- task and entry family name, and the index being the entry index.
elsif Nkind (Name (N)) = N_Indexed_Component then
Subp := Entity (Selector_Name (Prefix (Name (N))));
Parent_Subp := Empty;
-- Normal case
else
Subp := Entity (Name (N));
Parent_Subp := Alias (Subp);
if Ekind (Subp) = E_Entry then
Parent_Subp := Empty;
end if;
end if;
-- First step, insert default parameter values
Formal := First_Formal (Subp);
Actual := First_Actual (N);
while Present (Formal) loop
if Present (Actual) then
-- Check for named and positional parameters in proper place
if Nkind (Parent (Actual)) /= N_Parameter_Association
or else Chars (Selector_Name (Parent (Actual))) = Chars (Formal)
then
Prev := Actual;
Actual := Next_Actual (Actual);
else
Insert_Default;
end if;
-- Trailing actuals are all defaults
else
Insert_Default;
end if;
Formal := Next_Formal (Formal);
end loop;
if Nkind (N) /= N_Entry_Call_Statement
and then No (Controlling_Argument (N))
and then Present (Parent_Subp)
then
while Present (Alias (Parent_Subp)) loop
Parent_Subp := Alias (Parent_Subp);
end loop;
Set_Entity (Name (N), Parent_Subp);
Subp := Parent_Subp;
-- Expand an explicit conversion for parameter of the inherited type
Formal := First_Formal (Subp);
Parent_Formal := First_Formal (Parent_Subp);
Actual := First_Actual (N);
while Present (Formal) loop
if (Etype (Formal) /= Etype (Parent_Formal))
and then not Is_Intrinsic_Subprogram (Subp)
then
Rewrite_Substitute_Tree (Actual,
Make_Type_Conversion (Sloc (Actual),
Subtype_Mark =>
New_Occurrence_Of (Etype (Parent_Formal), Sloc (Actual)),
Expression => Relocate_Node (Actual)));
Set_Etype (Actual, Etype (Parent_Formal));
end if;
Formal := Next_Formal (Formal);
Parent_Formal := Next_Formal (Parent_Formal);
Actual := Next_Actual (Actual);
end loop;
end if;
-- Some more special cases for cases other than explicit dereference
if Nkind (Name (N)) /= N_Explicit_Dereference then
-- Calls to an enumeration literal are replaced by the literal
-- The only way that this case occurs is when we have a call to
-- a function that is a renaming of an enumeration literal. The
-- normal case of a direct reference to an enumeration literal
-- has already been dealt with by Resolve_Call
if Ekind (Subp) = E_Enumeration_Literal then
Rewrite_Substitute_Tree (N, Name (N));
end if;
end if;
-- Deals with Dispatch_Call if we still have a call
if (Nkind (N) = N_Function_Call
or else Nkind (N) = N_Procedure_Call_Statement)
and then Present (Controlling_Argument (N))
then
Expand_Dispatch_Call (N);
return;
end if;
-- Create a transient scope if the resulting type requires it
if Is_Type (Etype (Subp))
and then Requires_Transient_Scope (Etype (Subp))
then
Establish_Transient_Scope (N);
if Controlled_Type (Etype (Subp))
and then not Is_Return_By_Reference_Type (Etype (Subp))
then
Expand_Ctrl_Function_Call (N);
return;
end if;
end if;
if Ekind (Subp) = E_Procedure
or else Ekind (Subp) = E_Entry
or else Ekind (Subp) = E_Entry_Family
then
Expand_Actual_Conversions (N, Subp);
end if;
-- If this is a call to an intrinsic subprogram, then perform the
-- appropriate expansion to the corresponding tree node.
if Is_Intrinsic_Subprogram (Subp) then
Expand_Intrinsic_Call (N, Subp);
return;
end if;
if Ekind (Subp) = E_Function
or else Ekind (Subp) = E_Procedure
then
if Is_Inlined (Subp) then
Add_Inlined_Body (N, Subp);
end if;
end if;
-- Check for a protected subprogram. This is either an intra-object
-- call, or a protected function call. Protected procedure calls are
-- rewritten as entry calls and handled accordingly.
Scop := Scope (Subp);
if Nkind (N) /= N_Entry_Call_Statement
and then Is_Protected_Type (Scop)
then
-- If the call is an internal one, it is rewritten as a call to
-- to the corresponding unprotected subprogram.
declare
Param : Entity_Id;
Corr : Entity_Id;
Proc : Entity_Id;
Rec : Node_Id;
begin
-- If the protected object is not an enclosing scope, this is
-- an inter-object call.
-- ??? This appears to be dead code; inter-object calls
-- are actually expanded by Exp_Ch9.Build_Simple_Entry_Call.
if not In_Open_Scopes (Scop) then
if Nkind (Name (N)) = N_Selected_Component then
Rec := Prefix (Name (N));
elsif Nkind (Name (N)) = N_Indexed_Component then
Rec := Prefix (Prefix (Name (N)));
else
null;
pragma Assert (False);
end if;
Rewrite_Substitute_Tree (N,
Build_Protected_Subprogram_Call (N,
Name => New_Occurrence_Of (Subp, Sloc (N)),
Rec => Convert_Concurrent (Rec, Etype (Rec)),
External => True));
else
Rec := Make_Identifier (Loc, Name_uObject);
Set_Etype (Rec, Corresponding_Record_Type (Scop));
-- Find enclosing protected operation, and retrieve its first
-- parameter, which denotes the enclosing protected object.
-- If the enclosing operation is an entry, we are immediately
-- within the protected body, and we can retrieve the object
-- from the service entries procedure.
Proc := Current_Scope;
while Present (Proc)
and then Scope (Proc) /= Scop
loop
Proc := Scope (Proc);
end loop;
Corr := Protected_Body_Subprogram (Proc);
if No (Corr) then
-- Previous error left expansion incomplete.
-- Nothing to do on this call.
return;
end if;
Param := Defining_Identifier
(First
(Parameter_Specifications (Parent (Corr))));
if Is_Subprogram (Proc) then
Set_Entity (Rec, Param);
Set_Analyzed (Rec);
else
-- The first parameter of the entry body procedure is a
-- pointer to the object. We create a local variable
-- of the proper type, duplicating what is done to define
-- _object later on.
declare
Decls : List_Id;
Obj_Ptr : Entity_Id := Make_Defining_Identifier
(Loc, New_Internal_Name ('T'));
begin
Decls := New_List (
Make_Full_Type_Declaration (Loc,
Defining_Identifier => Obj_Ptr,
Type_Definition =>
Make_Access_To_Object_Definition (Loc,
Subtype_Indication =>
New_Reference_To
(Corresponding_Record_Type (Scop), Loc))));
Rec := Make_Expression_Actions (Loc,
Actions => Decls,
Expression => Make_Explicit_Dereference (Loc,
Make_Unchecked_Type_Conversion (Loc,
Subtype_Mark => New_Reference_To (Obj_Ptr, Loc),
Expression => New_Occurrence_Of (Param, Loc))));
end;
end if;
Rewrite_Substitute_Tree (N,
Build_Protected_Subprogram_Call (N,
Name => Name (N),
Rec => Rec,
External => False));
if not Is_Subprogram (Proc) then
Analyze (Rec);
end if;
end if;
end;
Analyze (N);
end if;
end Expand_Call;
----------------------------
-- Expand_N_Function_Call --
----------------------------
procedure Expand_N_Function_Call (N : Node_Id) is
begin
Expand_Call (N);
end Expand_N_Function_Call;
---------------------------------------
-- Expand_N_Procedure_Call_Statement --
---------------------------------------
procedure Expand_N_Procedure_Call_Statement (N : Node_Id) is
begin
Expand_Call (N);
end Expand_N_Procedure_Call_Statement;
------------------------------
-- Expand_N_Subprogram_Body --
------------------------------
-- Add return statement if last statement in body is not a return
-- statement (this makes things easier on Gigi which does not want
-- to have to handle a missing return).
-- Add call to Activate_Tasks if body is a task activator
procedure Expand_N_Subprogram_Body (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
H : constant Node_Id := Handled_Statement_Sequence (N);
Spec_Id : Entity_Id;
Except_H : Node_Id;
Scop : Entity_Id;
Dec : Node_Id;
Next_Op : Node_Id;
procedure Add_Termination (S : List_Id);
-- Append to S a return statement in the procedure case or a Raise
-- Program_Error in the function case if the last statement is not
-- already a return or a goto statement.
procedure Add_Termination (S : List_Id) is
Last_S : constant Node_Id := Last (S);
Loc_S : constant Source_Ptr := Sloc (Last_S);
begin
if Nkind (Last_S) /= N_Return_Statement
and then Nkind (Last_S) /= N_Goto_Statement
and then Nkind (Last_S) /= N_Raise_Statement
then
if Ekind (Spec_Id) = E_Procedure then
Append_To (S, Make_Return_Statement (Loc_S));
elsif Ekind (Spec_Id) = E_Function then
Append_To (S,
Make_Raise_Statement (Loc_S,
Name => New_Occurrence_Of (Standard_Program_Error, Loc_S)));
end if;
end if;
end Add_Termination;
-- Start of processing for Expand_N_Subprogram_Body
begin
-- Get entities for subprogram body and spec
if Present (Corresponding_Spec (N)) then
Spec_Id := Corresponding_Spec (N);
else
Spec_Id := Defining_Unit_Simple_Name (Specification (N));
end if;
-- Returns_By_Ref flag is normally set when the subprogram is frozen
-- but subprograms with no specs are not frozen
if Acts_As_Spec (N)
and then Is_Return_By_Reference_Type (Etype (Spec_Id))
then
Set_Returns_By_Ref (Spec_Id);
end if;
-- Now, add a termination for all possible syntactic ends of the
-- subprogram. We don't bother to reanalyze the new body with the added
-- return statement, since it would involve a lot of unnecessary work
-- that would achieve precisely nothing.
Add_Termination (Statements (H));
if Present (Exception_Handlers (H)) then
Except_H := First (Exception_Handlers (H));
while Present (Except_H) loop
Add_Termination (Statements (Except_H));
Except_H := Next (Except_H);
end loop;
end if;
Scop := Scope (Spec_Id);
-- Add discriminal renamings to protected subprograms.
-- Install new discriminals for expansion of the next
-- subprogram of this protected type, if any.
if Is_List_Member (N)
and then Present (Parent (List_Containing (N)))
and then Nkind (Parent (List_Containing (N))) = N_Protected_Body
then
Add_Discriminal_Declarations
(Declarations (N), Scop, Name_uObject, Loc);
Add_Private_Declarations (Declarations (N), Scop, Name_uObject, Loc);
-- Associate privals and discriminals with the next protected
-- operation body to be expanded. These are used to expand
-- references to private data objects and discriminants,
-- respectively.
Next_Op := Next_Protected_Operation (N);
if Present (Next_Op) then
Dec := Parent (Base_Type (Scop));
Set_Privals (Dec, Next_Op, Loc);
Set_Discriminals (Dec, Next_Op, Loc);
end if;
end if;
end Expand_N_Subprogram_Body;
-----------------------
-- Freeze_Subprogram --
-----------------------
procedure Freeze_Subprogram (N : Node_Id) is
E : constant Entity_Id := Entity (N);
begin
-- When a primitive is frozen, enter its name in the corresponding
-- dispatch table. If the DTC_Entity field is not set this is an
-- overriden primitive that can be ignored.
if Is_Dispatching_Operation (E)
and then not Is_Abstract (E)
and then Present (DTC_Entity (E))
and then not Is_CPP_Class (Scope (DTC_Entity (E)))
then
Insert_After (N, Fill_DT_Entry (Sloc (N), E));
end if;
-- Mark functions that return by reference. Note that it cannot be
-- part of the normal semantic analysis of the spec since the
-- underlying returned type may not be known yet (for private types)
declare
Typ : constant Entity_Id := Etype (E);
Utyp : constant Entity_Id := Underlying_Type (Typ);
begin
if Is_Return_By_Reference_Type (Typ) then
Set_Returns_By_Ref (E);
elsif Present (Utyp)
and then Is_Record_Type (Utyp)
and then Controlled_Type (Utyp)
then
Set_Returns_By_Ref (E);
end if;
end;
end Freeze_Subprogram;
end Exp_Ch6;