-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2011, Free Software Foundation, Inc. --
+-- 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- --
-- body or an accept body. The renamed object is a component of the
-- parameter block that is a parameter in the entry call.
- -- In Ada2012, If the formal is an incomplete tagged type, the renaming
+ -- In Ada 2012, if the formal is an incomplete tagged type, the renaming
-- does not dereference the corresponding component to prevent an illegal
-- use of the incomplete type (AI05-0151).
-- to handle properly the case of bounds that depend on discriminants.
-- If Cap is true, the result is capped according to Entry_Family_Bound.
+ procedure Find_Enclosing_Context
+ (N : Node_Id;
+ Context : out Node_Id;
+ Context_Id : out Entity_Id;
+ Context_Decls : out List_Id);
+ -- Subsidiary routine to procedures Build_Activation_Chain_Entity and
+ -- Build_Master_Entity. Given an arbitrary node in the tree, find the
+ -- nearest enclosing body, block, package or return statement and return
+ -- its constituents. Context is the enclosing construct, Context_Id is
+ -- the scope of Context_Id and Context_Decls is the declarative list of
+ -- Context.
+
procedure Extract_Dispatching_Call
(N : Node_Id;
Call_Ent : out Entity_Id;
-- Local variables
- Decls : List_Id;
- Par : Node_Id;
+ Context : Node_Id;
+ Context_Id : Entity_Id;
+ Decls : List_Id;
-- Start of processing for Build_Activation_Chain_Entity
begin
- -- Traverse the parent chain looking for an enclosing construct which
- -- contains an activation chain variable. The construct is either a
- -- body, a block, or an extended return.
-
- Par := Parent (N);
-
- while not Nkind_In (Par, N_Block_Statement,
- N_Entry_Body,
- N_Extended_Return_Statement,
- N_Package_Body,
- N_Package_Declaration,
- N_Subprogram_Body,
- N_Task_Body)
- loop
- Par := Parent (Par);
- end loop;
-
- -- When the enclosing construct is a package body, the activation chain
- -- variable is declared in the body, but the Activation_Chain_Entity is
- -- attached to the spec.
-
- if Nkind (Par) = N_Package_Body then
- Decls := Declarations (Par);
- Par := Unit_Declaration_Node (Corresponding_Spec (Par));
-
- elsif Nkind (Par) = N_Package_Declaration then
- Decls := Visible_Declarations (Specification (Par));
-
- elsif Nkind (Par) = N_Extended_Return_Statement then
- Decls := Return_Object_Declarations (Par);
-
- else
- Decls := Declarations (Par);
- end if;
+ Find_Enclosing_Context (N, Context, Context_Id, Decls);
-- If an activation chain entity has not been declared already, create
-- one.
- if Nkind (Par) = N_Extended_Return_Statement
- or else No (Activation_Chain_Entity (Par))
+ if Nkind (Context) = N_Extended_Return_Statement
+ or else No (Activation_Chain_Entity (Context))
then
-- Since extended return statements do not store the entity of the
-- chain, examine the return object declarations to avoid creating
-- a duplicate.
- if Nkind (Par) = N_Extended_Return_Statement
- and then Has_Activation_Chain (Par)
+ if Nkind (Context) = N_Extended_Return_Statement
+ and then Has_Activation_Chain (Context)
then
return;
end if;
declare
+ Loc : constant Source_Ptr := Sloc (Context);
Chain : Entity_Id;
Decl : Node_Id;
-- Activate_Tasks. Task activation is the responsibility of the
-- caller.
- if Nkind (Par) /= N_Extended_Return_Statement then
- Set_Activation_Chain_Entity (Par, Chain);
+ if Nkind (Context) /= N_Extended_Return_Statement then
+ Set_Activation_Chain_Entity (Context, Chain);
end if;
Decl :=
- Make_Object_Declaration (Sloc (Par),
+ Make_Object_Declaration (Loc,
Defining_Identifier => Chain,
Aliased_Present => True,
Object_Definition =>
- New_Reference_To (RTE (RE_Activation_Chain), Sloc (Par)));
+ New_Reference_To (RTE (RE_Activation_Chain), Loc));
Prepend_To (Decls, Decl);
- Analyze (Decl);
+
+ -- Ensure that the _chain appears in the proper scope of the
+ -- context.
+
+ if Context_Id /= Current_Scope then
+ Push_Scope (Context_Id);
+ Analyze (Decl);
+ Pop_Scope;
+ else
+ Analyze (Decl);
+ end if;
end;
end if;
end Build_Activation_Chain_Entity;
Parameter_Associations => New_List (Concurrent_Ref (N)));
end Build_Call_With_Task;
+ -----------------------------
+ -- Build_Class_Wide_Master --
+ -----------------------------
+
+ procedure Build_Class_Wide_Master (Typ : Entity_Id) is
+ Loc : constant Source_Ptr := Sloc (Typ);
+ Master_Id : Entity_Id;
+ Master_Scope : Entity_Id;
+ Name_Id : Node_Id;
+ Related_Node : Node_Id;
+ Ren_Decl : Node_Id;
+
+ begin
+ -- Nothing to do if there is no task hierarchy
+
+ if Restriction_Active (No_Task_Hierarchy) then
+ return;
+ end if;
+
+ -- Find the declaration that created the access type. It is either a
+ -- type declaration, or an object declaration with an access definition,
+ -- in which case the type is anonymous.
+
+ if Is_Itype (Typ) then
+ Related_Node := Associated_Node_For_Itype (Typ);
+ else
+ Related_Node := Parent (Typ);
+ end if;
+
+ Master_Scope := Find_Master_Scope (Typ);
+
+ -- Nothing to do if the master scope already contains a _master entity.
+ -- The only exception to this is the following scenario:
+
+ -- Source_Scope
+ -- Transient_Scope_1
+ -- _master
+
+ -- Transient_Scope_2
+ -- use of master
+
+ -- In this case the source scope is marked as having the master entity
+ -- even though the actual declaration appears inside an inner scope. If
+ -- the second transient scope requires a _master, it cannot use the one
+ -- already declared because the entity is not visible.
+
+ Name_Id := Make_Identifier (Loc, Name_uMaster);
+
+ if not Has_Master_Entity (Master_Scope)
+ or else No (Current_Entity_In_Scope (Name_Id))
+ then
+ declare
+ Master_Decl : Node_Id;
+
+ begin
+ Set_Has_Master_Entity (Master_Scope);
+
+ -- Generate:
+ -- _master : constant Integer := Current_Master.all;
+
+ Master_Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Name_uMaster),
+ Constant_Present => True,
+ Object_Definition =>
+ New_Reference_To (Standard_Integer, Loc),
+ Expression =>
+ Make_Explicit_Dereference (Loc,
+ New_Reference_To (RTE (RE_Current_Master), Loc)));
+
+ Insert_Action (Related_Node, Master_Decl);
+ Analyze (Master_Decl);
+
+ -- Mark the containing scope as a task master. Masters associated
+ -- with return statements are already marked at this stage (see
+ -- Analyze_Subprogram_Body).
+
+ if Ekind (Current_Scope) /= E_Return_Statement then
+ declare
+ Par : Node_Id := Related_Node;
+
+ begin
+ while Nkind (Par) /= N_Compilation_Unit loop
+ Par := Parent (Par);
+
+ -- If we fall off the top, we are at the outer level, and
+ -- the environment task is our effective master, so
+ -- nothing to mark.
+
+ if Nkind_In (Par, N_Block_Statement,
+ N_Subprogram_Body,
+ N_Task_Body)
+ then
+ Set_Is_Task_Master (Par);
+ exit;
+ end if;
+ end loop;
+ end;
+ end if;
+ end;
+ end if;
+
+ Master_Id :=
+ Make_Defining_Identifier (Loc,
+ New_External_Name (Chars (Typ), 'M'));
+
+ -- Generate:
+ -- Mnn renames _master;
+
+ Ren_Decl :=
+ Make_Object_Renaming_Declaration (Loc,
+ Defining_Identifier => Master_Id,
+ Subtype_Mark => New_Reference_To (Standard_Integer, Loc),
+ Name => Name_Id);
+
+ Insert_Action (Related_Node, Ren_Decl);
+
+ Set_Master_Id (Typ, Master_Id);
+ end Build_Class_Wide_Master;
+
--------------------------------
-- Build_Corresponding_Record --
--------------------------------
-- Build_Master_Entity --
-------------------------
- procedure Build_Master_Entity (E : Entity_Id) is
- Loc : constant Source_Ptr := Sloc (E);
- P : Node_Id;
- Decl : Node_Id;
- S : Entity_Id;
+ procedure Build_Master_Entity (Obj_Or_Typ : Entity_Id) is
+ Loc : constant Source_Ptr := Sloc (Obj_Or_Typ);
+ Context : Node_Id;
+ Context_Id : Entity_Id;
+ Decl : Node_Id;
+ Decls : List_Id;
+ Par : Node_Id;
begin
- S := Find_Master_Scope (E);
+ if Is_Itype (Obj_Or_Typ) then
+ Par := Associated_Node_For_Itype (Obj_Or_Typ);
+ else
+ Par := Parent (Obj_Or_Typ);
+ end if;
+
+ -- When creating a master for a record component which is either a task
+ -- or access-to-task, the enclosing record is the master scope and the
+ -- proper insertion point is the component list.
+
+ if Is_Record_Type (Current_Scope) then
+ Context := Par;
+ Context_Id := Current_Scope;
+ Decls := List_Containing (Context);
- -- Nothing to do if we already built a master entity for this scope
- -- or if there is no task hierarchy.
+ -- Default case for object declarations and access types. Note that the
+ -- context is updated to the nearest enclosing body, block, package or
+ -- return statement.
+
+ else
+ Find_Enclosing_Context (Par, Context, Context_Id, Decls);
+ end if;
- if Has_Master_Entity (S)
+ -- Do not create a master if one already exists or there is no task
+ -- hierarchy.
+
+ if Has_Master_Entity (Context_Id)
or else Restriction_Active (No_Task_Hierarchy)
then
return;
end if;
- -- Otherwise first build the master entity
+ -- Create a master, generate:
-- _Master : constant Master_Id := Current_Master.all;
- -- and insert it just before the current declaration
Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier =>
Make_Defining_Identifier (Loc, Name_uMaster),
- Constant_Present => True,
- Object_Definition => New_Reference_To (RTE (RE_Master_Id), Loc),
- Expression =>
+ Constant_Present => True,
+ Object_Definition => New_Reference_To (RTE (RE_Master_Id), Loc),
+ Expression =>
Make_Explicit_Dereference (Loc,
New_Reference_To (RTE (RE_Current_Master), Loc)));
- P := Parent (E);
- Insert_Before (P, Decl);
- Analyze (Decl);
+ -- The master is inserted at the start of the declarative list of the
+ -- context.
- Set_Has_Master_Entity (S);
+ Prepend_To (Decls, Decl);
- -- Now mark the containing scope as a task master
+ -- In certain cases where transient scopes are involved, the immediate
+ -- scope is not always the proper master scope. Ensure that the master
+ -- declaration and entity appear in the same context.
- while Nkind (P) /= N_Compilation_Unit loop
- P := Parent (P);
+ if Context_Id /= Current_Scope then
+ Push_Scope (Context_Id);
+ Analyze (Decl);
+ Pop_Scope;
+ else
+ Analyze (Decl);
+ end if;
- -- If we fall off the top, we are at the outer level, and the
- -- environment task is our effective master, so nothing to mark.
+ -- Mark the enclosing scope and its associated construct as being task
+ -- masters.
- if Nkind_In
- (P, N_Task_Body, N_Block_Statement, N_Subprogram_Body)
+ Set_Has_Master_Entity (Context_Id);
+
+ while Present (Context)
+ and then Nkind (Context) /= N_Compilation_Unit
+ loop
+ if Nkind_In (Context, N_Block_Statement,
+ N_Subprogram_Body,
+ N_Task_Body)
then
- Set_Is_Task_Master (P, True);
- return;
+ Set_Is_Task_Master (Context);
+ exit;
- elsif Nkind (Parent (P)) = N_Subunit then
- P := Corresponding_Stub (Parent (P));
+ elsif Nkind (Parent (Context)) = N_Subunit then
+ Context := Corresponding_Stub (Parent (Context));
end if;
+
+ Context := Parent (Context);
end loop;
end Build_Master_Entity;
+ ---------------------------
+ -- Build_Master_Renaming --
+ ---------------------------
+
+ procedure Build_Master_Renaming
+ (Ptr_Typ : Entity_Id;
+ Ins_Nod : Node_Id := Empty)
+ is
+ Loc : constant Source_Ptr := Sloc (Ptr_Typ);
+ Context : Node_Id;
+ Master_Decl : Node_Id;
+ Master_Id : Entity_Id;
+
+ begin
+ -- Nothing to do if there is no task hierarchy
+
+ if Restriction_Active (No_Task_Hierarchy) then
+ return;
+ end if;
+
+ -- Determine the proper context to insert the master renaming
+
+ if Present (Ins_Nod) then
+ Context := Ins_Nod;
+ elsif Is_Itype (Ptr_Typ) then
+ Context := Associated_Node_For_Itype (Ptr_Typ);
+ else
+ Context := Parent (Ptr_Typ);
+ end if;
+
+ -- Generate:
+ -- <Ptr_Typ>M : Master_Id renames _Master;
+
+ Master_Id :=
+ Make_Defining_Identifier (Loc,
+ New_External_Name (Chars (Ptr_Typ), 'M'));
+
+ Master_Decl :=
+ Make_Object_Renaming_Declaration (Loc,
+ Defining_Identifier => Master_Id,
+ Subtype_Mark => New_Reference_To (RTE (RE_Master_Id), Loc),
+ Name => Make_Identifier (Loc, Name_uMaster));
+
+ Insert_Action (Context, Master_Decl);
+
+ -- The renamed master now services the access type
+
+ Set_Master_Id (Ptr_Typ, Master_Id);
+ end Build_Master_Renaming;
+
-----------------------------------------
-- Build_Private_Protected_Declaration --
-----------------------------------------
Make_Object_Declaration (Loc,
Defining_Identifier => Chain,
- Aliased_Present => True,
+ Aliased_Present => True,
Object_Definition =>
New_Reference_To (RTE (RE_Activation_Chain), Loc))),
procedure Establish_Task_Master (N : Node_Id) is
Call : Node_Id;
+
begin
if Restriction_Active (No_Task_Hierarchy) = False then
Call := Build_Runtime_Call (Sloc (N), RE_Enter_Master);
- Prepend_To (Declarations (N), Call);
+
+ -- The block may have no declarations, and nevertheless be a task
+ -- master, if it contains a call that may return an object that
+ -- contains tasks.
+
+ if No (Declarations (N)) then
+ Set_Declarations (N, New_List (Call));
+ else
+ Prepend_To (Declarations (N), Call);
+ end if;
+
Analyze (Call);
end if;
end Establish_Task_Master;
-- Target.Primitive (Param1, ..., ParamN);
-- Ada 2012 (AI05-0030): Dispatching requeue to an interface primitive
- -- marked by pragma Implemented (XXX, By_Any) or not marked at all.
+ -- marked by pragma Implemented (XXX, By_Any | Optional) or not marked
+ -- at all.
-- declare
-- S : constant Offset_Index :=
function Build_Dispatching_Requeue_To_Any return Node_Id;
-- Ada 2012 (AI05-0030): N denotes a dispatching requeue statement of
-- the form Concval.Ename. Ename is either marked by pragma Implemented
- -- (XXX, By_Any) or not marked at all. Create a block which determines
- -- at runtime whether Ename denotes an entry or a procedure and perform
- -- the appropriate kind of dispatching select.
+ -- (XXX, By_Any | Optional) or not marked at all. Create a block which
+ -- determines at runtime whether Ename denotes an entry or a procedure
+ -- and perform the appropriate kind of dispatching select.
function Build_Normal_Requeue return Node_Id;
-- N denotes a non-dispatching requeue statement to either a task or a
-- Process the entry wrapper's position in the primary dispatch
-- table parameter. Generate:
- -- Ada.Tags.Get_Offset_Index
- -- (Ada.Tags.Tag (Concval),
- -- <interface dispatch table position of Ename>)
+ -- Ada.Tags.Get_Entry_Index
+ -- (T => To_Tag_Ptr (Obj'Address).all,
+ -- Position =>
+ -- Ada.Tags.Get_Offset_Index
+ -- (Ada.Tags.Tag (Concval),
+ -- <interface dispatch table position of Ename>));
+
+ -- Note that Obj'Address is recursively expanded into a call to
+ -- Base_Address (Obj).
if Tagged_Type_Expansion then
Prepend_To (Params,
Make_Function_Call (Loc,
- Name => New_Reference_To (RTE (RE_Get_Offset_Index), Loc),
+ Name => New_Reference_To (RTE (RE_Get_Entry_Index), Loc),
Parameter_Associations => New_List (
- Unchecked_Convert_To (RTE (RE_Tag), Concval),
- Make_Integer_Literal (Loc, DT_Position (Entity (Ename))))));
+
+ Make_Explicit_Dereference (Loc,
+ Unchecked_Convert_To (RTE (RE_Tag_Ptr),
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Copy_Tree (Concval),
+ Attribute_Name => Name_Address))),
+
+ Make_Function_Call (Loc,
+ Name => New_Reference_To (RTE (RE_Get_Offset_Index), Loc),
+ Parameter_Associations => New_List (
+ Unchecked_Convert_To (RTE (RE_Tag), Concval),
+ Make_Integer_Literal (Loc,
+ DT_Position (Entity (Ename))))))));
-- VM targets
else
Prepend_To (Params,
Make_Function_Call (Loc,
- Name => New_Reference_To (RTE (RE_Get_Offset_Index), Loc),
-
+ Name => New_Reference_To (RTE (RE_Get_Entry_Index), Loc),
Parameter_Associations => New_List (
- -- Obj_Typ
-
Make_Attribute_Reference (Loc,
Prefix => Concval,
Attribute_Name => Name_Tag),
- -- Tag_Typ
+ Make_Function_Call (Loc,
+ Name => New_Reference_To (RTE (RE_Get_Offset_Index), Loc),
+
+ Parameter_Associations => New_List (
- Make_Attribute_Reference (Loc,
- Prefix => New_Reference_To (Etype (Concval), Loc),
- Attribute_Name => Name_Tag),
+ -- Obj_Tag
- -- Position
+ Make_Attribute_Reference (Loc,
+ Prefix => Concval,
+ Attribute_Name => Name_Tag),
- Make_Integer_Literal (Loc, DT_Position (Entity (Ename))))));
+ -- Tag_Typ
+
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Reference_To (Etype (Concval), Loc),
+ Attribute_Name => Name_Tag),
+
+ -- Position
+
+ Make_Integer_Literal (Loc,
+ DT_Position (Entity (Ename))))))));
end if;
-- Specific actuals for protected to XXX requeue
-- Generate:
-- _Disp_Requeue (<Params>);
- return
- Make_Procedure_Call_Statement (Loc,
- Name => Make_Identifier (Loc, Name_uDisp_Requeue),
- Parameter_Associations => Params);
+ -- Find entity for Disp_Requeue operation, which belongs to
+ -- the type and may not be directly visible.
+
+ declare
+ Elmt : Elmt_Id;
+ Op : Entity_Id;
+
+ begin
+ Elmt := First_Elmt (Primitive_Operations (Etype (Conc_Typ)));
+ while Present (Elmt) loop
+ Op := Node (Elmt);
+ exit when Chars (Op) = Name_uDisp_Requeue;
+ Next_Elmt (Elmt);
+ end loop;
+
+ return
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Op, Loc),
+ Parameter_Associations => Params);
+ end;
end Build_Dispatching_Requeue;
--------------------------------------
Extract_Entry (N, Concval, Ename, Index);
Conc_Typ := Etype (Concval);
+ -- If the prefix is an access to class-wide type, dereference to get
+ -- object and entry type.
+
+ if Is_Access_Type (Conc_Typ) then
+ Conc_Typ := Designated_Type (Conc_Typ);
+ Rewrite (Concval,
+ Make_Explicit_Dereference (Loc, Relocate_Node (Concval)));
+ Analyze_And_Resolve (Concval, Conc_Typ);
+ end if;
+
-- Examine the scope stack in order to find nearest enclosing protected
-- or task type. This will constitute our invocation source.
Analyze (N);
-- The procedure_or_entry_NAME's implementation kind is either
- -- By_Any or pragma Implemented was not applied at all. In this
- -- case a runtime test determines whether Ename denotes an entry
- -- or a protected procedure and performs the appropriate call.
+ -- By_Any, Optional, or pragma Implemented was not applied at all.
+ -- In this case a runtime test determines whether Ename denotes an
+ -- entry or a protected procedure and performs the appropriate
+ -- call.
else
Rewrite (N, Build_Dispatching_Requeue_To_Any);
Make_Integer_Literal (Loc, 0)));
end Family_Size;
+ ----------------------------
+ -- Find_Enclosing_Context --
+ ----------------------------
+
+ procedure Find_Enclosing_Context
+ (N : Node_Id;
+ Context : out Node_Id;
+ Context_Id : out Entity_Id;
+ Context_Decls : out List_Id)
+ is
+ begin
+ -- Traverse the parent chain looking for an enclosing body, block,
+ -- package or return statement.
+
+ Context := Parent (N);
+ while not Nkind_In (Context, N_Block_Statement,
+ N_Entry_Body,
+ N_Extended_Return_Statement,
+ N_Package_Body,
+ N_Package_Declaration,
+ N_Subprogram_Body,
+ N_Task_Body)
+ loop
+ Context := Parent (Context);
+ end loop;
+
+ -- Extract the constituents of the context
+
+ if Nkind (Context) = N_Extended_Return_Statement then
+ Context_Decls := Return_Object_Declarations (Context);
+ Context_Id := Return_Statement_Entity (Context);
+
+ -- Package declarations and bodies use a common library-level activation
+ -- chain or task master, therefore return the package declaration as the
+ -- proper carrier for the appropriate flag.
+
+ elsif Nkind (Context) = N_Package_Body then
+ Context_Decls := Declarations (Context);
+ Context_Id := Corresponding_Spec (Context);
+ Context := Parent (Context_Id);
+
+ if Nkind (Context) = N_Defining_Program_Unit_Name then
+ Context := Parent (Parent (Context));
+ else
+ Context := Parent (Context);
+ end if;
+
+ elsif Nkind (Context) = N_Package_Declaration then
+ Context_Decls := Visible_Declarations (Specification (Context));
+ Context_Id := Defining_Unit_Name (Specification (Context));
+
+ if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
+ Context_Id := Defining_Identifier (Context_Id);
+ end if;
+
+ else
+ Context_Decls := Declarations (Context);
+
+ if Nkind (Context) = N_Block_Statement then
+ Context_Id := Entity (Identifier (Context));
+
+ elsif Nkind (Context) = N_Entry_Body then
+ Context_Id := Defining_Identifier (Context);
+
+ elsif Nkind (Context) = N_Subprogram_Body then
+ if Present (Corresponding_Spec (Context)) then
+ Context_Id := Corresponding_Spec (Context);
+ else
+ Context_Id := Defining_Unit_Name (Specification (Context));
+
+ if Nkind (Context_Id) = N_Defining_Program_Unit_Name then
+ Context_Id := Defining_Identifier (Context_Id);
+ end if;
+ end if;
+
+ elsif Nkind (Context) = N_Task_Body then
+ Context_Id := Corresponding_Spec (Context);
+
+ else
+ raise Program_Error;
+ end if;
+ end if;
+
+ pragma Assert (Present (Context));
+ pragma Assert (Present (Context_Id));
+ pragma Assert (Present (Context_Decls));
+ end Find_Enclosing_Context;
+
-----------------------
-- Find_Master_Scope --
-----------------------
S : Entity_Id;
begin
- -- In Ada2005, the master is the innermost enclosing scope that is not
+ -- In Ada 2005, the master is the innermost enclosing scope that is not
-- transient. If the enclosing block is the rewriting of a call or the
-- scope is an extended return statement this is valid master. The
-- master in an extended return is only used within the return, and is