-- Use generic machinery to build an unexpanded body for the subprogram.
-- This body is subsequently used for inline expansions at call sites.
+ procedure Build_Return_Object_Formal
+ (Loc : Source_Ptr;
+ Obj_Decl : Node_Id;
+ Formals : List_Id);
+ -- Create a formal parameter for return object declaration Obj_Decl of
+ -- an extended return statement and add it to list Formals.
+
function Can_Split_Unconstrained_Function (N : Node_Id) return Boolean;
-- Return true if we generate code for the function body N, the function
-- body N has no local declarations and its unique statement is a single
-- extended return statement with a handled statements sequence.
+ procedure Copy_Formals
+ (Loc : Source_Ptr;
+ Subp_Id : Entity_Id;
+ Formals : List_Id);
+ -- Create new formal parameters from the formal parameters of subprogram
+ -- Subp_Id and add them to list Formals.
+
+ function Copy_Return_Object (Obj_Decl : Node_Id) return Node_Id;
+ -- Create a copy of return object declaration Obj_Decl of an extended
+ -- return statement.
+
procedure Split_Unconstrained_Function
(N : Node_Id;
Spec_Id : Entity_Id);
Body_To_Inline :=
Copy_Generic_Node (N, Empty, Instantiating => True);
else
+ -- ??? Shouldn't this use New_Copy_Tree? What about global
+ -- references captured in the body to inline?
+
Body_To_Inline := Copy_Separate_Tree (N);
end if;
Set_Ekind (Defining_Entity (Original_Body), Ekind (Spec_Id));
end Build_Body_To_Inline;
+ --------------------------------
+ -- Build_Return_Object_Formal --
+ --------------------------------
+
+ procedure Build_Return_Object_Formal
+ (Loc : Source_Ptr;
+ Obj_Decl : Node_Id;
+ Formals : List_Id)
+ is
+ Obj_Def : constant Node_Id := Object_Definition (Obj_Decl);
+ Obj_Id : constant Entity_Id := Defining_Entity (Obj_Decl);
+ Typ_Def : Node_Id;
+
+ begin
+ -- Build the type definition of the formal parameter. The use of
+ -- New_Copy_Tree ensures that global references preserved in the
+ -- case of generics.
+
+ if Is_Entity_Name (Obj_Def) then
+ Typ_Def := New_Copy_Tree (Obj_Def);
+ else
+ Typ_Def := New_Copy_Tree (Subtype_Mark (Obj_Def));
+ end if;
+
+ -- Generate:
+ --
+ -- Obj_Id : [out] Typ_Def
+
+ -- Mode OUT should not be used when the return object is declared as
+ -- a constant. Check the definition of the object declaration because
+ -- the object has not been analyzed yet.
+
+ Append_To (Formals,
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Chars (Obj_Id)),
+ In_Present => False,
+ Out_Present => not Constant_Present (Obj_Decl),
+ Null_Exclusion_Present => False,
+ Parameter_Type => Typ_Def));
+ end Build_Return_Object_Formal;
+
--------------------------------------
-- Can_Split_Unconstrained_Function --
--------------------------------------
function Can_Split_Unconstrained_Function (N : Node_Id) return Boolean is
- Ret_Node : constant Node_Id :=
- First (Statements (Handled_Statement_Sequence (N)));
- D : Node_Id;
+ Stmt : constant Node_Id :=
+ First (Statements (Handled_Statement_Sequence (N)));
+ Decl : Node_Id;
begin
-- No user defined declarations allowed in the function except inside
-- the unique return statement; implicit labels are the only allowed
-- declarations.
- if not Is_Empty_List (Declarations (N)) then
- D := First (Declarations (N));
- while Present (D) loop
- if Nkind (D) /= N_Implicit_Label_Declaration then
- return False;
- end if;
+ Decl := First (Declarations (N));
+ while Present (Decl) loop
+ if Nkind (Decl) /= N_Implicit_Label_Declaration then
+ return False;
+ end if;
- Next (D);
- end loop;
- end if;
+ Next (Decl);
+ end loop;
-- We only split the inlined function when we are generating the code
-- of its body; otherwise we leave duplicated split subprograms in
-- time.
return In_Extended_Main_Code_Unit (N)
- and then Present (Ret_Node)
- and then Nkind (Ret_Node) = N_Extended_Return_Statement
- and then No (Next (Ret_Node))
- and then Present (Handled_Statement_Sequence (Ret_Node));
+ and then Present (Stmt)
+ and then Nkind (Stmt) = N_Extended_Return_Statement
+ and then No (Next (Stmt))
+ and then Present (Handled_Statement_Sequence (Stmt));
end Can_Split_Unconstrained_Function;
+ ------------------
+ -- Copy_Formals --
+ ------------------
+
+ procedure Copy_Formals
+ (Loc : Source_Ptr;
+ Subp_Id : Entity_Id;
+ Formals : List_Id)
+ is
+ Formal : Entity_Id;
+ Spec : Node_Id;
+
+ begin
+ Formal := First_Formal (Subp_Id);
+ while Present (Formal) loop
+ Spec := Parent (Formal);
+
+ -- Create an exact copy of the formal parameter. The use of
+ -- New_Copy_Tree ensures that global references are preserved
+ -- in case of generics.
+
+ Append_To (Formals,
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Sloc (Formal), Chars (Formal)),
+ In_Present => In_Present (Spec),
+ Out_Present => Out_Present (Spec),
+ Null_Exclusion_Present => Null_Exclusion_Present (Spec),
+ Parameter_Type =>
+ New_Copy_Tree (Parameter_Type (Spec)),
+ Expression => New_Copy_Tree (Expression (Spec))));
+
+ Next_Formal (Formal);
+ end loop;
+ end Copy_Formals;
+
+ ------------------------
+ -- Copy_Return_Object --
+ ------------------------
+
+ function Copy_Return_Object (Obj_Decl : Node_Id) return Node_Id is
+ Obj_Id : constant Entity_Id := Defining_Entity (Obj_Decl);
+
+ begin
+ -- The use of New_Copy_Tree ensures that global references are
+ -- preserved in case of generics.
+
+ return
+ Make_Object_Declaration (Sloc (Obj_Decl),
+ Defining_Identifier =>
+ Make_Defining_Identifier (Sloc (Obj_Id), Chars (Obj_Id)),
+ Aliased_Present => Aliased_Present (Obj_Decl),
+ Constant_Present => Constant_Present (Obj_Decl),
+ Null_Exclusion_Present => Null_Exclusion_Present (Obj_Decl),
+ Object_Definition =>
+ New_Copy_Tree (Object_Definition (Obj_Decl)),
+ Expression => New_Copy_Tree (Expression (Obj_Decl)));
+ end Copy_Return_Object;
+
----------------------------------
-- Split_Unconstrained_Function --
----------------------------------
Spec_Id : Entity_Id)
is
Loc : constant Source_Ptr := Sloc (N);
- Ret_Node : constant Node_Id :=
+ Ret_Stmt : constant Node_Id :=
First (Statements (Handled_Statement_Sequence (N)));
Ret_Obj : constant Node_Id :=
- First (Return_Object_Declarations (Ret_Node));
+ First (Return_Object_Declarations (Ret_Stmt));
procedure Build_Procedure
(Proc_Id : out Entity_Id;
(Proc_Id : out Entity_Id;
Decl_List : out List_Id)
is
- Formal : Entity_Id;
- Formal_List : constant List_Id := New_List;
- Proc_Spec : Node_Id;
- Proc_Body : Node_Id;
- Subp_Name : constant Name_Id := New_Internal_Name ('F');
- Body_Decl_List : List_Id := No_List;
- Param_Type : Node_Id;
+ Formals : constant List_Id := New_List;
+ Subp_Name : constant Name_Id := New_Internal_Name ('F');
- begin
- if Nkind (Object_Definition (Ret_Obj)) = N_Identifier then
- Param_Type :=
- New_Copy (Object_Definition (Ret_Obj));
- else
- Param_Type :=
- New_Copy (Subtype_Mark (Object_Definition (Ret_Obj)));
- end if;
+ Body_Decls : List_Id := No_List;
+ Decl : Node_Id;
+ Proc_Body : Node_Id;
+ Proc_Spec : Node_Id;
- Append_To (Formal_List,
- Make_Parameter_Specification (Loc,
- Defining_Identifier =>
- Make_Defining_Identifier (Loc,
- Chars => Chars (Defining_Identifier (Ret_Obj))),
- In_Present => False,
- Out_Present => True,
- Null_Exclusion_Present => False,
- Parameter_Type => Param_Type));
-
- Formal := First_Formal (Spec_Id);
-
- -- Note that we copy the parameter type rather than creating
- -- a reference to it, because it may be a class-wide entity
- -- that will not be retrieved by name.
+ begin
+ -- Create formal parameters for the return object and all formals
+ -- of the unconstrained function in order to pass their values to
+ -- the procedure.
- while Present (Formal) loop
- Append_To (Formal_List,
- Make_Parameter_Specification (Loc,
- Defining_Identifier =>
- Make_Defining_Identifier (Sloc (Formal),
- Chars => Chars (Formal)),
- In_Present => In_Present (Parent (Formal)),
- Out_Present => Out_Present (Parent (Formal)),
- Null_Exclusion_Present =>
- Null_Exclusion_Present (Parent (Formal)),
- Parameter_Type =>
- New_Copy_Tree (Parameter_Type (Parent (Formal))),
- Expression =>
- Copy_Separate_Tree (Expression (Parent (Formal)))));
+ Build_Return_Object_Formal
+ (Loc => Loc,
+ Obj_Decl => Ret_Obj,
+ Formals => Formals);
- Next_Formal (Formal);
- end loop;
+ Copy_Formals
+ (Loc => Loc,
+ Subp_Id => Spec_Id,
+ Formals => Formals);
Proc_Id := Make_Defining_Identifier (Loc, Chars => Subp_Name);
Proc_Spec :=
Make_Procedure_Specification (Loc,
Defining_Unit_Name => Proc_Id,
- Parameter_Specifications => Formal_List);
+ Parameter_Specifications => Formals);
Decl_List := New_List;
-- Copy these declarations to the built procedure.
if Present (Declarations (N)) then
- Body_Decl_List := New_List;
+ Body_Decls := New_List;
- declare
- D : Node_Id;
- New_D : Node_Id;
+ Decl := First (Declarations (N));
+ while Present (Decl) loop
+ pragma Assert (Nkind (Decl) = N_Implicit_Label_Declaration);
- begin
- D := First (Declarations (N));
- while Present (D) loop
- pragma Assert (Nkind (D) = N_Implicit_Label_Declaration);
-
- New_D :=
- Make_Implicit_Label_Declaration (Loc,
- Make_Defining_Identifier (Loc,
- Chars => Chars (Defining_Identifier (D))),
- Label_Construct => Empty);
- Append_To (Body_Decl_List, New_D);
-
- Next (D);
- end loop;
- end;
+ Append_To (Body_Decls,
+ Make_Implicit_Label_Declaration (Loc,
+ Make_Defining_Identifier (Loc,
+ Chars => Chars (Defining_Identifier (Decl))),
+ Label_Construct => Empty));
+
+ Next (Decl);
+ end loop;
end if;
- pragma Assert (Present (Handled_Statement_Sequence (Ret_Node)));
+ pragma Assert (Present (Handled_Statement_Sequence (Ret_Stmt)));
Proc_Body :=
Make_Subprogram_Body (Loc,
- Specification => Copy_Separate_Tree (Proc_Spec),
- Declarations => Body_Decl_List,
+ Specification => Copy_Subprogram_Spec (Proc_Spec),
+ Declarations => Body_Decls,
Handled_Statement_Sequence =>
- Copy_Separate_Tree (Handled_Statement_Sequence (Ret_Node)));
+ New_Copy_Tree (Handled_Statement_Sequence (Ret_Stmt)));
Set_Defining_Unit_Name (Specification (Proc_Body),
Make_Defining_Identifier (Loc, Subp_Name));
-- Local variables
- New_Obj : constant Node_Id := Copy_Separate_Tree (Ret_Obj);
+ New_Obj : constant Node_Id := Copy_Return_Object (Ret_Obj);
Blk_Stmt : Node_Id;
- Proc_Id : Entity_Id;
Proc_Call : Node_Id;
+ Proc_Id : Entity_Id;
-- Start of processing for Split_Unconstrained_Function
New_Occurrence_Of
(Defining_Identifier (New_Obj), Loc)))));
- Rewrite (Ret_Node, Blk_Stmt);
+ Rewrite (Ret_Stmt, Blk_Stmt);
end Split_Unconstrained_Function;
-- Local variables