with Atree; use Atree;
with Debug; use Debug;
with Einfo; use Einfo;
with Errout; use Errout;
with Exp_Ch9; use Exp_Ch9;
with Exp_Ch11; use Exp_Ch11;
with Exp_Dbug; use Exp_Dbug;
with Exp_Tss; use Exp_Tss;
with Exp_Util; use Exp_Util;
with Freeze; use Freeze;
with Hostparm; use Hostparm;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Output; use Output;
with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Targparm; use Targparm;
with Sinfo; use Sinfo;
with Sem; use Sem;
with Sem_Ch3; use Sem_Ch3;
with Sem_Ch7; use Sem_Ch7;
with Sem_Ch8; use Sem_Ch8;
with Sem_Res; use Sem_Res;
with Sem_Type; use Sem_Type;
with Sem_Util; use Sem_Util;
with Snames; use Snames;
with Stand; use Stand;
with Tbuild; use Tbuild;
with Uintp; use Uintp;
package body Exp_Ch7 is
function Find_Node_To_Be_Wrapped (N : Node_Id) return Node_Id;
function Make_Clean
(N : Node_Id;
Clean : Entity_Id;
Mark : Entity_Id;
Flist : Entity_Id;
Is_Task : Boolean;
Is_Master : Boolean;
Is_Protected_Subprogram : Boolean;
Is_Task_Allocation_Block : Boolean;
Is_Asynchronous_Call_Block : Boolean) return Node_Id;
procedure Set_Node_To_Be_Wrapped (N : Node_Id);
procedure Insert_Actions_In_Scope_Around (N : Node_Id);
function Make_Transient_Block
(Loc : Source_Ptr;
Action : Node_Id) return Node_Id;
type Final_Primitives is (Initialize_Case, Adjust_Case, Finalize_Case);
Name_Of : constant array (Final_Primitives) of Name_Id :=
(Initialize_Case => Name_Initialize,
Adjust_Case => Name_Adjust,
Finalize_Case => Name_Finalize);
Deep_Name_Of : constant array (Final_Primitives) of TSS_Name_Type :=
(Initialize_Case => TSS_Deep_Initialize,
Adjust_Case => TSS_Deep_Adjust,
Finalize_Case => TSS_Deep_Finalize);
procedure Build_Record_Deep_Procs (Typ : Entity_Id);
procedure Build_Array_Deep_Procs (Typ : Entity_Id);
function Make_Deep_Proc
(Prim : Final_Primitives;
Typ : Entity_Id;
Stmts : List_Id) return Node_Id;
function Make_Deep_Array_Body
(Prim : Final_Primitives;
Typ : Entity_Id) return List_Id;
function Make_Deep_Record_Body
(Prim : Final_Primitives;
Typ : Entity_Id) return List_Id;
procedure Check_Visibly_Controlled
(Prim : Final_Primitives;
Typ : Entity_Id;
E : in out Entity_Id;
Cref : in out Node_Id);
function Convert_View
(Proc : Entity_Id;
Arg : Node_Id;
Ind : Pos := 1) return Node_Id;
function Global_Flist_Ref (Flist_Ref : Node_Id) return Boolean;
procedure Clean_Simple_Protected_Objects (N : Node_Id);
procedure Build_Array_Deep_Procs (Typ : Entity_Id) is
begin
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Initialize_Case,
Typ => Typ,
Stmts => Make_Deep_Array_Body (Initialize_Case, Typ)));
if not Is_Return_By_Reference_Type (Typ) then
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Adjust_Case,
Typ => Typ,
Stmts => Make_Deep_Array_Body (Adjust_Case, Typ)));
end if;
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Finalize_Case,
Typ => Typ,
Stmts => Make_Deep_Array_Body (Finalize_Case, Typ)));
end Build_Array_Deep_Procs;
procedure Build_Controlling_Procs (Typ : Entity_Id) is
begin
if Is_Array_Type (Typ) then
Build_Array_Deep_Procs (Typ);
else pragma Assert (Is_Record_Type (Typ));
Build_Record_Deep_Procs (Typ);
end if;
end Build_Controlling_Procs;
procedure Build_Final_List (N : Node_Id; Typ : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
Decl : Node_Id;
begin
Set_Associated_Final_Chain (Typ,
Make_Defining_Identifier (Loc,
New_External_Name (Chars (Typ), 'L')));
Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier =>
Associated_Final_Chain (Typ),
Object_Definition =>
New_Reference_To
(RTE (RE_List_Controller), Loc));
if Is_Frozen (Typ)
or else (Nkind (N) = N_Allocator
and then Ekind (Etype (N)) = E_Anonymous_Access_Type)
then
Insert_Action (N, Decl);
else
Append_Freeze_Action (Typ, Decl);
end if;
end Build_Final_List;
procedure Build_Late_Proc (Typ : Entity_Id; Nam : Name_Id) is
begin
for Final_Prim in Name_Of'Range loop
if Name_Of (Final_Prim) = Nam then
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Final_Prim,
Typ => Typ,
Stmts => Make_Deep_Record_Body (Final_Prim, Typ)));
end if;
end loop;
end Build_Late_Proc;
procedure Build_Record_Deep_Procs (Typ : Entity_Id) is
begin
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Initialize_Case,
Typ => Typ,
Stmts => Make_Deep_Record_Body (Initialize_Case, Typ)));
if not Is_Return_By_Reference_Type (Typ) then
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Adjust_Case,
Typ => Typ,
Stmts => Make_Deep_Record_Body (Adjust_Case, Typ)));
end if;
Set_TSS (Typ,
Make_Deep_Proc (
Prim => Finalize_Case,
Typ => Typ,
Stmts => Make_Deep_Record_Body (Finalize_Case, Typ)));
end Build_Record_Deep_Procs;
function Cleanup_Array
(N : Node_Id;
Obj : Node_Id;
Typ : Entity_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (N);
Index_List : constant List_Id := New_List;
function Free_Component return List_Id;
function Free_One_Dimension (Dim : Int) return List_Id;
function Free_Component return List_Id is
Stmts : List_Id := New_List;
Tsk : Node_Id;
C_Typ : constant Entity_Id := Component_Type (Typ);
begin
Tsk :=
Make_Indexed_Component (Loc,
Prefix => Duplicate_Subexpr_No_Checks (Obj),
Expressions => Index_List);
Set_Etype (Tsk, C_Typ);
if Is_Task_Type (C_Typ) then
Append_To (Stmts, Cleanup_Task (N, Tsk));
elsif Is_Simple_Protected_Type (C_Typ) then
Append_To (Stmts, Cleanup_Protected_Object (N, Tsk));
elsif Is_Record_Type (C_Typ) then
Stmts := Cleanup_Record (N, Tsk, C_Typ);
elsif Is_Array_Type (C_Typ) then
Stmts := Cleanup_Array (N, Tsk, C_Typ);
end if;
return Stmts;
end Free_Component;
function Free_One_Dimension (Dim : Int) return List_Id is
Index : Entity_Id;
begin
if Dim > Number_Dimensions (Typ) then
return Free_Component;
else
Index :=
Make_Defining_Identifier (Loc, New_Internal_Name ('J'));
Append (New_Reference_To (Index, Loc), Index_List);
return New_List (
Make_Implicit_Loop_Statement (N,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => Index,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => Duplicate_Subexpr (Obj),
Attribute_Name => Name_Range,
Expressions => New_List (
Make_Integer_Literal (Loc, Dim))))),
Statements => Free_One_Dimension (Dim + 1)));
end if;
end Free_One_Dimension;
begin
return Free_One_Dimension (1);
end Cleanup_Array;
function Cleanup_Record
(N : Node_Id;
Obj : Node_Id;
Typ : Entity_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (N);
Tsk : Node_Id;
Comp : Entity_Id;
Stmts : constant List_Id := New_List;
U_Typ : constant Entity_Id := Underlying_Type (Typ);
begin
if Has_Discriminants (U_Typ)
and then Nkind (Parent (U_Typ)) = N_Full_Type_Declaration
and then
Nkind (Type_Definition (Parent (U_Typ))) = N_Record_Definition
and then
Present
(Variant_Part
(Component_List (Type_Definition (Parent (U_Typ)))))
then
Error_Msg_N
("task/protected object in variant record will not be freed?", N);
return New_List (Make_Null_Statement (Loc));
end if;
Comp := First_Component (Typ);
while Present (Comp) loop
if Has_Task (Etype (Comp))
or else Has_Simple_Protected_Object (Etype (Comp))
then
Tsk :=
Make_Selected_Component (Loc,
Prefix => Duplicate_Subexpr_No_Checks (Obj),
Selector_Name => New_Occurrence_Of (Comp, Loc));
Set_Etype (Tsk, Etype (Comp));
if Is_Task_Type (Etype (Comp)) then
Append_To (Stmts, Cleanup_Task (N, Tsk));
elsif Is_Simple_Protected_Type (Etype (Comp)) then
Append_To (Stmts, Cleanup_Protected_Object (N, Tsk));
elsif Is_Record_Type (Etype (Comp)) then
Append_List_To
(Stmts, Cleanup_Record (N, Tsk, Etype (Comp)));
elsif Is_Array_Type (Etype (Comp)) then
Append_List_To
(Stmts, Cleanup_Array (N, Tsk, Etype (Comp)));
end if;
end if;
Next_Component (Comp);
end loop;
return Stmts;
end Cleanup_Record;
function Cleanup_Protected_Object
(N : Node_Id;
Ref : Node_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (N);
begin
return
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Finalize_Protection), Loc),
Parameter_Associations => New_List (
Concurrent_Ref (Ref)));
end Cleanup_Protected_Object;
procedure Clean_Simple_Protected_Objects (N : Node_Id) is
Stmts : constant List_Id := Statements (Handled_Statement_Sequence (N));
Stmt : Node_Id := Last (Stmts);
E : Entity_Id;
begin
E := First_Entity (Current_Scope);
while Present (E) loop
if (Ekind (E) = E_Variable
or else Ekind (E) = E_Constant)
and then Has_Simple_Protected_Object (Etype (E))
and then not Has_Task (Etype (E))
and then Nkind (Parent (E)) /= N_Object_Renaming_Declaration
then
declare
Typ : constant Entity_Id := Etype (E);
Ref : constant Node_Id := New_Occurrence_Of (E, Sloc (Stmt));
begin
if Is_Simple_Protected_Type (Typ) then
Append_To (Stmts, Cleanup_Protected_Object (N, Ref));
elsif Has_Simple_Protected_Object (Typ) then
if Is_Record_Type (Typ) then
Append_List_To (Stmts, Cleanup_Record (N, Ref, Typ));
elsif Is_Array_Type (Typ) then
Append_List_To (Stmts, Cleanup_Array (N, Ref, Typ));
end if;
end if;
end;
end if;
Next_Entity (E);
end loop;
if Present (Stmt) then
Stmt := Next (Stmt);
while Present (Stmt) loop
Analyze (Stmt);
Next (Stmt);
end loop;
end if;
end Clean_Simple_Protected_Objects;
function Cleanup_Task
(N : Node_Id;
Ref : Node_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (N);
begin
return
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Free_Task), Loc),
Parameter_Associations =>
New_List (Concurrent_Ref (Ref)));
end Cleanup_Task;
function Has_Simple_Protected_Object (T : Entity_Id) return Boolean is
Comp : Entity_Id;
begin
if Is_Simple_Protected_Type (T) then
return True;
elsif Is_Array_Type (T) then
return Has_Simple_Protected_Object (Component_Type (T));
elsif Is_Record_Type (T) then
Comp := First_Component (T);
while Present (Comp) loop
if Has_Simple_Protected_Object (Etype (Comp)) then
return True;
end if;
Next_Component (Comp);
end loop;
return False;
else
return False;
end if;
end Has_Simple_Protected_Object;
function Is_Simple_Protected_Type (T : Entity_Id) return Boolean is
begin
return Is_Protected_Type (T) and then not Has_Entries (T);
end Is_Simple_Protected_Type;
procedure Check_Visibly_Controlled
(Prim : Final_Primitives;
Typ : Entity_Id;
E : in out Entity_Id;
Cref : in out Node_Id)
is
Parent_Type : Entity_Id;
Op : Entity_Id;
begin
if Is_Derived_Type (Typ)
and then Comes_From_Source (E)
and then not Is_Overriding_Operation (E)
then
Parent_Type := Etype (Typ);
Op := Find_Prim_Op (Parent_Type, Name_Of (Prim));
if Present (Op) then
E := Op;
if Nkind (Cref) = N_Unchecked_Type_Conversion then
Cref := Unchecked_Convert_To (Parent_Type, Expression (Cref));
else
Cref := Unchecked_Convert_To (Parent_Type, Cref);
end if;
end if;
end if;
end Check_Visibly_Controlled;
function Controlled_Type (T : Entity_Id) return Boolean is
function Has_Some_Controlled_Component (Rec : Entity_Id) return Boolean;
function Has_Some_Controlled_Component
(Rec : Entity_Id) return Boolean
is
Comp : Entity_Id;
begin
if Has_Controlled_Component (Rec) then
return True;
elsif not Is_Frozen (Rec) then
if Is_Record_Type (Rec) then
Comp := First_Entity (Rec);
while Present (Comp) loop
if not Is_Type (Comp)
and then Controlled_Type (Etype (Comp))
then
return True;
end if;
Next_Entity (Comp);
end loop;
return False;
elsif Is_Array_Type (Rec) then
return Is_Controlled (Component_Type (Rec));
else
return Has_Controlled_Component (Rec);
end if;
else
return False;
end if;
end Has_Some_Controlled_Component;
begin
return (Is_Class_Wide_Type (T)
and then not In_Finalization_Root (T)
and then not Restriction_Active (No_Finalization))
or else Is_Controlled (T)
or else Has_Some_Controlled_Component (T)
or else (Is_Concurrent_Type (T)
and then Present (Corresponding_Record_Type (T))
and then Controlled_Type (Corresponding_Record_Type (T)));
end Controlled_Type;
function Controller_Component (Typ : Entity_Id) return Entity_Id is
T : Entity_Id := Base_Type (Typ);
Comp : Entity_Id;
Comp_Scop : Entity_Id;
Res : Entity_Id := Empty;
Res_Scop : Entity_Id := Empty;
begin
if Is_Class_Wide_Type (T) then
T := Root_Type (T);
end if;
if Is_Private_Type (T) then
T := Underlying_Type (T);
end if;
Comp := First_Entity (T);
while Present (Comp) loop
if Chars (Comp) = Name_uController then
Comp_Scop := Scope (Original_Record_Component (Comp));
if Comp_Scop = T then
return Comp;
elsif Res = Empty or else Is_Ancestor (Res_Scop, Comp_Scop) then
Res := Comp;
Res_Scop := Comp_Scop;
end if;
end if;
Next_Entity (Comp);
end loop;
return Res;
end Controller_Component;
function Convert_View
(Proc : Entity_Id;
Arg : Node_Id;
Ind : Pos := 1) return Node_Id
is
Fent : Entity_Id := First_Entity (Proc);
Ftyp : Entity_Id;
Atyp : Entity_Id;
begin
for J in 2 .. Ind loop
Next_Entity (Fent);
end loop;
Ftyp := Etype (Fent);
if Nkind (Arg) = N_Type_Conversion
or else Nkind (Arg) = N_Unchecked_Type_Conversion
then
Atyp := Entity (Subtype_Mark (Arg));
else
Atyp := Etype (Arg);
end if;
if Is_Abstract (Proc) and then Is_Tagged_Type (Ftyp) then
return Unchecked_Convert_To (Class_Wide_Type (Ftyp), Arg);
elsif Ftyp /= Atyp
and then Present (Atyp)
and then
(Is_Private_Type (Ftyp) or else Is_Private_Type (Atyp))
and then Underlying_Type (Atyp) = Underlying_Type (Ftyp)
then
return Unchecked_Convert_To (Ftyp, Arg);
elsif (Nkind (Arg) = N_Unchecked_Type_Conversion
or else Nkind (Arg) = N_Type_Conversion)
and then not Is_Class_Wide_Type (Atyp)
then
Set_Subtype_Mark (Arg, New_Occurrence_Of (Ftyp, Sloc (Arg)));
Set_Etype (Arg, Ftyp);
return Arg;
else
return Arg;
end if;
end Convert_View;
procedure Establish_Transient_Scope (N : Node_Id; Sec_Stack : Boolean) is
Loc : constant Source_Ptr := Sloc (N);
Wrap_Node : Node_Id;
Sec_Stk : constant Boolean :=
Sec_Stack and not Functions_Return_By_DSP_On_Target;
begin
for S in reverse Scope_Stack.First .. Scope_Stack.Last loop
if Scope_Stack.Table (S).Is_Transient then
if Sec_Stk then
Set_Uses_Sec_Stack (Scope_Stack.Table (S).Entity);
end if;
return;
elsif Scope_Stack.Table (S).Entity = Standard_Standard then
exit;
end if;
end loop;
Wrap_Node := Find_Node_To_Be_Wrapped (N);
if No (Wrap_Node) then
null;
elsif Nkind (Wrap_Node) = N_Iteration_Scheme then
null;
else
New_Scope (New_Internal_Entity (E_Block, Current_Scope, Loc, 'B'));
Set_Scope_Is_Transient;
if Sec_Stk then
Set_Uses_Sec_Stack (Current_Scope);
Check_Restriction (No_Secondary_Stack, N);
end if;
Set_Etype (Current_Scope, Standard_Void_Type);
Set_Node_To_Be_Wrapped (Wrap_Node);
if Debug_Flag_W then
Write_Str (" <Transient>");
Write_Eol;
end if;
end if;
end Establish_Transient_Scope;
procedure Expand_Cleanup_Actions (N : Node_Id) is
Loc : Source_Ptr;
S : constant Entity_Id :=
Current_Scope;
Flist : constant Entity_Id :=
Finalization_Chain_Entity (S);
Is_Task : constant Boolean :=
(Nkind (Original_Node (N)) = N_Task_Body);
Is_Master : constant Boolean :=
Nkind (N) /= N_Entry_Body
and then Is_Task_Master (N);
Is_Protected : constant Boolean :=
Nkind (N) = N_Subprogram_Body
and then Is_Protected_Subprogram_Body (N);
Is_Task_Allocation : constant Boolean :=
Nkind (N) = N_Block_Statement
and then Is_Task_Allocation_Block (N);
Is_Asynchronous_Call : constant Boolean :=
Nkind (N) = N_Block_Statement
and then Is_Asynchronous_Call_Block (N);
Clean : Entity_Id;
Mark : Entity_Id := Empty;
New_Decls : constant List_Id := New_List;
Blok : Node_Id;
End_Lab : Node_Id;
Wrapped : Boolean;
Chain : Entity_Id := Empty;
Decl : Node_Id;
Old_Poll : Boolean;
begin
declare
S1 : Entity_Id := S;
begin
while not Comes_From_Source (S1) and then S1 /= Standard_Standard loop
S1 := Scope (S1);
end loop;
Loc := Sloc (S1);
end;
if Uses_Sec_Stack (Current_Scope)
and then not Sec_Stack_Needed_For_Return (Current_Scope)
then
null;
elsif No (Flist)
and then not Is_Master
and then not Is_Task
and then not Is_Protected
and then not Is_Task_Allocation
and then not Is_Asynchronous_Call
then
Clean_Simple_Protected_Objects (N);
return;
end if;
if Nkind (N) = N_Subprogram_Body
and then Nkind (Original_Node (N)) = N_Task_Body
and then not Delay_Subprogram_Descriptors (Corresponding_Spec (N))
then
return;
end if;
Old_Poll := Polling_Required;
Polling_Required := False;
if No (Declarations (N)) then
Set_Declarations (N, New_List);
end if;
if not Is_Task_Allocation then
Build_Task_Activation_Call (N);
end if;
if Is_Master then
Establish_Task_Master (N);
end if;
if Uses_Sec_Stack (Current_Scope)
and then not Sec_Stack_Needed_For_Return (Current_Scope)
and then not Java_VM
then
Mark := Make_Defining_Identifier (Loc, New_Internal_Name ('M'));
Append_To (New_Decls,
Make_Object_Declaration (Loc,
Defining_Identifier => Mark,
Object_Definition => New_Reference_To (RTE (RE_Mark_Id), Loc),
Expression =>
Make_Function_Call (Loc,
Name => New_Reference_To (RTE (RE_SS_Mark), Loc))));
Set_Uses_Sec_Stack (Current_Scope, False);
end if;
if Present (Flist) then
Append_To (New_Decls,
Make_Object_Declaration (Loc,
Defining_Identifier => Flist,
Object_Definition =>
New_Reference_To (RTE (RE_Finalizable_Ptr), Loc)));
end if;
Clean := Make_Defining_Identifier (Loc, Name_uClean);
Set_Suppress_Elaboration_Warnings (Clean);
Append_To (New_Decls,
Make_Clean (N, Clean, Mark, Flist,
Is_Task,
Is_Master,
Is_Protected,
Is_Task_Allocation,
Is_Asynchronous_Call));
if Present (Exception_Handlers (Handled_Statement_Sequence (N))) then
End_Lab := End_Label (Handled_Statement_Sequence (N));
Blok :=
Make_Block_Statement (Loc,
Handled_Statement_Sequence => Handled_Statement_Sequence (N));
Set_Handled_Statement_Sequence (N,
Make_Handled_Sequence_Of_Statements (Loc, New_List (Blok)));
Set_End_Label (Handled_Statement_Sequence (N), End_Lab);
Wrapped := True;
else
Wrapped := False;
Blok := Empty;
end if;
if Is_Task_Allocation then
Chain := Activation_Chain_Entity (N);
Decl := First (Declarations (N));
while Nkind (Decl) /= N_Object_Declaration
or else Defining_Identifier (Decl) /= Chain
loop
Next (Decl);
pragma Assert (Present (Decl));
end loop;
Remove (Decl);
Prepend_To (New_Decls, Decl);
end if;
if not Wrapped then
if No (First_Real_Statement (Handled_Statement_Sequence (N))) then
Set_First_Real_Statement (Handled_Statement_Sequence (N),
First (Statements (Handled_Statement_Sequence (N))));
end if;
else
Set_First_Real_Statement (Handled_Statement_Sequence (N), Blok);
end if;
Append_List_To (Declarations (N),
Statements (Handled_Statement_Sequence (N)));
Set_Statements (Handled_Statement_Sequence (N), Declarations (N));
Set_Sloc
(Handled_Statement_Sequence (N), Sloc (First (Declarations (N))));
Set_Declarations (N, New_Decls);
Analyze_Declarations (New_Decls);
declare
HSS : Node_Id;
begin
if Is_Protected then
HSS := Handled_Statement_Sequence
(Last (Statements (Handled_Statement_Sequence (N))));
else
HSS := Handled_Statement_Sequence (N);
end if;
Set_At_End_Proc (HSS, New_Occurrence_Of (Clean, Loc));
Expand_At_End_Handler (HSS, Empty);
end;
Polling_Required := Old_Poll;
end Expand_Cleanup_Actions;
procedure Expand_Ctrl_Function_Call (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Rtype : constant Entity_Id := Etype (N);
Utype : constant Entity_Id := Underlying_Type (Rtype);
Ref : Node_Id;
Action : Node_Id;
Action2 : Node_Id := Empty;
Attach_Level : Uint := Uint_1;
Len_Ref : Node_Id := Empty;
function Last_Array_Component
(Ref : Node_Id;
Typ : Entity_Id) return Node_Id;
function Last_Array_Component
(Ref : Node_Id;
Typ : Entity_Id) return Node_Id
is
Index_List : constant List_Id := New_List;
begin
for N in 1 .. Number_Dimensions (Typ) loop
Append_To (Index_List,
Make_Attribute_Reference (Loc,
Prefix => Duplicate_Subexpr_No_Checks (Ref),
Attribute_Name => Name_Last,
Expressions => New_List (
Make_Integer_Literal (Loc, N))));
end loop;
return
Make_Indexed_Component (Loc,
Prefix => Duplicate_Subexpr (Ref),
Expressions => Index_List);
end Last_Array_Component;
begin
if Nkind (Parent (N)) = N_Return_Statement then
return;
end if;
Set_Analyzed (N);
Ref := Duplicate_Subexpr_No_Checks (N);
if Has_Controlled_Component (Rtype) then
declare
T1 : Entity_Id := Rtype;
T2 : Entity_Id := Utype;
begin
if Is_Array_Type (T2) then
Len_Ref :=
Make_Attribute_Reference (Loc,
Prefix =>
Duplicate_Subexpr_Move_Checks
(Unchecked_Convert_To (T2, Ref)),
Attribute_Name => Name_Length);
end if;
while Is_Array_Type (T2) loop
if T1 /= T2 then
Ref := Unchecked_Convert_To (T2, Ref);
end if;
Ref := Last_Array_Component (Ref, T2);
Attach_Level := Uint_3;
T1 := Component_Type (T2);
T2 := Underlying_Type (T1);
end loop;
if Is_Array_Type (Rtype) and then Is_Controlled (T2) then
null;
elsif Has_Controlled_Component (T2) then
if T1 /= T2 then
Ref := Unchecked_Convert_To (T2, Ref);
end if;
Ref :=
Make_Selected_Component (Loc,
Prefix => Ref,
Selector_Name => Make_Identifier (Loc, Name_uController));
end if;
end;
Action :=
Make_Attach_Call (
Obj_Ref => Ref,
Flist_Ref => Find_Final_List (Current_Scope),
With_Attach => Make_Integer_Literal (Loc, Attach_Level));
if Is_Controlled (Rtype) then
Action2 :=
Make_Attach_Call (
Obj_Ref => Duplicate_Subexpr_No_Checks (N),
Flist_Ref => Find_Final_List (Current_Scope),
With_Attach => Make_Integer_Literal (Loc, Attach_Level));
end if;
else
Action :=
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Deep_Tag_Attach), Loc),
Parameter_Associations => New_List (
Find_Final_List (Current_Scope),
Make_Attribute_Reference (Loc,
Prefix => Ref,
Attribute_Name => Name_Address),
Make_Integer_Literal (Loc, Attach_Level)));
end if;
if Present (Len_Ref) then
Action :=
Make_Implicit_If_Statement (N,
Condition => Make_Op_Gt (Loc,
Left_Opnd => Len_Ref,
Right_Opnd => Make_Integer_Literal (Loc, 0)),
Then_Statements => New_List (Action));
end if;
Insert_Action (N, Action);
if Present (Action2) then
Insert_Action (N, Action2);
end if;
end Expand_Ctrl_Function_Call;
procedure Expand_N_Package_Body (N : Node_Id) is
Ent : constant Entity_Id := Corresponding_Spec (N);
begin
if Ekind (Ent) = E_Package then
New_Scope (Corresponding_Spec (N));
Build_Task_Activation_Call (N);
Pop_Scope;
end if;
Set_Elaboration_Flag (N, Corresponding_Spec (N));
if Present (Handler_Records (Body_Entity (Ent)))
and then Is_Compilation_Unit (Ent)
and then not Delay_Subprogram_Descriptors (Body_Entity (Ent))
then
Generate_Subprogram_Descriptor_For_Package
(N, Body_Entity (Ent));
end if;
Set_In_Package_Body (Ent, False);
Qualify_Entity_Names (N);
end Expand_N_Package_Body;
procedure Expand_N_Package_Declaration (N : Node_Id) is
begin
if Nkind (Parent (N)) = N_Compilation_Unit
and then not Body_Required (Parent (N))
and then not Unit_Requires_Body (Defining_Entity (N))
and then Present (Activation_Chain_Entity (N))
then
New_Scope (Defining_Entity (N));
Build_Task_Activation_Call (N);
Pop_Scope;
end if;
Qualify_Entity_Names (N);
end Expand_N_Package_Declaration;
function Find_Final_List
(E : Entity_Id;
Ref : Node_Id := Empty) return Node_Id
is
Loc : constant Source_Ptr := Sloc (Ref);
S : Entity_Id;
Id : Entity_Id;
R : Node_Id;
begin
if Present (Ref) then
R := Ref;
loop
case Nkind (R) is
when N_Unchecked_Type_Conversion | N_Type_Conversion =>
R := Expression (R);
when N_Indexed_Component | N_Explicit_Dereference =>
R := Prefix (R);
when N_Selected_Component =>
R := Prefix (R);
exit;
when N_Identifier =>
exit;
when others =>
raise Program_Error;
end case;
end loop;
return
Make_Selected_Component (Loc,
Prefix =>
Make_Selected_Component (Loc,
Prefix => R,
Selector_Name => Make_Identifier (Loc, Name_uController)),
Selector_Name => Make_Identifier (Loc, Name_F));
elsif Is_Access_Type (E) then
if not From_With_Type (E) then
return
Make_Selected_Component (Loc,
Prefix =>
New_Reference_To
(Associated_Final_Chain (Base_Type (E)), Loc),
Selector_Name => Make_Identifier (Loc, Name_F));
else
return New_Reference_To (RTE (RE_Global_Final_List), Sloc (E));
end if;
else
if Is_Dynamic_Scope (E) then
S := E;
else
S := Enclosing_Dynamic_Scope (E);
end if;
while Finalization_Chain_Entity (S) = Error loop
S := Enclosing_Dynamic_Scope (S);
end loop;
if S = Standard_Standard then
return New_Reference_To (RTE (RE_Global_Final_List), Sloc (E));
else
if No (Finalization_Chain_Entity (S)) then
Id := Make_Defining_Identifier (Sloc (S),
New_Internal_Name ('F'));
Set_Finalization_Chain_Entity (S, Id);
Set_Ekind (Id, E_Variable);
Set_Etype (Id, RTE (RE_Finalizable_Ptr));
end if;
return New_Reference_To (Finalization_Chain_Entity (S), Sloc (E));
end if;
end if;
end Find_Final_List;
function Find_Node_To_Be_Wrapped (N : Node_Id) return Node_Id is
P : Node_Id;
The_Parent : Node_Id;
begin
The_Parent := N;
loop
P := The_Parent;
pragma Assert (P /= Empty);
The_Parent := Parent (P);
case Nkind (The_Parent) is
when N_Pragma =>
return The_Parent;
when N_Assignment_Statement =>
if No_Ctrl_Actions (The_Parent) then
null;
else
return The_Parent;
end if;
when N_Entry_Call_Statement |
N_Procedure_Call_Statement =>
if Nkind (Parent (The_Parent)) = N_Entry_Call_Alternative
and then
Nkind (Parent (Parent (The_Parent))) = N_Timed_Entry_Call
then
return Parent (Parent (The_Parent));
else
return The_Parent;
end if;
when N_Object_Declaration |
N_Object_Renaming_Declaration |
N_Subtype_Declaration =>
return The_Parent;
when N_Accept_Alternative |
N_Attribute_Definition_Clause |
N_Case_Statement |
N_Code_Statement |
N_Delay_Alternative |
N_Delay_Until_Statement |
N_Delay_Relative_Statement |
N_Discriminant_Association |
N_Elsif_Part |
N_Entry_Body_Formal_Part |
N_Exit_Statement |
N_If_Statement |
N_Iteration_Scheme |
N_Terminate_Alternative =>
return P;
when N_Attribute_Reference =>
if Is_Procedure_Attribute_Name
(Attribute_Name (The_Parent))
then
return The_Parent;
end if;
when N_Loop_Parameter_Specification =>
return Parent (The_Parent);
when N_Parameter_Specification |
N_Discriminant_Specification |
N_Component_Declaration =>
return Empty;
when N_Return_Statement =>
if Requires_Transient_Scope (Return_Type (The_Parent)) then
return Empty;
else
return The_Parent;
end if;
when N_Subprogram_Body |
N_Package_Declaration |
N_Package_Body |
N_Block_Statement =>
return Empty;
when others =>
null;
end case;
end loop;
end Find_Node_To_Be_Wrapped;
function Global_Flist_Ref (Flist_Ref : Node_Id) return Boolean is
Flist : Entity_Id;
begin
if Is_Entity_Name (Flist_Ref) then
Flist := Entity (Flist_Ref);
elsif Nkind (Flist_Ref) = N_Selected_Component
and then Is_Entity_Name (Prefix (Flist_Ref))
then
Flist := Entity (Prefix (Flist_Ref));
else
return False;
end if;
return Present (Flist)
and then Present (Scope (Flist))
and then Enclosing_Dynamic_Scope (Flist) = Standard_Standard;
end Global_Flist_Ref;
function Has_New_Controlled_Component (E : Entity_Id) return Boolean is
Comp : Entity_Id;
begin
if not Is_Tagged_Type (E) then
return Has_Controlled_Component (E);
elsif not Is_Derived_Type (E) then
return Has_Controlled_Component (E);
end if;
Comp := First_Component (E);
while Present (Comp) loop
if Chars (Comp) = Name_uParent then
null;
elsif Scope (Original_Record_Component (Comp)) = E
and then Controlled_Type (Etype (Comp))
then
return True;
end if;
Next_Component (Comp);
end loop;
return False;
end Has_New_Controlled_Component;
function In_Finalization_Root (E : Entity_Id) return Boolean is
S : constant Entity_Id := Scope (E);
begin
return Chars (Scope (S)) = Name_System
and then Chars (S) = Name_Finalization_Root
and then Scope (Scope (S)) = Standard_Standard;
end In_Finalization_Root;
procedure Insert_Actions_In_Scope_Around (N : Node_Id) is
SE : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
Target : Node_Id;
begin
if Nkind (Parent (Node_To_Be_Wrapped)) = N_Triggering_Alternative then
Target := Parent (Parent (Node_To_Be_Wrapped));
else
Target := N;
end if;
if Present (SE.Actions_To_Be_Wrapped_Before) then
Insert_List_Before (Target, SE.Actions_To_Be_Wrapped_Before);
SE.Actions_To_Be_Wrapped_Before := No_List;
end if;
if Present (SE.Actions_To_Be_Wrapped_After) then
Insert_List_After (Target, SE.Actions_To_Be_Wrapped_After);
SE.Actions_To_Be_Wrapped_After := No_List;
end if;
end Insert_Actions_In_Scope_Around;
function Make_Adjust_Call
(Ref : Node_Id;
Typ : Entity_Id;
Flist_Ref : Node_Id;
With_Attach : Node_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (Ref);
Res : constant List_Id := New_List;
Utyp : Entity_Id;
Proc : Entity_Id;
Cref : Node_Id := Ref;
Cref2 : Node_Id;
Attach : Node_Id := With_Attach;
begin
if Is_Class_Wide_Type (Typ) then
Utyp := Underlying_Type (Base_Type (Root_Type (Typ)));
else
Utyp := Underlying_Type (Base_Type (Typ));
end if;
Set_Assignment_OK (Cref);
if Is_Untagged_Derivation (Typ) then
Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
Cref := Unchecked_Convert_To (Utyp, Cref);
Set_Assignment_OK (Cref);
end if;
if Utyp /= Base_Type (Utyp) then
pragma Assert (Is_Private_Type (Typ));
Utyp := Base_Type (Utyp);
Cref := Unchecked_Convert_To (Utyp, Cref);
end if;
if No (Etype (Cref))
and then Nkind (Cref) /= N_Unchecked_Type_Conversion
then
Set_Etype (Cref, Typ);
end if;
if Finalize_Storage_Only (Typ)
and then (Global_Flist_Ref (Flist_Ref)
or else Entity (Constant_Value (RTE (RE_Garbage_Collected)))
= Standard_True)
then
Attach := Make_Integer_Literal (Loc, 0);
end if;
if Has_Controlled_Component (Utyp)
or else Is_Class_Wide_Type (Typ)
then
if Is_Tagged_Type (Utyp) then
Proc := Find_Prim_Op (Utyp, TSS_Deep_Adjust);
else
Proc := TSS (Utyp, TSS_Deep_Adjust);
end if;
Cref := Convert_View (Proc, Cref, 2);
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations =>
New_List (Flist_Ref, Cref, Attach)));
else
Proc := Find_Prim_Op (Utyp, Name_Of (Adjust_Case));
Cref := Convert_View (Proc, Cref);
Cref2 := New_Copy_Tree (Cref);
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations => New_List (Cref2)));
Append_To (Res, Make_Attach_Call (Cref, Flist_Ref, Attach));
end if;
return Res;
end Make_Adjust_Call;
function Make_Attach_Call
(Obj_Ref : Node_Id;
Flist_Ref : Node_Id;
With_Attach : Node_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (Obj_Ref);
begin
if Nkind (With_Attach) = N_Integer_Literal
and then Intval (With_Attach) = Uint_0
then
return Make_Null_Statement (Loc);
end if;
return
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Attach_To_Final_List), Loc),
Parameter_Associations => New_List (
Flist_Ref,
OK_Convert_To (RTE (RE_Finalizable), Obj_Ref),
With_Attach));
end Make_Attach_Call;
function Make_Clean
(N : Node_Id;
Clean : Entity_Id;
Mark : Entity_Id;
Flist : Entity_Id;
Is_Task : Boolean;
Is_Master : Boolean;
Is_Protected_Subprogram : Boolean;
Is_Task_Allocation_Block : Boolean;
Is_Asynchronous_Call_Block : Boolean) return Node_Id
is
Loc : constant Source_Ptr := Sloc (Clean);
Stmt : constant List_Id := New_List;
Sbody : Node_Id;
Spec : Node_Id;
Name : Node_Id;
Param : Node_Id;
Param_Type : Entity_Id;
Pid : Entity_Id := Empty;
Cancel_Param : Entity_Id;
begin
if Is_Task then
if Restricted_Profile then
Append_To
(Stmt, Build_Runtime_Call (Loc, RE_Complete_Restricted_Task));
else
Append_To (Stmt, Build_Runtime_Call (Loc, RE_Complete_Task));
end if;
elsif Is_Master then
if Restriction_Active (No_Task_Hierarchy) = False then
Append_To (Stmt, Build_Runtime_Call (Loc, RE_Complete_Master));
end if;
elsif Is_Protected_Subprogram then
Spec := Parent (Corresponding_Spec (N));
Param := First (Parameter_Specifications (Spec));
loop
Param_Type := Etype (Parameter_Type (Param));
if Ekind (Param_Type) = E_Record_Type then
Pid := Corresponding_Concurrent_Type (Param_Type);
end if;
exit when not Present (Param) or else Present (Pid);
Next (Param);
end loop;
pragma Assert (Present (Param));
if Nkind (Specification (N)) = N_Procedure_Specification
and then Has_Entries (Pid)
then
if Abort_Allowed
or else Restriction_Active (No_Entry_Queue) = False
or else Number_Entries (Pid) > 1
then
Name := New_Reference_To (RTE (RE_Service_Entries), Loc);
else
Name := New_Reference_To (RTE (RE_Service_Entry), Loc);
end if;
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => Name,
Parameter_Associations => New_List (
Make_Attribute_Reference (Loc,
Prefix =>
Make_Selected_Component (Loc,
Prefix => New_Reference_To (
Defining_Identifier (Param), Loc),
Selector_Name =>
Make_Identifier (Loc, Name_uObject)),
Attribute_Name => Name_Unchecked_Access))));
else
if Has_Entries (Pid)
or else Has_Interrupt_Handler (Pid)
or else (Has_Attach_Handler (Pid)
and then not Restricted_Profile)
then
if Abort_Allowed
or else Restriction_Active (No_Entry_Queue) = False
or else Number_Entries (Pid) > 1
then
Name := New_Reference_To (RTE (RE_Unlock_Entries), Loc);
else
Name := New_Reference_To (RTE (RE_Unlock_Entry), Loc);
end if;
else
Name := New_Reference_To (RTE (RE_Unlock), Loc);
end if;
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => Name,
Parameter_Associations => New_List (
Make_Attribute_Reference (Loc,
Prefix =>
Make_Selected_Component (Loc,
Prefix =>
New_Reference_To (Defining_Identifier (Param), Loc),
Selector_Name =>
Make_Identifier (Loc, Name_uObject)),
Attribute_Name => Name_Unchecked_Access))));
end if;
if Abort_Allowed then
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name =>
New_Reference_To (
RTE (RE_Abort_Undefer), Loc),
Parameter_Associations => Empty_List));
end if;
elsif Is_Task_Allocation_Block then
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name =>
New_Reference_To (
RTE (RE_Expunge_Unactivated_Tasks), Loc),
Parameter_Associations => New_List (
New_Reference_To (Activation_Chain_Entity (N), Loc))));
elsif Is_Asynchronous_Call_Block then
Cancel_Param := Entry_Cancel_Parameter (Entity (Identifier (N)));
if Is_RTE (Etype (Cancel_Param), RE_Communication_Block) then
Append_To (Stmt,
Make_Implicit_If_Statement (Clean,
Condition => Make_Function_Call (Loc,
Name => New_Reference_To (
RTE (RE_Enqueued), Loc),
Parameter_Associations => New_List (
New_Reference_To (Cancel_Param, Loc))),
Then_Statements => New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (
RTE (RE_Cancel_Protected_Entry_Call), Loc),
Parameter_Associations => New_List (
New_Reference_To (Cancel_Param, Loc))))));
elsif Is_RTE (Etype (Cancel_Param), RE_Delay_Block) then
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Cancel_Async_Delay), Loc),
Parameter_Associations => New_List (
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Cancel_Param, Loc),
Attribute_Name => Name_Unchecked_Access))));
else
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (
RTE (RE_Cancel_Task_Entry_Call),
Loc),
Parameter_Associations => New_List (
New_Reference_To (Cancel_Param, Loc))));
end if;
end if;
if Present (Flist) then
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Finalize_List), Loc),
Parameter_Associations => New_List (
New_Reference_To (Flist, Loc))));
end if;
if Present (Mark) then
Append_To (Stmt,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_SS_Release), Loc),
Parameter_Associations => New_List (
New_Reference_To (Mark, Loc))));
end if;
Sbody :=
Make_Subprogram_Body (Loc,
Specification =>
Make_Procedure_Specification (Loc,
Defining_Unit_Name => Clean),
Declarations => New_List,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => Stmt));
if Present (Flist) or else Is_Task or else Is_Master then
Wrap_Cleanup_Procedure (Sbody);
end if;
if not Debug_Generated_Code then
Set_Debug_Info_Off (Clean, True);
end if;
return Sbody;
end Make_Clean;
function Make_Deep_Array_Body
(Prim : Final_Primitives;
Typ : Entity_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (Typ);
Index_List : constant List_Id := New_List;
function One_Component return List_Id;
function One_Dimension (N : Int) return List_Id;
function One_Component return List_Id is
Comp_Typ : constant Entity_Id := Component_Type (Typ);
Comp_Ref : constant Node_Id :=
Make_Indexed_Component (Loc,
Prefix => Make_Identifier (Loc, Name_V),
Expressions => Index_List);
begin
Set_Etype (Comp_Ref, Comp_Typ);
case Prim is
when Initialize_Case =>
return Make_Init_Call (Comp_Ref, Comp_Typ,
Make_Identifier (Loc, Name_L),
Make_Identifier (Loc, Name_B));
when Adjust_Case =>
return Make_Adjust_Call (Comp_Ref, Comp_Typ,
Make_Identifier (Loc, Name_L),
Make_Identifier (Loc, Name_B));
when Finalize_Case =>
return Make_Final_Call (Comp_Ref, Comp_Typ,
Make_Identifier (Loc, Name_B));
end case;
end One_Component;
function One_Dimension (N : Int) return List_Id is
Index : Entity_Id;
begin
if N > Number_Dimensions (Typ) then
return One_Component;
else
Index :=
Make_Defining_Identifier (Loc, New_External_Name ('J', N));
Append_To (Index_List, New_Reference_To (Index, Loc));
return New_List (
Make_Implicit_Loop_Statement (Typ,
Identifier => Empty,
Iteration_Scheme =>
Make_Iteration_Scheme (Loc,
Loop_Parameter_Specification =>
Make_Loop_Parameter_Specification (Loc,
Defining_Identifier => Index,
Discrete_Subtype_Definition =>
Make_Attribute_Reference (Loc,
Prefix => Make_Identifier (Loc, Name_V),
Attribute_Name => Name_Range,
Expressions => New_List (
Make_Integer_Literal (Loc, N))),
Reverse_Present => Prim = Finalize_Case)),
Statements => One_Dimension (N + 1)));
end if;
end One_Dimension;
begin
return One_Dimension (1);
end Make_Deep_Array_Body;
function Make_Deep_Proc
(Prim : Final_Primitives;
Typ : Entity_Id;
Stmts : List_Id) return Entity_Id
is
Loc : constant Source_Ptr := Sloc (Typ);
Formals : List_Id;
Proc_Name : Entity_Id;
Handler : List_Id := No_List;
Type_B : Entity_Id;
begin
if Prim = Finalize_Case then
Formals := New_List;
Type_B := Standard_Boolean;
else
Formals := New_List (
Make_Parameter_Specification (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_L),
In_Present => True,
Out_Present => True,
Parameter_Type =>
New_Reference_To (RTE (RE_Finalizable_Ptr), Loc)));
Type_B := Standard_Short_Short_Integer;
end if;
Append_To (Formals,
Make_Parameter_Specification (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
In_Present => True,
Out_Present => True,
Parameter_Type => New_Reference_To (Typ, Loc)));
Append_To (Formals,
Make_Parameter_Specification (Loc,
Defining_Identifier => Make_Defining_Identifier (Loc, Name_B),
Parameter_Type => New_Reference_To (Type_B, Loc)));
if Prim = Finalize_Case or else Prim = Adjust_Case then
Handler := New_List (
Make_Exception_Handler (Loc,
Exception_Choices => New_List (Make_Others_Choice (Loc)),
Statements => New_List (
Make_Raise_Program_Error (Loc,
Reason => PE_Finalize_Raised_Exception))));
end if;
Proc_Name :=
Make_Defining_Identifier (Loc,
Chars => Make_TSS_Name (Typ, Deep_Name_Of (Prim)));
Discard_Node (
Make_Subprogram_Body (Loc,
Specification =>
Make_Procedure_Specification (Loc,
Defining_Unit_Name => Proc_Name,
Parameter_Specifications => Formals),
Declarations => Empty_List,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => Stmts,
Exception_Handlers => Handler)));
return Proc_Name;
end Make_Deep_Proc;
function Make_Deep_Record_Body
(Prim : Final_Primitives;
Typ : Entity_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (Typ);
Controller_Typ : Entity_Id;
Obj_Ref : constant Node_Id := Make_Identifier (Loc, Name_V);
Controller_Ref : constant Node_Id :=
Make_Selected_Component (Loc,
Prefix => Obj_Ref,
Selector_Name =>
Make_Identifier (Loc, Name_uController));
Res : constant List_Id := New_List;
begin
if Is_Return_By_Reference_Type (Typ) then
Controller_Typ := RTE (RE_Limited_Record_Controller);
else
Controller_Typ := RTE (RE_Record_Controller);
end if;
case Prim is
when Initialize_Case =>
Append_List_To (Res,
Make_Init_Call (
Ref => Controller_Ref,
Typ => Controller_Typ,
Flist_Ref => Make_Identifier (Loc, Name_L),
With_Attach => Make_Identifier (Loc, Name_B)));
if Is_Controlled (Typ) then
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (
Find_Prim_Op (Typ, Name_Of (Prim)), Loc),
Parameter_Associations =>
New_List (New_Copy_Tree (Obj_Ref))));
Append_To (Res, Make_Attach_Call (
Obj_Ref => New_Copy_Tree (Obj_Ref),
Flist_Ref => Make_Identifier (Loc, Name_L),
With_Attach => Make_Identifier (Loc, Name_B)));
end if;
when Adjust_Case =>
Append_List_To (Res,
Make_Adjust_Call (Controller_Ref, Controller_Typ,
Make_Identifier (Loc, Name_L),
Make_Identifier (Loc, Name_B)));
if Is_Controlled (Typ) then
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (
Find_Prim_Op (Typ, Name_Of (Prim)), Loc),
Parameter_Associations =>
New_List (New_Copy_Tree (Obj_Ref))));
Append_To (Res, Make_Attach_Call (
Obj_Ref => New_Copy_Tree (Obj_Ref),
Flist_Ref => Make_Identifier (Loc, Name_L),
With_Attach => Make_Identifier (Loc, Name_B)));
end if;
when Finalize_Case =>
if Is_Controlled (Typ) then
Append_To (Res,
Make_Implicit_If_Statement (Obj_Ref,
Condition => Make_Identifier (Loc, Name_B),
Then_Statements => New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Finalize_One), Loc),
Parameter_Associations => New_List (
OK_Convert_To (RTE (RE_Finalizable),
New_Copy_Tree (Obj_Ref))))),
Else_Statements => New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (
Find_Prim_Op (Typ, Name_Of (Prim)), Loc),
Parameter_Associations =>
New_List (New_Copy_Tree (Obj_Ref))))));
end if;
Append_List_To (Res,
Make_Final_Call (Controller_Ref, Controller_Typ,
Make_Identifier (Loc, Name_B)));
end case;
return Res;
end Make_Deep_Record_Body;
function Make_Final_Call
(Ref : Node_Id;
Typ : Entity_Id;
With_Detach : Node_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (Ref);
Res : constant List_Id := New_List;
Cref : Node_Id;
Cref2 : Node_Id;
Proc : Entity_Id;
Utyp : Entity_Id;
begin
if Is_Class_Wide_Type (Typ) then
Utyp := Root_Type (Typ);
Cref := Ref;
elsif Is_Concurrent_Type (Typ) then
Utyp := Corresponding_Record_Type (Typ);
Cref := Convert_Concurrent (Ref, Typ);
elsif Is_Private_Type (Typ)
and then Present (Full_View (Typ))
and then Is_Concurrent_Type (Full_View (Typ))
then
Utyp := Corresponding_Record_Type (Full_View (Typ));
Cref := Convert_Concurrent (Ref, Full_View (Typ));
else
Utyp := Typ;
Cref := Ref;
end if;
Utyp := Underlying_Type (Base_Type (Utyp));
Set_Assignment_OK (Cref);
if Is_Untagged_Derivation (Typ) then
Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
Cref := Unchecked_Convert_To (Utyp, Cref);
Set_Assignment_OK (Cref);
end if;
if Utyp /= Base_Type (Utyp) then
pragma Assert (Is_Private_Type (Typ));
Utyp := Base_Type (Utyp);
Cref := Unchecked_Convert_To (Utyp, Cref);
end if;
if Has_Controlled_Component (Utyp)
or else Is_Class_Wide_Type (Typ)
then
if Is_Tagged_Type (Utyp) then
Proc := Find_Prim_Op (Utyp, TSS_Deep_Finalize);
else
Proc := TSS (Utyp, TSS_Deep_Finalize);
end if;
Cref := Convert_View (Proc, Cref);
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations =>
New_List (Cref, With_Detach)));
else
Proc := Find_Prim_Op (Utyp, Name_Of (Finalize_Case));
if Chars (With_Detach) = Chars (Standard_True) then
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Finalize_One), Loc),
Parameter_Associations => New_List (
OK_Convert_To (RTE (RE_Finalizable), Cref))));
elsif Chars (With_Detach) = Chars (Standard_False) then
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations =>
New_List (Convert_View (Proc, Cref))));
else
Cref2 := New_Copy_Tree (Cref);
Append_To (Res,
Make_Implicit_If_Statement (Ref,
Condition => With_Detach,
Then_Statements => New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (RTE (RE_Finalize_One), Loc),
Parameter_Associations => New_List (
OK_Convert_To (RTE (RE_Finalizable), Cref)))),
Else_Statements => New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations =>
New_List (Convert_View (Proc, Cref2))))));
end if;
end if;
return Res;
end Make_Final_Call;
function Make_Init_Call
(Ref : Node_Id;
Typ : Entity_Id;
Flist_Ref : Node_Id;
With_Attach : Node_Id) return List_Id
is
Loc : constant Source_Ptr := Sloc (Ref);
Is_Conc : Boolean;
Res : constant List_Id := New_List;
Proc : Entity_Id;
Utyp : Entity_Id;
Cref : Node_Id;
Cref2 : Node_Id;
Attach : Node_Id := With_Attach;
begin
if Is_Concurrent_Type (Typ) then
Is_Conc := True;
Utyp := Corresponding_Record_Type (Typ);
Cref := Convert_Concurrent (Ref, Typ);
elsif Is_Private_Type (Typ)
and then Present (Full_View (Typ))
and then Is_Concurrent_Type (Underlying_Type (Typ))
then
Is_Conc := True;
Utyp := Corresponding_Record_Type (Underlying_Type (Typ));
Cref := Convert_Concurrent (Ref, Underlying_Type (Typ));
else
Is_Conc := False;
Utyp := Typ;
Cref := Ref;
end if;
Utyp := Underlying_Type (Base_Type (Utyp));
Set_Assignment_OK (Cref);
if Is_Untagged_Derivation (Typ)
and then not Is_Conc
then
Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
Cref := Unchecked_Convert_To (Utyp, Cref);
Set_Assignment_OK (Cref);
end if;
if Utyp /= Base_Type (Utyp) then
pragma Assert (Is_Private_Type (Typ));
Utyp := Base_Type (Utyp);
Cref := Unchecked_Convert_To (Utyp, Cref);
end if;
if Finalize_Storage_Only (Typ)
and then (Global_Flist_Ref (Flist_Ref)
or else Entity (Constant_Value (RTE (RE_Garbage_Collected)))
= Standard_True)
then
Attach := Make_Integer_Literal (Loc, 0);
end if;
if Has_Controlled_Component (Utyp) then
Proc := TSS (Utyp, Deep_Name_Of (Initialize_Case));
Cref := Convert_View (Proc, Cref, 2);
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations => New_List (
Node1 => Flist_Ref,
Node2 => Cref,
Node3 => Attach)));
else Proc := Find_Prim_Op (Utyp, Name_Of (Initialize_Case));
Check_Visibly_Controlled (Initialize_Case, Typ, Proc, Cref);
Cref := Convert_View (Proc, Cref);
Cref2 := New_Copy_Tree (Cref);
Append_To (Res,
Make_Procedure_Call_Statement (Loc,
Name => New_Reference_To (Proc, Loc),
Parameter_Associations => New_List (Cref2)));
Append_To (Res,
Make_Attach_Call (Cref, Flist_Ref, Attach));
end if;
return Res;
end Make_Init_Call;
function Make_Transient_Block
(Loc : Source_Ptr;
Action : Node_Id) return Node_Id
is
Flist : constant Entity_Id := Finalization_Chain_Entity (Current_Scope);
Decls : constant List_Id := New_List;
Par : constant Node_Id := Parent (Action);
Instrs : constant List_Id := New_List (Action);
Blk : Node_Id;
begin
if Uses_Sec_Stack (Current_Scope)
and then No (Flist)
and then Nkind (Action) /= N_Return_Statement
and then Nkind (Par) /= N_Exception_Handler
then
declare
S : Entity_Id;
K : Entity_Kind;
begin
S := Scope (Current_Scope);
loop
K := Ekind (S);
if S = Standard_Standard then
Set_Uses_Sec_Stack (Current_Scope, False);
exit;
elsif K = E_Function then
Set_Uses_Sec_Stack (Current_Scope, False);
if not Requires_Transient_Scope (Etype (S)) then
if not Functions_Return_By_DSP_On_Target then
Set_Uses_Sec_Stack (S, True);
Check_Restriction (No_Secondary_Stack, Action);
end if;
end if;
exit;
elsif K = E_Loop or else K = E_Entry then
exit;
elsif K = E_Procedure
or else K = E_Block
then
if not Functions_Return_By_DSP_On_Target then
Set_Uses_Sec_Stack (S, True);
Check_Restriction (No_Secondary_Stack, Action);
end if;
Set_Uses_Sec_Stack (Current_Scope, False);
exit;
else
S := Scope (S);
end if;
end loop;
end;
end if;
Insert_Actions_In_Scope_Around (Action);
declare
Last_Inserted : Node_Id := Prev (Action);
begin
if Present (Last_Inserted) then
Freeze_All (First_Entity (Current_Scope), Last_Inserted);
end if;
end;
Blk :=
Make_Block_Statement (Loc,
Identifier => New_Reference_To (Current_Scope, Loc),
Declarations => Decls,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc, Statements => Instrs),
Has_Created_Identifier => True);
Pop_Scope;
return Blk;
end Make_Transient_Block;
function Node_To_Be_Wrapped return Node_Id is
begin
return Scope_Stack.Table (Scope_Stack.Last).Node_To_Be_Wrapped;
end Node_To_Be_Wrapped;
procedure Set_Node_To_Be_Wrapped (N : Node_Id) is
begin
Scope_Stack.Table (Scope_Stack.Last).Node_To_Be_Wrapped := N;
end Set_Node_To_Be_Wrapped;
procedure Store_After_Actions_In_Scope (L : List_Id) is
SE : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
begin
if Present (SE.Actions_To_Be_Wrapped_After) then
Insert_List_Before_And_Analyze (
First (SE.Actions_To_Be_Wrapped_After), L);
else
SE.Actions_To_Be_Wrapped_After := L;
if Is_List_Member (SE.Node_To_Be_Wrapped) then
Set_Parent (L, Parent (SE.Node_To_Be_Wrapped));
else
Set_Parent (L, SE.Node_To_Be_Wrapped);
end if;
Analyze_List (L);
end if;
end Store_After_Actions_In_Scope;
procedure Store_Before_Actions_In_Scope (L : List_Id) is
SE : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
begin
if Present (SE.Actions_To_Be_Wrapped_Before) then
Insert_List_After_And_Analyze (
Last (SE.Actions_To_Be_Wrapped_Before), L);
else
SE.Actions_To_Be_Wrapped_Before := L;
if Is_List_Member (SE.Node_To_Be_Wrapped) then
Set_Parent (L, Parent (SE.Node_To_Be_Wrapped));
else
Set_Parent (L, SE.Node_To_Be_Wrapped);
end if;
Analyze_List (L);
end if;
end Store_Before_Actions_In_Scope;
procedure Wrap_Transient_Declaration (N : Node_Id) is
S : Entity_Id;
LC : Entity_Id := Empty;
Nodes : List_Id;
Loc : constant Source_Ptr := Sloc (N);
Enclosing_S : Entity_Id;
Uses_SS : Boolean;
Next_N : constant Node_Id := Next (N);
begin
S := Current_Scope;
Enclosing_S := Scope (S);
Insert_Actions_In_Scope_Around (N);
Uses_SS := Uses_Sec_Stack (S);
Pop_Scope;
if Present (Finalization_Chain_Entity (S)) then
LC := Make_Defining_Identifier (Loc, New_Internal_Name ('L'));
Nodes := New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => LC,
Object_Definition =>
New_Reference_To (RTE (RE_Simple_List_Controller), Loc)),
Make_Object_Renaming_Declaration (Loc,
Defining_Identifier => Finalization_Chain_Entity (S),
Subtype_Mark => New_Reference_To (RTE (RE_Finalizable_Ptr), Loc),
Name =>
Make_Selected_Component (Loc,
Prefix => New_Reference_To (LC, Loc),
Selector_Name => Make_Identifier (Loc, Name_F))));
Insert_List_Before_And_Analyze (First (List_Containing (N)), Nodes);
if Nkind (N) = N_Object_Renaming_Declaration
and then Controlled_Type (Etype (Defining_Identifier (N)))
then
null;
else
Nodes :=
Make_Final_Call (
Ref => New_Reference_To (LC, Loc),
Typ => Etype (LC),
With_Detach => New_Reference_To (Standard_False, Loc));
if Present (Next_N) then
Insert_List_Before_And_Analyze (Next_N, Nodes);
else
Append_List_To (List_Containing (N), Nodes);
end if;
end if;
end if;
Transfer_Entities (S, Enclosing_S);
if Uses_SS then
S := Enclosing_Dynamic_Scope (S);
if Ekind (S) = E_Function
and then Requires_Transient_Scope (Etype (S))
then
null;
else
Set_Uses_Sec_Stack (S);
Check_Restriction (No_Secondary_Stack, N);
end if;
end if;
end Wrap_Transient_Declaration;
procedure Wrap_Transient_Expression (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
E : constant Entity_Id :=
Make_Defining_Identifier (Loc, New_Internal_Name ('E'));
Etyp : constant Entity_Id := Etype (N);
begin
Insert_Actions (N, New_List (
Make_Object_Declaration (Loc,
Defining_Identifier => E,
Object_Definition => New_Reference_To (Etyp, Loc)),
Make_Transient_Block (Loc,
Action =>
Make_Assignment_Statement (Loc,
Name => New_Reference_To (E, Loc),
Expression => Relocate_Node (N)))));
Rewrite (N, New_Reference_To (E, Loc));
Analyze_And_Resolve (N, Etyp);
end Wrap_Transient_Expression;
procedure Wrap_Transient_Statement (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
New_Statement : constant Node_Id := Relocate_Node (N);
begin
Rewrite (N, Make_Transient_Block (Loc, New_Statement));
Analyze (N);
end Wrap_Transient_Statement;
end Exp_Ch7;