aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/gcc/ada/exp_ch7.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/gcc/ada/exp_ch7.adb')
-rw-r--r--gcc-4.8/gcc/ada/exp_ch7.adb7917
1 files changed, 0 insertions, 7917 deletions
diff --git a/gcc-4.8/gcc/ada/exp_ch7.adb b/gcc-4.8/gcc/ada/exp_ch7.adb
deleted file mode 100644
index 72892828b..000000000
--- a/gcc-4.8/gcc/ada/exp_ch7.adb
+++ /dev/null
@@ -1,7917 +0,0 @@
-------------------------------------------------------------------------------
--- --
--- GNAT COMPILER COMPONENTS --
--- --
--- E X P _ C H 7 --
--- --
--- B o d y --
--- --
--- Copyright (C) 1992-2012, Free Software Foundation, Inc. --
--- --
--- 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 3, 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 COPYING3. If not, go to --
--- http://www.gnu.org/licenses for a complete copy of the license. --
--- --
--- GNAT was originally developed by the GNAT team at New York University. --
--- Extensive contributions were provided by Ada Core Technologies Inc. --
--- --
-------------------------------------------------------------------------------
-
--- This package contains virtually all expansion mechanisms related to
--- - controlled types
--- - transient scopes
-
-with Atree; use Atree;
-with Debug; use Debug;
-with Einfo; use Einfo;
-with Elists; use Elists;
-with Errout; use Errout;
-with Exp_Ch6; use Exp_Ch6;
-with Exp_Ch9; use Exp_Ch9;
-with Exp_Ch11; use Exp_Ch11;
-with Exp_Dbug; use Exp_Dbug;
-with Exp_Dist; use Exp_Dist;
-with Exp_Disp; use Exp_Disp;
-with Exp_Tss; use Exp_Tss;
-with Exp_Util; use Exp_Util;
-with Freeze; use Freeze;
-with Lib; use Lib;
-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 Sinfo; use Sinfo;
-with Sem; use Sem;
-with Sem_Aux; use Sem_Aux;
-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_Util; use Sem_Util;
-with Snames; use Snames;
-with Stand; use Stand;
-with Targparm; use Targparm;
-with Tbuild; use Tbuild;
-with Ttypes; use Ttypes;
-with Uintp; use Uintp;
-
-package body Exp_Ch7 is
-
- --------------------------------
- -- Transient Scope Management --
- --------------------------------
-
- -- A transient scope is created when temporary objects are created by the
- -- compiler. These temporary objects are allocated on the secondary stack
- -- and the transient scope is responsible for finalizing the object when
- -- appropriate and reclaiming the memory at the right time. The temporary
- -- objects are generally the objects allocated to store the result of a
- -- function returning an unconstrained or a tagged value. Expressions
- -- needing to be wrapped in a transient scope (functions calls returning
- -- unconstrained or tagged values) may appear in 3 different contexts which
- -- lead to 3 different kinds of transient scope expansion:
-
- -- 1. In a simple statement (procedure call, assignment, ...). In this
- -- case the instruction is wrapped into a transient block. See
- -- Wrap_Transient_Statement for details.
-
- -- 2. In an expression of a control structure (test in a IF statement,
- -- expression in a CASE statement, ...). See Wrap_Transient_Expression
- -- for details.
-
- -- 3. In a expression of an object_declaration. No wrapping is possible
- -- here, so the finalization actions, if any, are done right after the
- -- declaration and the secondary stack deallocation is done in the
- -- proper enclosing scope. See Wrap_Transient_Declaration for details.
-
- -- Note about functions returning tagged types: it has been decided to
- -- always allocate their result in the secondary stack, even though is not
- -- absolutely mandatory when the tagged type is constrained because the
- -- caller knows the size of the returned object and thus could allocate the
- -- result in the primary stack. An exception to this is when the function
- -- builds its result in place, as is done for functions with inherently
- -- limited result types for Ada 2005. In that case, certain callers may
- -- pass the address of a constrained object as the target object for the
- -- function result.
-
- -- By allocating tagged results in the secondary stack a number of
- -- implementation difficulties are avoided:
-
- -- - If it is a dispatching function call, the computation of the size of
- -- the result is possible but complex from the outside.
-
- -- - If the returned type is controlled, the assignment of the returned
- -- value to the anonymous object involves an Adjust, and we have no
- -- easy way to access the anonymous object created by the back end.
-
- -- - If the returned type is class-wide, this is an unconstrained type
- -- anyway.
-
- -- Furthermore, the small loss in efficiency which is the result of this
- -- decision is not such a big deal because functions returning tagged types
- -- are not as common in practice compared to functions returning access to
- -- a tagged type.
-
- --------------------------------------------------
- -- Transient Blocks and Finalization Management --
- --------------------------------------------------
-
- function Find_Node_To_Be_Wrapped (N : Node_Id) return Node_Id;
- -- N is a node which may generate a transient scope. Loop over the parent
- -- pointers of N until it find the appropriate node to wrap. If it returns
- -- Empty, it means that no transient scope is needed in this context.
-
- procedure Insert_Actions_In_Scope_Around (N : Node_Id);
- -- Insert the before-actions kept in the scope stack before N, and the
- -- after-actions after N, which must be a member of a list.
-
- function Make_Transient_Block
- (Loc : Source_Ptr;
- Action : Node_Id;
- Par : Node_Id) return Node_Id;
- -- Action is a single statement or object declaration. Par is the proper
- -- parent of the generated block. Create a transient block whose name is
- -- the current scope and the only handled statement is Action. If Action
- -- involves controlled objects or secondary stack usage, the corresponding
- -- cleanup actions are performed at the end of the block.
-
- procedure Set_Node_To_Be_Wrapped (N : Node_Id);
- -- Set the field Node_To_Be_Wrapped of the current scope
-
- -- ??? The entire comment needs to be rewritten
- -- ??? which entire comment?
-
- -----------------------------
- -- Finalization Management --
- -----------------------------
-
- -- This part describe how Initialization/Adjustment/Finalization procedures
- -- are generated and called. Two cases must be considered, types that are
- -- Controlled (Is_Controlled flag set) and composite types that contain
- -- controlled components (Has_Controlled_Component flag set). In the first
- -- case the procedures to call are the user-defined primitive operations
- -- Initialize/Adjust/Finalize. In the second case, GNAT generates
- -- Deep_Initialize, Deep_Adjust and Deep_Finalize that are in charge
- -- of calling the former procedures on the controlled components.
-
- -- For records with Has_Controlled_Component set, a hidden "controller"
- -- component is inserted. This controller component contains its own
- -- finalization list on which all controlled components are attached
- -- creating an indirection on the upper-level Finalization list. This
- -- technique facilitates the management of objects whose number of
- -- controlled components changes during execution. This controller
- -- component is itself controlled and is attached to the upper-level
- -- finalization chain. Its adjust primitive is in charge of calling adjust
- -- on the components and adjusting the finalization pointer to match their
- -- new location (see a-finali.adb).
-
- -- It is not possible to use a similar technique for arrays that have
- -- Has_Controlled_Component set. In this case, deep procedures are
- -- generated that call initialize/adjust/finalize + attachment or
- -- detachment on the finalization list for all component.
-
- -- Initialize calls: they are generated for declarations or dynamic
- -- allocations of Controlled objects with no initial value. They are always
- -- followed by an attachment to the current Finalization Chain. For the
- -- dynamic allocation case this the chain attached to the scope of the
- -- access type definition otherwise, this is the chain of the current
- -- scope.
-
- -- Adjust Calls: They are generated on 2 occasions: (1) for declarations
- -- or dynamic allocations of Controlled objects with an initial value.
- -- (2) after an assignment. In the first case they are followed by an
- -- attachment to the final chain, in the second case they are not.
-
- -- Finalization Calls: They are generated on (1) scope exit, (2)
- -- assignments, (3) unchecked deallocations. In case (3) they have to
- -- be detached from the final chain, in case (2) they must not and in
- -- case (1) this is not important since we are exiting the scope anyway.
-
- -- Other details:
-
- -- Type extensions will have a new record controller at each derivation
- -- level containing controlled components. The record controller for
- -- the parent/ancestor is attached to the finalization list of the
- -- extension's record controller (i.e. the parent is like a component
- -- of the extension).
-
- -- For types that are both Is_Controlled and Has_Controlled_Components,
- -- the record controller and the object itself are handled separately.
- -- It could seem simpler to attach the object at the end of its record
- -- controller but this would not tackle view conversions properly.
-
- -- A classwide type can always potentially have controlled components
- -- but the record controller of the corresponding actual type may not
- -- be known at compile time so the dispatch table contains a special
- -- field that allows to compute the offset of the record controller
- -- dynamically. See s-finimp.Deep_Tag_Attach and a-tags.RC_Offset.
-
- -- Here is a simple example of the expansion of a controlled block :
-
- -- declare
- -- X : Controlled;
- -- Y : Controlled := Init;
- --
- -- type R is record
- -- C : Controlled;
- -- end record;
- -- W : R;
- -- Z : R := (C => X);
-
- -- begin
- -- X := Y;
- -- W := Z;
- -- end;
- --
- -- is expanded into
- --
- -- declare
- -- _L : System.FI.Finalizable_Ptr;
-
- -- procedure _Clean is
- -- begin
- -- Abort_Defer;
- -- System.FI.Finalize_List (_L);
- -- Abort_Undefer;
- -- end _Clean;
-
- -- X : Controlled;
- -- begin
- -- Abort_Defer;
- -- Initialize (X);
- -- Attach_To_Final_List (_L, Finalizable (X), 1);
- -- at end: Abort_Undefer;
- -- Y : Controlled := Init;
- -- Adjust (Y);
- -- Attach_To_Final_List (_L, Finalizable (Y), 1);
- --
- -- type R is record
- -- C : Controlled;
- -- end record;
- -- W : R;
- -- begin
- -- Abort_Defer;
- -- Deep_Initialize (W, _L, 1);
- -- at end: Abort_Under;
- -- Z : R := (C => X);
- -- Deep_Adjust (Z, _L, 1);
-
- -- begin
- -- _Assign (X, Y);
- -- Deep_Finalize (W, False);
- -- <save W's final pointers>
- -- W := Z;
- -- <restore W's final pointers>
- -- Deep_Adjust (W, _L, 0);
- -- at end
- -- _Clean;
- -- end;
-
- type Final_Primitives is
- (Initialize_Case, Adjust_Case, Finalize_Case, Address_Case);
- -- This enumeration type is defined in order to ease sharing code for
- -- building finalization procedures for composite types.
-
- Name_Of : constant array (Final_Primitives) of Name_Id :=
- (Initialize_Case => Name_Initialize,
- Adjust_Case => Name_Adjust,
- Finalize_Case => Name_Finalize,
- Address_Case => Name_Finalize_Address);
- 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,
- Address_Case => TSS_Finalize_Address);
-
- procedure Build_Array_Deep_Procs (Typ : Entity_Id);
- -- Build the deep Initialize/Adjust/Finalize for a record Typ with
- -- Has_Controlled_Component set and store them using the TSS mechanism.
-
- function Build_Cleanup_Statements (N : Node_Id) return List_Id;
- -- Create the clean up calls for an asynchronous call block, task master,
- -- protected subprogram body, task allocation block or task body. If the
- -- context does not contain the above constructs, the routine returns an
- -- empty list.
-
- procedure Build_Finalizer
- (N : Node_Id;
- Clean_Stmts : List_Id;
- Mark_Id : Entity_Id;
- Top_Decls : List_Id;
- Defer_Abort : Boolean;
- Fin_Id : out Entity_Id);
- -- N may denote an accept statement, block, entry body, package body,
- -- package spec, protected body, subprogram body, and a task body. Create
- -- a procedure which contains finalization calls for all controlled objects
- -- declared in the declarative or statement region of N. The calls are
- -- built in reverse order relative to the original declarations. In the
- -- case of a tack body, the routine delays the creation of the finalizer
- -- until all statements have been moved to the task body procedure.
- -- Clean_Stmts may contain additional context-dependent code used to abort
- -- asynchronous calls or complete tasks (see Build_Cleanup_Statements).
- -- Mark_Id is the secondary stack used in the current context or Empty if
- -- missing. Top_Decls is the list on which the declaration of the finalizer
- -- is attached in the non-package case. Defer_Abort indicates that the
- -- statements passed in perform actions that require abort to be deferred,
- -- such as for task termination. Fin_Id is the finalizer declaration
- -- entity.
-
- procedure Build_Finalizer_Call (N : Node_Id; Fin_Id : Entity_Id);
- -- N is a construct which contains a handled sequence of statements, Fin_Id
- -- is the entity of a finalizer. Create an At_End handler which covers the
- -- statements of N and calls Fin_Id. If the handled statement sequence has
- -- an exception handler, the statements will be wrapped in a block to avoid
- -- unwanted interaction with the new At_End handler.
-
- procedure Build_Record_Deep_Procs (Typ : Entity_Id);
- -- Build the deep Initialize/Adjust/Finalize for a record Typ with
- -- Has_Component_Component set and store them using the TSS mechanism.
-
- procedure Check_Visibly_Controlled
- (Prim : Final_Primitives;
- Typ : Entity_Id;
- E : in out Entity_Id;
- Cref : in out Node_Id);
- -- The controlled operation declared for a derived type may not be
- -- overriding, if the controlled operations of the parent type are hidden,
- -- for example when the parent is a private type whose full view is
- -- controlled. For other primitive operations we modify the name of the
- -- operation to indicate that it is not overriding, but this is not
- -- possible for Initialize, etc. because they have to be retrievable by
- -- name. Before generating the proper call to one of these operations we
- -- check whether Typ is known to be controlled at the point of definition.
- -- If it is not then we must retrieve the hidden operation of the parent
- -- and use it instead. This is one case that might be solved more cleanly
- -- once Overriding pragmas or declarations are in place.
-
- function Convert_View
- (Proc : Entity_Id;
- Arg : Node_Id;
- Ind : Pos := 1) return Node_Id;
- -- Proc is one of the Initialize/Adjust/Finalize operations, and Arg is the
- -- argument being passed to it. Ind indicates which formal of procedure
- -- Proc we are trying to match. This function will, if necessary, generate
- -- a conversion between the partial and full view of Arg to match the type
- -- of the formal of Proc, or force a conversion to the class-wide type in
- -- the case where the operation is abstract.
-
- function Enclosing_Function (E : Entity_Id) return Entity_Id;
- -- Given an arbitrary entity, traverse the scope chain looking for the
- -- first enclosing function. Return Empty if no function was found.
-
- function Make_Call
- (Loc : Source_Ptr;
- Proc_Id : Entity_Id;
- Param : Node_Id;
- For_Parent : Boolean := False) return Node_Id;
- -- Subsidiary to Make_Adjust_Call and Make_Final_Call. Given the entity of
- -- routine [Deep_]Adjust / Finalize and an object parameter, create an
- -- adjust / finalization call. Flag For_Parent should be set when field
- -- _parent is being processed.
-
- function Make_Deep_Proc
- (Prim : Final_Primitives;
- Typ : Entity_Id;
- Stmts : List_Id) return Node_Id;
- -- This function generates the tree for Deep_Initialize, Deep_Adjust or
- -- Deep_Finalize procedures according to the first parameter, these
- -- procedures operate on the type Typ. The Stmts parameter gives the body
- -- of the procedure.
-
- function Make_Deep_Array_Body
- (Prim : Final_Primitives;
- Typ : Entity_Id) return List_Id;
- -- This function generates the list of statements for implementing
- -- Deep_Initialize, Deep_Adjust or Deep_Finalize procedures according to
- -- the first parameter, these procedures operate on the array type Typ.
-
- function Make_Deep_Record_Body
- (Prim : Final_Primitives;
- Typ : Entity_Id;
- Is_Local : Boolean := False) return List_Id;
- -- This function generates the list of statements for implementing
- -- Deep_Initialize, Deep_Adjust or Deep_Finalize procedures according to
- -- the first parameter, these procedures operate on the record type Typ.
- -- Flag Is_Local is used in conjunction with Deep_Finalize to designate
- -- whether the inner logic should be dictated by state counters.
-
- function Make_Finalize_Address_Stmts (Typ : Entity_Id) return List_Id;
- -- Subsidiary to Make_Finalize_Address_Body, Make_Deep_Array_Body and
- -- Make_Deep_Record_Body. Generate the following statements:
- --
- -- declare
- -- type Acc_Typ is access all Typ;
- -- for Acc_Typ'Storage_Size use 0;
- -- begin
- -- [Deep_]Finalize (Acc_Typ (V).all);
- -- end;
-
- ----------------------------
- -- Build_Array_Deep_Procs --
- ----------------------------
-
- 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_Immutably_Limited_Type (Typ) then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Adjust_Case,
- Typ => Typ,
- Stmts => Make_Deep_Array_Body (Adjust_Case, Typ)));
- end if;
-
- -- Do not generate Deep_Finalize and Finalize_Address if finalization is
- -- suppressed since these routine will not be used.
-
- if not Restriction_Active (No_Finalization) then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Finalize_Case,
- Typ => Typ,
- Stmts => Make_Deep_Array_Body (Finalize_Case, Typ)));
-
- -- Create TSS primitive Finalize_Address for non-VM targets. JVM and
- -- .NET do not support address arithmetic and unchecked conversions.
-
- if VM_Target = No_VM then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Address_Case,
- Typ => Typ,
- Stmts => Make_Deep_Array_Body (Address_Case, Typ)));
- end if;
- end if;
- end Build_Array_Deep_Procs;
-
- ------------------------------
- -- Build_Cleanup_Statements --
- ------------------------------
-
- function Build_Cleanup_Statements (N : Node_Id) return List_Id is
- Is_Asynchronous_Call : constant Boolean :=
- Nkind (N) = N_Block_Statement
- and then Is_Asynchronous_Call_Block (N);
- Is_Master : constant Boolean :=
- Nkind (N) /= N_Entry_Body
- and then Is_Task_Master (N);
- Is_Protected_Body : 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_Task_Body : constant Boolean :=
- Nkind (Original_Node (N)) = N_Task_Body;
-
- Loc : constant Source_Ptr := Sloc (N);
- Stmts : constant List_Id := New_List;
-
- begin
- if Is_Task_Body then
- if Restricted_Profile then
- Append_To (Stmts,
- Build_Runtime_Call (Loc, RE_Complete_Restricted_Task));
- else
- Append_To (Stmts, Build_Runtime_Call (Loc, RE_Complete_Task));
- end if;
-
- elsif Is_Master then
- if Restriction_Active (No_Task_Hierarchy) = False then
- Append_To (Stmts, Build_Runtime_Call (Loc, RE_Complete_Master));
- end if;
-
- -- Add statements to unlock the protected object parameter and to
- -- undefer abort. If the context is a protected procedure and the object
- -- has entries, call the entry service routine.
-
- -- NOTE: The generated code references _object, a parameter to the
- -- procedure.
-
- elsif Is_Protected_Body then
- declare
- Spec : constant Node_Id := Parent (Corresponding_Spec (N));
- Conc_Typ : Entity_Id;
- Nam : Node_Id;
- Param : Node_Id;
- Param_Typ : Entity_Id;
-
- begin
- -- Find the _object parameter representing the protected object
-
- Param := First (Parameter_Specifications (Spec));
- loop
- Param_Typ := Etype (Parameter_Type (Param));
-
- if Ekind (Param_Typ) = E_Record_Type then
- Conc_Typ := Corresponding_Concurrent_Type (Param_Typ);
- end if;
-
- exit when No (Param) or else Present (Conc_Typ);
- Next (Param);
- end loop;
-
- pragma Assert (Present (Param));
-
- -- If the associated protected object has entries, a protected
- -- procedure has to service entry queues. In this case generate:
-
- -- Service_Entries (_object._object'Access);
-
- if Nkind (Specification (N)) = N_Procedure_Specification
- and then Has_Entries (Conc_Typ)
- then
- case Corresponding_Runtime_Package (Conc_Typ) is
- when System_Tasking_Protected_Objects_Entries =>
- Nam := New_Reference_To (RTE (RE_Service_Entries), Loc);
-
- when System_Tasking_Protected_Objects_Single_Entry =>
- Nam := New_Reference_To (RTE (RE_Service_Entry), Loc);
-
- when others =>
- raise Program_Error;
- end case;
-
- Append_To (Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name => Nam,
- 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
- -- Generate:
- -- Unlock (_object._object'Access);
-
- case Corresponding_Runtime_Package (Conc_Typ) is
- when System_Tasking_Protected_Objects_Entries =>
- Nam := New_Reference_To (RTE (RE_Unlock_Entries), Loc);
-
- when System_Tasking_Protected_Objects_Single_Entry =>
- Nam := New_Reference_To (RTE (RE_Unlock_Entry), Loc);
-
- when System_Tasking_Protected_Objects =>
- Nam := New_Reference_To (RTE (RE_Unlock), Loc);
-
- when others =>
- raise Program_Error;
- end case;
-
- Append_To (Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name => Nam,
- 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;
-
- -- Generate:
- -- Abort_Undefer;
-
- if Abort_Allowed then
- Append_To (Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Abort_Undefer), Loc),
- Parameter_Associations => Empty_List));
- end if;
- end;
-
- -- Add a call to Expunge_Unactivated_Tasks for dynamically allocated
- -- tasks. Other unactivated tasks are completed by Complete_Task or
- -- Complete_Master.
-
- -- NOTE: The generated code references _chain, a local object
-
- elsif Is_Task_Allocation then
-
- -- Generate:
- -- Expunge_Unactivated_Tasks (_chain);
-
- -- where _chain is the list of tasks created by the allocator but not
- -- yet activated. This list will be empty unless the block completes
- -- abnormally.
-
- Append_To (Stmts,
- 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))));
-
- -- Attempt to cancel an asynchronous entry call whenever the block which
- -- contains the abortable part is exited.
-
- -- NOTE: The generated code references Cnn, a local object
-
- elsif Is_Asynchronous_Call then
- declare
- Cancel_Param : constant Entity_Id :=
- Entry_Cancel_Parameter (Entity (Identifier (N)));
-
- begin
- -- If it is of type Communication_Block, this must be a protected
- -- entry call. Generate:
-
- -- if Enqueued (Cancel_Param) then
- -- Cancel_Protected_Entry_Call (Cancel_Param);
- -- end if;
-
- if Is_RTE (Etype (Cancel_Param), RE_Communication_Block) then
- Append_To (Stmts,
- Make_If_Statement (Loc,
- 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))))));
-
- -- Asynchronous delay, generate:
- -- Cancel_Async_Delay (Cancel_Param);
-
- elsif Is_RTE (Etype (Cancel_Param), RE_Delay_Block) then
- Append_To (Stmts,
- 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))));
-
- -- Task entry call, generate:
- -- Cancel_Task_Entry_Call (Cancel_Param);
-
- else
- Append_To (Stmts,
- 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;
- end if;
-
- return Stmts;
- end Build_Cleanup_Statements;
-
- -----------------------------
- -- Build_Controlling_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;
-
- -----------------------------
- -- Build_Exception_Handler --
- -----------------------------
-
- function Build_Exception_Handler
- (Data : Finalization_Exception_Data;
- For_Library : Boolean := False) return Node_Id
- is
- Actuals : List_Id;
- Proc_To_Call : Entity_Id;
- Except : Node_Id;
- Stmts : List_Id;
-
- begin
- pragma Assert (Present (Data.Raised_Id));
-
- if Exception_Extra_Info
- or else (For_Library and not Restricted_Profile)
- then
- if Exception_Extra_Info then
-
- -- Generate:
-
- -- Get_Current_Excep.all
-
- Except :=
- Make_Function_Call (Data.Loc,
- Name =>
- Make_Explicit_Dereference (Data.Loc,
- Prefix =>
- New_Reference_To
- (RTE (RE_Get_Current_Excep), Data.Loc)));
-
- else
- -- Generate:
-
- -- null
-
- Except := Make_Null (Data.Loc);
- end if;
-
- if For_Library and then not Restricted_Profile then
- Proc_To_Call := RTE (RE_Save_Library_Occurrence);
- Actuals := New_List (Except);
-
- else
- Proc_To_Call := RTE (RE_Save_Occurrence);
-
- -- The dereference occurs only when Exception_Extra_Info is true,
- -- and therefore Except is not null.
-
- Actuals :=
- New_List (
- New_Reference_To (Data.E_Id, Data.Loc),
- Make_Explicit_Dereference (Data.Loc, Except));
- end if;
-
- -- Generate:
-
- -- when others =>
- -- if not Raised_Id then
- -- Raised_Id := True;
-
- -- Save_Occurrence (E_Id, Get_Current_Excep.all.all);
- -- or
- -- Save_Library_Occurrence (Get_Current_Excep.all);
- -- end if;
-
- Stmts :=
- New_List (
- Make_If_Statement (Data.Loc,
- Condition =>
- Make_Op_Not (Data.Loc,
- Right_Opnd => New_Reference_To (Data.Raised_Id, Data.Loc)),
-
- Then_Statements => New_List (
- Make_Assignment_Statement (Data.Loc,
- Name => New_Reference_To (Data.Raised_Id, Data.Loc),
- Expression => New_Reference_To (Standard_True, Data.Loc)),
-
- Make_Procedure_Call_Statement (Data.Loc,
- Name =>
- New_Reference_To (Proc_To_Call, Data.Loc),
- Parameter_Associations => Actuals))));
-
- else
- -- Generate:
-
- -- Raised_Id := True;
-
- Stmts := New_List (
- Make_Assignment_Statement (Data.Loc,
- Name => New_Reference_To (Data.Raised_Id, Data.Loc),
- Expression => New_Reference_To (Standard_True, Data.Loc)));
- end if;
-
- -- Generate:
-
- -- when others =>
-
- return
- Make_Exception_Handler (Data.Loc,
- Exception_Choices => New_List (Make_Others_Choice (Data.Loc)),
- Statements => Stmts);
- end Build_Exception_Handler;
-
- -------------------------------
- -- Build_Finalization_Master --
- -------------------------------
-
- procedure Build_Finalization_Master
- (Typ : Entity_Id;
- Ins_Node : Node_Id := Empty;
- Encl_Scope : Entity_Id := Empty)
- is
- Desig_Typ : constant Entity_Id := Directly_Designated_Type (Typ);
- Ptr_Typ : Entity_Id := Root_Type (Base_Type (Typ));
-
- function In_Deallocation_Instance (E : Entity_Id) return Boolean;
- -- Determine whether entity E is inside a wrapper package created for
- -- an instance of Ada.Unchecked_Deallocation.
-
- ------------------------------
- -- In_Deallocation_Instance --
- ------------------------------
-
- function In_Deallocation_Instance (E : Entity_Id) return Boolean is
- Pkg : constant Entity_Id := Scope (E);
- Par : Node_Id := Empty;
-
- begin
- if Ekind (Pkg) = E_Package
- and then Present (Related_Instance (Pkg))
- and then Ekind (Related_Instance (Pkg)) = E_Procedure
- then
- Par := Generic_Parent (Parent (Related_Instance (Pkg)));
-
- return
- Present (Par)
- and then Chars (Par) = Name_Unchecked_Deallocation
- and then Chars (Scope (Par)) = Name_Ada
- and then Scope (Scope (Par)) = Standard_Standard;
- end if;
-
- return False;
- end In_Deallocation_Instance;
-
- -- Start of processing for Build_Finalization_Master
-
- begin
- if Is_Private_Type (Ptr_Typ)
- and then Present (Full_View (Ptr_Typ))
- then
- Ptr_Typ := Full_View (Ptr_Typ);
- end if;
-
- -- Certain run-time configurations and targets do not provide support
- -- for controlled types.
-
- if Restriction_Active (No_Finalization) then
- return;
-
- -- Do not process C, C++, CIL and Java types since it is assumend that
- -- the non-Ada side will handle their clean up.
-
- elsif Convention (Desig_Typ) = Convention_C
- or else Convention (Desig_Typ) = Convention_CIL
- or else Convention (Desig_Typ) = Convention_CPP
- or else Convention (Desig_Typ) = Convention_Java
- then
- return;
-
- -- Various machinery such as freezing may have already created a
- -- finalization master.
-
- elsif Present (Finalization_Master (Ptr_Typ)) then
- return;
-
- -- Do not process types that return on the secondary stack
-
- elsif Present (Associated_Storage_Pool (Ptr_Typ))
- and then Is_RTE (Associated_Storage_Pool (Ptr_Typ), RE_SS_Pool)
- then
- return;
-
- -- Do not process types which may never allocate an object
-
- elsif No_Pool_Assigned (Ptr_Typ) then
- return;
-
- -- Do not process access types coming from Ada.Unchecked_Deallocation
- -- instances. Even though the designated type may be controlled, the
- -- access type will never participate in allocation.
-
- elsif In_Deallocation_Instance (Ptr_Typ) then
- return;
-
- -- Ignore the general use of anonymous access types unless the context
- -- requires a finalization master.
-
- elsif Ekind (Ptr_Typ) = E_Anonymous_Access_Type
- and then No (Ins_Node)
- then
- return;
-
- -- Do not process non-library access types when restriction No_Nested_
- -- Finalization is in effect since masters are controlled objects.
-
- elsif Restriction_Active (No_Nested_Finalization)
- and then not Is_Library_Level_Entity (Ptr_Typ)
- then
- return;
-
- -- For .NET/JVM targets, allow the processing of access-to-controlled
- -- types where the designated type is explicitly derived from [Limited_]
- -- Controlled.
-
- elsif VM_Target /= No_VM
- and then not Is_Controlled (Desig_Typ)
- then
- return;
-
- -- Do not create finalization masters in Alfa mode because they result
- -- in unwanted expansion.
-
- elsif Alfa_Mode then
- return;
- end if;
-
- declare
- Loc : constant Source_Ptr := Sloc (Ptr_Typ);
- Actions : constant List_Id := New_List;
- Fin_Mas_Id : Entity_Id;
- Pool_Id : Entity_Id;
-
- begin
- -- Generate:
- -- Fnn : aliased Finalization_Master;
-
- -- Source access types use fixed master names since the master is
- -- inserted in the same source unit only once. The only exception to
- -- this are instances using the same access type as generic actual.
-
- if Comes_From_Source (Ptr_Typ)
- and then not Inside_A_Generic
- then
- Fin_Mas_Id :=
- Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Chars (Ptr_Typ), "FM"));
-
- -- Internally generated access types use temporaries as their names
- -- due to possible collision with identical names coming from other
- -- packages.
-
- else
- Fin_Mas_Id := Make_Temporary (Loc, 'F');
- end if;
-
- Append_To (Actions,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Fin_Mas_Id,
- Aliased_Present => True,
- Object_Definition =>
- New_Reference_To (RTE (RE_Finalization_Master), Loc)));
-
- -- Storage pool selection and attribute decoration of the generated
- -- master. Since .NET/JVM compilers do not support pools, this step
- -- is skipped.
-
- if VM_Target = No_VM then
-
- -- If the access type has a user-defined pool, use it as the base
- -- storage medium for the finalization pool.
-
- if Present (Associated_Storage_Pool (Ptr_Typ)) then
- Pool_Id := Associated_Storage_Pool (Ptr_Typ);
-
- -- The default choice is the global pool
-
- else
- Pool_Id := Get_Global_Pool_For_Access_Type (Ptr_Typ);
- Set_Associated_Storage_Pool (Ptr_Typ, Pool_Id);
- end if;
-
- -- Generate:
- -- Set_Base_Pool (Fnn, Pool_Id'Unchecked_Access);
-
- Append_To (Actions,
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Set_Base_Pool), Loc),
- Parameter_Associations => New_List (
- New_Reference_To (Fin_Mas_Id, Loc),
- Make_Attribute_Reference (Loc,
- Prefix => New_Reference_To (Pool_Id, Loc),
- Attribute_Name => Name_Unrestricted_Access))));
- end if;
-
- Set_Finalization_Master (Ptr_Typ, Fin_Mas_Id);
-
- -- A finalization master created for an anonymous access type must be
- -- inserted before a context-dependent node.
-
- if Present (Ins_Node) then
- Push_Scope (Encl_Scope);
-
- -- Treat use clauses as declarations and insert directly in front
- -- of them.
-
- if Nkind_In (Ins_Node, N_Use_Package_Clause,
- N_Use_Type_Clause)
- then
- Insert_List_Before_And_Analyze (Ins_Node, Actions);
- else
- Insert_Actions (Ins_Node, Actions);
- end if;
-
- Pop_Scope;
-
- elsif Ekind (Desig_Typ) = E_Incomplete_Type
- and then Has_Completion_In_Body (Desig_Typ)
- then
- Insert_Actions (Parent (Ptr_Typ), Actions);
-
- -- If the designated type is not yet frozen, then append the actions
- -- to that type's freeze actions. The actions need to be appended to
- -- whichever type is frozen later, similarly to what Freeze_Type does
- -- for appending the storage pool declaration for an access type.
- -- Otherwise, the call to Set_Storage_Pool_Ptr might reference the
- -- pool object before it's declared. However, it's not clear that
- -- this is exactly the right test to accomplish that here. ???
-
- elsif Present (Freeze_Node (Desig_Typ))
- and then not Analyzed (Freeze_Node (Desig_Typ))
- then
- Append_Freeze_Actions (Desig_Typ, Actions);
-
- elsif Present (Freeze_Node (Ptr_Typ))
- and then not Analyzed (Freeze_Node (Ptr_Typ))
- then
- Append_Freeze_Actions (Ptr_Typ, Actions);
-
- -- If there's a pool created locally for the access type, then we
- -- need to ensure that the master gets created after the pool object,
- -- because otherwise we can have a forward reference, so we force the
- -- master actions to be inserted and analyzed after the pool entity.
- -- Note that both the access type and its designated type may have
- -- already been frozen and had their freezing actions analyzed at
- -- this point. (This seems a little unclean.???)
-
- elsif VM_Target = No_VM
- and then Scope (Pool_Id) = Scope (Ptr_Typ)
- then
- Insert_List_After_And_Analyze (Parent (Pool_Id), Actions);
-
- else
- Insert_Actions (Parent (Ptr_Typ), Actions);
- end if;
- end;
- end Build_Finalization_Master;
-
- ---------------------
- -- Build_Finalizer --
- ---------------------
-
- procedure Build_Finalizer
- (N : Node_Id;
- Clean_Stmts : List_Id;
- Mark_Id : Entity_Id;
- Top_Decls : List_Id;
- Defer_Abort : Boolean;
- Fin_Id : out Entity_Id)
- is
- Acts_As_Clean : constant Boolean :=
- Present (Mark_Id)
- or else
- (Present (Clean_Stmts)
- and then Is_Non_Empty_List (Clean_Stmts));
- Exceptions_OK : constant Boolean :=
- not Restriction_Active (No_Exception_Propagation);
- For_Package_Body : constant Boolean := Nkind (N) = N_Package_Body;
- For_Package_Spec : constant Boolean := Nkind (N) = N_Package_Declaration;
- For_Package : constant Boolean :=
- For_Package_Body or else For_Package_Spec;
- Loc : constant Source_Ptr := Sloc (N);
-
- -- NOTE: Local variable declarations are conservative and do not create
- -- structures right from the start. Entities and lists are created once
- -- it has been established that N has at least one controlled object.
-
- Components_Built : Boolean := False;
- -- A flag used to avoid double initialization of entities and lists. If
- -- the flag is set then the following variables have been initialized:
- -- Counter_Id
- -- Finalizer_Decls
- -- Finalizer_Stmts
- -- Jump_Alts
-
- Counter_Id : Entity_Id := Empty;
- Counter_Val : Int := 0;
- -- Name and value of the state counter
-
- Decls : List_Id := No_List;
- -- Declarative region of N (if available). If N is a package declaration
- -- Decls denotes the visible declarations.
-
- Finalizer_Data : Finalization_Exception_Data;
- -- Data for the exception
-
- Finalizer_Decls : List_Id := No_List;
- -- Local variable declarations. This list holds the label declarations
- -- of all jump block alternatives as well as the declaration of the
- -- local exception occurence and the raised flag:
- -- E : Exception_Occurrence;
- -- Raised : Boolean := False;
- -- L<counter value> : label;
-
- Finalizer_Insert_Nod : Node_Id := Empty;
- -- Insertion point for the finalizer body. Depending on the context
- -- (Nkind of N) and the individual grouping of controlled objects, this
- -- node may denote a package declaration or body, package instantiation,
- -- block statement or a counter update statement.
-
- Finalizer_Stmts : List_Id := No_List;
- -- The statement list of the finalizer body. It contains the following:
- --
- -- Abort_Defer; -- Added if abort is allowed
- -- <call to Prev_At_End> -- Added if exists
- -- <cleanup statements> -- Added if Acts_As_Clean
- -- <jump block> -- Added if Has_Ctrl_Objs
- -- <finalization statements> -- Added if Has_Ctrl_Objs
- -- <stack release> -- Added if Mark_Id exists
- -- Abort_Undefer; -- Added if abort is allowed
-
- Has_Ctrl_Objs : Boolean := False;
- -- A general flag which denotes whether N has at least one controlled
- -- object.
-
- Has_Tagged_Types : Boolean := False;
- -- A general flag which indicates whether N has at least one library-
- -- level tagged type declaration.
-
- HSS : Node_Id := Empty;
- -- The sequence of statements of N (if available)
-
- Jump_Alts : List_Id := No_List;
- -- Jump block alternatives. Depending on the value of the state counter,
- -- the control flow jumps to a sequence of finalization statements. This
- -- list contains the following:
- --
- -- when <counter value> =>
- -- goto L<counter value>;
-
- Jump_Block_Insert_Nod : Node_Id := Empty;
- -- Specific point in the finalizer statements where the jump block is
- -- inserted.
-
- Last_Top_Level_Ctrl_Construct : Node_Id := Empty;
- -- The last controlled construct encountered when processing the top
- -- level lists of N. This can be a nested package, an instantiation or
- -- an object declaration.
-
- Prev_At_End : Entity_Id := Empty;
- -- The previous at end procedure of the handled statements block of N
-
- Priv_Decls : List_Id := No_List;
- -- The private declarations of N if N is a package declaration
-
- Spec_Id : Entity_Id := Empty;
- Spec_Decls : List_Id := Top_Decls;
- Stmts : List_Id := No_List;
-
- Tagged_Type_Stmts : List_Id := No_List;
- -- Contains calls to Ada.Tags.Unregister_Tag for all library-level
- -- tagged types found in N.
-
- -----------------------
- -- Local subprograms --
- -----------------------
-
- procedure Build_Components;
- -- Create all entites and initialize all lists used in the creation of
- -- the finalizer.
-
- procedure Create_Finalizer;
- -- Create the spec and body of the finalizer and insert them in the
- -- proper place in the tree depending on the context.
-
- procedure Process_Declarations
- (Decls : List_Id;
- Preprocess : Boolean := False;
- Top_Level : Boolean := False);
- -- Inspect a list of declarations or statements which may contain
- -- objects that need finalization. When flag Preprocess is set, the
- -- routine will simply count the total number of controlled objects in
- -- Decls. Flag Top_Level denotes whether the processing is done for
- -- objects in nested package declarations or instances.
-
- procedure Process_Object_Declaration
- (Decl : Node_Id;
- Has_No_Init : Boolean := False;
- Is_Protected : Boolean := False);
- -- Generate all the machinery associated with the finalization of a
- -- single object. Flag Has_No_Init is used to denote certain contexts
- -- where Decl does not have initialization call(s). Flag Is_Protected
- -- is set when Decl denotes a simple protected object.
-
- procedure Process_Tagged_Type_Declaration (Decl : Node_Id);
- -- Generate all the code necessary to unregister the external tag of a
- -- tagged type.
-
- ----------------------
- -- Build_Components --
- ----------------------
-
- procedure Build_Components is
- Counter_Decl : Node_Id;
- Counter_Typ : Entity_Id;
- Counter_Typ_Decl : Node_Id;
-
- begin
- pragma Assert (Present (Decls));
-
- -- This routine might be invoked several times when dealing with
- -- constructs that have two lists (either two declarative regions
- -- or declarations and statements). Avoid double initialization.
-
- if Components_Built then
- return;
- end if;
-
- Components_Built := True;
-
- if Has_Ctrl_Objs then
-
- -- Create entities for the counter, its type, the local exception
- -- and the raised flag.
-
- Counter_Id := Make_Temporary (Loc, 'C');
- Counter_Typ := Make_Temporary (Loc, 'T');
-
- Finalizer_Decls := New_List;
-
- Build_Object_Declarations
- (Finalizer_Data, Finalizer_Decls, Loc, For_Package);
-
- -- Since the total number of controlled objects is always known,
- -- build a subtype of Natural with precise bounds. This allows
- -- the backend to optimize the case statement. Generate:
- --
- -- subtype Tnn is Natural range 0 .. Counter_Val;
-
- Counter_Typ_Decl :=
- Make_Subtype_Declaration (Loc,
- Defining_Identifier => Counter_Typ,
- Subtype_Indication =>
- Make_Subtype_Indication (Loc,
- Subtype_Mark => New_Reference_To (Standard_Natural, Loc),
- Constraint =>
- Make_Range_Constraint (Loc,
- Range_Expression =>
- Make_Range (Loc,
- Low_Bound =>
- Make_Integer_Literal (Loc, Uint_0),
- High_Bound =>
- Make_Integer_Literal (Loc, Counter_Val)))));
-
- -- Generate the declaration of the counter itself:
- --
- -- Counter : Integer := 0;
-
- Counter_Decl :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Counter_Id,
- Object_Definition => New_Reference_To (Counter_Typ, Loc),
- Expression => Make_Integer_Literal (Loc, 0));
-
- -- Set the type of the counter explicitly to prevent errors when
- -- examining object declarations later on.
-
- Set_Etype (Counter_Id, Counter_Typ);
-
- -- The counter and its type are inserted before the source
- -- declarations of N.
-
- Prepend_To (Decls, Counter_Decl);
- Prepend_To (Decls, Counter_Typ_Decl);
-
- -- The counter and its associated type must be manually analized
- -- since N has already been analyzed. Use the scope of the spec
- -- when inserting in a package.
-
- if For_Package then
- Push_Scope (Spec_Id);
- Analyze (Counter_Typ_Decl);
- Analyze (Counter_Decl);
- Pop_Scope;
-
- else
- Analyze (Counter_Typ_Decl);
- Analyze (Counter_Decl);
- end if;
-
- Jump_Alts := New_List;
- end if;
-
- -- If the context requires additional clean up, the finalization
- -- machinery is added after the clean up code.
-
- if Acts_As_Clean then
- Finalizer_Stmts := Clean_Stmts;
- Jump_Block_Insert_Nod := Last (Finalizer_Stmts);
- else
- Finalizer_Stmts := New_List;
- end if;
-
- if Has_Tagged_Types then
- Tagged_Type_Stmts := New_List;
- end if;
- end Build_Components;
-
- ----------------------
- -- Create_Finalizer --
- ----------------------
-
- procedure Create_Finalizer is
- Body_Id : Entity_Id;
- Fin_Body : Node_Id;
- Fin_Spec : Node_Id;
- Jump_Block : Node_Id;
- Label : Node_Id;
- Label_Id : Entity_Id;
-
- function New_Finalizer_Name return Name_Id;
- -- Create a fully qualified name of a package spec or body finalizer.
- -- The generated name is of the form: xx__yy__finalize_[spec|body].
-
- ------------------------
- -- New_Finalizer_Name --
- ------------------------
-
- function New_Finalizer_Name return Name_Id is
- procedure New_Finalizer_Name (Id : Entity_Id);
- -- Place "__<name-of-Id>" in the name buffer. If the identifier
- -- has a non-standard scope, process the scope first.
-
- ------------------------
- -- New_Finalizer_Name --
- ------------------------
-
- procedure New_Finalizer_Name (Id : Entity_Id) is
- begin
- if Scope (Id) = Standard_Standard then
- Get_Name_String (Chars (Id));
-
- else
- New_Finalizer_Name (Scope (Id));
- Add_Str_To_Name_Buffer ("__");
- Add_Str_To_Name_Buffer (Get_Name_String (Chars (Id)));
- end if;
- end New_Finalizer_Name;
-
- -- Start of processing for New_Finalizer_Name
-
- begin
- -- Create the fully qualified name of the enclosing scope
-
- New_Finalizer_Name (Spec_Id);
-
- -- Generate:
- -- __finalize_[spec|body]
-
- Add_Str_To_Name_Buffer ("__finalize_");
-
- if For_Package_Spec then
- Add_Str_To_Name_Buffer ("spec");
- else
- Add_Str_To_Name_Buffer ("body");
- end if;
-
- return Name_Find;
- end New_Finalizer_Name;
-
- -- Start of processing for Create_Finalizer
-
- begin
- -- Step 1: Creation of the finalizer name
-
- -- Packages must use a distinct name for their finalizers since the
- -- binder will have to generate calls to them by name. The name is
- -- of the following form:
-
- -- xx__yy__finalize_[spec|body]
-
- if For_Package then
- Fin_Id := Make_Defining_Identifier (Loc, New_Finalizer_Name);
- Set_Has_Qualified_Name (Fin_Id);
- Set_Has_Fully_Qualified_Name (Fin_Id);
-
- -- The default name is _finalizer
-
- else
- Fin_Id :=
- Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Name_uFinalizer));
-
- -- The visibility semantics of AT_END handlers force a strange
- -- separation of spec and body for stack-related finalizers:
-
- -- declare : Enclosing_Scope
- -- procedure _finalizer;
- -- begin
- -- <controlled objects>
- -- procedure _finalizer is
- -- ...
- -- at end
- -- _finalizer;
- -- end;
-
- -- Both spec and body are within the same construct and scope, but
- -- the body is part of the handled sequence of statements. This
- -- placement confuses the elaboration mechanism on targets where
- -- AT_END handlers are expanded into "when all others" handlers:
-
- -- exception
- -- when all others =>
- -- _finalizer; -- appears to require elab checks
- -- at end
- -- _finalizer;
- -- end;
-
- -- Since the compiler guarantees that the body of a _finalizer is
- -- always inserted in the same construct where the AT_END handler
- -- resides, there is no need for elaboration checks.
-
- Set_Kill_Elaboration_Checks (Fin_Id);
- end if;
-
- -- Step 2: Creation of the finalizer specification
-
- -- Generate:
- -- procedure Fin_Id;
-
- Fin_Spec :=
- Make_Subprogram_Declaration (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Fin_Id));
-
- -- Step 3: Creation of the finalizer body
-
- if Has_Ctrl_Objs then
-
- -- Add L0, the default destination to the jump block
-
- Label_Id := Make_Identifier (Loc, New_External_Name ('L', 0));
- Set_Entity (Label_Id,
- Make_Defining_Identifier (Loc, Chars (Label_Id)));
- Label := Make_Label (Loc, Label_Id);
-
- -- Generate:
- -- L0 : label;
-
- Prepend_To (Finalizer_Decls,
- Make_Implicit_Label_Declaration (Loc,
- Defining_Identifier => Entity (Label_Id),
- Label_Construct => Label));
-
- -- Generate:
- -- when others =>
- -- goto L0;
-
- Append_To (Jump_Alts,
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices => New_List (Make_Others_Choice (Loc)),
- Statements => New_List (
- Make_Goto_Statement (Loc,
- Name => New_Reference_To (Entity (Label_Id), Loc)))));
-
- -- Generate:
- -- <<L0>>
-
- Append_To (Finalizer_Stmts, Label);
-
- -- Create the jump block which controls the finalization flow
- -- depending on the value of the state counter.
-
- Jump_Block :=
- Make_Case_Statement (Loc,
- Expression => Make_Identifier (Loc, Chars (Counter_Id)),
- Alternatives => Jump_Alts);
-
- if Acts_As_Clean
- and then Present (Jump_Block_Insert_Nod)
- then
- Insert_After (Jump_Block_Insert_Nod, Jump_Block);
- else
- Prepend_To (Finalizer_Stmts, Jump_Block);
- end if;
- end if;
-
- -- Add the library-level tagged type unregistration machinery before
- -- the jump block circuitry. This ensures that external tags will be
- -- removed even if a finalization exception occurs at some point.
-
- if Has_Tagged_Types then
- Prepend_List_To (Finalizer_Stmts, Tagged_Type_Stmts);
- end if;
-
- -- Add a call to the previous At_End handler if it exists. The call
- -- must always precede the jump block.
-
- if Present (Prev_At_End) then
- Prepend_To (Finalizer_Stmts,
- Make_Procedure_Call_Statement (Loc, Prev_At_End));
-
- -- Clear the At_End handler since we have already generated the
- -- proper replacement call for it.
-
- Set_At_End_Proc (HSS, Empty);
- end if;
-
- -- Release the secondary stack mark
-
- if Present (Mark_Id) then
- Append_To (Finalizer_Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_SS_Release), Loc),
- Parameter_Associations => New_List (
- New_Reference_To (Mark_Id, Loc))));
- end if;
-
- -- Protect the statements with abort defer/undefer. This is only when
- -- aborts are allowed and the clean up statements require deferral or
- -- there are controlled objects to be finalized.
-
- if Abort_Allowed
- and then
- (Defer_Abort or else Has_Ctrl_Objs)
- then
- Prepend_To (Finalizer_Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name => New_Reference_To (RTE (RE_Abort_Defer), Loc)));
-
- Append_To (Finalizer_Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)));
- end if;
-
- -- The local exception does not need to be reraised for library-level
- -- finalizers. Note that this action must be carried out after object
- -- clean up, secondary stack release and abort undeferral. Generate:
-
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
-
- if Has_Ctrl_Objs
- and then Exceptions_OK
- and then not For_Package
- then
- Append_To (Finalizer_Stmts,
- Build_Raise_Statement (Finalizer_Data));
- end if;
-
- -- Generate:
- -- procedure Fin_Id is
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
-
- -- E : Exception_Occurrence; -- All added if flag
- -- Raised : Boolean := False; -- Has_Ctrl_Objs is set
- -- L0 : label;
- -- ...
- -- Lnn : label;
-
- -- begin
- -- Abort_Defer; -- Added if abort is allowed
- -- <call to Prev_At_End> -- Added if exists
- -- <cleanup statements> -- Added if Acts_As_Clean
- -- <jump block> -- Added if Has_Ctrl_Objs
- -- <finalization statements> -- Added if Has_Ctrl_Objs
- -- <stack release> -- Added if Mark_Id exists
- -- Abort_Undefer; -- Added if abort is allowed
- -- <exception propagation> -- Added if Has_Ctrl_Objs
- -- end Fin_Id;
-
- -- Create the body of the finalizer
-
- Body_Id := Make_Defining_Identifier (Loc, Chars (Fin_Id));
-
- if For_Package then
- Set_Has_Qualified_Name (Body_Id);
- Set_Has_Fully_Qualified_Name (Body_Id);
- end if;
-
- Fin_Body :=
- Make_Subprogram_Body (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Body_Id),
- Declarations => Finalizer_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Finalizer_Stmts));
-
- -- Step 4: Spec and body insertion, analysis
-
- if For_Package then
-
- -- If the package spec has private declarations, the finalizer
- -- body must be added to the end of the list in order to have
- -- visibility of all private controlled objects.
-
- if For_Package_Spec then
- if Present (Priv_Decls) then
- Append_To (Priv_Decls, Fin_Spec);
- Append_To (Priv_Decls, Fin_Body);
- else
- Append_To (Decls, Fin_Spec);
- Append_To (Decls, Fin_Body);
- end if;
-
- -- For package bodies, both the finalizer spec and body are
- -- inserted at the end of the package declarations.
-
- else
- Append_To (Decls, Fin_Spec);
- Append_To (Decls, Fin_Body);
- end if;
-
- -- Push the name of the package
-
- Push_Scope (Spec_Id);
- Analyze (Fin_Spec);
- Analyze (Fin_Body);
- Pop_Scope;
-
- -- Non-package case
-
- else
- -- Create the spec for the finalizer. The At_End handler must be
- -- able to call the body which resides in a nested structure.
-
- -- Generate:
- -- declare
- -- procedure Fin_Id; -- Spec
- -- begin
- -- <objects and possibly statements>
- -- procedure Fin_Id is ... -- Body
- -- <statements>
- -- at end
- -- Fin_Id; -- At_End handler
- -- end;
-
- pragma Assert (Present (Spec_Decls));
-
- Append_To (Spec_Decls, Fin_Spec);
- Analyze (Fin_Spec);
-
- -- When the finalizer acts solely as a clean up routine, the body
- -- is inserted right after the spec.
-
- if Acts_As_Clean
- and then not Has_Ctrl_Objs
- then
- Insert_After (Fin_Spec, Fin_Body);
-
- -- In all other cases the body is inserted after either:
- --
- -- 1) The counter update statement of the last controlled object
- -- 2) The last top level nested controlled package
- -- 3) The last top level controlled instantiation
-
- else
- -- Manually freeze the spec. This is somewhat of a hack because
- -- a subprogram is frozen when its body is seen and the freeze
- -- node appears right before the body. However, in this case,
- -- the spec must be frozen earlier since the At_End handler
- -- must be able to call it.
- --
- -- declare
- -- procedure Fin_Id; -- Spec
- -- [Fin_Id] -- Freeze node
- -- begin
- -- ...
- -- at end
- -- Fin_Id; -- At_End handler
- -- end;
-
- Ensure_Freeze_Node (Fin_Id);
- Insert_After (Fin_Spec, Freeze_Node (Fin_Id));
- Set_Is_Frozen (Fin_Id);
-
- -- In the case where the last construct to contain a controlled
- -- object is either a nested package, an instantiation or a
- -- freeze node, the body must be inserted directly after the
- -- construct.
-
- if Nkind_In (Last_Top_Level_Ctrl_Construct,
- N_Freeze_Entity,
- N_Package_Declaration,
- N_Package_Body)
- then
- Finalizer_Insert_Nod := Last_Top_Level_Ctrl_Construct;
- end if;
-
- Insert_After (Finalizer_Insert_Nod, Fin_Body);
- end if;
-
- Analyze (Fin_Body);
- end if;
- end Create_Finalizer;
-
- --------------------------
- -- Process_Declarations --
- --------------------------
-
- procedure Process_Declarations
- (Decls : List_Id;
- Preprocess : Boolean := False;
- Top_Level : Boolean := False)
- is
- Decl : Node_Id;
- Expr : Node_Id;
- Obj_Id : Entity_Id;
- Obj_Typ : Entity_Id;
- Pack_Id : Entity_Id;
- Spec : Node_Id;
- Typ : Entity_Id;
-
- Old_Counter_Val : Int;
- -- This variable is used to determine whether a nested package or
- -- instance contains at least one controlled object.
-
- procedure Processing_Actions
- (Has_No_Init : Boolean := False;
- Is_Protected : Boolean := False);
- -- Depending on the mode of operation of Process_Declarations, either
- -- increment the controlled object counter, set the controlled object
- -- flag and store the last top level construct or process the current
- -- declaration. Flag Has_No_Init is used to propagate scenarios where
- -- the current declaration may not have initialization proc(s). Flag
- -- Is_Protected should be set when the current declaration denotes a
- -- simple protected object.
-
- ------------------------
- -- Processing_Actions --
- ------------------------
-
- procedure Processing_Actions
- (Has_No_Init : Boolean := False;
- Is_Protected : Boolean := False)
- is
- begin
- -- Library-level tagged type
-
- if Nkind (Decl) = N_Full_Type_Declaration then
- if Preprocess then
- Has_Tagged_Types := True;
-
- if Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
-
- else
- Process_Tagged_Type_Declaration (Decl);
- end if;
-
- -- Controlled object declaration
-
- else
- if Preprocess then
- Counter_Val := Counter_Val + 1;
- Has_Ctrl_Objs := True;
-
- if Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
-
- else
- Process_Object_Declaration (Decl, Has_No_Init, Is_Protected);
- end if;
- end if;
- end Processing_Actions;
-
- -- Start of processing for Process_Declarations
-
- begin
- if No (Decls) or else Is_Empty_List (Decls) then
- return;
- end if;
-
- -- Process all declarations in reverse order
-
- Decl := Last_Non_Pragma (Decls);
- while Present (Decl) loop
-
- -- Library-level tagged types
-
- if Nkind (Decl) = N_Full_Type_Declaration then
- Typ := Defining_Identifier (Decl);
-
- if Is_Tagged_Type (Typ)
- and then Is_Library_Level_Entity (Typ)
- and then Convention (Typ) = Convention_Ada
- and then Present (Access_Disp_Table (Typ))
- and then RTE_Available (RE_Register_Tag)
- and then not No_Run_Time_Mode
- and then not Is_Abstract_Type (Typ)
- then
- Processing_Actions;
- end if;
-
- -- Regular object declarations
-
- elsif Nkind (Decl) = N_Object_Declaration then
- Obj_Id := Defining_Identifier (Decl);
- Obj_Typ := Base_Type (Etype (Obj_Id));
- Expr := Expression (Decl);
-
- -- Bypass any form of processing for objects which have their
- -- finalization disabled. This applies only to objects at the
- -- library level.
-
- if For_Package
- and then Finalize_Storage_Only (Obj_Typ)
- then
- null;
-
- -- Transient variables are treated separately in order to
- -- minimize the size of the generated code. For details, see
- -- Process_Transient_Objects.
-
- elsif Is_Processed_Transient (Obj_Id) then
- null;
-
- -- The object is of the form:
- -- Obj : Typ [:= Expr];
-
- -- Do not process the incomplete view of a deferred constant.
- -- Do not consider tag-to-class-wide conversions.
-
- elsif not Is_Imported (Obj_Id)
- and then Needs_Finalization (Obj_Typ)
- and then not (Ekind (Obj_Id) = E_Constant
- and then not Has_Completion (Obj_Id))
- and then not Is_Tag_To_Class_Wide_Conversion (Obj_Id)
- then
- Processing_Actions;
-
- -- The object is of the form:
- -- Obj : Access_Typ := Non_BIP_Function_Call'reference;
-
- -- Obj : Access_Typ :=
- -- BIP_Function_Call (BIPalloc => 2, ...)'reference;
-
- elsif Is_Access_Type (Obj_Typ)
- and then Needs_Finalization
- (Available_View (Designated_Type (Obj_Typ)))
- and then Present (Expr)
- and then
- (Is_Secondary_Stack_BIP_Func_Call (Expr)
- or else
- (Is_Non_BIP_Func_Call (Expr)
- and then not Is_Related_To_Func_Return (Obj_Id)))
- then
- Processing_Actions (Has_No_Init => True);
-
- -- Processing for "hook" objects generated for controlled
- -- transients declared inside an Expression_With_Actions.
-
- elsif Is_Access_Type (Obj_Typ)
- and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
- and then Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) =
- N_Object_Declaration
- and then Is_Finalizable_Transient
- (Status_Flag_Or_Transient_Decl (Obj_Id), Decl)
- then
- Processing_Actions (Has_No_Init => True);
-
- -- Process intermediate results of an if expression with one
- -- of the alternatives using a controlled function call.
-
- elsif Is_Access_Type (Obj_Typ)
- and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
- and then Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) =
- N_Defining_Identifier
- and then Present (Expr)
- and then Nkind (Expr) = N_Null
- then
- Processing_Actions (Has_No_Init => True);
-
- -- Simple protected objects which use type System.Tasking.
- -- Protected_Objects.Protection to manage their locks should
- -- be treated as controlled since they require manual cleanup.
- -- The only exception is illustrated in the following example:
-
- -- package Pkg is
- -- type Ctrl is new Controlled ...
- -- procedure Finalize (Obj : in out Ctrl);
- -- Lib_Obj : Ctrl;
- -- end Pkg;
-
- -- package body Pkg is
- -- protected Prot is
- -- procedure Do_Something (Obj : in out Ctrl);
- -- end Prot;
-
- -- protected body Prot is
- -- procedure Do_Something (Obj : in out Ctrl) is ...
- -- end Prot;
-
- -- procedure Finalize (Obj : in out Ctrl) is
- -- begin
- -- Prot.Do_Something (Obj);
- -- end Finalize;
- -- end Pkg;
-
- -- Since for the most part entities in package bodies depend on
- -- those in package specs, Prot's lock should be cleaned up
- -- first. The subsequent cleanup of the spec finalizes Lib_Obj.
- -- This act however attempts to invoke Do_Something and fails
- -- because the lock has disappeared.
-
- elsif Ekind (Obj_Id) = E_Variable
- and then not In_Library_Level_Package_Body (Obj_Id)
- and then
- (Is_Simple_Protected_Type (Obj_Typ)
- or else Has_Simple_Protected_Object (Obj_Typ))
- then
- Processing_Actions (Is_Protected => True);
- end if;
-
- -- Specific cases of object renamings
-
- elsif Nkind (Decl) = N_Object_Renaming_Declaration then
- Obj_Id := Defining_Identifier (Decl);
- Obj_Typ := Base_Type (Etype (Obj_Id));
-
- -- Bypass any form of processing for objects which have their
- -- finalization disabled. This applies only to objects at the
- -- library level.
-
- if For_Package
- and then Finalize_Storage_Only (Obj_Typ)
- then
- null;
-
- -- Return object of a build-in-place function. This case is
- -- recognized and marked by the expansion of an extended return
- -- statement (see Expand_N_Extended_Return_Statement).
-
- elsif Needs_Finalization (Obj_Typ)
- and then Is_Return_Object (Obj_Id)
- and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
- then
- Processing_Actions (Has_No_Init => True);
-
- -- Detect a case where a source object has been initialized by
- -- a controlled function call or another object which was later
- -- rewritten as a class-wide conversion of Ada.Tags.Displace.
-
- -- Obj1 : CW_Type := Src_Obj;
- -- Obj2 : CW_Type := Function_Call (...);
-
- -- Obj1 : CW_Type renames (... Ada.Tags.Displace (Src_Obj));
- -- Tmp : ... := Function_Call (...)'reference;
- -- Obj2 : CW_Type renames (... Ada.Tags.Displace (Tmp));
-
- elsif Is_Displacement_Of_Object_Or_Function_Result (Obj_Id) then
- Processing_Actions (Has_No_Init => True);
- end if;
-
- -- Inspect the freeze node of an access-to-controlled type and
- -- look for a delayed finalization master. This case arises when
- -- the freeze actions are inserted at a later time than the
- -- expansion of the context. Since Build_Finalizer is never called
- -- on a single construct twice, the master will be ultimately
- -- left out and never finalized. This is also needed for freeze
- -- actions of designated types themselves, since in some cases the
- -- finalization master is associated with a designated type's
- -- freeze node rather than that of the access type (see handling
- -- for freeze actions in Build_Finalization_Master).
-
- elsif Nkind (Decl) = N_Freeze_Entity
- and then Present (Actions (Decl))
- then
- Typ := Entity (Decl);
-
- if (Is_Access_Type (Typ)
- and then not Is_Access_Subprogram_Type (Typ)
- and then Needs_Finalization
- (Available_View (Designated_Type (Typ))))
- or else (Is_Type (Typ) and then Needs_Finalization (Typ))
- then
- Old_Counter_Val := Counter_Val;
-
- -- Freeze nodes are considered to be identical to packages
- -- and blocks in terms of nesting. The difference is that
- -- a finalization master created inside the freeze node is
- -- at the same nesting level as the node itself.
-
- Process_Declarations (Actions (Decl), Preprocess);
-
- -- The freeze node contains a finalization master
-
- if Preprocess
- and then Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- and then Counter_Val > Old_Counter_Val
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
- end if;
-
- -- Nested package declarations, avoid generics
-
- elsif Nkind (Decl) = N_Package_Declaration then
- Spec := Specification (Decl);
- Pack_Id := Defining_Unit_Name (Spec);
-
- if Nkind (Pack_Id) = N_Defining_Program_Unit_Name then
- Pack_Id := Defining_Identifier (Pack_Id);
- end if;
-
- if Ekind (Pack_Id) /= E_Generic_Package then
- Old_Counter_Val := Counter_Val;
- Process_Declarations
- (Private_Declarations (Spec), Preprocess);
- Process_Declarations
- (Visible_Declarations (Spec), Preprocess);
-
- -- Either the visible or the private declarations contain a
- -- controlled object. The nested package declaration is the
- -- last such construct.
-
- if Preprocess
- and then Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- and then Counter_Val > Old_Counter_Val
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
- end if;
-
- -- Nested package bodies, avoid generics
-
- elsif Nkind (Decl) = N_Package_Body then
- Spec := Corresponding_Spec (Decl);
-
- if Ekind (Spec) /= E_Generic_Package then
- Old_Counter_Val := Counter_Val;
- Process_Declarations (Declarations (Decl), Preprocess);
-
- -- The nested package body is the last construct to contain
- -- a controlled object.
-
- if Preprocess
- and then Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- and then Counter_Val > Old_Counter_Val
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
- end if;
-
- -- Handle a rare case caused by a controlled transient variable
- -- created as part of a record init proc. The variable is wrapped
- -- in a block, but the block is not associated with a transient
- -- scope.
-
- elsif Nkind (Decl) = N_Block_Statement
- and then Inside_Init_Proc
- then
- Old_Counter_Val := Counter_Val;
-
- if Present (Handled_Statement_Sequence (Decl)) then
- Process_Declarations
- (Statements (Handled_Statement_Sequence (Decl)),
- Preprocess);
- end if;
-
- Process_Declarations (Declarations (Decl), Preprocess);
-
- -- Either the declaration or statement list of the block has a
- -- controlled object.
-
- if Preprocess
- and then Top_Level
- and then No (Last_Top_Level_Ctrl_Construct)
- and then Counter_Val > Old_Counter_Val
- then
- Last_Top_Level_Ctrl_Construct := Decl;
- end if;
-
- -- Handle the case where the original context has been wrapped in
- -- a block to avoid interference between exception handlers and
- -- At_End handlers. Treat the block as transparent and process its
- -- contents.
-
- elsif Nkind (Decl) = N_Block_Statement
- and then Is_Finalization_Wrapper (Decl)
- then
- if Present (Handled_Statement_Sequence (Decl)) then
- Process_Declarations
- (Statements (Handled_Statement_Sequence (Decl)),
- Preprocess);
- end if;
-
- Process_Declarations (Declarations (Decl), Preprocess);
- end if;
-
- Prev_Non_Pragma (Decl);
- end loop;
- end Process_Declarations;
-
- --------------------------------
- -- Process_Object_Declaration --
- --------------------------------
-
- procedure Process_Object_Declaration
- (Decl : Node_Id;
- Has_No_Init : Boolean := False;
- Is_Protected : Boolean := False)
- is
- Obj_Id : constant Entity_Id := Defining_Identifier (Decl);
- Loc : constant Source_Ptr := Sloc (Decl);
- Body_Ins : Node_Id;
- Count_Ins : Node_Id;
- Fin_Call : Node_Id;
- Fin_Stmts : List_Id;
- Inc_Decl : Node_Id;
- Label : Node_Id;
- Label_Id : Entity_Id;
- Obj_Ref : Node_Id;
- Obj_Typ : Entity_Id;
-
- function Build_BIP_Cleanup_Stmts (Func_Id : Entity_Id) return Node_Id;
- -- Once it has been established that the current object is in fact a
- -- return object of build-in-place function Func_Id, generate the
- -- following cleanup code:
- --
- -- if BIPallocfrom > Secondary_Stack'Pos
- -- and then BIPfinalizationmaster /= null
- -- then
- -- declare
- -- type Ptr_Typ is access Obj_Typ;
- -- for Ptr_Typ'Storage_Pool
- -- use Base_Pool (BIPfinalizationmaster);
- -- begin
- -- Free (Ptr_Typ (Temp));
- -- end;
- -- end if;
- --
- -- Obj_Typ is the type of the current object, Temp is the original
- -- allocation which Obj_Id renames.
-
- procedure Find_Last_Init
- (Decl : Node_Id;
- Typ : Entity_Id;
- Last_Init : out Node_Id;
- Body_Insert : out Node_Id);
- -- An object declaration has at least one and at most two init calls:
- -- that of the type and the user-defined initialize. Given an object
- -- declaration, Last_Init denotes the last initialization call which
- -- follows the declaration. Body_Insert denotes the place where the
- -- finalizer body could be potentially inserted.
-
- -----------------------------
- -- Build_BIP_Cleanup_Stmts --
- -----------------------------
-
- function Build_BIP_Cleanup_Stmts
- (Func_Id : Entity_Id) return Node_Id
- is
- Decls : constant List_Id := New_List;
- Fin_Mas_Id : constant Entity_Id :=
- Build_In_Place_Formal
- (Func_Id, BIP_Finalization_Master);
- Obj_Typ : constant Entity_Id := Etype (Func_Id);
- Temp_Id : constant Entity_Id :=
- Entity (Prefix (Name (Parent (Obj_Id))));
-
- Cond : Node_Id;
- Free_Blk : Node_Id;
- Free_Stmt : Node_Id;
- Pool_Id : Entity_Id;
- Ptr_Typ : Entity_Id;
-
- begin
- -- Generate:
- -- Pool_Id renames Base_Pool (BIPfinalizationmaster.all).all;
-
- Pool_Id := Make_Temporary (Loc, 'P');
-
- Append_To (Decls,
- Make_Object_Renaming_Declaration (Loc,
- Defining_Identifier => Pool_Id,
- Subtype_Mark =>
- New_Reference_To (RTE (RE_Root_Storage_Pool), Loc),
- Name =>
- Make_Explicit_Dereference (Loc,
- Prefix =>
- Make_Function_Call (Loc,
- Name =>
- New_Reference_To (RTE (RE_Base_Pool), Loc),
- Parameter_Associations => New_List (
- Make_Explicit_Dereference (Loc,
- Prefix => New_Reference_To (Fin_Mas_Id, Loc)))))));
-
- -- Create an access type which uses the storage pool of the
- -- caller's finalization master.
-
- -- Generate:
- -- type Ptr_Typ is access Obj_Typ;
-
- Ptr_Typ := Make_Temporary (Loc, 'P');
-
- Append_To (Decls,
- Make_Full_Type_Declaration (Loc,
- Defining_Identifier => Ptr_Typ,
- Type_Definition =>
- Make_Access_To_Object_Definition (Loc,
- Subtype_Indication => New_Reference_To (Obj_Typ, Loc))));
-
- -- Perform minor decoration in order to set the master and the
- -- storage pool attributes.
-
- Set_Ekind (Ptr_Typ, E_Access_Type);
- Set_Finalization_Master (Ptr_Typ, Fin_Mas_Id);
- Set_Associated_Storage_Pool (Ptr_Typ, Pool_Id);
-
- -- Create an explicit free statement. Note that the free uses the
- -- caller's pool expressed as a renaming.
-
- Free_Stmt :=
- Make_Free_Statement (Loc,
- Expression =>
- Unchecked_Convert_To (Ptr_Typ,
- New_Reference_To (Temp_Id, Loc)));
-
- Set_Storage_Pool (Free_Stmt, Pool_Id);
-
- -- Create a block to house the dummy type and the instantiation as
- -- well as to perform the cleanup the temporary.
-
- -- Generate:
- -- declare
- -- <Decls>
- -- begin
- -- Free (Ptr_Typ (Temp_Id));
- -- end;
-
- Free_Blk :=
- Make_Block_Statement (Loc,
- Declarations => Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Free_Stmt)));
-
- -- Generate:
- -- if BIPfinalizationmaster /= null then
-
- Cond :=
- Make_Op_Ne (Loc,
- Left_Opnd => New_Reference_To (Fin_Mas_Id, Loc),
- Right_Opnd => Make_Null (Loc));
-
- -- For constrained or tagged results escalate the condition to
- -- include the allocation format. Generate:
- --
- -- if BIPallocform > Secondary_Stack'Pos
- -- and then BIPfinalizationmaster /= null
- -- then
-
- if not Is_Constrained (Obj_Typ)
- or else Is_Tagged_Type (Obj_Typ)
- then
- declare
- Alloc : constant Entity_Id :=
- Build_In_Place_Formal (Func_Id, BIP_Alloc_Form);
- begin
- Cond :=
- Make_And_Then (Loc,
- Left_Opnd =>
- Make_Op_Gt (Loc,
- Left_Opnd => New_Reference_To (Alloc, Loc),
- Right_Opnd =>
- Make_Integer_Literal (Loc,
- UI_From_Int
- (BIP_Allocation_Form'Pos (Secondary_Stack)))),
-
- Right_Opnd => Cond);
- end;
- end if;
-
- -- Generate:
- -- if <Cond> then
- -- <Free_Blk>
- -- end if;
-
- return
- Make_If_Statement (Loc,
- Condition => Cond,
- Then_Statements => New_List (Free_Blk));
- end Build_BIP_Cleanup_Stmts;
-
- --------------------
- -- Find_Last_Init --
- --------------------
-
- procedure Find_Last_Init
- (Decl : Node_Id;
- Typ : Entity_Id;
- Last_Init : out Node_Id;
- Body_Insert : out Node_Id)
- is
- Nod_1 : Node_Id := Empty;
- Nod_2 : Node_Id := Empty;
- Utyp : Entity_Id;
-
- function Is_Init_Call
- (N : Node_Id;
- Typ : Entity_Id) return Boolean;
- -- Given an arbitrary node, determine whether N is a procedure
- -- call and if it is, try to match the name of the call with the
- -- [Deep_]Initialize proc of Typ.
-
- function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id;
- -- Given a statement which is part of a list, return the next
- -- real statement while skipping over dynamic elab checks.
-
- ------------------
- -- Is_Init_Call --
- ------------------
-
- function Is_Init_Call
- (N : Node_Id;
- Typ : Entity_Id) return Boolean
- is
- begin
- -- A call to [Deep_]Initialize is always direct
-
- if Nkind (N) = N_Procedure_Call_Statement
- and then Nkind (Name (N)) = N_Identifier
- then
- declare
- Call_Ent : constant Entity_Id := Entity (Name (N));
- Deep_Init : constant Entity_Id :=
- TSS (Typ, TSS_Deep_Initialize);
- Init : Entity_Id := Empty;
-
- begin
- -- A type may have controlled components but not be
- -- controlled.
-
- if Is_Controlled (Typ) then
- Init := Find_Prim_Op (Typ, Name_Initialize);
-
- if Present (Init) then
- Init := Ultimate_Alias (Init);
- end if;
- end if;
-
- return
- (Present (Deep_Init) and then Call_Ent = Deep_Init)
- or else
- (Present (Init) and then Call_Ent = Init);
- end;
- end if;
-
- return False;
- end Is_Init_Call;
-
- -----------------------------
- -- Next_Suitable_Statement --
- -----------------------------
-
- function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id is
- Result : Node_Id := Next (Stmt);
-
- begin
- -- Skip over access-before-elaboration checks
-
- if Dynamic_Elaboration_Checks
- and then Nkind (Result) = N_Raise_Program_Error
- then
- Result := Next (Result);
- end if;
-
- return Result;
- end Next_Suitable_Statement;
-
- -- Start of processing for Find_Last_Init
-
- begin
- Last_Init := Decl;
- Body_Insert := Empty;
-
- -- Object renamings and objects associated with controlled
- -- function results do not have initialization calls.
-
- if Has_No_Init then
- return;
- end if;
-
- if Is_Concurrent_Type (Typ) then
- Utyp := Corresponding_Record_Type (Typ);
- else
- Utyp := Typ;
- end if;
-
- if Is_Private_Type (Utyp)
- and then Present (Full_View (Utyp))
- then
- Utyp := Full_View (Utyp);
- end if;
-
- -- The init procedures are arranged as follows:
-
- -- Object : Controlled_Type;
- -- Controlled_TypeIP (Object);
- -- [[Deep_]Initialize (Object);]
-
- -- where the user-defined initialize may be optional or may appear
- -- inside a block when abort deferral is needed.
-
- Nod_1 := Next_Suitable_Statement (Decl);
- if Present (Nod_1) then
- Nod_2 := Next_Suitable_Statement (Nod_1);
-
- -- The statement following an object declaration is always a
- -- call to the type init proc.
-
- Last_Init := Nod_1;
- end if;
-
- -- Optional user-defined init or deep init processing
-
- if Present (Nod_2) then
-
- -- The statement following the type init proc may be a block
- -- statement in cases where abort deferral is required.
-
- if Nkind (Nod_2) = N_Block_Statement then
- declare
- HSS : constant Node_Id :=
- Handled_Statement_Sequence (Nod_2);
- Stmt : Node_Id;
-
- begin
- if Present (HSS)
- and then Present (Statements (HSS))
- then
- Stmt := First (Statements (HSS));
-
- -- Examine individual block statements and locate the
- -- call to [Deep_]Initialze.
-
- while Present (Stmt) loop
- if Is_Init_Call (Stmt, Utyp) then
- Last_Init := Stmt;
- Body_Insert := Nod_2;
-
- exit;
- end if;
-
- Next (Stmt);
- end loop;
- end if;
- end;
-
- elsif Is_Init_Call (Nod_2, Utyp) then
- Last_Init := Nod_2;
- end if;
- end if;
- end Find_Last_Init;
-
- -- Start of processing for Process_Object_Declaration
-
- begin
- Obj_Ref := New_Reference_To (Obj_Id, Loc);
- Obj_Typ := Base_Type (Etype (Obj_Id));
-
- -- Handle access types
-
- if Is_Access_Type (Obj_Typ) then
- Obj_Ref := Make_Explicit_Dereference (Loc, Obj_Ref);
- Obj_Typ := Directly_Designated_Type (Obj_Typ);
- end if;
-
- Set_Etype (Obj_Ref, Obj_Typ);
-
- -- Set a new value for the state counter and insert the statement
- -- after the object declaration. Generate:
- --
- -- Counter := <value>;
-
- Inc_Decl :=
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Counter_Id, Loc),
- Expression => Make_Integer_Literal (Loc, Counter_Val));
-
- -- Insert the counter after all initialization has been done. The
- -- place of insertion depends on the context. When dealing with a
- -- controlled function, the counter is inserted directly after the
- -- declaration because such objects lack init calls.
-
- Find_Last_Init (Decl, Obj_Typ, Count_Ins, Body_Ins);
-
- Insert_After (Count_Ins, Inc_Decl);
- Analyze (Inc_Decl);
-
- -- If the current declaration is the last in the list, the finalizer
- -- body needs to be inserted after the set counter statement for the
- -- current object declaration. This is complicated by the fact that
- -- the set counter statement may appear in abort deferred block. In
- -- that case, the proper insertion place is after the block.
-
- if No (Finalizer_Insert_Nod) then
-
- -- Insertion after an abort deffered block
-
- if Present (Body_Ins) then
- Finalizer_Insert_Nod := Body_Ins;
- else
- Finalizer_Insert_Nod := Inc_Decl;
- end if;
- end if;
-
- -- Create the associated label with this object, generate:
- --
- -- L<counter> : label;
-
- Label_Id :=
- Make_Identifier (Loc, New_External_Name ('L', Counter_Val));
- Set_Entity
- (Label_Id, Make_Defining_Identifier (Loc, Chars (Label_Id)));
- Label := Make_Label (Loc, Label_Id);
-
- Prepend_To (Finalizer_Decls,
- Make_Implicit_Label_Declaration (Loc,
- Defining_Identifier => Entity (Label_Id),
- Label_Construct => Label));
-
- -- Create the associated jump with this object, generate:
- --
- -- when <counter> =>
- -- goto L<counter>;
-
- Prepend_To (Jump_Alts,
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices => New_List (
- Make_Integer_Literal (Loc, Counter_Val)),
- Statements => New_List (
- Make_Goto_Statement (Loc,
- Name => New_Reference_To (Entity (Label_Id), Loc)))));
-
- -- Insert the jump destination, generate:
- --
- -- <<L<counter>>>
-
- Append_To (Finalizer_Stmts, Label);
-
- -- Processing for simple protected objects. Such objects require
- -- manual finalization of their lock managers.
-
- if Is_Protected then
- Fin_Stmts := No_List;
-
- if Is_Simple_Protected_Type (Obj_Typ) then
- Fin_Call := Cleanup_Protected_Object (Decl, Obj_Ref);
-
- if Present (Fin_Call) then
- Fin_Stmts := New_List (Fin_Call);
- end if;
-
- elsif Has_Simple_Protected_Object (Obj_Typ) then
- if Is_Record_Type (Obj_Typ) then
- Fin_Stmts := Cleanup_Record (Decl, Obj_Ref, Obj_Typ);
- elsif Is_Array_Type (Obj_Typ) then
- Fin_Stmts := Cleanup_Array (Decl, Obj_Ref, Obj_Typ);
- end if;
- end if;
-
- -- Generate:
- -- begin
- -- System.Tasking.Protected_Objects.Finalize_Protection
- -- (Obj._object);
-
- -- exception
- -- when others =>
- -- null;
- -- end;
-
- if Present (Fin_Stmts) then
- Append_To (Finalizer_Stmts,
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Fin_Stmts,
-
- Exception_Handlers => New_List (
- Make_Exception_Handler (Loc,
- Exception_Choices => New_List (
- Make_Others_Choice (Loc)),
-
- Statements => New_List (
- Make_Null_Statement (Loc)))))));
- end if;
-
- -- Processing for regular controlled objects
-
- else
- -- Generate:
- -- [Deep_]Finalize (Obj); -- No_Exception_Propagation
-
- -- begin -- Exception handlers allowed
- -- [Deep_]Finalize (Obj);
-
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Id);
- -- end if;
- -- end;
-
- Fin_Call :=
- Make_Final_Call (
- Obj_Ref => Obj_Ref,
- Typ => Obj_Typ);
-
- -- For CodePeer, the exception handlers normally generated here
- -- generate complex flowgraphs which result in capacity problems.
- -- Omitting these handlers for CodePeer is justified as follows:
-
- -- If a handler is dead, then omitting it is surely ok
-
- -- If a handler is live, then CodePeer should flag the
- -- potentially-exception-raising construct that causes it
- -- to be live. That is what we are interested in, not what
- -- happens after the exception is raised.
-
- if Exceptions_OK and not CodePeer_Mode then
- Fin_Stmts := New_List (
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Call),
-
- Exception_Handlers => New_List (
- Build_Exception_Handler
- (Finalizer_Data, For_Package)))));
-
- -- When exception handlers are prohibited, the finalization call
- -- appears unprotected. Any exception raised during finalization
- -- will bypass the circuitry which ensures the cleanup of all
- -- remaining objects.
-
- else
- Fin_Stmts := New_List (Fin_Call);
- end if;
-
- -- If we are dealing with a return object of a build-in-place
- -- function, generate the following cleanup statements:
-
- -- if BIPallocfrom > Secondary_Stack'Pos
- -- and then BIPfinalizationmaster /= null
- -- then
- -- declare
- -- type Ptr_Typ is access Obj_Typ;
- -- for Ptr_Typ'Storage_Pool use
- -- Base_Pool (BIPfinalizationmaster.all).all;
- -- begin
- -- Free (Ptr_Typ (Temp));
- -- end;
- -- end if;
- --
- -- The generated code effectively detaches the temporary from the
- -- caller finalization master and deallocates the object. This is
- -- disabled on .NET/JVM because pools are not supported.
-
- if VM_Target = No_VM and then Is_Return_Object (Obj_Id) then
- declare
- Func_Id : constant Entity_Id := Enclosing_Function (Obj_Id);
- begin
- if Is_Build_In_Place_Function (Func_Id)
- and then Needs_BIP_Finalization_Master (Func_Id)
- then
- Append_To (Fin_Stmts, Build_BIP_Cleanup_Stmts (Func_Id));
- end if;
- end;
- end if;
-
- if Ekind_In (Obj_Id, E_Constant, E_Variable)
- and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
- then
- -- Temporaries created for the purpose of "exporting" a
- -- controlled transient out of an Expression_With_Actions (EWA)
- -- need guards. The following illustrates the usage of such
- -- temporaries.
-
- -- Access_Typ : access [all] Obj_Typ;
- -- Temp : Access_Typ := null;
- -- <Counter> := ...;
-
- -- do
- -- Ctrl_Trans : [access [all]] Obj_Typ := ...;
- -- Temp := Access_Typ (Ctrl_Trans); -- when a pointer
- -- <or>
- -- Temp := Ctrl_Trans'Unchecked_Access;
- -- in ... end;
-
- -- The finalization machinery does not process EWA nodes as
- -- this may lead to premature finalization of expressions. Note
- -- that Temp is marked as being properly initialized regardless
- -- of whether the initialization of Ctrl_Trans succeeded. Since
- -- a failed initialization may leave Temp with a value of null,
- -- add a guard to handle this case:
-
- -- if Obj /= null then
- -- <object finalization statements>
- -- end if;
-
- if Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) =
- N_Object_Declaration
- then
- Fin_Stmts := New_List (
- Make_If_Statement (Loc,
- Condition =>
- Make_Op_Ne (Loc,
- Left_Opnd => New_Reference_To (Obj_Id, Loc),
- Right_Opnd => Make_Null (Loc)),
- Then_Statements => Fin_Stmts));
-
- -- Return objects use a flag to aid in processing their
- -- potential finalization when the enclosing function fails
- -- to return properly. Generate:
-
- -- if not Flag then
- -- <object finalization statements>
- -- end if;
-
- else
- Fin_Stmts := New_List (
- Make_If_Statement (Loc,
- Condition =>
- Make_Op_Not (Loc,
- Right_Opnd =>
- New_Reference_To
- (Status_Flag_Or_Transient_Decl (Obj_Id), Loc)),
-
- Then_Statements => Fin_Stmts));
- end if;
- end if;
- end if;
-
- Append_List_To (Finalizer_Stmts, Fin_Stmts);
-
- -- Since the declarations are examined in reverse, the state counter
- -- must be decremented in order to keep with the true position of
- -- objects.
-
- Counter_Val := Counter_Val - 1;
- end Process_Object_Declaration;
-
- -------------------------------------
- -- Process_Tagged_Type_Declaration --
- -------------------------------------
-
- procedure Process_Tagged_Type_Declaration (Decl : Node_Id) is
- Typ : constant Entity_Id := Defining_Identifier (Decl);
- DT_Ptr : constant Entity_Id :=
- Node (First_Elmt (Access_Disp_Table (Typ)));
- begin
- -- Generate:
- -- Ada.Tags.Unregister_Tag (<Typ>P);
-
- Append_To (Tagged_Type_Stmts,
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Unregister_Tag), Loc),
- Parameter_Associations => New_List (
- New_Reference_To (DT_Ptr, Loc))));
- end Process_Tagged_Type_Declaration;
-
- -- Start of processing for Build_Finalizer
-
- begin
- Fin_Id := Empty;
-
- -- Do not perform this expansion in Alfa mode because it is not
- -- necessary.
-
- if Alfa_Mode then
- return;
- end if;
-
- -- Step 1: Extract all lists which may contain controlled objects or
- -- library-level tagged types.
-
- if For_Package_Spec then
- Decls := Visible_Declarations (Specification (N));
- Priv_Decls := Private_Declarations (Specification (N));
-
- -- Retrieve the package spec id
-
- Spec_Id := Defining_Unit_Name (Specification (N));
-
- if Nkind (Spec_Id) = N_Defining_Program_Unit_Name then
- Spec_Id := Defining_Identifier (Spec_Id);
- end if;
-
- -- Accept statement, block, entry body, package body, protected body,
- -- subprogram body or task body.
-
- else
- Decls := Declarations (N);
- HSS := Handled_Statement_Sequence (N);
-
- if Present (HSS) then
- if Present (Statements (HSS)) then
- Stmts := Statements (HSS);
- end if;
-
- if Present (At_End_Proc (HSS)) then
- Prev_At_End := At_End_Proc (HSS);
- end if;
- end if;
-
- -- Retrieve the package spec id for package bodies
-
- if For_Package_Body then
- Spec_Id := Corresponding_Spec (N);
- end if;
- end if;
-
- -- Do not process nested packages since those are handled by the
- -- enclosing scope's finalizer. Do not process non-expanded package
- -- instantiations since those will be re-analyzed and re-expanded.
-
- if For_Package
- and then
- (not Is_Library_Level_Entity (Spec_Id)
-
- -- Nested packages are considered to be library level entities,
- -- but do not need to be processed separately. True library level
- -- packages have a scope value of 1.
-
- or else Scope_Depth_Value (Spec_Id) /= Uint_1
- or else (Is_Generic_Instance (Spec_Id)
- and then Package_Instantiation (Spec_Id) /= N))
- then
- return;
- end if;
-
- -- Step 2: Object [pre]processing
-
- if For_Package then
-
- -- Preprocess the visible declarations now in order to obtain the
- -- correct number of controlled object by the time the private
- -- declarations are processed.
-
- Process_Declarations (Decls, Preprocess => True, Top_Level => True);
-
- -- From all the possible contexts, only package specifications may
- -- have private declarations.
-
- if For_Package_Spec then
- Process_Declarations
- (Priv_Decls, Preprocess => True, Top_Level => True);
- end if;
-
- -- The current context may lack controlled objects, but require some
- -- other form of completion (task termination for instance). In such
- -- cases, the finalizer must be created and carry the additional
- -- statements.
-
- if Acts_As_Clean or Has_Ctrl_Objs or Has_Tagged_Types then
- Build_Components;
- end if;
-
- -- The preprocessing has determined that the context has controlled
- -- objects or library-level tagged types.
-
- if Has_Ctrl_Objs or Has_Tagged_Types then
-
- -- Private declarations are processed first in order to preserve
- -- possible dependencies between public and private objects.
-
- if For_Package_Spec then
- Process_Declarations (Priv_Decls);
- end if;
-
- Process_Declarations (Decls);
- end if;
-
- -- Non-package case
-
- else
- -- Preprocess both declarations and statements
-
- Process_Declarations (Decls, Preprocess => True, Top_Level => True);
- Process_Declarations (Stmts, Preprocess => True, Top_Level => True);
-
- -- At this point it is known that N has controlled objects. Ensure
- -- that N has a declarative list since the finalizer spec will be
- -- attached to it.
-
- if Has_Ctrl_Objs and then No (Decls) then
- Set_Declarations (N, New_List);
- Decls := Declarations (N);
- Spec_Decls := Decls;
- end if;
-
- -- The current context may lack controlled objects, but require some
- -- other form of completion (task termination for instance). In such
- -- cases, the finalizer must be created and carry the additional
- -- statements.
-
- if Acts_As_Clean or Has_Ctrl_Objs or Has_Tagged_Types then
- Build_Components;
- end if;
-
- if Has_Ctrl_Objs or Has_Tagged_Types then
- Process_Declarations (Stmts);
- Process_Declarations (Decls);
- end if;
- end if;
-
- -- Step 3: Finalizer creation
-
- if Acts_As_Clean or Has_Ctrl_Objs or Has_Tagged_Types then
- Create_Finalizer;
- end if;
- end Build_Finalizer;
-
- --------------------------
- -- Build_Finalizer_Call --
- --------------------------
-
- procedure Build_Finalizer_Call (N : Node_Id; Fin_Id : Entity_Id) is
- Is_Prot_Body : constant Boolean :=
- Nkind (N) = N_Subprogram_Body
- and then Is_Protected_Subprogram_Body (N);
- -- Determine whether N denotes the protected version of a subprogram
- -- which belongs to a protected type.
-
- Loc : constant Source_Ptr := Sloc (N);
- HSS : Node_Id;
-
- begin
- -- Do not perform this expansion in Alfa mode because we do not create
- -- finalizers in the first place.
-
- if Alfa_Mode then
- return;
- end if;
-
- -- The At_End handler should have been assimilated by the finalizer
-
- HSS := Handled_Statement_Sequence (N);
- pragma Assert (No (At_End_Proc (HSS)));
-
- -- If the construct to be cleaned up is a protected subprogram body, the
- -- finalizer call needs to be associated with the block which wraps the
- -- unprotected version of the subprogram. The following illustrates this
- -- scenario:
-
- -- procedure Prot_SubpP is
- -- procedure finalizer is
- -- begin
- -- Service_Entries (Prot_Obj);
- -- Abort_Undefer;
- -- end finalizer;
-
- -- begin
- -- . . .
- -- begin
- -- Prot_SubpN (Prot_Obj);
- -- at end
- -- finalizer;
- -- end;
- -- end Prot_SubpP;
-
- if Is_Prot_Body then
- HSS := Handled_Statement_Sequence (Last (Statements (HSS)));
-
- -- An At_End handler and regular exception handlers cannot coexist in
- -- the same statement sequence. Wrap the original statements in a block.
-
- elsif Present (Exception_Handlers (HSS)) then
- declare
- End_Lab : constant Node_Id := End_Label (HSS);
- Block : Node_Id;
-
- begin
- Block :=
- Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS);
-
- Set_Handled_Statement_Sequence (N,
- Make_Handled_Sequence_Of_Statements (Loc, New_List (Block)));
-
- HSS := Handled_Statement_Sequence (N);
- Set_End_Label (HSS, End_Lab);
- end;
- end if;
-
- Set_At_End_Proc (HSS, New_Reference_To (Fin_Id, Loc));
-
- Analyze (At_End_Proc (HSS));
- Expand_At_End_Handler (HSS, Empty);
- end Build_Finalizer_Call;
-
- ---------------------
- -- Build_Late_Proc --
- ---------------------
-
- 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;
-
- -------------------------------
- -- Build_Object_Declarations --
- -------------------------------
-
- procedure Build_Object_Declarations
- (Data : out Finalization_Exception_Data;
- Decls : List_Id;
- Loc : Source_Ptr;
- For_Package : Boolean := False)
- is
- A_Expr : Node_Id;
- E_Decl : Node_Id;
-
- begin
- pragma Assert (Decls /= No_List);
-
- -- Always set the proper location as it may be needed even when
- -- exception propagation is forbidden.
-
- Data.Loc := Loc;
-
- if Restriction_Active (No_Exception_Propagation) then
- Data.Abort_Id := Empty;
- Data.E_Id := Empty;
- Data.Raised_Id := Empty;
- return;
- end if;
-
- Data.Raised_Id := Make_Temporary (Loc, 'R');
-
- -- In certain scenarios, finalization can be triggered by an abort. If
- -- the finalization itself fails and raises an exception, the resulting
- -- Program_Error must be supressed and replaced by an abort signal. In
- -- order to detect this scenario, save the state of entry into the
- -- finalization code.
-
- -- No need to do this for VM case, since VM version of Ada.Exceptions
- -- does not include routine Raise_From_Controlled_Operation which is the
- -- the sole user of flag Abort.
-
- -- This is not needed for library-level finalizers as they are called
- -- by the environment task and cannot be aborted.
-
- if Abort_Allowed
- and then VM_Target = No_VM
- and then not For_Package
- then
- Data.Abort_Id := Make_Temporary (Loc, 'A');
-
- A_Expr := New_Reference_To (RTE (RE_Triggered_By_Abort), Loc);
-
- -- Generate:
-
- -- Abort_Id : constant Boolean := <A_Expr>;
-
- Append_To (Decls,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Data.Abort_Id,
- Constant_Present => True,
- Object_Definition => New_Reference_To (Standard_Boolean, Loc),
- Expression => A_Expr));
-
- else
- -- No abort, .NET/JVM or library-level finalizers
-
- Data.Abort_Id := Empty;
- end if;
-
- if Exception_Extra_Info then
- Data.E_Id := Make_Temporary (Loc, 'E');
-
- -- Generate:
-
- -- E_Id : Exception_Occurrence;
-
- E_Decl :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Data.E_Id,
- Object_Definition =>
- New_Reference_To (RTE (RE_Exception_Occurrence), Loc));
- Set_No_Initialization (E_Decl);
-
- Append_To (Decls, E_Decl);
-
- else
- Data.E_Id := Empty;
- end if;
-
- -- Generate:
-
- -- Raised_Id : Boolean := False;
-
- Append_To (Decls,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Data.Raised_Id,
- Object_Definition => New_Reference_To (Standard_Boolean, Loc),
- Expression => New_Reference_To (Standard_False, Loc)));
- end Build_Object_Declarations;
-
- ---------------------------
- -- Build_Raise_Statement --
- ---------------------------
-
- function Build_Raise_Statement
- (Data : Finalization_Exception_Data) return Node_Id
- is
- Stmt : Node_Id;
- Expr : Node_Id;
-
- begin
- -- Standard run-time and .NET/JVM targets use the specialized routine
- -- Raise_From_Controlled_Operation.
-
- if Exception_Extra_Info
- and then RTE_Available (RE_Raise_From_Controlled_Operation)
- then
- Stmt :=
- Make_Procedure_Call_Statement (Data.Loc,
- Name =>
- New_Reference_To
- (RTE (RE_Raise_From_Controlled_Operation), Data.Loc),
- Parameter_Associations =>
- New_List (New_Reference_To (Data.E_Id, Data.Loc)));
-
- -- Restricted run-time: exception messages are not supported and hence
- -- Raise_From_Controlled_Operation is not supported. Raise Program_Error
- -- instead.
-
- else
- Stmt :=
- Make_Raise_Program_Error (Data.Loc,
- Reason => PE_Finalize_Raised_Exception);
- end if;
-
- -- Generate:
-
- -- Raised_Id and then not Abort_Id
- -- <or>
- -- Raised_Id
-
- Expr := New_Reference_To (Data.Raised_Id, Data.Loc);
-
- if Present (Data.Abort_Id) then
- Expr := Make_And_Then (Data.Loc,
- Left_Opnd => Expr,
- Right_Opnd =>
- Make_Op_Not (Data.Loc,
- Right_Opnd => New_Reference_To (Data.Abort_Id, Data.Loc)));
- end if;
-
- -- Generate:
-
- -- if Raised_Id and then not Abort_Id then
- -- Raise_From_Controlled_Operation (E_Id);
- -- <or>
- -- raise Program_Error; -- restricted runtime
- -- end if;
-
- return
- Make_If_Statement (Data.Loc,
- Condition => Expr,
- Then_Statements => New_List (Stmt));
- end Build_Raise_Statement;
-
- -----------------------------
- -- Build_Record_Deep_Procs --
- -----------------------------
-
- 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_Immutably_Limited_Type (Typ) then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Adjust_Case,
- Typ => Typ,
- Stmts => Make_Deep_Record_Body (Adjust_Case, Typ)));
- end if;
-
- -- Do not generate Deep_Finalize and Finalize_Address if finalization is
- -- suppressed since these routine will not be used.
-
- if not Restriction_Active (No_Finalization) then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Finalize_Case,
- Typ => Typ,
- Stmts => Make_Deep_Record_Body (Finalize_Case, Typ)));
-
- -- Create TSS primitive Finalize_Address for non-VM targets. JVM and
- -- .NET do not support address arithmetic and unchecked conversions.
-
- if VM_Target = No_VM then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Address_Case,
- Typ => Typ,
- Stmts => Make_Deep_Record_Body (Address_Case, Typ)));
- end if;
- end if;
- end Build_Record_Deep_Procs;
-
- -------------------
- -- Cleanup_Array --
- -------------------
-
- 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;
- -- Generate the code to finalize the task or protected subcomponents
- -- of a single component of the array.
-
- function Free_One_Dimension (Dim : Int) return List_Id;
- -- Generate a loop over one dimension of the array
-
- --------------------
- -- Free_Component --
- --------------------
-
- function Free_Component return List_Id is
- Stmts : List_Id := New_List;
- Tsk : Node_Id;
- C_Typ : constant Entity_Id := Component_Type (Typ);
-
- begin
- -- Component type is known to contain tasks or protected objects
-
- 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;
-
- ------------------------
- -- Free_One_Dimension --
- ------------------------
-
- function Free_One_Dimension (Dim : Int) return List_Id is
- Index : Entity_Id;
-
- begin
- if Dim > Number_Dimensions (Typ) then
- return Free_Component;
-
- -- Here we generate the required loop
-
- else
- Index := Make_Temporary (Loc, '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;
-
- -- Start of processing for Cleanup_Array
-
- begin
- return Free_One_Dimension (1);
- end Cleanup_Array;
-
- --------------------
- -- Cleanup_Record --
- --------------------
-
- 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
- -- For now, do not attempt to free a component that may appear in a
- -- variant, and instead issue a warning. Doing this "properly" would
- -- require building a case statement and would be quite a mess. Note
- -- that the RM only requires that free "work" for the case of a task
- -- access value, so already we go way beyond this in that we deal
- -- with the array case and non-discriminated record cases.
-
- 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
-
- -- Recurse, by generating the prefix of the argument to
- -- the eventual cleanup call.
-
- 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;
-
- ------------------------------
- -- Cleanup_Protected_Object --
- ------------------------------
-
- function Cleanup_Protected_Object
- (N : Node_Id;
- Ref : Node_Id) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (N);
-
- begin
- -- For restricted run-time libraries (Ravenscar), tasks are
- -- non-terminating, and protected objects can only appear at library
- -- level, so we do not want finalization of protected objects.
-
- if Restricted_Profile then
- return Empty;
-
- else
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Finalize_Protection), Loc),
- Parameter_Associations => New_List (Concurrent_Ref (Ref)));
- end if;
- end Cleanup_Protected_Object;
-
- ------------------
- -- Cleanup_Task --
- ------------------
-
- function Cleanup_Task
- (N : Node_Id;
- Ref : Node_Id) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (N);
-
- begin
- -- For restricted run-time libraries (Ravenscar), tasks are
- -- non-terminating and they can only appear at library level, so we do
- -- not want finalization of task objects.
-
- if Restricted_Profile then
- return Empty;
-
- else
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Free_Task), Loc),
- Parameter_Associations => New_List (Concurrent_Ref (Ref)));
- end if;
- end Cleanup_Task;
-
- ------------------------------
- -- Check_Visibly_Controlled --
- ------------------------------
-
- 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 Present (Overridden_Operation (E))
- then
- -- We know that the explicit operation on the type does not override
- -- the inherited operation of the parent, and that the derivation
- -- is from a private type that is not visibly controlled.
-
- Parent_Type := Etype (Typ);
- Op := Find_Prim_Op (Parent_Type, Name_Of (Prim));
-
- if Present (Op) then
- E := Op;
-
- -- Wrap the object to be initialized into the proper
- -- unchecked conversion, to be compatible with the operation
- -- to be called.
-
- 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;
-
- -------------------------------
- -- CW_Or_Has_Controlled_Part --
- -------------------------------
-
- function CW_Or_Has_Controlled_Part (T : Entity_Id) return Boolean is
- begin
- return Is_Class_Wide_Type (T) or else Needs_Finalization (T);
- end CW_Or_Has_Controlled_Part;
-
- ------------------
- -- Convert_View --
- ------------------
-
- 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_In (Arg, N_Type_Conversion, N_Unchecked_Type_Conversion) then
- Atyp := Entity (Subtype_Mark (Arg));
- else
- Atyp := Etype (Arg);
- end if;
-
- if Is_Abstract_Subprogram (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 Base_Type (Underlying_Type (Atyp)) =
- Base_Type (Underlying_Type (Ftyp))
- then
- return Unchecked_Convert_To (Ftyp, Arg);
-
- -- If the argument is already a conversion, as generated by
- -- Make_Init_Call, set the target type to the type of the formal
- -- directly, to avoid spurious typing problems.
-
- elsif Nkind_In (Arg, N_Unchecked_Type_Conversion, 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;
-
- ------------------------
- -- Enclosing_Function --
- ------------------------
-
- function Enclosing_Function (E : Entity_Id) return Entity_Id is
- Func_Id : Entity_Id;
-
- begin
- Func_Id := E;
- while Present (Func_Id)
- and then Func_Id /= Standard_Standard
- loop
- if Ekind (Func_Id) = E_Function then
- return Func_Id;
- end if;
-
- Func_Id := Scope (Func_Id);
- end loop;
-
- return Empty;
- end Enclosing_Function;
-
- -------------------------------
- -- Establish_Transient_Scope --
- -------------------------------
-
- -- This procedure is called each time a transient block has to be inserted
- -- that is to say for each call to a function with unconstrained or tagged
- -- result. It creates a new scope on the stack scope in order to enclose
- -- all transient variables generated
-
- procedure Establish_Transient_Scope (N : Node_Id; Sec_Stack : Boolean) is
- Loc : constant Source_Ptr := Sloc (N);
- Wrap_Node : Node_Id;
-
- begin
- -- Do not create a transient scope if we are already inside one
-
- for S in reverse Scope_Stack.First .. Scope_Stack.Last loop
- if Scope_Stack.Table (S).Is_Transient then
- if Sec_Stack then
- Set_Uses_Sec_Stack (Scope_Stack.Table (S).Entity);
- end if;
-
- return;
-
- -- If we have encountered Standard there are no enclosing
- -- transient scopes.
-
- elsif Scope_Stack.Table (S).Entity = Standard_Standard then
- exit;
- end if;
- end loop;
-
- Wrap_Node := Find_Node_To_Be_Wrapped (N);
-
- -- Case of no wrap node, false alert, no transient scope needed
-
- if No (Wrap_Node) then
- null;
-
- -- If the node to wrap is an iteration_scheme, the expression is
- -- one of the bounds, and the expansion will make an explicit
- -- declaration for it (see Analyze_Iteration_Scheme, sem_ch5.adb),
- -- so do not apply any transformations here. Same for an Ada 2012
- -- iterator specification, where a block is created for the expression
- -- that build the container.
-
- elsif Nkind_In (Wrap_Node, N_Iteration_Scheme,
- N_Iterator_Specification)
- then
- null;
-
- -- In formal verification mode, if the node to wrap is a pragma check,
- -- this node and enclosed expression are not expanded, so do not apply
- -- any transformations here.
-
- elsif Alfa_Mode
- and then Nkind (Wrap_Node) = N_Pragma
- and then Get_Pragma_Id (Wrap_Node) = Pragma_Check
- then
- null;
-
- else
- Push_Scope (New_Internal_Entity (E_Block, Current_Scope, Loc, 'B'));
- Set_Scope_Is_Transient;
-
- if Sec_Stack 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;
-
- ----------------------------
- -- Expand_Cleanup_Actions --
- ----------------------------
-
- procedure Expand_Cleanup_Actions (N : Node_Id) is
- Scop : constant Entity_Id := Current_Scope;
-
- Is_Asynchronous_Call : constant Boolean :=
- Nkind (N) = N_Block_Statement
- and then Is_Asynchronous_Call_Block (N);
- Is_Master : constant Boolean :=
- Nkind (N) /= N_Entry_Body
- and then Is_Task_Master (N);
- Is_Protected_Body : 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_Task_Body : constant Boolean :=
- Nkind (Original_Node (N)) = N_Task_Body;
- Needs_Sec_Stack_Mark : constant Boolean :=
- Uses_Sec_Stack (Scop)
- and then
- not Sec_Stack_Needed_For_Return (Scop)
- and then VM_Target = No_VM;
-
- Actions_Required : constant Boolean :=
- Requires_Cleanup_Actions (N, True)
- or else Is_Asynchronous_Call
- or else Is_Master
- or else Is_Protected_Body
- or else Is_Task_Allocation
- or else Is_Task_Body
- or else Needs_Sec_Stack_Mark;
-
- HSS : Node_Id := Handled_Statement_Sequence (N);
- Loc : Source_Ptr;
-
- procedure Wrap_HSS_In_Block;
- -- Move HSS inside a new block along with the original exception
- -- handlers. Make the newly generated block the sole statement of HSS.
-
- -----------------------
- -- Wrap_HSS_In_Block --
- -----------------------
-
- procedure Wrap_HSS_In_Block is
- Block : Node_Id;
- End_Lab : Node_Id;
-
- begin
- -- Preserve end label to provide proper cross-reference information
-
- End_Lab := End_Label (HSS);
- Block :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence => HSS);
-
- -- Signal the finalization machinery that this particular block
- -- contains the original context.
-
- Set_Is_Finalization_Wrapper (Block);
-
- Set_Handled_Statement_Sequence (N,
- Make_Handled_Sequence_Of_Statements (Loc, New_List (Block)));
- HSS := Handled_Statement_Sequence (N);
-
- Set_First_Real_Statement (HSS, Block);
- Set_End_Label (HSS, End_Lab);
-
- -- Comment needed here, see RH for 1.306 ???
-
- if Nkind (N) = N_Subprogram_Body then
- Set_Has_Nested_Block_With_Handler (Scop);
- end if;
- end Wrap_HSS_In_Block;
-
- -- Start of processing for Expand_Cleanup_Actions
-
- begin
- -- The current construct does not need any form of servicing
-
- if not Actions_Required then
- return;
-
- -- If the current node is a rewritten task body and the descriptors have
- -- not been delayed (due to some nested instantiations), do not generate
- -- redundant cleanup actions.
-
- elsif Is_Task_Body
- and then Nkind (N) = N_Subprogram_Body
- and then not Delay_Subprogram_Descriptors (Corresponding_Spec (N))
- then
- return;
- end if;
-
- declare
- Decls : List_Id := Declarations (N);
- Fin_Id : Entity_Id;
- Mark : Entity_Id := Empty;
- New_Decls : List_Id;
- Old_Poll : Boolean;
-
- begin
- -- If we are generating expanded code for debugging purposes, use the
- -- Sloc of the point of insertion for the cleanup code. The Sloc will
- -- be updated subsequently to reference the proper line in .dg files.
- -- If we are not debugging generated code, use No_Location instead,
- -- so that no debug information is generated for the cleanup code.
- -- This makes the behavior of the NEXT command in GDB monotonic, and
- -- makes the placement of breakpoints more accurate.
-
- if Debug_Generated_Code then
- Loc := Sloc (Scop);
- else
- Loc := No_Location;
- end if;
-
- -- Set polling off. The finalization and cleanup code is executed
- -- with aborts deferred.
-
- Old_Poll := Polling_Required;
- Polling_Required := False;
-
- -- A task activation call has already been built for a task
- -- allocation block.
-
- if not Is_Task_Allocation then
- Build_Task_Activation_Call (N);
- end if;
-
- if Is_Master then
- Establish_Task_Master (N);
- end if;
-
- New_Decls := New_List;
-
- -- If secondary stack is in use, generate:
- --
- -- Mnn : constant Mark_Id := SS_Mark;
-
- -- Suppress calls to SS_Mark and SS_Release if VM_Target, since the
- -- secondary stack is never used on a VM.
-
- if Needs_Sec_Stack_Mark then
- Mark := Make_Temporary (Loc, '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 (Scop, False);
- end if;
-
- -- If exception handlers are present, wrap the sequence of statements
- -- in a block since it is not possible to have exception handlers and
- -- an At_End handler in the same construct.
-
- if Present (Exception_Handlers (HSS)) then
- Wrap_HSS_In_Block;
-
- -- Ensure that the First_Real_Statement field is set
-
- elsif No (First_Real_Statement (HSS)) then
- Set_First_Real_Statement (HSS, First (Statements (HSS)));
- end if;
-
- -- Do not move the Activation_Chain declaration in the context of
- -- task allocation blocks. Task allocation blocks use _chain in their
- -- cleanup handlers and gigi complains if it is declared in the
- -- sequence of statements of the scope that declares the handler.
-
- if Is_Task_Allocation then
- declare
- Chain : constant Entity_Id := Activation_Chain_Entity (N);
- Decl : Node_Id;
-
- begin
- Decl := First (Decls);
- while Nkind (Decl) /= N_Object_Declaration
- or else Defining_Identifier (Decl) /= Chain
- loop
- Next (Decl);
-
- -- A task allocation block should always include a _chain
- -- declaration.
-
- pragma Assert (Present (Decl));
- end loop;
-
- Remove (Decl);
- Prepend_To (New_Decls, Decl);
- end;
- end if;
-
- -- Ensure the presence of a declaration list in order to successfully
- -- append all original statements to it.
-
- if No (Decls) then
- Set_Declarations (N, New_List);
- Decls := Declarations (N);
- end if;
-
- -- Move the declarations into the sequence of statements in order to
- -- have them protected by the At_End handler. It may seem weird to
- -- put declarations in the sequence of statement but in fact nothing
- -- forbids that at the tree level.
-
- Append_List_To (Decls, Statements (HSS));
- Set_Statements (HSS, Decls);
-
- -- Reset the Sloc of the handled statement sequence to properly
- -- reflect the new initial "statement" in the sequence.
-
- Set_Sloc (HSS, Sloc (First (Decls)));
-
- -- The declarations of finalizer spec and auxiliary variables replace
- -- the old declarations that have been moved inward.
-
- Set_Declarations (N, New_Decls);
- Analyze_Declarations (New_Decls);
-
- -- Generate finalization calls for all controlled objects appearing
- -- in the statements of N. Add context specific cleanup for various
- -- constructs.
-
- Build_Finalizer
- (N => N,
- Clean_Stmts => Build_Cleanup_Statements (N),
- Mark_Id => Mark,
- Top_Decls => New_Decls,
- Defer_Abort => Nkind (Original_Node (N)) = N_Task_Body
- or else Is_Master,
- Fin_Id => Fin_Id);
-
- if Present (Fin_Id) then
- Build_Finalizer_Call (N, Fin_Id);
- end if;
-
- -- Restore saved polling mode
-
- Polling_Required := Old_Poll;
- end;
- end Expand_Cleanup_Actions;
-
- ---------------------------
- -- Expand_N_Package_Body --
- ---------------------------
-
- -- Add call to Activate_Tasks if body is an activator (actual processing
- -- is in chapter 9).
-
- -- Generate subprogram descriptor for elaboration routine
-
- -- Encode entity names in package body
-
- procedure Expand_N_Package_Body (N : Node_Id) is
- Spec_Ent : constant Entity_Id := Corresponding_Spec (N);
- Fin_Id : Entity_Id;
-
- begin
- -- This is done only for non-generic packages
-
- if Ekind (Spec_Ent) = E_Package then
- Push_Scope (Corresponding_Spec (N));
-
- -- Build dispatch tables of library level tagged types
-
- if Tagged_Type_Expansion
- and then Is_Library_Level_Entity (Spec_Ent)
- then
- Build_Static_Dispatch_Tables (N);
- end if;
-
- Build_Task_Activation_Call (N);
- Pop_Scope;
- end if;
-
- Set_Elaboration_Flag (N, Corresponding_Spec (N));
- Set_In_Package_Body (Spec_Ent, False);
-
- -- Set to encode entity names in package body before gigi is called
-
- Qualify_Entity_Names (N);
-
- if Ekind (Spec_Ent) /= E_Generic_Package then
- Build_Finalizer
- (N => N,
- Clean_Stmts => No_List,
- Mark_Id => Empty,
- Top_Decls => No_List,
- Defer_Abort => False,
- Fin_Id => Fin_Id);
-
- if Present (Fin_Id) then
- declare
- Body_Ent : Node_Id := Defining_Unit_Name (N);
-
- begin
- if Nkind (Body_Ent) = N_Defining_Program_Unit_Name then
- Body_Ent := Defining_Identifier (Body_Ent);
- end if;
-
- Set_Finalizer (Body_Ent, Fin_Id);
- end;
- end if;
- end if;
- end Expand_N_Package_Body;
-
- ----------------------------------
- -- Expand_N_Package_Declaration --
- ----------------------------------
-
- -- Add call to Activate_Tasks if there are tasks declared and the package
- -- has no body. Note that in Ada 83 this may result in premature activation
- -- of some tasks, given that we cannot tell whether a body will eventually
- -- appear.
-
- procedure Expand_N_Package_Declaration (N : Node_Id) is
- Id : constant Entity_Id := Defining_Entity (N);
- Spec : constant Node_Id := Specification (N);
- Decls : List_Id;
- Fin_Id : Entity_Id;
-
- No_Body : Boolean := False;
- -- True in the case of a package declaration that is a compilation
- -- unit and for which no associated body will be compiled in this
- -- compilation.
-
- begin
- -- Case of a package declaration other than a compilation unit
-
- if Nkind (Parent (N)) /= N_Compilation_Unit then
- null;
-
- -- Case of a compilation unit that does not require a body
-
- elsif not Body_Required (Parent (N))
- and then not Unit_Requires_Body (Id)
- then
- No_Body := True;
-
- -- Special case of generating calling stubs for a remote call interface
- -- package: even though the package declaration requires one, the body
- -- won't be processed in this compilation (so any stubs for RACWs
- -- declared in the package must be generated here, along with the spec).
-
- elsif Parent (N) = Cunit (Main_Unit)
- and then Is_Remote_Call_Interface (Id)
- and then Distribution_Stub_Mode = Generate_Caller_Stub_Body
- then
- No_Body := True;
- end if;
-
- -- For a nested instance, delay processing until freeze point
-
- if Has_Delayed_Freeze (Id)
- and then Nkind (Parent (N)) /= N_Compilation_Unit
- then
- return;
- end if;
-
- -- For a package declaration that implies no associated body, generate
- -- task activation call and RACW supporting bodies now (since we won't
- -- have a specific separate compilation unit for that).
-
- if No_Body then
- Push_Scope (Id);
-
- if Has_RACW (Id) then
-
- -- Generate RACW subprogram bodies
-
- Decls := Private_Declarations (Spec);
-
- if No (Decls) then
- Decls := Visible_Declarations (Spec);
- end if;
-
- if No (Decls) then
- Decls := New_List;
- Set_Visible_Declarations (Spec, Decls);
- end if;
-
- Append_RACW_Bodies (Decls, Id);
- Analyze_List (Decls);
- end if;
-
- if Present (Activation_Chain_Entity (N)) then
-
- -- Generate task activation call as last step of elaboration
-
- Build_Task_Activation_Call (N);
- end if;
-
- Pop_Scope;
- end if;
-
- -- Build dispatch tables of library level tagged types
-
- if Tagged_Type_Expansion
- and then (Is_Compilation_Unit (Id)
- or else (Is_Generic_Instance (Id)
- and then Is_Library_Level_Entity (Id)))
- then
- Build_Static_Dispatch_Tables (N);
- end if;
-
- -- Note: it is not necessary to worry about generating a subprogram
- -- descriptor, since the only way to get exception handlers into a
- -- package spec is to include instantiations, and that would cause
- -- generation of subprogram descriptors to be delayed in any case.
-
- -- Set to encode entity names in package spec before gigi is called
-
- Qualify_Entity_Names (N);
-
- if Ekind (Id) /= E_Generic_Package then
- Build_Finalizer
- (N => N,
- Clean_Stmts => No_List,
- Mark_Id => Empty,
- Top_Decls => No_List,
- Defer_Abort => False,
- Fin_Id => Fin_Id);
-
- Set_Finalizer (Id, Fin_Id);
- end if;
- end Expand_N_Package_Declaration;
-
- -----------------------------
- -- Find_Node_To_Be_Wrapped --
- -----------------------------
-
- 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
-
- -- Simple statement can be wrapped
-
- when N_Pragma =>
- return The_Parent;
-
- -- Usually assignments are good candidate for wrapping except
- -- when they have been generated as part of a controlled aggregate
- -- where the wrapping should take place more globally.
-
- when N_Assignment_Statement =>
- if No_Ctrl_Actions (The_Parent) then
- null;
- else
- return The_Parent;
- end if;
-
- -- An entry call statement is a special case if it occurs in the
- -- context of a Timed_Entry_Call. In this case we wrap the entire
- -- timed entry call.
-
- when N_Entry_Call_Statement |
- N_Procedure_Call_Statement =>
- if Nkind (Parent (The_Parent)) = N_Entry_Call_Alternative
- and then Nkind_In (Parent (Parent (The_Parent)),
- N_Timed_Entry_Call,
- N_Conditional_Entry_Call)
- then
- return Parent (Parent (The_Parent));
- else
- return The_Parent;
- end if;
-
- -- Object declarations are also a boundary for the transient scope
- -- even if they are not really wrapped. For further details, see
- -- Wrap_Transient_Declaration.
-
- when N_Object_Declaration |
- N_Object_Renaming_Declaration |
- N_Subtype_Declaration =>
- return The_Parent;
-
- -- The expression itself is to be wrapped if its parent is a
- -- compound statement or any other statement where the expression
- -- is known to be scalar
-
- 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;
-
- -- A raise statement can be wrapped. This will arise when the
- -- expression in a raise_with_expression uses the secondary
- -- stack, for example.
-
- when N_Raise_Statement =>
- return The_Parent;
-
- -- If the expression is within the iteration scheme of a loop,
- -- we must create a declaration for it, followed by an assignment
- -- in order to have a usable statement to wrap.
-
- when N_Loop_Parameter_Specification =>
- return Parent (The_Parent);
-
- -- The following nodes contains "dummy calls" which don't need to
- -- be wrapped.
-
- when N_Parameter_Specification |
- N_Discriminant_Specification |
- N_Component_Declaration =>
- return Empty;
-
- -- The return statement is not to be wrapped when the function
- -- itself needs wrapping at the outer-level
-
- when N_Simple_Return_Statement =>
- declare
- Applies_To : constant Entity_Id :=
- Return_Applies_To
- (Return_Statement_Entity (The_Parent));
- Return_Type : constant Entity_Id := Etype (Applies_To);
- begin
- if Requires_Transient_Scope (Return_Type) then
- return Empty;
- else
- return The_Parent;
- end if;
- end;
-
- -- If we leave a scope without having been able to find a node to
- -- wrap, something is going wrong but this can happen in error
- -- situation that are not detected yet (such as a dynamic string
- -- in a pragma export)
-
- when N_Subprogram_Body |
- N_Package_Declaration |
- N_Package_Body |
- N_Block_Statement =>
- return Empty;
-
- -- Otherwise continue the search
-
- when others =>
- null;
- end case;
- end loop;
- end Find_Node_To_Be_Wrapped;
-
- -------------------------------------
- -- Get_Global_Pool_For_Access_Type --
- -------------------------------------
-
- function Get_Global_Pool_For_Access_Type (T : Entity_Id) return Entity_Id is
- begin
- -- Access types whose size is smaller than System.Address size can exist
- -- only on VMS. We can't use the usual global pool which returns an
- -- object of type Address as truncation will make it invalid. To handle
- -- this case, VMS has a dedicated global pool that returns addresses
- -- that fit into 32 bit accesses.
-
- if Opt.True_VMS_Target and then Esize (T) = 32 then
- return RTE (RE_Global_Pool_32_Object);
- else
- return RTE (RE_Global_Pool_Object);
- end if;
- end Get_Global_Pool_For_Access_Type;
-
- ----------------------------------
- -- Has_New_Controlled_Component --
- ----------------------------------
-
- 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 Needs_Finalization (Etype (Comp))
- then
- return True;
- end if;
-
- Next_Component (Comp);
- end loop;
-
- return False;
- end Has_New_Controlled_Component;
-
- ---------------------------------
- -- Has_Simple_Protected_Object --
- ---------------------------------
-
- function Has_Simple_Protected_Object (T : Entity_Id) return Boolean is
- begin
- if Has_Task (T) then
- return False;
-
- elsif 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
- declare
- Comp : Entity_Id;
-
- begin
- 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;
- end;
-
- else
- return False;
- end if;
- end Has_Simple_Protected_Object;
-
- ------------------------------------
- -- Insert_Actions_In_Scope_Around --
- ------------------------------------
-
- procedure Insert_Actions_In_Scope_Around (N : Node_Id) is
- After : constant List_Id :=
- Scope_Stack.Table (Scope_Stack.Last).Actions_To_Be_Wrapped_After;
- Before : constant List_Id :=
- Scope_Stack.Table (Scope_Stack.Last).Actions_To_Be_Wrapped_Before;
- -- Note: We used to use renamings of Scope_Stack.Table (Scope_Stack.
- -- Last), but this was incorrect as Process_Transient_Object may
- -- introduce new scopes and cause a reallocation of Scope_Stack.Table.
-
- procedure Process_Transient_Objects
- (First_Object : Node_Id;
- Last_Object : Node_Id;
- Related_Node : Node_Id);
- -- First_Object and Last_Object define a list which contains potential
- -- controlled transient objects. Finalization flags are inserted before
- -- First_Object and finalization calls are inserted after Last_Object.
- -- Related_Node is the node for which transient objects have been
- -- created.
-
- -------------------------------
- -- Process_Transient_Objects --
- -------------------------------
-
- procedure Process_Transient_Objects
- (First_Object : Node_Id;
- Last_Object : Node_Id;
- Related_Node : Node_Id)
- is
- function Requires_Hooking return Boolean;
- -- Determine whether the context requires transient variable export
- -- to the outer finalizer. This scenario arises when the context may
- -- raise an exception.
-
- ----------------------
- -- Requires_Hooking --
- ----------------------
-
- function Requires_Hooking return Boolean is
- begin
- -- The context is either a procedure or function call or an object
- -- declaration initialized by a function call. Note that in the
- -- latter case, a function call that returns on the secondary
- -- stack is usually rewritten into something else. Its proper
- -- detection requires examination of the original initialization
- -- expression.
-
- return Nkind (N) in N_Subprogram_Call
- or else (Nkind (N) = N_Object_Declaration
- and then Nkind (Original_Node (Expression (N))) =
- N_Function_Call);
- end Requires_Hooking;
-
- -- Local variables
-
- Must_Hook : constant Boolean := Requires_Hooking;
- Built : Boolean := False;
- Desig_Typ : Entity_Id;
- Fin_Block : Node_Id;
- Fin_Data : Finalization_Exception_Data;
- Fin_Decls : List_Id;
- Last_Fin : Node_Id := Empty;
- Loc : Source_Ptr;
- Obj_Id : Entity_Id;
- Obj_Ref : Node_Id;
- Obj_Typ : Entity_Id;
- Prev_Fin : Node_Id := Empty;
- Stmt : Node_Id;
- Stmts : List_Id;
- Temp_Id : Entity_Id;
-
- -- Start of processing for Process_Transient_Objects
-
- begin
- -- Examine all objects in the list First_Object .. Last_Object
-
- Stmt := First_Object;
- while Present (Stmt) loop
- if Nkind (Stmt) = N_Object_Declaration
- and then Analyzed (Stmt)
- and then Is_Finalizable_Transient (Stmt, N)
-
- -- Do not process the node to be wrapped since it will be
- -- handled by the enclosing finalizer.
-
- and then Stmt /= Related_Node
- then
- Loc := Sloc (Stmt);
- Obj_Id := Defining_Identifier (Stmt);
- Obj_Typ := Base_Type (Etype (Obj_Id));
- Desig_Typ := Obj_Typ;
-
- Set_Is_Processed_Transient (Obj_Id);
-
- -- Handle access types
-
- if Is_Access_Type (Desig_Typ) then
- Desig_Typ := Available_View (Designated_Type (Desig_Typ));
- end if;
-
- -- Create the necessary entities and declarations the first
- -- time around.
-
- if not Built then
- Fin_Decls := New_List;
-
- Build_Object_Declarations (Fin_Data, Fin_Decls, Loc);
-
- Built := True;
- end if;
-
- -- Transient variables associated with subprogram calls need
- -- extra processing. These variables are usually created right
- -- before the call and finalized immediately after the call.
- -- If an exception occurs during the call, the clean up code
- -- is skipped due to the sudden change in control and the
- -- transient is never finalized.
-
- -- To handle this case, such variables are "exported" to the
- -- enclosing sequence of statements where their corresponding
- -- "hooks" are picked up by the finalization machinery.
-
- if Must_Hook then
- declare
- Expr : Node_Id;
- Ptr_Id : Entity_Id;
-
- begin
- -- Step 1: Create an access type which provides a
- -- reference to the transient object. Generate:
-
- -- Ann : access [all] <Desig_Typ>;
-
- Ptr_Id := Make_Temporary (Loc, 'A');
-
- Insert_Action (Stmt,
- Make_Full_Type_Declaration (Loc,
- Defining_Identifier => Ptr_Id,
- Type_Definition =>
- Make_Access_To_Object_Definition (Loc,
- All_Present =>
- Ekind (Obj_Typ) = E_General_Access_Type,
- Subtype_Indication =>
- New_Reference_To (Desig_Typ, Loc))));
-
- -- Step 2: Create a temporary which acts as a hook to
- -- the transient object. Generate:
-
- -- Temp : Ptr_Id := null;
-
- Temp_Id := Make_Temporary (Loc, 'T');
-
- Insert_Action (Stmt,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Temp_Id,
- Object_Definition =>
- New_Reference_To (Ptr_Id, Loc)));
-
- -- Mark the temporary as a transient hook. This signals
- -- the machinery in Build_Finalizer to recognize this
- -- special case.
-
- Set_Status_Flag_Or_Transient_Decl (Temp_Id, Stmt);
-
- -- Step 3: Hook the transient object to the temporary
-
- if Is_Access_Type (Obj_Typ) then
- Expr :=
- Convert_To (Ptr_Id, New_Reference_To (Obj_Id, Loc));
- else
- Expr :=
- Make_Attribute_Reference (Loc,
- Prefix => New_Reference_To (Obj_Id, Loc),
- Attribute_Name => Name_Unrestricted_Access);
- end if;
-
- -- Generate:
- -- Temp := Ptr_Id (Obj_Id);
- -- <or>
- -- Temp := Obj_Id'Unrestricted_Access;
-
- Insert_After_And_Analyze (Stmt,
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Temp_Id, Loc),
- Expression => Expr));
- end;
- end if;
-
- Stmts := New_List;
-
- -- The transient object is about to be finalized by the clean
- -- up code following the subprogram call. In order to avoid
- -- double finalization, clear the hook.
-
- -- Generate:
- -- Temp := null;
-
- if Must_Hook then
- Append_To (Stmts,
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Temp_Id, Loc),
- Expression => Make_Null (Loc)));
- end if;
-
- -- Generate:
- -- [Deep_]Finalize (Obj_Ref);
-
- Obj_Ref := New_Reference_To (Obj_Id, Loc);
-
- if Is_Access_Type (Obj_Typ) then
- Obj_Ref := Make_Explicit_Dereference (Loc, Obj_Ref);
- end if;
-
- Append_To (Stmts,
- Make_Final_Call (Obj_Ref => Obj_Ref, Typ => Desig_Typ));
-
- -- Generate:
- -- [Temp := null;]
- -- begin
- -- [Deep_]Finalize (Obj_Ref);
-
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence
- -- (Enn, Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- Fin_Block :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Stmts,
- Exception_Handlers => New_List (
- Build_Exception_Handler (Fin_Data))));
-
- -- The single raise statement must be inserted after all the
- -- finalization blocks, and we put everything into a wrapper
- -- block to clearly expose the construct to the back-end.
-
- if Present (Prev_Fin) then
- Insert_Before_And_Analyze (Prev_Fin, Fin_Block);
- else
- Insert_After_And_Analyze (Last_Object,
- Make_Block_Statement (Loc,
- Declarations => Fin_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Block))));
-
- Last_Fin := Fin_Block;
- end if;
-
- Prev_Fin := Fin_Block;
- end if;
-
- -- Terminate the scan after the last object has been processed to
- -- avoid touching unrelated code.
-
- if Stmt = Last_Object then
- exit;
- end if;
-
- Next (Stmt);
- end loop;
-
- -- Generate:
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
-
- if Built
- and then Present (Last_Fin)
- then
- Insert_After_And_Analyze (Last_Fin,
- Build_Raise_Statement (Fin_Data));
- end if;
- end Process_Transient_Objects;
-
- -- Start of processing for Insert_Actions_In_Scope_Around
-
- begin
- if No (Before) and then No (After) then
- return;
- end if;
-
- declare
- Node_To_Wrap : constant Node_Id := Node_To_Be_Wrapped;
- First_Obj : Node_Id;
- Last_Obj : Node_Id;
- Target : Node_Id;
-
- begin
- -- If the node to be wrapped is the trigger of an asynchronous
- -- select, it is not part of a statement list. The actions must be
- -- inserted before the select itself, which is part of some list of
- -- statements. Note that the triggering alternative includes the
- -- triggering statement and an optional statement list. If the node
- -- to be wrapped is part of that list, the normal insertion applies.
-
- if Nkind (Parent (Node_To_Wrap)) = N_Triggering_Alternative
- and then not Is_List_Member (Node_To_Wrap)
- then
- Target := Parent (Parent (Node_To_Wrap));
- else
- Target := N;
- end if;
-
- First_Obj := Target;
- Last_Obj := Target;
-
- -- Add all actions associated with a transient scope into the main
- -- tree. There are several scenarios here:
-
- -- +--- Before ----+ +----- After ---+
- -- 1) First_Obj ....... Target ........ Last_Obj
-
- -- 2) First_Obj ....... Target
-
- -- 3) Target ........ Last_Obj
-
- if Present (Before) then
-
- -- Flag declarations are inserted before the first object
-
- First_Obj := First (Before);
-
- Insert_List_Before (Target, Before);
- end if;
-
- if Present (After) then
-
- -- Finalization calls are inserted after the last object
-
- Last_Obj := Last (After);
-
- Insert_List_After (Target, After);
- end if;
-
- -- Check for transient controlled objects associated with Target and
- -- generate the appropriate finalization actions for them.
-
- Process_Transient_Objects
- (First_Object => First_Obj,
- Last_Object => Last_Obj,
- Related_Node => Target);
-
- -- Reset the action lists
-
- if Present (Before) then
- Scope_Stack.Table (Scope_Stack.Last).
- Actions_To_Be_Wrapped_Before := No_List;
- end if;
-
- if Present (After) then
- Scope_Stack.Table (Scope_Stack.Last).
- Actions_To_Be_Wrapped_After := No_List;
- end if;
- end;
- end Insert_Actions_In_Scope_Around;
-
- ------------------------------
- -- Is_Simple_Protected_Type --
- ------------------------------
-
- function Is_Simple_Protected_Type (T : Entity_Id) return Boolean is
- begin
- return
- Is_Protected_Type (T)
- and then not Uses_Lock_Free (T)
- and then not Has_Entries (T)
- and then Is_RTE (Find_Protection_Type (T), RE_Protection);
- end Is_Simple_Protected_Type;
-
- -----------------------
- -- Make_Adjust_Call --
- -----------------------
-
- function Make_Adjust_Call
- (Obj_Ref : Node_Id;
- Typ : Entity_Id;
- For_Parent : Boolean := False) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (Obj_Ref);
- Adj_Id : Entity_Id := Empty;
- Ref : Node_Id := Obj_Ref;
- Utyp : Entity_Id;
-
- begin
- -- Recover the proper type which contains Deep_Adjust
-
- if Is_Class_Wide_Type (Typ) then
- Utyp := Root_Type (Typ);
- else
- Utyp := Typ;
- end if;
-
- Utyp := Underlying_Type (Base_Type (Utyp));
- Set_Assignment_OK (Ref);
-
- -- Deal with non-tagged derivation of private views
-
- if Is_Untagged_Derivation (Typ) then
- Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
- Ref := Unchecked_Convert_To (Utyp, Ref);
- Set_Assignment_OK (Ref);
- end if;
-
- -- When dealing with the completion of a private type, use the base
- -- type instead.
-
- if Utyp /= Base_Type (Utyp) then
- pragma Assert (Is_Private_Type (Typ));
-
- Utyp := Base_Type (Utyp);
- Ref := Unchecked_Convert_To (Utyp, Ref);
- end if;
-
- -- Select the appropriate version of adjust
-
- if For_Parent then
- if Has_Controlled_Component (Utyp) then
- Adj_Id := Find_Prim_Op (Utyp, TSS_Deep_Adjust);
- end if;
-
- -- Class-wide types, interfaces and types with controlled components
-
- elsif Is_Class_Wide_Type (Typ)
- or else Is_Interface (Typ)
- or else Has_Controlled_Component (Utyp)
- then
- if Is_Tagged_Type (Utyp) then
- Adj_Id := Find_Prim_Op (Utyp, TSS_Deep_Adjust);
- else
- Adj_Id := TSS (Utyp, TSS_Deep_Adjust);
- end if;
-
- -- Derivations from [Limited_]Controlled
-
- elsif Is_Controlled (Utyp) then
- if Has_Controlled_Component (Utyp) then
- Adj_Id := Find_Prim_Op (Utyp, TSS_Deep_Adjust);
- else
- Adj_Id := Find_Prim_Op (Utyp, Name_Of (Adjust_Case));
- end if;
-
- -- Tagged types
-
- elsif Is_Tagged_Type (Utyp) then
- Adj_Id := Find_Prim_Op (Utyp, TSS_Deep_Adjust);
-
- else
- raise Program_Error;
- end if;
-
- if Present (Adj_Id) then
-
- -- If the object is unanalyzed, set its expected type for use in
- -- Convert_View in case an additional conversion is needed.
-
- if No (Etype (Ref))
- and then Nkind (Ref) /= N_Unchecked_Type_Conversion
- then
- Set_Etype (Ref, Typ);
- end if;
-
- -- The object reference may need another conversion depending on the
- -- type of the formal and that of the actual.
-
- if not Is_Class_Wide_Type (Typ) then
- Ref := Convert_View (Adj_Id, Ref);
- end if;
-
- return Make_Call (Loc, Adj_Id, New_Copy_Tree (Ref), For_Parent);
- else
- return Empty;
- end if;
- end Make_Adjust_Call;
-
- ----------------------
- -- Make_Attach_Call --
- ----------------------
-
- function Make_Attach_Call
- (Obj_Ref : Node_Id;
- Ptr_Typ : Entity_Id) return Node_Id
- is
- pragma Assert (VM_Target /= No_VM);
-
- Loc : constant Source_Ptr := Sloc (Obj_Ref);
- begin
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Attach), Loc),
- Parameter_Associations => New_List (
- New_Reference_To (Finalization_Master (Ptr_Typ), Loc),
- Unchecked_Convert_To (RTE (RE_Root_Controlled_Ptr), Obj_Ref)));
- end Make_Attach_Call;
-
- ----------------------
- -- Make_Detach_Call --
- ----------------------
-
- function Make_Detach_Call (Obj_Ref : Node_Id) return Node_Id is
- Loc : constant Source_Ptr := Sloc (Obj_Ref);
-
- begin
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Detach), Loc),
- Parameter_Associations => New_List (
- Unchecked_Convert_To (RTE (RE_Root_Controlled_Ptr), Obj_Ref)));
- end Make_Detach_Call;
-
- ---------------
- -- Make_Call --
- ---------------
-
- function Make_Call
- (Loc : Source_Ptr;
- Proc_Id : Entity_Id;
- Param : Node_Id;
- For_Parent : Boolean := False) return Node_Id
- is
- Params : constant List_Id := New_List (Param);
-
- begin
- -- When creating a call to Deep_Finalize for a _parent field of a
- -- derived type, disable the invocation of the nested Finalize by giving
- -- the corresponding flag a False value.
-
- if For_Parent then
- Append_To (Params, New_Reference_To (Standard_False, Loc));
- end if;
-
- return
- Make_Procedure_Call_Statement (Loc,
- Name => New_Reference_To (Proc_Id, Loc),
- Parameter_Associations => Params);
- end Make_Call;
-
- --------------------------
- -- Make_Deep_Array_Body --
- --------------------------
-
- function Make_Deep_Array_Body
- (Prim : Final_Primitives;
- Typ : Entity_Id) return List_Id
- is
- function Build_Adjust_Or_Finalize_Statements
- (Typ : Entity_Id) return List_Id;
- -- Create the statements necessary to adjust or finalize an array of
- -- controlled elements. Generate:
- --
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
- --
- -- E : Exception_Occurrence;
- -- Raised : Boolean := False;
- --
- -- begin
- -- for J1 in [reverse] Typ'First (1) .. Typ'Last (1) loop
- -- ^-- in the finalization case
- -- ...
- -- for Jn in [reverse] Typ'First (n) .. Typ'Last (n) loop
- -- begin
- -- [Deep_]Adjust / Finalize (V (J1, ..., Jn));
- --
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end loop;
- -- ...
- -- end loop;
- --
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- function Build_Initialize_Statements (Typ : Entity_Id) return List_Id;
- -- Create the statements necessary to initialize an array of controlled
- -- elements. Include a mechanism to carry out partial finalization if an
- -- exception occurs. Generate:
- --
- -- declare
- -- Counter : Integer := 0;
- --
- -- begin
- -- for J1 in V'Range (1) loop
- -- ...
- -- for JN in V'Range (N) loop
- -- begin
- -- [Deep_]Initialize (V (J1, ..., JN));
- --
- -- Counter := Counter + 1;
- --
- -- exception
- -- when others =>
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
- -- E : Exception_Occurence;
- -- Raised : Boolean := False;
-
- -- begin
- -- Counter :=
- -- V'Length (1) *
- -- V'Length (2) *
- -- ...
- -- V'Length (N) - Counter;
-
- -- for F1 in reverse V'Range (1) loop
- -- ...
- -- for FN in reverse V'Range (N) loop
- -- if Counter > 0 then
- -- Counter := Counter - 1;
- -- else
- -- begin
- -- [Deep_]Finalize (V (F1, ..., FN));
-
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
- -- end loop;
- -- ...
- -- end loop;
- -- end;
- --
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- --
- -- raise;
- -- end;
- -- end loop;
- -- end loop;
- -- end;
-
- function New_References_To
- (L : List_Id;
- Loc : Source_Ptr) return List_Id;
- -- Given a list of defining identifiers, return a list of references to
- -- the original identifiers, in the same order as they appear.
-
- -----------------------------------------
- -- Build_Adjust_Or_Finalize_Statements --
- -----------------------------------------
-
- function Build_Adjust_Or_Finalize_Statements
- (Typ : Entity_Id) return List_Id
- is
- Comp_Typ : constant Entity_Id := Component_Type (Typ);
- Index_List : constant List_Id := New_List;
- Loc : constant Source_Ptr := Sloc (Typ);
- Num_Dims : constant Int := Number_Dimensions (Typ);
- Finalizer_Decls : List_Id := No_List;
- Finalizer_Data : Finalization_Exception_Data;
- Call : Node_Id;
- Comp_Ref : Node_Id;
- Core_Loop : Node_Id;
- Dim : Int;
- J : Entity_Id;
- Loop_Id : Entity_Id;
- Stmts : List_Id;
-
- Exceptions_OK : constant Boolean :=
- not Restriction_Active (No_Exception_Propagation);
-
- procedure Build_Indices;
- -- Generate the indices used in the dimension loops
-
- -------------------
- -- Build_Indices --
- -------------------
-
- procedure Build_Indices is
- begin
- -- Generate the following identifiers:
- -- Jnn - for initialization
-
- for Dim in 1 .. Num_Dims loop
- Append_To (Index_List,
- Make_Defining_Identifier (Loc, New_External_Name ('J', Dim)));
- end loop;
- end Build_Indices;
-
- -- Start of processing for Build_Adjust_Or_Finalize_Statements
-
- begin
- Finalizer_Decls := New_List;
-
- Build_Indices;
- Build_Object_Declarations (Finalizer_Data, Finalizer_Decls, Loc);
-
- Comp_Ref :=
- Make_Indexed_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Expressions => New_References_To (Index_List, Loc));
- Set_Etype (Comp_Ref, Comp_Typ);
-
- -- Generate:
- -- [Deep_]Adjust (V (J1, ..., JN))
-
- if Prim = Adjust_Case then
- Call := Make_Adjust_Call (Obj_Ref => Comp_Ref, Typ => Comp_Typ);
-
- -- Generate:
- -- [Deep_]Finalize (V (J1, ..., JN))
-
- else pragma Assert (Prim = Finalize_Case);
- Call := Make_Final_Call (Obj_Ref => Comp_Ref, Typ => Comp_Typ);
- end if;
-
- -- Generate the block which houses the adjust or finalize call:
-
- -- <adjust or finalize call>; -- No_Exception_Propagation
-
- -- begin -- Exception handlers allowed
- -- <adjust or finalize call>
-
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- if Exceptions_OK then
- Core_Loop :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Call),
- Exception_Handlers => New_List (
- Build_Exception_Handler (Finalizer_Data))));
- else
- Core_Loop := Call;
- end if;
-
- -- Generate the dimension loops starting from the innermost one
-
- -- for Jnn in [reverse] V'Range (Dim) loop
- -- <core loop>
- -- end loop;
-
- J := Last (Index_List);
- Dim := Num_Dims;
- while Present (J) and then Dim > 0 loop
- Loop_Id := J;
- Prev (J);
- Remove (Loop_Id);
-
- Core_Loop :=
- Make_Loop_Statement (Loc,
- Iteration_Scheme =>
- Make_Iteration_Scheme (Loc,
- Loop_Parameter_Specification =>
- Make_Loop_Parameter_Specification (Loc,
- Defining_Identifier => Loop_Id,
- Discrete_Subtype_Definition =>
- Make_Attribute_Reference (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Attribute_Name => Name_Range,
- Expressions => New_List (
- Make_Integer_Literal (Loc, Dim))),
-
- Reverse_Present => Prim = Finalize_Case)),
-
- Statements => New_List (Core_Loop),
- End_Label => Empty);
-
- Dim := Dim - 1;
- end loop;
-
- -- Generate the block which contains the core loop, the declarations
- -- of the abort flag, the exception occurrence, the raised flag and
- -- the conditional raise:
-
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
-
- -- E : Exception_Occurrence;
- -- Raised : Boolean := False;
-
- -- begin
- -- <core loop>
-
- -- if Raised and then not Abort then -- Expection handlers OK
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- Stmts := New_List (Core_Loop);
-
- if Exceptions_OK then
- Append_To (Stmts,
- Build_Raise_Statement (Finalizer_Data));
- end if;
-
- return
- New_List (
- Make_Block_Statement (Loc,
- Declarations =>
- Finalizer_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
- end Build_Adjust_Or_Finalize_Statements;
-
- ---------------------------------
- -- Build_Initialize_Statements --
- ---------------------------------
-
- function Build_Initialize_Statements (Typ : Entity_Id) return List_Id is
- Comp_Typ : constant Entity_Id := Component_Type (Typ);
- Final_List : constant List_Id := New_List;
- Index_List : constant List_Id := New_List;
- Loc : constant Source_Ptr := Sloc (Typ);
- Num_Dims : constant Int := Number_Dimensions (Typ);
- Counter_Id : Entity_Id;
- Dim : Int;
- F : Node_Id;
- Fin_Stmt : Node_Id;
- Final_Block : Node_Id;
- Final_Loop : Node_Id;
- Finalizer_Data : Finalization_Exception_Data;
- Finalizer_Decls : List_Id := No_List;
- Init_Loop : Node_Id;
- J : Node_Id;
- Loop_Id : Node_Id;
- Stmts : List_Id;
-
- Exceptions_OK : constant Boolean :=
- not Restriction_Active (No_Exception_Propagation);
-
- function Build_Counter_Assignment return Node_Id;
- -- Generate the following assignment:
- -- Counter := V'Length (1) *
- -- ...
- -- V'Length (N) - Counter;
-
- function Build_Finalization_Call return Node_Id;
- -- Generate a deep finalization call for an array element
-
- procedure Build_Indices;
- -- Generate the initialization and finalization indices used in the
- -- dimension loops.
-
- function Build_Initialization_Call return Node_Id;
- -- Generate a deep initialization call for an array element
-
- ------------------------------
- -- Build_Counter_Assignment --
- ------------------------------
-
- function Build_Counter_Assignment return Node_Id is
- Dim : Int;
- Expr : Node_Id;
-
- begin
- -- Start from the first dimension and generate:
- -- V'Length (1)
-
- Dim := 1;
- Expr :=
- Make_Attribute_Reference (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Attribute_Name => Name_Length,
- Expressions => New_List (Make_Integer_Literal (Loc, Dim)));
-
- -- Process the rest of the dimensions, generate:
- -- Expr * V'Length (N)
-
- Dim := Dim + 1;
- while Dim <= Num_Dims loop
- Expr :=
- Make_Op_Multiply (Loc,
- Left_Opnd => Expr,
- Right_Opnd =>
- Make_Attribute_Reference (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Attribute_Name => Name_Length,
- Expressions => New_List (
- Make_Integer_Literal (Loc, Dim))));
-
- Dim := Dim + 1;
- end loop;
-
- -- Generate:
- -- Counter := Expr - Counter;
-
- return
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Counter_Id, Loc),
- Expression =>
- Make_Op_Subtract (Loc,
- Left_Opnd => Expr,
- Right_Opnd => New_Reference_To (Counter_Id, Loc)));
- end Build_Counter_Assignment;
-
- -----------------------------
- -- Build_Finalization_Call --
- -----------------------------
-
- function Build_Finalization_Call return Node_Id is
- Comp_Ref : constant Node_Id :=
- Make_Indexed_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Expressions => New_References_To (Final_List, Loc));
-
- begin
- Set_Etype (Comp_Ref, Comp_Typ);
-
- -- Generate:
- -- [Deep_]Finalize (V);
-
- return Make_Final_Call (Obj_Ref => Comp_Ref, Typ => Comp_Typ);
- end Build_Finalization_Call;
-
- -------------------
- -- Build_Indices --
- -------------------
-
- procedure Build_Indices is
- begin
- -- Generate the following identifiers:
- -- Jnn - for initialization
- -- Fnn - for finalization
-
- for Dim in 1 .. Num_Dims loop
- Append_To (Index_List,
- Make_Defining_Identifier (Loc, New_External_Name ('J', Dim)));
-
- Append_To (Final_List,
- Make_Defining_Identifier (Loc, New_External_Name ('F', Dim)));
- end loop;
- end Build_Indices;
-
- -------------------------------
- -- Build_Initialization_Call --
- -------------------------------
-
- function Build_Initialization_Call return Node_Id is
- Comp_Ref : constant Node_Id :=
- Make_Indexed_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Expressions => New_References_To (Index_List, Loc));
-
- begin
- Set_Etype (Comp_Ref, Comp_Typ);
-
- -- Generate:
- -- [Deep_]Initialize (V (J1, ..., JN));
-
- return Make_Init_Call (Obj_Ref => Comp_Ref, Typ => Comp_Typ);
- end Build_Initialization_Call;
-
- -- Start of processing for Build_Initialize_Statements
-
- begin
- Counter_Id := Make_Temporary (Loc, 'C');
- Finalizer_Decls := New_List;
-
- Build_Indices;
- Build_Object_Declarations (Finalizer_Data, Finalizer_Decls, Loc);
-
- -- Generate the block which houses the finalization call, the index
- -- guard and the handler which triggers Program_Error later on.
-
- -- if Counter > 0 then
- -- Counter := Counter - 1;
- -- else
- -- [Deep_]Finalize (V (F1, ..., FN)); -- No_Except_Propagation
-
- -- begin -- Exceptions allowed
- -- [Deep_]Finalize (V (F1, ..., FN));
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
-
- if Exceptions_OK then
- Fin_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Build_Finalization_Call),
- Exception_Handlers => New_List (
- Build_Exception_Handler (Finalizer_Data))));
- else
- Fin_Stmt := Build_Finalization_Call;
- end if;
-
- -- This is the core of the loop, the dimension iterators are added
- -- one by one in reverse.
-
- Final_Loop :=
- Make_If_Statement (Loc,
- Condition =>
- Make_Op_Gt (Loc,
- Left_Opnd => New_Reference_To (Counter_Id, Loc),
- Right_Opnd => Make_Integer_Literal (Loc, 0)),
-
- Then_Statements => New_List (
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Counter_Id, Loc),
- Expression =>
- Make_Op_Subtract (Loc,
- Left_Opnd => New_Reference_To (Counter_Id, Loc),
- Right_Opnd => Make_Integer_Literal (Loc, 1)))),
-
- Else_Statements => New_List (Fin_Stmt));
-
- -- Generate all finalization loops starting from the innermost
- -- dimension.
-
- -- for Fnn in reverse V'Range (Dim) loop
- -- <final loop>
- -- end loop;
-
- F := Last (Final_List);
- Dim := Num_Dims;
- while Present (F) and then Dim > 0 loop
- Loop_Id := F;
- Prev (F);
- Remove (Loop_Id);
-
- Final_Loop :=
- Make_Loop_Statement (Loc,
- Iteration_Scheme =>
- Make_Iteration_Scheme (Loc,
- Loop_Parameter_Specification =>
- Make_Loop_Parameter_Specification (Loc,
- Defining_Identifier => Loop_Id,
- Discrete_Subtype_Definition =>
- Make_Attribute_Reference (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Attribute_Name => Name_Range,
- Expressions => New_List (
- Make_Integer_Literal (Loc, Dim))),
-
- Reverse_Present => True)),
-
- Statements => New_List (Final_Loop),
- End_Label => Empty);
-
- Dim := Dim - 1;
- end loop;
-
- -- Generate the block which contains the finalization loops, the
- -- declarations of the abort flag, the exception occurrence, the
- -- raised flag and the conditional raise.
-
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
-
- -- E : Exception_Occurrence;
- -- Raised : Boolean := False;
-
- -- begin
- -- Counter :=
- -- V'Length (1) *
- -- ...
- -- V'Length (N) - Counter;
-
- -- <final loop>
-
- -- if Raised and then not Abort then -- Exception handlers OK
- -- Raise_From_Controlled_Operation (E);
- -- end if;
-
- -- raise; -- Exception handlers OK
- -- end;
-
- Stmts := New_List (Build_Counter_Assignment, Final_Loop);
-
- if Exceptions_OK then
- Append_To (Stmts,
- Build_Raise_Statement (Finalizer_Data));
- Append_To (Stmts, Make_Raise_Statement (Loc));
- end if;
-
- Final_Block :=
- Make_Block_Statement (Loc,
- Declarations =>
- Finalizer_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts));
-
- -- Generate the block which contains the initialization call and
- -- the partial finalization code.
-
- -- begin
- -- [Deep_]Initialize (V (J1, ..., JN));
-
- -- Counter := Counter + 1;
-
- -- exception
- -- when others =>
- -- <finalization code>
- -- end;
-
- Init_Loop :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Build_Initialization_Call),
- Exception_Handlers => New_List (
- Make_Exception_Handler (Loc,
- Exception_Choices => New_List (Make_Others_Choice (Loc)),
- Statements => New_List (Final_Block)))));
-
- Append_To (Statements (Handled_Statement_Sequence (Init_Loop)),
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Counter_Id, Loc),
- Expression =>
- Make_Op_Add (Loc,
- Left_Opnd => New_Reference_To (Counter_Id, Loc),
- Right_Opnd => Make_Integer_Literal (Loc, 1))));
-
- -- Generate all initialization loops starting from the innermost
- -- dimension.
-
- -- for Jnn in V'Range (Dim) loop
- -- <init loop>
- -- end loop;
-
- J := Last (Index_List);
- Dim := Num_Dims;
- while Present (J) and then Dim > 0 loop
- Loop_Id := J;
- Prev (J);
- Remove (Loop_Id);
-
- Init_Loop :=
- Make_Loop_Statement (Loc,
- Iteration_Scheme =>
- Make_Iteration_Scheme (Loc,
- Loop_Parameter_Specification =>
- Make_Loop_Parameter_Specification (Loc,
- Defining_Identifier => Loop_Id,
- Discrete_Subtype_Definition =>
- Make_Attribute_Reference (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Attribute_Name => Name_Range,
- Expressions => New_List (
- Make_Integer_Literal (Loc, Dim))))),
-
- Statements => New_List (Init_Loop),
- End_Label => Empty);
-
- Dim := Dim - 1;
- end loop;
-
- -- Generate the block which contains the counter variable and the
- -- initialization loops.
-
- -- declare
- -- Counter : Integer := 0;
- -- begin
- -- <init loop>
- -- end;
-
- return
- New_List (
- Make_Block_Statement (Loc,
- Declarations => New_List (
- Make_Object_Declaration (Loc,
- Defining_Identifier => Counter_Id,
- Object_Definition =>
- New_Reference_To (Standard_Integer, Loc),
- Expression => Make_Integer_Literal (Loc, 0))),
-
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Init_Loop))));
- end Build_Initialize_Statements;
-
- -----------------------
- -- New_References_To --
- -----------------------
-
- function New_References_To
- (L : List_Id;
- Loc : Source_Ptr) return List_Id
- is
- Refs : constant List_Id := New_List;
- Id : Node_Id;
-
- begin
- Id := First (L);
- while Present (Id) loop
- Append_To (Refs, New_Reference_To (Id, Loc));
- Next (Id);
- end loop;
-
- return Refs;
- end New_References_To;
-
- -- Start of processing for Make_Deep_Array_Body
-
- begin
- case Prim is
- when Address_Case =>
- return Make_Finalize_Address_Stmts (Typ);
-
- when Adjust_Case |
- Finalize_Case =>
- return Build_Adjust_Or_Finalize_Statements (Typ);
-
- when Initialize_Case =>
- return Build_Initialize_Statements (Typ);
- end case;
- end Make_Deep_Array_Body;
-
- --------------------
- -- Make_Deep_Proc --
- --------------------
-
- 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_Id : Entity_Id;
-
- begin
- -- Create the object formal, generate:
- -- V : System.Address
-
- if Prim = Address_Case then
- Formals := New_List (
- Make_Parameter_Specification (Loc,
- Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
- Parameter_Type => New_Reference_To (RTE (RE_Address), Loc)));
-
- -- Default case
-
- else
- -- V : in out Typ
-
- Formals := New_List (
- 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)));
-
- -- F : Boolean := True
-
- if Prim = Adjust_Case
- or else Prim = Finalize_Case
- then
- Append_To (Formals,
- Make_Parameter_Specification (Loc,
- Defining_Identifier => Make_Defining_Identifier (Loc, Name_F),
- Parameter_Type =>
- New_Reference_To (Standard_Boolean, Loc),
- Expression =>
- New_Reference_To (Standard_True, Loc)));
- end if;
- end if;
-
- Proc_Id :=
- Make_Defining_Identifier (Loc,
- Chars => Make_TSS_Name (Typ, Deep_Name_Of (Prim)));
-
- -- Generate:
- -- procedure Deep_Initialize / Adjust / Finalize (V : in out <typ>) is
- -- begin
- -- <stmts>
- -- exception -- Finalize and Adjust cases only
- -- raise Program_Error;
- -- end Deep_Initialize / Adjust / Finalize;
-
- -- or
-
- -- procedure Finalize_Address (V : System.Address) is
- -- begin
- -- <stmts>
- -- end Finalize_Address;
-
- Discard_Node (
- Make_Subprogram_Body (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Proc_Id,
- Parameter_Specifications => Formals),
-
- Declarations => Empty_List,
-
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Statements => Stmts)));
-
- return Proc_Id;
- end Make_Deep_Proc;
-
- ---------------------------
- -- Make_Deep_Record_Body --
- ---------------------------
-
- function Make_Deep_Record_Body
- (Prim : Final_Primitives;
- Typ : Entity_Id;
- Is_Local : Boolean := False) return List_Id
- is
- function Build_Adjust_Statements (Typ : Entity_Id) return List_Id;
- -- Build the statements necessary to adjust a record type. The type may
- -- have discriminants and contain variant parts. Generate:
- --
- -- begin
- -- begin
- -- [Deep_]Adjust (V.Comp_1);
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- . . .
- -- begin
- -- [Deep_]Adjust (V.Comp_N);
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- --
- -- begin
- -- Deep_Adjust (V._parent, False); -- If applicable
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- --
- -- if F then
- -- begin
- -- Adjust (V); -- If applicable
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
- --
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- function Build_Finalize_Statements (Typ : Entity_Id) return List_Id;
- -- Build the statements necessary to finalize a record type. The type
- -- may have discriminants and contain variant parts. Generate:
- --
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
- -- E : Exception_Occurence;
- -- Raised : Boolean := False;
- --
- -- begin
- -- if F then
- -- begin
- -- Finalize (V); -- If applicable
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
- --
- -- case Variant_1 is
- -- when Value_1 =>
- -- case State_Counter_N => -- If Is_Local is enabled
- -- when N => .
- -- goto LN; .
- -- ... .
- -- when 1 => .
- -- goto L1; .
- -- when others => .
- -- goto L0; .
- -- end case; .
- --
- -- <<LN>> -- If Is_Local is enabled
- -- begin
- -- [Deep_]Finalize (V.Comp_N);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- . . .
- -- <<L1>>
- -- begin
- -- [Deep_]Finalize (V.Comp_1);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- <<L0>>
- -- end case;
- --
- -- case State_Counter_1 => -- If Is_Local is enabled
- -- when M => .
- -- goto LM; .
- -- ...
- --
- -- begin
- -- Deep_Finalize (V._parent, False); -- If applicable
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
- --
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- function Parent_Field_Type (Typ : Entity_Id) return Entity_Id;
- -- Given a derived tagged type Typ, traverse all components, find field
- -- _parent and return its type.
-
- procedure Preprocess_Components
- (Comps : Node_Id;
- Num_Comps : out Int;
- Has_POC : out Boolean);
- -- Examine all components in component list Comps, count all controlled
- -- components and determine whether at least one of them is per-object
- -- constrained. Component _parent is always skipped.
-
- -----------------------------
- -- Build_Adjust_Statements --
- -----------------------------
-
- function Build_Adjust_Statements (Typ : Entity_Id) return List_Id is
- Loc : constant Source_Ptr := Sloc (Typ);
- Typ_Def : constant Node_Id := Type_Definition (Parent (Typ));
- Bod_Stmts : List_Id;
- Finalizer_Data : Finalization_Exception_Data;
- Finalizer_Decls : List_Id := No_List;
- Rec_Def : Node_Id;
- Var_Case : Node_Id;
-
- Exceptions_OK : constant Boolean :=
- not Restriction_Active (No_Exception_Propagation);
-
- function Process_Component_List_For_Adjust
- (Comps : Node_Id) return List_Id;
- -- Build all necessary adjust statements for a single component list
-
- ---------------------------------------
- -- Process_Component_List_For_Adjust --
- ---------------------------------------
-
- function Process_Component_List_For_Adjust
- (Comps : Node_Id) return List_Id
- is
- Stmts : constant List_Id := New_List;
- Decl : Node_Id;
- Decl_Id : Entity_Id;
- Decl_Typ : Entity_Id;
- Has_POC : Boolean;
- Num_Comps : Int;
-
- procedure Process_Component_For_Adjust (Decl : Node_Id);
- -- Process the declaration of a single controlled component
-
- ----------------------------------
- -- Process_Component_For_Adjust --
- ----------------------------------
-
- procedure Process_Component_For_Adjust (Decl : Node_Id) is
- Id : constant Entity_Id := Defining_Identifier (Decl);
- Typ : constant Entity_Id := Etype (Id);
- Adj_Stmt : Node_Id;
-
- begin
- -- Generate:
- -- [Deep_]Adjust (V.Id); -- No_Exception_Propagation
-
- -- begin -- Exception handlers allowed
- -- [Deep_]Adjust (V.Id);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E, Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- Adj_Stmt :=
- Make_Adjust_Call (
- Obj_Ref =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name => Make_Identifier (Loc, Chars (Id))),
- Typ => Typ);
-
- if Exceptions_OK then
- Adj_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Adj_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler (Finalizer_Data))));
- end if;
-
- Append_To (Stmts, Adj_Stmt);
- end Process_Component_For_Adjust;
-
- -- Start of processing for Process_Component_List_For_Adjust
-
- begin
- -- Perform an initial check, determine the number of controlled
- -- components in the current list and whether at least one of them
- -- is per-object constrained.
-
- Preprocess_Components (Comps, Num_Comps, Has_POC);
-
- -- The processing in this routine is done in the following order:
- -- 1) Regular components
- -- 2) Per-object constrained components
- -- 3) Variant parts
-
- if Num_Comps > 0 then
-
- -- Process all regular components in order of declarations
-
- Decl := First_Non_Pragma (Component_Items (Comps));
- while Present (Decl) loop
- Decl_Id := Defining_Identifier (Decl);
- Decl_Typ := Etype (Decl_Id);
-
- -- Skip _parent as well as per-object constrained components
-
- if Chars (Decl_Id) /= Name_uParent
- and then Needs_Finalization (Decl_Typ)
- then
- if Has_Access_Constraint (Decl_Id)
- and then No (Expression (Decl))
- then
- null;
- else
- Process_Component_For_Adjust (Decl);
- end if;
- end if;
-
- Next_Non_Pragma (Decl);
- end loop;
-
- -- Process all per-object constrained components in order of
- -- declarations.
-
- if Has_POC then
- Decl := First_Non_Pragma (Component_Items (Comps));
- while Present (Decl) loop
- Decl_Id := Defining_Identifier (Decl);
- Decl_Typ := Etype (Decl_Id);
-
- -- Skip _parent
-
- if Chars (Decl_Id) /= Name_uParent
- and then Needs_Finalization (Decl_Typ)
- and then Has_Access_Constraint (Decl_Id)
- and then No (Expression (Decl))
- then
- Process_Component_For_Adjust (Decl);
- end if;
-
- Next_Non_Pragma (Decl);
- end loop;
- end if;
- end if;
-
- -- Process all variants, if any
-
- Var_Case := Empty;
- if Present (Variant_Part (Comps)) then
- declare
- Var_Alts : constant List_Id := New_List;
- Var : Node_Id;
-
- begin
- Var := First_Non_Pragma (Variants (Variant_Part (Comps)));
- while Present (Var) loop
-
- -- Generate:
- -- when <discrete choices> =>
- -- <adjust statements>
-
- Append_To (Var_Alts,
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices =>
- New_Copy_List (Discrete_Choices (Var)),
- Statements =>
- Process_Component_List_For_Adjust (
- Component_List (Var))));
-
- Next_Non_Pragma (Var);
- end loop;
-
- -- Generate:
- -- case V.<discriminant> is
- -- when <discrete choices 1> =>
- -- <adjust statements 1>
- -- ...
- -- when <discrete choices N> =>
- -- <adjust statements N>
- -- end case;
-
- Var_Case :=
- Make_Case_Statement (Loc,
- Expression =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name =>
- Make_Identifier (Loc,
- Chars => Chars (Name (Variant_Part (Comps))))),
- Alternatives => Var_Alts);
- end;
- end if;
-
- -- Add the variant case statement to the list of statements
-
- if Present (Var_Case) then
- Append_To (Stmts, Var_Case);
- end if;
-
- -- If the component list did not have any controlled components
- -- nor variants, return null.
-
- if Is_Empty_List (Stmts) then
- Append_To (Stmts, Make_Null_Statement (Loc));
- end if;
-
- return Stmts;
- end Process_Component_List_For_Adjust;
-
- -- Start of processing for Build_Adjust_Statements
-
- begin
- Finalizer_Decls := New_List;
- Build_Object_Declarations (Finalizer_Data, Finalizer_Decls, Loc);
-
- if Nkind (Typ_Def) = N_Derived_Type_Definition then
- Rec_Def := Record_Extension_Part (Typ_Def);
- else
- Rec_Def := Typ_Def;
- end if;
-
- -- Create an adjust sequence for all record components
-
- if Present (Component_List (Rec_Def)) then
- Bod_Stmts :=
- Process_Component_List_For_Adjust (Component_List (Rec_Def));
- end if;
-
- -- A derived record type must adjust all inherited components. This
- -- action poses the following problem:
-
- -- procedure Deep_Adjust (Obj : in out Parent_Typ) is
- -- begin
- -- Adjust (Obj);
- -- ...
-
- -- procedure Deep_Adjust (Obj : in out Derived_Typ) is
- -- begin
- -- Deep_Adjust (Obj._parent);
- -- ...
- -- Adjust (Obj);
- -- ...
-
- -- Adjusting the derived type will invoke Adjust of the parent and
- -- then that of the derived type. This is undesirable because both
- -- routines may modify shared components. Only the Adjust of the
- -- derived type should be invoked.
-
- -- To prevent this double adjustment of shared components,
- -- Deep_Adjust uses a flag to control the invocation of Adjust:
-
- -- procedure Deep_Adjust
- -- (Obj : in out Some_Type;
- -- Flag : Boolean := True)
- -- is
- -- begin
- -- if Flag then
- -- Adjust (Obj);
- -- end if;
- -- ...
-
- -- When Deep_Adjust is invokes for field _parent, a value of False is
- -- provided for the flag:
-
- -- Deep_Adjust (Obj._parent, False);
-
- if Is_Tagged_Type (Typ) and then Is_Derived_Type (Typ) then
- declare
- Par_Typ : constant Entity_Id := Parent_Field_Type (Typ);
- Adj_Stmt : Node_Id;
- Call : Node_Id;
-
- begin
- if Needs_Finalization (Par_Typ) then
- Call :=
- Make_Adjust_Call
- (Obj_Ref =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name =>
- Make_Identifier (Loc, Name_uParent)),
- Typ => Par_Typ,
- For_Parent => True);
-
- -- Generate:
- -- Deep_Adjust (V._parent, False); -- No_Except_Propagat
-
- -- begin -- Exceptions OK
- -- Deep_Adjust (V._parent, False);
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- if Present (Call) then
- Adj_Stmt := Call;
-
- if Exceptions_OK then
- Adj_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Adj_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler (Finalizer_Data))));
- end if;
-
- Prepend_To (Bod_Stmts, Adj_Stmt);
- end if;
- end if;
- end;
- end if;
-
- -- Adjust the object. This action must be performed last after all
- -- components have been adjusted.
-
- if Is_Controlled (Typ) then
- declare
- Adj_Stmt : Node_Id;
- Proc : Entity_Id;
-
- begin
- Proc := Find_Prim_Op (Typ, Name_Adjust);
-
- -- Generate:
- -- if F then
- -- Adjust (V); -- No_Exception_Propagation
-
- -- begin -- Exception handlers allowed
- -- Adjust (V);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
-
- if Present (Proc) then
- Adj_Stmt :=
- Make_Procedure_Call_Statement (Loc,
- Name => New_Reference_To (Proc, Loc),
- Parameter_Associations => New_List (
- Make_Identifier (Loc, Name_V)));
-
- if Exceptions_OK then
- Adj_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Adj_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler
- (Finalizer_Data))));
- end if;
-
- Append_To (Bod_Stmts,
- Make_If_Statement (Loc,
- Condition => Make_Identifier (Loc, Name_F),
- Then_Statements => New_List (Adj_Stmt)));
- end if;
- end;
- end if;
-
- -- At this point either all adjustment statements have been generated
- -- or the type is not controlled.
-
- if Is_Empty_List (Bod_Stmts) then
- Append_To (Bod_Stmts, Make_Null_Statement (Loc));
-
- return Bod_Stmts;
-
- -- Generate:
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
-
- -- E : Exception_Occurence;
- -- Raised : Boolean := False;
-
- -- begin
- -- <adjust statements>
-
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- else
- if Exceptions_OK then
- Append_To (Bod_Stmts,
- Build_Raise_Statement (Finalizer_Data));
- end if;
-
- return
- New_List (
- Make_Block_Statement (Loc,
- Declarations =>
- Finalizer_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Bod_Stmts)));
- end if;
- end Build_Adjust_Statements;
-
- -------------------------------
- -- Build_Finalize_Statements --
- -------------------------------
-
- function Build_Finalize_Statements (Typ : Entity_Id) return List_Id is
- Loc : constant Source_Ptr := Sloc (Typ);
- Typ_Def : constant Node_Id := Type_Definition (Parent (Typ));
- Bod_Stmts : List_Id;
- Counter : Int := 0;
- Finalizer_Data : Finalization_Exception_Data;
- Finalizer_Decls : List_Id := No_List;
- Rec_Def : Node_Id;
- Var_Case : Node_Id;
-
- Exceptions_OK : constant Boolean :=
- not Restriction_Active (No_Exception_Propagation);
-
- function Process_Component_List_For_Finalize
- (Comps : Node_Id) return List_Id;
- -- Build all necessary finalization statements for a single component
- -- list. The statements may include a jump circuitry if flag Is_Local
- -- is enabled.
-
- -----------------------------------------
- -- Process_Component_List_For_Finalize --
- -----------------------------------------
-
- function Process_Component_List_For_Finalize
- (Comps : Node_Id) return List_Id
- is
- Alts : List_Id;
- Counter_Id : Entity_Id;
- Decl : Node_Id;
- Decl_Id : Entity_Id;
- Decl_Typ : Entity_Id;
- Decls : List_Id;
- Has_POC : Boolean;
- Jump_Block : Node_Id;
- Label : Node_Id;
- Label_Id : Entity_Id;
- Num_Comps : Int;
- Stmts : List_Id;
-
- procedure Process_Component_For_Finalize
- (Decl : Node_Id;
- Alts : List_Id;
- Decls : List_Id;
- Stmts : List_Id);
- -- Process the declaration of a single controlled component. If
- -- flag Is_Local is enabled, create the corresponding label and
- -- jump circuitry. Alts is the list of case alternatives, Decls
- -- is the top level declaration list where labels are declared
- -- and Stmts is the list of finalization actions.
-
- ------------------------------------
- -- Process_Component_For_Finalize --
- ------------------------------------
-
- procedure Process_Component_For_Finalize
- (Decl : Node_Id;
- Alts : List_Id;
- Decls : List_Id;
- Stmts : List_Id)
- is
- Id : constant Entity_Id := Defining_Identifier (Decl);
- Typ : constant Entity_Id := Etype (Id);
- Fin_Stmt : Node_Id;
-
- begin
- if Is_Local then
- declare
- Label : Node_Id;
- Label_Id : Entity_Id;
-
- begin
- -- Generate:
- -- LN : label;
-
- Label_Id :=
- Make_Identifier (Loc,
- Chars => New_External_Name ('L', Num_Comps));
- Set_Entity (Label_Id,
- Make_Defining_Identifier (Loc, Chars (Label_Id)));
- Label := Make_Label (Loc, Label_Id);
-
- Append_To (Decls,
- Make_Implicit_Label_Declaration (Loc,
- Defining_Identifier => Entity (Label_Id),
- Label_Construct => Label));
-
- -- Generate:
- -- when N =>
- -- goto LN;
-
- Append_To (Alts,
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices => New_List (
- Make_Integer_Literal (Loc, Num_Comps)),
-
- Statements => New_List (
- Make_Goto_Statement (Loc,
- Name =>
- New_Reference_To (Entity (Label_Id), Loc)))));
-
- -- Generate:
- -- <<LN>>
-
- Append_To (Stmts, Label);
-
- -- Decrease the number of components to be processed.
- -- This action yields a new Label_Id in future calls.
-
- Num_Comps := Num_Comps - 1;
- end;
- end if;
-
- -- Generate:
- -- [Deep_]Finalize (V.Id); -- No_Exception_Propagation
-
- -- begin -- Exception handlers allowed
- -- [Deep_]Finalize (V.Id);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- Fin_Stmt :=
- Make_Final_Call
- (Obj_Ref =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name => Make_Identifier (Loc, Chars (Id))),
- Typ => Typ);
-
- if not Restriction_Active (No_Exception_Propagation) then
- Fin_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler (Finalizer_Data))));
- end if;
-
- Append_To (Stmts, Fin_Stmt);
- end Process_Component_For_Finalize;
-
- -- Start of processing for Process_Component_List_For_Finalize
-
- begin
- -- Perform an initial check, look for controlled and per-object
- -- constrained components.
-
- Preprocess_Components (Comps, Num_Comps, Has_POC);
-
- -- Create a state counter to service the current component list.
- -- This step is performed before the variants are inspected in
- -- order to generate the same state counter names as those from
- -- Build_Initialize_Statements.
-
- if Num_Comps > 0
- and then Is_Local
- then
- Counter := Counter + 1;
-
- Counter_Id :=
- Make_Defining_Identifier (Loc,
- Chars => New_External_Name ('C', Counter));
- end if;
-
- -- Process the component in the following order:
- -- 1) Variants
- -- 2) Per-object constrained components
- -- 3) Regular components
-
- -- Start with the variant parts
-
- Var_Case := Empty;
- if Present (Variant_Part (Comps)) then
- declare
- Var_Alts : constant List_Id := New_List;
- Var : Node_Id;
-
- begin
- Var := First_Non_Pragma (Variants (Variant_Part (Comps)));
- while Present (Var) loop
-
- -- Generate:
- -- when <discrete choices> =>
- -- <finalize statements>
-
- Append_To (Var_Alts,
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices =>
- New_Copy_List (Discrete_Choices (Var)),
- Statements =>
- Process_Component_List_For_Finalize (
- Component_List (Var))));
-
- Next_Non_Pragma (Var);
- end loop;
-
- -- Generate:
- -- case V.<discriminant> is
- -- when <discrete choices 1> =>
- -- <finalize statements 1>
- -- ...
- -- when <discrete choices N> =>
- -- <finalize statements N>
- -- end case;
-
- Var_Case :=
- Make_Case_Statement (Loc,
- Expression =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name =>
- Make_Identifier (Loc,
- Chars => Chars (Name (Variant_Part (Comps))))),
- Alternatives => Var_Alts);
- end;
- end if;
-
- -- The current component list does not have a single controlled
- -- component, however it may contain variants. Return the case
- -- statement for the variants or nothing.
-
- if Num_Comps = 0 then
- if Present (Var_Case) then
- return New_List (Var_Case);
- else
- return New_List (Make_Null_Statement (Loc));
- end if;
- end if;
-
- -- Prepare all lists
-
- Alts := New_List;
- Decls := New_List;
- Stmts := New_List;
-
- -- Process all per-object constrained components in reverse order
-
- if Has_POC then
- Decl := Last_Non_Pragma (Component_Items (Comps));
- while Present (Decl) loop
- Decl_Id := Defining_Identifier (Decl);
- Decl_Typ := Etype (Decl_Id);
-
- -- Skip _parent
-
- if Chars (Decl_Id) /= Name_uParent
- and then Needs_Finalization (Decl_Typ)
- and then Has_Access_Constraint (Decl_Id)
- and then No (Expression (Decl))
- then
- Process_Component_For_Finalize (Decl, Alts, Decls, Stmts);
- end if;
-
- Prev_Non_Pragma (Decl);
- end loop;
- end if;
-
- -- Process the rest of the components in reverse order
-
- Decl := Last_Non_Pragma (Component_Items (Comps));
- while Present (Decl) loop
- Decl_Id := Defining_Identifier (Decl);
- Decl_Typ := Etype (Decl_Id);
-
- -- Skip _parent
-
- if Chars (Decl_Id) /= Name_uParent
- and then Needs_Finalization (Decl_Typ)
- then
- -- Skip per-object constrained components since they were
- -- handled in the above step.
-
- if Has_Access_Constraint (Decl_Id)
- and then No (Expression (Decl))
- then
- null;
- else
- Process_Component_For_Finalize (Decl, Alts, Decls, Stmts);
- end if;
- end if;
-
- Prev_Non_Pragma (Decl);
- end loop;
-
- -- Generate:
- -- declare
- -- LN : label; -- If Is_Local is enabled
- -- ... .
- -- L0 : label; .
-
- -- begin .
- -- case CounterX is .
- -- when N => .
- -- goto LN; .
- -- ... .
- -- when 1 => .
- -- goto L1; .
- -- when others => .
- -- goto L0; .
- -- end case; .
-
- -- <<LN>> -- If Is_Local is enabled
- -- begin
- -- [Deep_]Finalize (V.CompY);
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- ...
- -- <<L0>> -- If Is_Local is enabled
- -- end;
-
- if Is_Local then
-
- -- Add the declaration of default jump location L0, its
- -- corresponding alternative and its place in the statements.
-
- Label_Id := Make_Identifier (Loc, New_External_Name ('L', 0));
- Set_Entity (Label_Id,
- Make_Defining_Identifier (Loc, Chars (Label_Id)));
- Label := Make_Label (Loc, Label_Id);
-
- Append_To (Decls, -- declaration
- Make_Implicit_Label_Declaration (Loc,
- Defining_Identifier => Entity (Label_Id),
- Label_Construct => Label));
-
- Append_To (Alts, -- alternative
- Make_Case_Statement_Alternative (Loc,
- Discrete_Choices => New_List (
- Make_Others_Choice (Loc)),
-
- Statements => New_List (
- Make_Goto_Statement (Loc,
- Name => New_Reference_To (Entity (Label_Id), Loc)))));
-
- Append_To (Stmts, Label); -- statement
-
- -- Create the jump block
-
- Prepend_To (Stmts,
- Make_Case_Statement (Loc,
- Expression => Make_Identifier (Loc, Chars (Counter_Id)),
- Alternatives => Alts));
- end if;
-
- Jump_Block :=
- Make_Block_Statement (Loc,
- Declarations => Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Stmts));
-
- if Present (Var_Case) then
- return New_List (Var_Case, Jump_Block);
- else
- return New_List (Jump_Block);
- end if;
- end Process_Component_List_For_Finalize;
-
- -- Start of processing for Build_Finalize_Statements
-
- begin
- Finalizer_Decls := New_List;
- Build_Object_Declarations (Finalizer_Data, Finalizer_Decls, Loc);
-
- if Nkind (Typ_Def) = N_Derived_Type_Definition then
- Rec_Def := Record_Extension_Part (Typ_Def);
- else
- Rec_Def := Typ_Def;
- end if;
-
- -- Create a finalization sequence for all record components
-
- if Present (Component_List (Rec_Def)) then
- Bod_Stmts :=
- Process_Component_List_For_Finalize (Component_List (Rec_Def));
- end if;
-
- -- A derived record type must finalize all inherited components. This
- -- action poses the following problem:
-
- -- procedure Deep_Finalize (Obj : in out Parent_Typ) is
- -- begin
- -- Finalize (Obj);
- -- ...
-
- -- procedure Deep_Finalize (Obj : in out Derived_Typ) is
- -- begin
- -- Deep_Finalize (Obj._parent);
- -- ...
- -- Finalize (Obj);
- -- ...
-
- -- Finalizing the derived type will invoke Finalize of the parent and
- -- then that of the derived type. This is undesirable because both
- -- routines may modify shared components. Only the Finalize of the
- -- derived type should be invoked.
-
- -- To prevent this double adjustment of shared components,
- -- Deep_Finalize uses a flag to control the invocation of Finalize:
-
- -- procedure Deep_Finalize
- -- (Obj : in out Some_Type;
- -- Flag : Boolean := True)
- -- is
- -- begin
- -- if Flag then
- -- Finalize (Obj);
- -- end if;
- -- ...
-
- -- When Deep_Finalize is invokes for field _parent, a value of False
- -- is provided for the flag:
-
- -- Deep_Finalize (Obj._parent, False);
-
- if Is_Tagged_Type (Typ)
- and then Is_Derived_Type (Typ)
- then
- declare
- Par_Typ : constant Entity_Id := Parent_Field_Type (Typ);
- Call : Node_Id;
- Fin_Stmt : Node_Id;
-
- begin
- if Needs_Finalization (Par_Typ) then
- Call :=
- Make_Final_Call
- (Obj_Ref =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name =>
- Make_Identifier (Loc, Name_uParent)),
- Typ => Par_Typ,
- For_Parent => True);
-
- -- Generate:
- -- Deep_Finalize (V._parent, False); -- No_Except_Propag
-
- -- begin -- Exceptions OK
- -- Deep_Finalize (V._parent, False);
- -- exception
- -- when Id : others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
-
- if Present (Call) then
- Fin_Stmt := Call;
-
- if Exceptions_OK then
- Fin_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler
- (Finalizer_Data))));
- end if;
-
- Append_To (Bod_Stmts, Fin_Stmt);
- end if;
- end if;
- end;
- end if;
-
- -- Finalize the object. This action must be performed first before
- -- all components have been finalized.
-
- if Is_Controlled (Typ)
- and then not Is_Local
- then
- declare
- Fin_Stmt : Node_Id;
- Proc : Entity_Id;
-
- begin
- Proc := Find_Prim_Op (Typ, Name_Finalize);
-
- -- Generate:
- -- if F then
- -- Finalize (V); -- No_Exception_Propagation
-
- -- begin
- -- Finalize (V);
- -- exception
- -- when others =>
- -- if not Raised then
- -- Raised := True;
- -- Save_Occurrence (E,
- -- Get_Current_Excep.all.all);
- -- end if;
- -- end;
- -- end if;
-
- if Present (Proc) then
- Fin_Stmt :=
- Make_Procedure_Call_Statement (Loc,
- Name => New_Reference_To (Proc, Loc),
- Parameter_Associations => New_List (
- Make_Identifier (Loc, Name_V)));
-
- if Exceptions_OK then
- Fin_Stmt :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Stmt),
- Exception_Handlers => New_List (
- Build_Exception_Handler
- (Finalizer_Data))));
- end if;
-
- Prepend_To (Bod_Stmts,
- Make_If_Statement (Loc,
- Condition => Make_Identifier (Loc, Name_F),
- Then_Statements => New_List (Fin_Stmt)));
- end if;
- end;
- end if;
-
- -- At this point either all finalization statements have been
- -- generated or the type is not controlled.
-
- if No (Bod_Stmts) then
- return New_List (Make_Null_Statement (Loc));
-
- -- Generate:
- -- declare
- -- Abort : constant Boolean := Triggered_By_Abort;
- -- <or>
- -- Abort : constant Boolean := False; -- no abort
-
- -- E : Exception_Occurence;
- -- Raised : Boolean := False;
-
- -- begin
- -- <finalize statements>
-
- -- if Raised and then not Abort then
- -- Raise_From_Controlled_Operation (E);
- -- end if;
- -- end;
-
- else
- if Exceptions_OK then
- Append_To (Bod_Stmts,
- Build_Raise_Statement (Finalizer_Data));
- end if;
-
- return
- New_List (
- Make_Block_Statement (Loc,
- Declarations =>
- Finalizer_Decls,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Bod_Stmts)));
- end if;
- end Build_Finalize_Statements;
-
- -----------------------
- -- Parent_Field_Type --
- -----------------------
-
- function Parent_Field_Type (Typ : Entity_Id) return Entity_Id is
- Field : Entity_Id;
-
- begin
- Field := First_Entity (Typ);
- while Present (Field) loop
- if Chars (Field) = Name_uParent then
- return Etype (Field);
- end if;
-
- Next_Entity (Field);
- end loop;
-
- -- A derived tagged type should always have a parent field
-
- raise Program_Error;
- end Parent_Field_Type;
-
- ---------------------------
- -- Preprocess_Components --
- ---------------------------
-
- procedure Preprocess_Components
- (Comps : Node_Id;
- Num_Comps : out Int;
- Has_POC : out Boolean)
- is
- Decl : Node_Id;
- Id : Entity_Id;
- Typ : Entity_Id;
-
- begin
- Num_Comps := 0;
- Has_POC := False;
-
- Decl := First_Non_Pragma (Component_Items (Comps));
- while Present (Decl) loop
- Id := Defining_Identifier (Decl);
- Typ := Etype (Id);
-
- -- Skip field _parent
-
- if Chars (Id) /= Name_uParent
- and then Needs_Finalization (Typ)
- then
- Num_Comps := Num_Comps + 1;
-
- if Has_Access_Constraint (Id)
- and then No (Expression (Decl))
- then
- Has_POC := True;
- end if;
- end if;
-
- Next_Non_Pragma (Decl);
- end loop;
- end Preprocess_Components;
-
- -- Start of processing for Make_Deep_Record_Body
-
- begin
- case Prim is
- when Address_Case =>
- return Make_Finalize_Address_Stmts (Typ);
-
- when Adjust_Case =>
- return Build_Adjust_Statements (Typ);
-
- when Finalize_Case =>
- return Build_Finalize_Statements (Typ);
-
- when Initialize_Case =>
- declare
- Loc : constant Source_Ptr := Sloc (Typ);
-
- begin
- if Is_Controlled (Typ) then
- return New_List (
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To
- (Find_Prim_Op (Typ, Name_Of (Prim)), Loc),
- Parameter_Associations => New_List (
- Make_Identifier (Loc, Name_V))));
- else
- return Empty_List;
- end if;
- end;
- end case;
- end Make_Deep_Record_Body;
-
- ----------------------
- -- Make_Final_Call --
- ----------------------
-
- function Make_Final_Call
- (Obj_Ref : Node_Id;
- Typ : Entity_Id;
- For_Parent : Boolean := False) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (Obj_Ref);
- Atyp : Entity_Id;
- Fin_Id : Entity_Id := Empty;
- Ref : Node_Id;
- Utyp : Entity_Id;
-
- begin
- -- Recover the proper type which contains [Deep_]Finalize
-
- if Is_Class_Wide_Type (Typ) then
- Utyp := Root_Type (Typ);
- Atyp := Utyp;
- Ref := Obj_Ref;
-
- elsif Is_Concurrent_Type (Typ) then
- Utyp := Corresponding_Record_Type (Typ);
- Atyp := Empty;
- Ref := Convert_Concurrent (Obj_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));
- Atyp := Typ;
- Ref := Convert_Concurrent (Obj_Ref, Full_View (Typ));
-
- else
- Utyp := Typ;
- Atyp := Typ;
- Ref := Obj_Ref;
- end if;
-
- Utyp := Underlying_Type (Base_Type (Utyp));
- Set_Assignment_OK (Ref);
-
- -- Deal with non-tagged derivation of private views. If the parent type
- -- is a protected type, Deep_Finalize is found on the corresponding
- -- record of the ancestor.
-
- if Is_Untagged_Derivation (Typ) then
- if Is_Protected_Type (Typ) then
- Utyp := Corresponding_Record_Type (Root_Type (Base_Type (Typ)));
- else
- Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
-
- if Is_Protected_Type (Utyp) then
- Utyp := Corresponding_Record_Type (Utyp);
- end if;
- end if;
-
- Ref := Unchecked_Convert_To (Utyp, Ref);
- Set_Assignment_OK (Ref);
- end if;
-
- -- Deal with derived private types which do not inherit primitives from
- -- their parents. In this case, [Deep_]Finalize can be found in the full
- -- view of the parent type.
-
- if Is_Tagged_Type (Utyp)
- and then Is_Derived_Type (Utyp)
- and then Is_Empty_Elmt_List (Primitive_Operations (Utyp))
- and then Is_Private_Type (Etype (Utyp))
- and then Present (Full_View (Etype (Utyp)))
- then
- Utyp := Full_View (Etype (Utyp));
- Ref := Unchecked_Convert_To (Utyp, Ref);
- Set_Assignment_OK (Ref);
- end if;
-
- -- When dealing with the completion of a private type, use the base type
- -- instead.
-
- if Utyp /= Base_Type (Utyp) then
- pragma Assert (Present (Atyp) and then Is_Private_Type (Atyp));
-
- Utyp := Base_Type (Utyp);
- Ref := Unchecked_Convert_To (Utyp, Ref);
- Set_Assignment_OK (Ref);
- end if;
-
- -- Select the appropriate version of Finalize
-
- if For_Parent then
- if Has_Controlled_Component (Utyp) then
- Fin_Id := Find_Prim_Op (Utyp, TSS_Deep_Finalize);
- end if;
-
- -- Class-wide types, interfaces and types with controlled components
-
- elsif Is_Class_Wide_Type (Typ)
- or else Is_Interface (Typ)
- or else Has_Controlled_Component (Utyp)
- then
- if Is_Tagged_Type (Utyp) then
- Fin_Id := Find_Prim_Op (Utyp, TSS_Deep_Finalize);
- else
- Fin_Id := TSS (Utyp, TSS_Deep_Finalize);
- end if;
-
- -- Derivations from [Limited_]Controlled
-
- elsif Is_Controlled (Utyp) then
- if Has_Controlled_Component (Utyp) then
- Fin_Id := Find_Prim_Op (Utyp, TSS_Deep_Finalize);
- else
- Fin_Id := Find_Prim_Op (Utyp, Name_Of (Finalize_Case));
- end if;
-
- -- Tagged types
-
- elsif Is_Tagged_Type (Utyp) then
- Fin_Id := Find_Prim_Op (Utyp, TSS_Deep_Finalize);
-
- else
- raise Program_Error;
- end if;
-
- if Present (Fin_Id) then
-
- -- When finalizing a class-wide object, do not convert to the root
- -- type in order to produce a dispatching call.
-
- if Is_Class_Wide_Type (Typ) then
- null;
-
- -- Ensure that a finalization routine is at least decorated in order
- -- to inspect the object parameter.
-
- elsif Analyzed (Fin_Id)
- or else Ekind (Fin_Id) = E_Procedure
- then
- -- In certain cases, such as the creation of Stream_Read, the
- -- visible entity of the type is its full view. Since Stream_Read
- -- will have to create an object of type Typ, the local object
- -- will be finalzed by the scope finalizer generated later on. The
- -- object parameter of Deep_Finalize will always use the private
- -- view of the type. To avoid such a clash between a private and a
- -- full view, perform an unchecked conversion of the object
- -- reference to the private view.
-
- declare
- Formal_Typ : constant Entity_Id :=
- Etype (First_Formal (Fin_Id));
- begin
- if Is_Private_Type (Formal_Typ)
- and then Present (Full_View (Formal_Typ))
- and then Full_View (Formal_Typ) = Utyp
- then
- Ref := Unchecked_Convert_To (Formal_Typ, Ref);
- end if;
- end;
-
- Ref := Convert_View (Fin_Id, Ref);
- end if;
-
- return Make_Call (Loc, Fin_Id, New_Copy_Tree (Ref), For_Parent);
- else
- return Empty;
- end if;
- end Make_Final_Call;
-
- --------------------------------
- -- Make_Finalize_Address_Body --
- --------------------------------
-
- procedure Make_Finalize_Address_Body (Typ : Entity_Id) is
- Is_Task : constant Boolean :=
- Ekind (Typ) = E_Record_Type
- and then Is_Concurrent_Record_Type (Typ)
- and then Ekind (Corresponding_Concurrent_Type (Typ)) =
- E_Task_Type;
- Loc : constant Source_Ptr := Sloc (Typ);
- Proc_Id : Entity_Id;
- Stmts : List_Id;
-
- begin
- -- The corresponding records of task types are not controlled by design.
- -- For the sake of completeness, create an empty Finalize_Address to be
- -- used in task class-wide allocations.
-
- if Is_Task then
- null;
-
- -- Nothing to do if the type is not controlled or it already has a
- -- TSS entry for Finalize_Address. Skip class-wide subtypes which do not
- -- come from source. These are usually generated for completeness and
- -- do not need the Finalize_Address primitive.
-
- elsif not Needs_Finalization (Typ)
- or else Is_Abstract_Type (Typ)
- or else Present (TSS (Typ, TSS_Finalize_Address))
- or else
- (Is_Class_Wide_Type (Typ)
- and then Ekind (Root_Type (Typ)) = E_Record_Subtype
- and then not Comes_From_Source (Root_Type (Typ)))
- then
- return;
- end if;
-
- Proc_Id :=
- Make_Defining_Identifier (Loc,
- Make_TSS_Name (Typ, TSS_Finalize_Address));
-
- -- Generate:
-
- -- procedure <Typ>FD (V : System.Address) is
- -- begin
- -- null; -- for tasks
-
- -- declare -- for all other types
- -- type Pnn is access all Typ;
- -- for Pnn'Storage_Size use 0;
- -- begin
- -- [Deep_]Finalize (Pnn (V).all);
- -- end;
- -- end TypFD;
-
- if Is_Task then
- Stmts := New_List (Make_Null_Statement (Loc));
- else
- Stmts := Make_Finalize_Address_Stmts (Typ);
- end if;
-
- Discard_Node (
- Make_Subprogram_Body (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Proc_Id,
-
- Parameter_Specifications => New_List (
- Make_Parameter_Specification (Loc,
- Defining_Identifier =>
- Make_Defining_Identifier (Loc, Name_V),
- Parameter_Type =>
- New_Reference_To (RTE (RE_Address), Loc)))),
-
- Declarations => No_List,
-
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Stmts)));
-
- Set_TSS (Typ, Proc_Id);
- end Make_Finalize_Address_Body;
-
- ---------------------------------
- -- Make_Finalize_Address_Stmts --
- ---------------------------------
-
- function Make_Finalize_Address_Stmts (Typ : Entity_Id) return List_Id is
- Loc : constant Source_Ptr := Sloc (Typ);
- Ptr_Typ : constant Entity_Id := Make_Temporary (Loc, 'P');
- Decls : List_Id;
- Desg_Typ : Entity_Id;
- Obj_Expr : Node_Id;
-
- begin
- if Is_Array_Type (Typ) then
- if Is_Constrained (First_Subtype (Typ)) then
- Desg_Typ := First_Subtype (Typ);
- else
- Desg_Typ := Base_Type (Typ);
- end if;
-
- -- Class-wide types of constrained root types
-
- elsif Is_Class_Wide_Type (Typ)
- and then Has_Discriminants (Root_Type (Typ))
- and then not
- Is_Empty_Elmt_List (Discriminant_Constraint (Root_Type (Typ)))
- then
- declare
- Parent_Typ : Entity_Id;
-
- begin
- -- Climb the parent type chain looking for a non-constrained type
-
- Parent_Typ := Root_Type (Typ);
- while Parent_Typ /= Etype (Parent_Typ)
- and then Has_Discriminants (Parent_Typ)
- and then not
- Is_Empty_Elmt_List (Discriminant_Constraint (Parent_Typ))
- loop
- Parent_Typ := Etype (Parent_Typ);
- end loop;
-
- -- Handle views created for tagged types with unknown
- -- discriminants.
-
- if Is_Underlying_Record_View (Parent_Typ) then
- Parent_Typ := Underlying_Record_View (Parent_Typ);
- end if;
-
- Desg_Typ := Class_Wide_Type (Underlying_Type (Parent_Typ));
- end;
-
- -- General case
-
- else
- Desg_Typ := Typ;
- end if;
-
- -- Generate:
- -- type Ptr_Typ is access all Typ;
- -- for Ptr_Typ'Storage_Size use 0;
-
- Decls := New_List (
- Make_Full_Type_Declaration (Loc,
- Defining_Identifier => Ptr_Typ,
- Type_Definition =>
- Make_Access_To_Object_Definition (Loc,
- All_Present => True,
- Subtype_Indication => New_Reference_To (Desg_Typ, Loc))),
-
- Make_Attribute_Definition_Clause (Loc,
- Name => New_Reference_To (Ptr_Typ, Loc),
- Chars => Name_Storage_Size,
- Expression => Make_Integer_Literal (Loc, 0)));
-
- Obj_Expr := Make_Identifier (Loc, Name_V);
-
- -- Unconstrained arrays require special processing in order to retrieve
- -- the elements. To achieve this, we have to skip the dope vector which
- -- lays in front of the elements and then use a thin pointer to perform
- -- the address-to-access conversion.
-
- if Is_Array_Type (Typ)
- and then not Is_Constrained (First_Subtype (Typ))
- then
- declare
- Dope_Id : Entity_Id;
-
- begin
- -- Ensure that Ptr_Typ a thin pointer, generate:
- -- for Ptr_Typ'Size use System.Address'Size;
-
- Append_To (Decls,
- Make_Attribute_Definition_Clause (Loc,
- Name => New_Reference_To (Ptr_Typ, Loc),
- Chars => Name_Size,
- Expression =>
- Make_Integer_Literal (Loc, System_Address_Size)));
-
- -- Generate:
- -- Dnn : constant Storage_Offset :=
- -- Desg_Typ'Descriptor_Size / Storage_Unit;
-
- Dope_Id := Make_Temporary (Loc, 'D');
-
- Append_To (Decls,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Dope_Id,
- Constant_Present => True,
- Object_Definition =>
- New_Reference_To (RTE (RE_Storage_Offset), Loc),
- Expression =>
- Make_Op_Divide (Loc,
- Left_Opnd =>
- Make_Attribute_Reference (Loc,
- Prefix => New_Reference_To (Desg_Typ, Loc),
- Attribute_Name => Name_Descriptor_Size),
- Right_Opnd =>
- Make_Integer_Literal (Loc, System_Storage_Unit))));
-
- -- Shift the address from the start of the dope vector to the
- -- start of the elements:
- --
- -- V + Dnn
- --
- -- Note that this is done through a wrapper routine since RTSfind
- -- cannot retrieve operations with string names of the form "+".
-
- Obj_Expr :=
- Make_Function_Call (Loc,
- Name =>
- New_Reference_To (RTE (RE_Add_Offset_To_Address), Loc),
- Parameter_Associations => New_List (
- Obj_Expr,
- New_Reference_To (Dope_Id, Loc)));
- end;
- end if;
-
- -- Create the block and the finalization call
-
- return New_List (
- Make_Block_Statement (Loc,
- Declarations => Decls,
-
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (
- Make_Final_Call (
- Obj_Ref =>
- Make_Explicit_Dereference (Loc,
- Prefix => Unchecked_Convert_To (Ptr_Typ, Obj_Expr)),
- Typ => Desg_Typ)))));
- end Make_Finalize_Address_Stmts;
-
- -------------------------------------
- -- Make_Handler_For_Ctrl_Operation --
- -------------------------------------
-
- -- Generate:
-
- -- when E : others =>
- -- Raise_From_Controlled_Operation (E);
-
- -- or:
-
- -- when others =>
- -- raise Program_Error [finalize raised exception];
-
- -- depending on whether Raise_From_Controlled_Operation is available
-
- function Make_Handler_For_Ctrl_Operation
- (Loc : Source_Ptr) return Node_Id
- is
- E_Occ : Entity_Id;
- -- Choice parameter (for the first case above)
-
- Raise_Node : Node_Id;
- -- Procedure call or raise statement
-
- begin
- -- Standard run-time, .NET/JVM targets: add choice parameter E and pass
- -- it to Raise_From_Controlled_Operation so that the original exception
- -- name and message can be recorded in the exception message for
- -- Program_Error.
-
- if RTE_Available (RE_Raise_From_Controlled_Operation) then
- E_Occ := Make_Defining_Identifier (Loc, Name_E);
- Raise_Node :=
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To
- (RTE (RE_Raise_From_Controlled_Operation), Loc),
- Parameter_Associations => New_List (
- New_Reference_To (E_Occ, Loc)));
-
- -- Restricted run-time: exception messages are not supported
-
- else
- E_Occ := Empty;
- Raise_Node :=
- Make_Raise_Program_Error (Loc,
- Reason => PE_Finalize_Raised_Exception);
- end if;
-
- return
- Make_Implicit_Exception_Handler (Loc,
- Exception_Choices => New_List (Make_Others_Choice (Loc)),
- Choice_Parameter => E_Occ,
- Statements => New_List (Raise_Node));
- end Make_Handler_For_Ctrl_Operation;
-
- --------------------
- -- Make_Init_Call --
- --------------------
-
- function Make_Init_Call
- (Obj_Ref : Node_Id;
- Typ : Entity_Id) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (Obj_Ref);
- Is_Conc : Boolean;
- Proc : Entity_Id;
- Ref : Node_Id;
- Utyp : Entity_Id;
-
- begin
- -- Deal with the type and object reference. Depending on the context, an
- -- object reference may need several conversions.
-
- if Is_Concurrent_Type (Typ) then
- Is_Conc := True;
- Utyp := Corresponding_Record_Type (Typ);
- Ref := Convert_Concurrent (Obj_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));
- Ref := Convert_Concurrent (Obj_Ref, Underlying_Type (Typ));
-
- else
- Is_Conc := False;
- Utyp := Typ;
- Ref := Obj_Ref;
- end if;
-
- Set_Assignment_OK (Ref);
-
- Utyp := Underlying_Type (Base_Type (Utyp));
-
- -- Deal with non-tagged derivation of private views
-
- if Is_Untagged_Derivation (Typ)
- and then not Is_Conc
- then
- Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
- Ref := Unchecked_Convert_To (Utyp, Ref);
-
- -- The following is to prevent problems with UC see 1.156 RH ???
-
- Set_Assignment_OK (Ref);
- end if;
-
- -- If the underlying_type is a subtype, then we are dealing with the
- -- completion of a private type. We need to access the base type and
- -- generate a conversion to it.
-
- if Utyp /= Base_Type (Utyp) then
- pragma Assert (Is_Private_Type (Typ));
- Utyp := Base_Type (Utyp);
- Ref := Unchecked_Convert_To (Utyp, Ref);
- end if;
-
- -- Select the appropriate version of initialize
-
- if Has_Controlled_Component (Utyp) then
- Proc := TSS (Utyp, Deep_Name_Of (Initialize_Case));
- else
- Proc := Find_Prim_Op (Utyp, Name_Of (Initialize_Case));
- Check_Visibly_Controlled (Initialize_Case, Typ, Proc, Ref);
- end if;
-
- -- The object reference may need another conversion depending on the
- -- type of the formal and that of the actual.
-
- Ref := Convert_View (Proc, Ref);
-
- -- Generate:
- -- [Deep_]Initialize (Ref);
-
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (Proc, Loc),
- Parameter_Associations => New_List (Ref));
- end Make_Init_Call;
-
- ------------------------------
- -- Make_Local_Deep_Finalize --
- ------------------------------
-
- function Make_Local_Deep_Finalize
- (Typ : Entity_Id;
- Nam : Entity_Id) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (Typ);
- Formals : List_Id;
-
- begin
- Formals := New_List (
-
- -- V : in out Typ
-
- 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)),
-
- -- F : Boolean := True
-
- Make_Parameter_Specification (Loc,
- Defining_Identifier => Make_Defining_Identifier (Loc, Name_F),
- Parameter_Type => New_Reference_To (Standard_Boolean, Loc),
- Expression => New_Reference_To (Standard_True, Loc)));
-
- -- Add the necessary number of counters to represent the initialization
- -- state of an object.
-
- return
- Make_Subprogram_Body (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Nam,
- Parameter_Specifications => Formals),
-
- Declarations => No_List,
-
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Make_Deep_Record_Body (Finalize_Case, Typ, True)));
- end Make_Local_Deep_Finalize;
-
- ------------------------------------
- -- Make_Set_Finalize_Address_Call --
- ------------------------------------
-
- function Make_Set_Finalize_Address_Call
- (Loc : Source_Ptr;
- Typ : Entity_Id;
- Ptr_Typ : Entity_Id) return Node_Id
- is
- Desig_Typ : constant Entity_Id :=
- Available_View (Designated_Type (Ptr_Typ));
- Fin_Mas_Id : constant Entity_Id := Finalization_Master (Ptr_Typ);
- Fin_Mas_Ref : Node_Id;
- Utyp : Entity_Id;
-
- begin
- -- If the context is a class-wide allocator, we use the class-wide type
- -- to obtain the proper Finalize_Address routine.
-
- if Is_Class_Wide_Type (Desig_Typ) then
- Utyp := Desig_Typ;
-
- else
- Utyp := Typ;
-
- if Is_Private_Type (Utyp) and then Present (Full_View (Utyp)) then
- Utyp := Full_View (Utyp);
- end if;
-
- if Is_Concurrent_Type (Utyp) then
- Utyp := Corresponding_Record_Type (Utyp);
- end if;
- end if;
-
- Utyp := Underlying_Type (Base_Type (Utyp));
-
- -- Deal with non-tagged derivation of private views. If the parent is
- -- now known to be protected, the finalization routine is the one
- -- defined on the corresponding record of the ancestor (corresponding
- -- records do not automatically inherit operations, but maybe they
- -- should???)
-
- if Is_Untagged_Derivation (Typ) then
- if Is_Protected_Type (Typ) then
- Utyp := Corresponding_Record_Type (Root_Type (Base_Type (Typ)));
- else
- Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
-
- if Is_Protected_Type (Utyp) then
- Utyp := Corresponding_Record_Type (Utyp);
- end if;
- end if;
- end if;
-
- -- If the underlying_type is a subtype, we are dealing with the
- -- completion of a private type. We need to access the base type and
- -- generate a conversion to it.
-
- if Utyp /= Base_Type (Utyp) then
- pragma Assert (Is_Private_Type (Typ));
-
- Utyp := Base_Type (Utyp);
- end if;
-
- Fin_Mas_Ref := New_Occurrence_Of (Fin_Mas_Id, Loc);
-
- -- If the call is from a build-in-place function, the Master parameter
- -- is actually a pointer. Dereference it for the call.
-
- if Is_Access_Type (Etype (Fin_Mas_Id)) then
- Fin_Mas_Ref := Make_Explicit_Dereference (Loc, Fin_Mas_Ref);
- end if;
-
- -- Generate:
- -- Set_Finalize_Address (<Ptr_Typ>FM, <Utyp>FD'Unrestricted_Access);
-
- return
- Make_Procedure_Call_Statement (Loc,
- Name =>
- New_Reference_To (RTE (RE_Set_Finalize_Address), Loc),
- Parameter_Associations => New_List (
- Fin_Mas_Ref,
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Reference_To (TSS (Utyp, TSS_Finalize_Address), Loc),
- Attribute_Name => Name_Unrestricted_Access)));
- end Make_Set_Finalize_Address_Call;
-
- --------------------------
- -- Make_Transient_Block --
- --------------------------
-
- function Make_Transient_Block
- (Loc : Source_Ptr;
- Action : Node_Id;
- Par : Node_Id) return Node_Id
- is
- Decls : constant List_Id := New_List;
- Instrs : constant List_Id := New_List (Action);
- Block : Node_Id;
- Insert : Node_Id;
-
- begin
- -- Case where only secondary stack use is involved
-
- if VM_Target = No_VM
- and then Uses_Sec_Stack (Current_Scope)
- and then Nkind (Action) /= N_Simple_Return_Statement
- and then Nkind (Par) /= N_Exception_Handler
- then
- declare
- S : Entity_Id;
-
- begin
- S := Scope (Current_Scope);
- loop
- -- At the outer level, no need to release the sec stack
-
- if S = Standard_Standard then
- Set_Uses_Sec_Stack (Current_Scope, False);
- exit;
-
- -- In a function, only release the sec stack if the function
- -- does not return on the sec stack otherwise the result may
- -- be lost. The caller is responsible for releasing.
-
- elsif Ekind (S) = E_Function then
- Set_Uses_Sec_Stack (Current_Scope, False);
-
- if not Requires_Transient_Scope (Etype (S)) then
- Set_Uses_Sec_Stack (S, True);
- Check_Restriction (No_Secondary_Stack, Action);
- end if;
-
- exit;
-
- -- In a loop or entry we should install a block encompassing
- -- all the construct. For now just release right away.
-
- elsif Ekind_In (S, E_Entry, E_Loop) then
- exit;
-
- -- In a procedure or a block, we release on exit of the
- -- procedure or block. ??? memory leak can be created by
- -- recursive calls.
-
- elsif Ekind_In (S, E_Block, E_Procedure) then
- Set_Uses_Sec_Stack (S, True);
- Check_Restriction (No_Secondary_Stack, Action);
- Set_Uses_Sec_Stack (Current_Scope, False);
- exit;
-
- else
- S := Scope (S);
- end if;
- end loop;
- end;
- end if;
-
- -- Create the transient block. Set the parent now since the block itself
- -- is not part of the tree.
-
- Block :=
- 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);
- Set_Parent (Block, Par);
-
- -- Insert actions stuck in the transient scopes as well as all freezing
- -- nodes needed by those actions.
-
- Insert_Actions_In_Scope_Around (Action);
-
- Insert := Prev (Action);
- if Present (Insert) then
- Freeze_All (First_Entity (Current_Scope), Insert);
- end if;
-
- -- When the transient scope was established, we pushed the entry for the
- -- transient scope onto the scope stack, so that the scope was active
- -- for the installation of finalizable entities etc. Now we must remove
- -- this entry, since we have constructed a proper block.
-
- Pop_Scope;
-
- return Block;
- end Make_Transient_Block;
-
- ------------------------
- -- Node_To_Be_Wrapped --
- ------------------------
-
- 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;
-
- ----------------------------
- -- Set_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;
-
- ----------------------------------
- -- Store_After_Actions_In_Scope --
- ----------------------------------
-
- 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;
-
- -----------------------------------
- -- Store_Before_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;
-
- --------------------------------
- -- Wrap_Transient_Declaration --
- --------------------------------
-
- -- If a transient scope has been established during the processing of the
- -- Expression of an Object_Declaration, it is not possible to wrap the
- -- declaration into a transient block as usual case, otherwise the object
- -- would be itself declared in the wrong scope. Therefore, all entities (if
- -- any) defined in the transient block are moved to the proper enclosing
- -- scope, furthermore, if they are controlled variables they are finalized
- -- right after the declaration. The finalization list of the transient
- -- scope is defined as a renaming of the enclosing one so during their
- -- initialization they will be attached to the proper finalization list.
- -- For instance, the following declaration :
-
- -- X : Typ := F (G (A), G (B));
-
- -- (where G(A) and G(B) return controlled values, expanded as _v1 and _v2)
- -- is expanded into :
-
- -- X : Typ := [ complex Expression-Action ];
- -- [Deep_]Finalize (_v1);
- -- [Deep_]Finalize (_v2);
-
- procedure Wrap_Transient_Declaration (N : Node_Id) is
- Encl_S : Entity_Id;
- S : Entity_Id;
- Uses_SS : Boolean;
-
- begin
- S := Current_Scope;
- Encl_S := Scope (S);
-
- -- Insert Actions kept in the Scope stack
-
- Insert_Actions_In_Scope_Around (N);
-
- -- If the declaration is consuming some secondary stack, mark the
- -- enclosing scope appropriately.
-
- Uses_SS := Uses_Sec_Stack (S);
- Pop_Scope;
-
- -- Put the local entities back in the enclosing scope, and set the
- -- Is_Public flag appropriately.
-
- Transfer_Entities (S, Encl_S);
-
- -- Mark the enclosing dynamic scope so that the sec stack will be
- -- released upon its exit unless this is a function that returns on
- -- the sec stack in which case this will be done by the caller.
-
- if VM_Target = No_VM and then 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;
-
- -------------------------------
- -- Wrap_Transient_Expression --
- -------------------------------
-
- procedure Wrap_Transient_Expression (N : Node_Id) is
- Expr : constant Node_Id := Relocate_Node (N);
- Loc : constant Source_Ptr := Sloc (N);
- Temp : constant Entity_Id := Make_Temporary (Loc, 'E', N);
- Typ : constant Entity_Id := Etype (N);
-
- begin
- -- Generate:
-
- -- Temp : Typ;
- -- declare
- -- M : constant Mark_Id := SS_Mark;
- -- procedure Finalizer is ... (See Build_Finalizer)
-
- -- begin
- -- Temp := <Expr>;
- --
- -- at end
- -- Finalizer;
- -- end;
-
- Insert_Actions (N, New_List (
- Make_Object_Declaration (Loc,
- Defining_Identifier => Temp,
- Object_Definition => New_Reference_To (Typ, Loc)),
-
- Make_Transient_Block (Loc,
- Action =>
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Temp, Loc),
- Expression => Expr),
- Par => Parent (N))));
-
- Rewrite (N, New_Reference_To (Temp, Loc));
- Analyze_And_Resolve (N, Typ);
- end Wrap_Transient_Expression;
-
- ------------------------------
- -- Wrap_Transient_Statement --
- ------------------------------
-
- procedure Wrap_Transient_Statement (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- New_Stmt : constant Node_Id := Relocate_Node (N);
-
- begin
- -- Generate:
- -- declare
- -- M : constant Mark_Id := SS_Mark;
- -- procedure Finalizer is ... (See Build_Finalizer)
- --
- -- begin
- -- <New_Stmt>;
- --
- -- at end
- -- Finalizer;
- -- end;
-
- Rewrite (N,
- Make_Transient_Block (Loc,
- Action => New_Stmt,
- Par => Parent (N)));
-
- -- With the scope stack back to normal, we can call analyze on the
- -- resulting block. At this point, the transient scope is being
- -- treated like a perfectly normal scope, so there is nothing
- -- special about it.
-
- -- Note: Wrap_Transient_Statement is called with the node already
- -- analyzed (i.e. Analyzed (N) is True). This is important, since
- -- otherwise we would get a recursive processing of the node when
- -- we do this Analyze call.
-
- Analyze (N);
- end Wrap_Transient_Statement;
-
-end Exp_Ch7;