------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                              E X P_ D I S T                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                            $Revision: 1.1.16.1 $
--                                                                          --
--          Copyright (C) 1992-2001 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 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
-- MA 02111-1307, USA.                                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

with Atree;       use Atree;
with Einfo;       use Einfo;
with Elists;      use Elists;
with Exp_Tss;     use Exp_Tss;
with Exp_Util;    use Exp_Util;
with GNAT.HTable; use GNAT.HTable;
with Lib;         use Lib;
with Namet;       use Namet;
with Nlists;      use Nlists;
with Nmake;       use Nmake;
with Opt;         use Opt;
with Rtsfind;     use Rtsfind;
with Sem;         use Sem;
with Sem_Ch3;     use Sem_Ch3;
with Sem_Ch8;     use Sem_Ch8;
with Sem_Dist;    use Sem_Dist;
with Sem_Util;    use Sem_Util;
with Sinfo;       use Sinfo;
with Snames;      use Snames;
with Stand;       use Stand;
with Stringt;     use Stringt;
with Tbuild;      use Tbuild;
with Uintp;       use Uintp;
with Uname;       use Uname;

package body Exp_Dist is

   --  The following model has been used to implement distributed objects:
   --  given a designated type D and a RACW type R, then a record of the
   --  form:
   --    type Stub is tagged record
   --       [...declaration similar to s-parint.ads RACW_Stub_Type...]
   --    end Stub;
   --  is built. This type has two properties:
   --
   --    1) Since it has the same structure than RACW_Stub_Type, it can be
   --       converted to and from this type to make it suitable for
   --       System.Partition_Interface.Get_Unique_Remote_Pointer in order
   --       to avoid memory leaks when the same remote object arrive on the
   --       same partition by following different pathes
   --
   --    2) It also has the same dispatching table as the designated type D,
   --       and thus can be used as an object designated by a value of type
   --       R on any partition other than the one on which the object has
   --       been created, since only dispatching calls will be performed and
   --       the fields themselves will not be used. We call Derive_Subprograms
   --       to fake half a derivation to ensure that the subprograms do have
   --       the same dispatching table.

   -----------------------
   -- Local subprograms --
   -----------------------

   procedure Build_General_Calling_Stubs
     (Decls                     : in List_Id;
      Statements                : in List_Id;
      Target_Partition          : in Entity_Id;
      RPC_Receiver              : in Node_Id;
      Subprogram_Id             : in Node_Id;
      Asynchronous              : in Node_Id := Empty;
      Is_Known_Asynchronous     : in Boolean := False;
      Is_Known_Non_Asynchronous : in Boolean := False;
      Is_Function               : in Boolean;
      Spec                      : in Node_Id;
      Object_Type               : in Entity_Id := Empty;
      Nod                       : in Node_Id);
   --  Build calling stubs for general purpose. The parameters are:
   --    Decls             : a place to put declarations
   --    Statements        : a place to put statements
   --    Target_Partition  : a node containing the target partition that must
   --                        be a N_Defining_Identifier
   --    RPC_Receiver      : a node containing the RPC receiver
   --    Subprogram_Id     : a node containing the subprogram ID
   --    Asynchronous      : True if an APC must be made instead of an RPC.
   --                        The value needs not be supplied if one of the
   --                        Is_Known_... is True.
   --    Is_Known_Async... : True if we know that this is asynchronous
   --    Is_Known_Non_A... : True if we know that this is not asynchronous
   --    Spec              : a node with a Parameter_Specifications and
   --                        a Subtype_Mark if applicable
   --    Object_Type       : in case of a RACW, parameters of type access to
   --                        Object_Type will be marshalled using the
   --                        address of this object (the addr field) rather
   --                        than using the 'Write on the object itself
   --    Nod               : used to provide sloc for generated code

   function Build_Subprogram_Calling_Stubs
     (Vis_Decl                 : Node_Id;
      Subp_Id                  : Int;
      Asynchronous             : Boolean;
      Dynamically_Asynchronous : Boolean   := False;
      Stub_Type                : Entity_Id := Empty;
      Locator                  : Entity_Id := Empty;
      New_Name                 : Name_Id   := No_Name)
      return                     Node_Id;
   --  Build the calling stub for a given subprogram with the subprogram ID
   --  being Subp_Id. If Stub_Type is given, then the "addr" field of
   --  parameters of this type will be marshalled instead of the object
   --  itself. It will then be converted into Stub_Type before performing
   --  the real call. If Dynamically_Asynchronous is True, then it will be
   --  computed at run time whether the call is asynchronous or not.
   --  Otherwise, the value of the formal Asynchronous will be used.
   --  If Locator is not Empty, it will be used instead of RCI_Cache. If
   --  New_Name is given, then it will be used instead of the original name.

   function Build_Subprogram_Receiving_Stubs
     (Vis_Decl                 : Node_Id;
      Asynchronous             : Boolean;
      Dynamically_Asynchronous : Boolean   := False;
      Stub_Type                : Entity_Id := Empty;
      RACW_Type                : Entity_Id := Empty;
      Parent_Primitive         : Entity_Id := Empty)
      return                     Node_Id;
   --  Build the receiving stub for a given subprogram. The subprogram
   --  declaration is also built by this procedure, and the value returned
   --  is a N_Subprogram_Body. If a parameter of type access to Stub_Type is
   --  found in the specification, then its address is read from the stream
   --  instead of the object itself and converted into an access to
   --  class-wide type before doing the real call using any of the RACW type
   --  pointing on the designated type.

   function Build_Ordered_Parameters_List (Spec : Node_Id) return List_Id;
   --  Return an ordered parameter list: unconstrained parameters are put
   --  at the beginning of the list and constrained ones are put after. If
   --  there are no parameters, an empty list is returned.

   procedure Add_Calling_Stubs_To_Declarations
     (Pkg_Spec : in Node_Id;
      Decls    : in List_Id);
   --  Add calling stubs to the declarative part

   procedure Add_Receiving_Stubs_To_Declarations
     (Pkg_Spec : in Node_Id;
      Decls    : in List_Id);
   --  Add receiving stubs to the declarative part

   procedure Add_RAS_Dereference_Attribute (N : in Node_Id);
   --  Add a subprogram body for RAS dereference

   procedure Add_RAS_Access_Attribute (N : in Node_Id);
   --  Add a subprogram body for RAS Access attribute

   function Could_Be_Asynchronous (Spec : Node_Id) return Boolean;
   --  Return True if nothing prevents the program whose specification is
   --  given to be asynchronous (i.e. no out parameter).

   function Get_Pkg_Name_String_Id (Decl_Node : Node_Id) return String_Id;
   function Get_String_Id (Val : String) return String_Id;
   --  Ugly functions used to retrieve a package name. Inherited from the
   --  old exp_dist.adb and not rewritten yet ???

   function Pack_Entity_Into_Stream_Access
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Entity_Id;
      Etyp   : Entity_Id := Empty)
      return   Node_Id;
   --  Pack Object (of type Etyp) into Stream. If Etyp is not given,
   --  then Etype (Object) will be used if present. If the type is
   --  constrained, then 'Write will be used to output the object,
   --  If the type is unconstrained, 'Output will be used.

   function Pack_Node_Into_Stream
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Node_Id;
      Etyp   : Entity_Id)
      return   Node_Id;
   --  Similar to above, with an arbitrary node instead of an entity

   function Pack_Node_Into_Stream_Access
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Node_Id;
      Etyp   : Entity_Id)
      return   Node_Id;
   --  Similar to above, with Stream instead of Stream'Access

   function Copy_Specification
     (Loc         : Source_Ptr;
      Spec        : Node_Id;
      Object_Type : Entity_Id := Empty;
      Stub_Type   : Entity_Id := Empty;
      New_Name    : Name_Id   := No_Name)
      return        Node_Id;
   --  Build a specification from another one. If Object_Type is not Empty
   --  and any access to Object_Type is found, then it is replaced by an
   --  access to Stub_Type. If New_Name is given, then it will be used as
   --  the name for the newly created spec.

   function Scope_Of_Spec (Spec : Node_Id) return Entity_Id;
   --  Return the scope represented by a given spec

   function Need_Extra_Constrained (Parameter : Node_Id) return Boolean;
   --  Return True if the current parameter needs an extra formal to reflect
   --  its constrained status.

   function Is_RACW_Controlling_Formal
     (Parameter : Node_Id; Stub_Type : Entity_Id)
      return Boolean;
   --  Return True if the current parameter is a controlling formal argument
   --  of type Stub_Type or access to Stub_Type.

   type Stub_Structure is record
      Stub_Type           : Entity_Id;
      Stub_Type_Access    : Entity_Id;
      Object_RPC_Receiver : Entity_Id;
      RPC_Receiver_Stream : Entity_Id;
      RPC_Receiver_Result : Entity_Id;
      RACW_Type           : Entity_Id;
   end record;
   --  This structure is necessary because of the two phases analysis of
   --  a RACW declaration occurring in the same Remote_Types package as the
   --  designated type. RACW_Type is any of the RACW types pointing on this
   --  designated type, it is used here to save an anonymous type creation
   --  for each primitive operation.

   Empty_Stub_Structure : constant Stub_Structure :=
     (Empty, Empty, Empty, Empty, Empty, Empty);

   type Hash_Index is range 0 .. 50;
   function Hash (F : Entity_Id) return Hash_Index;

   package Stubs_Table is
      new Simple_HTable (Header_Num => Hash_Index,
                         Element    => Stub_Structure,
                         No_Element => Empty_Stub_Structure,
                         Key        => Entity_Id,
                         Hash       => Hash,
                         Equal      => "=");
   --  Mapping between a RACW designated type and its stub type

   package Asynchronous_Flags_Table is
      new Simple_HTable (Header_Num => Hash_Index,
                         Element    => Node_Id,
                         No_Element => Empty,
                         Key        => Entity_Id,
                         Hash       => Hash,
                         Equal      => "=");
   --  Mapping between a RACW type and the node holding the value True if
   --  the RACW is asynchronous and False otherwise.

   package RCI_Locator_Table is
      new Simple_HTable (Header_Num => Hash_Index,
                         Element    => Entity_Id,
                         No_Element => Empty,
                         Key        => Entity_Id,
                         Hash       => Hash,
                         Equal      => "=");
   --  Mapping between a RCI package on which All_Calls_Remote applies and
   --  the generic instantiation of RCI_Info for this package.

   package RCI_Calling_Stubs_Table is
      new Simple_HTable (Header_Num => Hash_Index,
                         Element    => Entity_Id,
                         No_Element => Empty,
                         Key        => Entity_Id,
                         Hash       => Hash,
                         Equal      => "=");
   --  Mapping between a RCI subprogram and the corresponding calling stubs

   procedure Add_Stub_Type
     (Designated_Type     : in Entity_Id;
      RACW_Type           : in Entity_Id;
      Decls               : in List_Id;
      Stub_Type           : out Entity_Id;
      Stub_Type_Access    : out Entity_Id;
      Object_RPC_Receiver : out Entity_Id;
      Existing            : out Boolean);
   --  Add the declaration of the stub type, the access to stub type and the
   --  object RPC receiver at the end of Decls. If these already exist,
   --  then nothing is added in the tree but the right values are returned
   --  anyhow and Existing is set to True.

   procedure Add_RACW_Read_Attribute
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Declarations        : in List_Id);
   --  Add Read attribute in Decls for the RACW type. The Read attribute
   --  is added right after the RACW_Type declaration while the body is
   --  inserted after Declarations.

   procedure Add_RACW_Write_Attribute
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Object_RPC_Receiver : in Entity_Id;
      Declarations        : in List_Id);
   --  Same thing for the Write attribute

   procedure Add_RACW_Read_Write_Attributes
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Object_RPC_Receiver : in Entity_Id;
      Declarations        : in List_Id);
   --  Add Read and Write attributes declarations and bodies for a given
   --  RACW type. The declarations are added just after the declaration
   --  of the RACW type itself, while the bodies are inserted at the end
   --  of Decls.

   function RCI_Package_Locator
     (Loc          : Source_Ptr;
      Package_Spec : Node_Id)
      return         Node_Id;
   --  Instantiate the generic package RCI_Info in order to locate the
   --  RCI package whose spec is given as argument.

   function Make_Tag_Check (Loc : Source_Ptr; N : Node_Id) return Node_Id;
   --  Surround a node N by a tag check, as in:
   --      begin
   --         <N>;
   --      exception
   --         when E : Ada.Tags.Tag_Error =>
   --           Raise_Exception (Program_Error'Identity,
   --                            Exception_Message (E));
   --      end;

   function Input_With_Tag_Check
     (Loc      : Source_Ptr;
      Var_Type : Entity_Id;
      Stream   : Entity_Id)
     return Node_Id;
   --  Return a function with the following form:
   --    function R return Var_Type is
   --    begin
   --       return Var_Type'Input (S);
   --    exception
   --       when E : Ada.Tags.Tag_Error =>
   --           Raise_Exception (Program_Error'Identity,
   --                            Exception_Message (E));
   --    end R;

   ------------------------------------
   -- Local variables and structures --
   ------------------------------------

   RCI_Cache : Node_Id;

   Output_From_Constrained : constant array (Boolean) of Name_Id :=
     (False => Name_Output,
      True  => Name_Write);
   --  The attribute to choose depending on the fact that the parameter
   --  is constrained or not. There is no such thing as Input_From_Constrained
   --  since this require separate mechanisms ('Input is a function while
   --  'Read is a procedure).

   ---------------------------------------
   -- Add_Calling_Stubs_To_Declarations --
   ---------------------------------------

   procedure Add_Calling_Stubs_To_Declarations
     (Pkg_Spec : in Node_Id;
      Decls    : in List_Id)
   is
      Current_Subprogram_Number : Int := 0;
      Current_Declaration       : Node_Id;

      Loc                       : constant Source_Ptr := Sloc (Pkg_Spec);

      RCI_Instantiation         : Node_Id;

      Subp_Stubs                : Node_Id;

   begin
      --  The first thing added is an instantiation of the generic package
      --  System.Partition_interface.RCI_Info with the name of the (current)
      --  remote package. This will act as an interface with the name server
      --  to determine the Partition_ID and the RPC_Receiver for the
      --  receiver of this package.

      RCI_Instantiation := RCI_Package_Locator (Loc, Pkg_Spec);
      RCI_Cache         := Defining_Unit_Name (RCI_Instantiation);

      Append_To (Decls, RCI_Instantiation);
      Analyze (RCI_Instantiation);

      --  For each subprogram declaration visible in the spec, we do
      --  build a body. We also increment a counter to assign a different
      --  Subprogram_Id to each subprograms. The receiving stubs processing
      --  do use the same mechanism and will thus assign the same Id and
      --  do the correct dispatching.

      Current_Declaration := First (Visible_Declarations (Pkg_Spec));

      while Current_Declaration /= Empty loop

         if Nkind (Current_Declaration) = N_Subprogram_Declaration
           and then Comes_From_Source (Current_Declaration)
         then
            pragma Assert (Current_Subprogram_Number =
              Get_Subprogram_Id (Defining_Unit_Name (Specification (
                Current_Declaration))));

            Subp_Stubs :=
              Build_Subprogram_Calling_Stubs (
                Vis_Decl     => Current_Declaration,
                Subp_Id      => Current_Subprogram_Number,
                Asynchronous =>
                  Nkind (Specification (Current_Declaration)) =
                    N_Procedure_Specification
                  and then
                    Is_Asynchronous (Defining_Unit_Name (Specification
                      (Current_Declaration))));

            Append_To (Decls, Subp_Stubs);
            Analyze (Subp_Stubs);

            Current_Subprogram_Number := Current_Subprogram_Number + 1;
         end if;

         Next (Current_Declaration);
      end loop;

   end Add_Calling_Stubs_To_Declarations;

   -----------------------
   -- Add_RACW_Features --
   -----------------------

   procedure Add_RACW_Features (RACW_Type : in Entity_Id)
   is
      Desig : constant Entity_Id :=
                Etype (Designated_Type (RACW_Type));
      Decls : List_Id :=
                List_Containing (Declaration_Node (RACW_Type));

      Same_Scope : constant Boolean :=
                     Scope (Desig) = Scope (RACW_Type);

      Stub_Type           : Entity_Id;
      Stub_Type_Access    : Entity_Id;
      Object_RPC_Receiver : Entity_Id;
      Existing            : Boolean;

   begin
      if not Expander_Active then
         return;
      end if;

      if Same_Scope then

         --  We are declaring a RACW in the same package than its designated
         --  type, so the list to use for late declarations must be the
         --  private part of the package. We do know that this private part
         --  exists since the designated type has to be a private one.

         Decls := Private_Declarations
           (Package_Specification_Of_Scope (Current_Scope));

      elsif Nkind (Parent (Decls)) = N_Package_Specification
        and then Present (Private_Declarations (Parent (Decls)))
      then
         Decls := Private_Declarations (Parent (Decls));
      end if;

      --  If we were unable to find the declarations, that means that the
      --  completion of the type was missing. We can safely return and let
      --  the error be caught by the semantic analysis.

      if No (Decls) then
         return;
      end if;

      Add_Stub_Type
        (Designated_Type     => Desig,
         RACW_Type           => RACW_Type,
         Decls               => Decls,
         Stub_Type           => Stub_Type,
         Stub_Type_Access    => Stub_Type_Access,
         Object_RPC_Receiver => Object_RPC_Receiver,
         Existing            => Existing);

      Add_RACW_Read_Write_Attributes
        (RACW_Type           => RACW_Type,
         Stub_Type           => Stub_Type,
         Stub_Type_Access    => Stub_Type_Access,
         Object_RPC_Receiver => Object_RPC_Receiver,
         Declarations        => Decls);

      if not Same_Scope and then not Existing then

         --  The RACW has been declared in another scope than the designated
         --  type and has not been handled by another RACW in the same
         --  package as the first one, so add primitive for the stub type
         --  here.

         Add_RACW_Primitive_Declarations_And_Bodies
           (Designated_Type  => Desig,
            Insertion_Node   =>
              Parent (Declaration_Node (Object_RPC_Receiver)),
            Decls            => Decls);

      else
         Add_Access_Type_To_Process (E => Desig, A => RACW_Type);
      end if;
   end Add_RACW_Features;

   -------------------------------------------------
   --  Add_RACW_Primitive_Declarations_And_Bodies --
   -------------------------------------------------

   procedure Add_RACW_Primitive_Declarations_And_Bodies
     (Designated_Type : in Entity_Id;
      Insertion_Node  : in Node_Id;
      Decls           : in List_Id)
   is
      --  Set sloc of generated declaration to be that of the
      --  insertion node, so the declarations are recognized as
      --  belonging to the current package.

      Loc : constant Source_Ptr := Sloc (Insertion_Node);

      Stub_Elements : constant Stub_Structure :=
        Stubs_Table.Get (Designated_Type);

      pragma Assert (Stub_Elements /= Empty_Stub_Structure);

      Current_Insertion_Node : Node_Id := Insertion_Node;

      RPC_Receiver_Declarations      : List_Id;
      RPC_Receiver_Statements        : List_Id;
      RPC_Receiver_Case_Alternatives : constant List_Id := New_List;
      RPC_Receiver_Subp_Id           : Entity_Id;

      Current_Primitive_Elmt   : Elmt_Id;
      Current_Primitive        : Entity_Id;
      Current_Primitive_Body   : Node_Id;
      Current_Primitive_Spec   : Node_Id;
      Current_Primitive_Decl   : Node_Id;
      Current_Primitive_Number : Int := 0;

      Current_Primitive_Alias : Node_Id;

      Current_Receiver      : Entity_Id;
      Current_Receiver_Body : Node_Id;

      RPC_Receiver_Decl : Node_Id;

      Possibly_Asynchronous : Boolean;

   begin

      if not Expander_Active then
         return;
      end if;

      --  Build callers, receivers for every primitive operations and a RPC
      --  receiver for this type.

      if Present (Primitive_Operations (Designated_Type)) then

         Current_Primitive_Elmt :=
           First_Elmt (Primitive_Operations (Designated_Type));

         while Current_Primitive_Elmt /= No_Elmt loop

            Current_Primitive := Node (Current_Primitive_Elmt);

            --  Copy the primitive of all the parents, except predefined
            --  ones that are not remotely dispatching.

            if Chars (Current_Primitive) /= Name_uSize
              and then Chars (Current_Primitive) /= Name_uDeep_Finalize
            then
               --  The first thing to do is build an up-to-date copy of
               --  the spec with all the formals referencing Designated_Type
               --  transformed into formals referencing Stub_Type. Since this
               --  primitive may have been inherited, go back the alias chain
               --  until the real primitive has been found.

               Current_Primitive_Alias := Current_Primitive;
               while Present (Alias (Current_Primitive_Alias)) loop
                  pragma Assert
                    (Current_Primitive_Alias
                      /= Alias (Current_Primitive_Alias));
                  Current_Primitive_Alias := Alias (Current_Primitive_Alias);
               end loop;

               Current_Primitive_Spec :=
                 Copy_Specification (Loc,
                   Spec        => Parent (Current_Primitive_Alias),
                   Object_Type => Designated_Type,
                   Stub_Type   => Stub_Elements.Stub_Type);

               Current_Primitive_Decl :=
                 Make_Subprogram_Declaration (Loc,
                   Specification => Current_Primitive_Spec);

               Insert_After (Current_Insertion_Node, Current_Primitive_Decl);
               Analyze (Current_Primitive_Decl);
               Current_Insertion_Node := Current_Primitive_Decl;

               Possibly_Asynchronous :=
                 Nkind (Current_Primitive_Spec) = N_Procedure_Specification
                 and then Could_Be_Asynchronous (Current_Primitive_Spec);

               Current_Primitive_Body :=
                 Build_Subprogram_Calling_Stubs
                   (Vis_Decl                 => Current_Primitive_Decl,
                    Subp_Id                  => Current_Primitive_Number,
                    Asynchronous             => Possibly_Asynchronous,
                    Dynamically_Asynchronous => Possibly_Asynchronous,
                    Stub_Type                => Stub_Elements.Stub_Type);
               Append_To (Decls, Current_Primitive_Body);

               --  Analyzing the body here would cause the Stub type to be
               --  frozen, thus preventing subsequent primitive declarations.
               --  For this reason, it will be analyzed later in the
               --  regular flow.

               --  Build the receiver stubs

               Current_Receiver_Body :=
                 Build_Subprogram_Receiving_Stubs
                   (Vis_Decl                 => Current_Primitive_Decl,
                    Asynchronous             => Possibly_Asynchronous,
                    Dynamically_Asynchronous => Possibly_Asynchronous,
                    Stub_Type                => Stub_Elements.Stub_Type,
                    RACW_Type                => Stub_Elements.RACW_Type,
                    Parent_Primitive         => Current_Primitive);

               Current_Receiver :=
                  Defining_Unit_Name (Specification (Current_Receiver_Body));

               Append_To (Decls, Current_Receiver_Body);

               --  Add a case alternative to the receiver

               Append_To (RPC_Receiver_Case_Alternatives,
                 Make_Case_Statement_Alternative (Loc,
                   Discrete_Choices => New_List (
                     Make_Integer_Literal (Loc, Current_Primitive_Number)),

                   Statements       => New_List (
                     Make_Procedure_Call_Statement (Loc,
                       Name                   =>
                         New_Occurrence_Of (Current_Receiver, Loc),
                       Parameter_Associations => New_List (
                         New_Occurrence_Of
                           (Stub_Elements.RPC_Receiver_Stream, Loc),
                         New_Occurrence_Of
                           (Stub_Elements.RPC_Receiver_Result, Loc))))));

               --  Increment the index of current primitive

               Current_Primitive_Number := Current_Primitive_Number + 1;
            end if;

            Next_Elmt (Current_Primitive_Elmt);
         end loop;
      end if;

      --  Build the case statement and the heart of the subprogram

      Append_To (RPC_Receiver_Case_Alternatives,
        Make_Case_Statement_Alternative (Loc,
          Discrete_Choices => New_List (Make_Others_Choice (Loc)),
          Statements       => New_List (Make_Null_Statement (Loc))));

      RPC_Receiver_Subp_Id :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));

      RPC_Receiver_Declarations := New_List (
        Make_Object_Declaration (Loc,
          Defining_Identifier => RPC_Receiver_Subp_Id,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc)));

      RPC_Receiver_Statements := New_List (
        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc),
          Attribute_Name =>
            Name_Read,
          Expressions    => New_List (
            New_Occurrence_Of (Stub_Elements.RPC_Receiver_Stream, Loc),
            New_Occurrence_Of (RPC_Receiver_Subp_Id, Loc))));

      Append_To (RPC_Receiver_Statements,
        Make_Case_Statement (Loc,
          Expression   =>
            New_Occurrence_Of (RPC_Receiver_Subp_Id, Loc),
          Alternatives => RPC_Receiver_Case_Alternatives));

      RPC_Receiver_Decl :=
        Make_Subprogram_Body (Loc,
          Specification              =>
            Copy_Specification (Loc,
              Parent (Stub_Elements.Object_RPC_Receiver)),
          Declarations               => RPC_Receiver_Declarations,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => RPC_Receiver_Statements));

      Append_To (Decls, RPC_Receiver_Decl);

      --  Do not analyze RPC receiver at this stage since it will otherwise
      --  reference subprograms that have not been analyzed yet. It will
      --  be analyzed in the regular flow.

   end Add_RACW_Primitive_Declarations_And_Bodies;

   -----------------------------
   -- Add_RACW_Read_Attribute --
   -----------------------------

   procedure Add_RACW_Read_Attribute
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Declarations        : in List_Id)
   is
      Loc : constant Source_Ptr := Sloc (RACW_Type);

      Proc_Spec : Node_Id;
      --  Specification and body of the currently built procedure

      Proc_Body_Spec : Node_Id;

      Proc_Decl : Node_Id;
      Attr_Decl : Node_Id;

      Body_Node : Node_Id;

      Decls             : List_Id;
      Statements        : List_Id;
      Local_Statements  : List_Id;
      Remote_Statements : List_Id;
      --  Various parts of the procedure

      Procedure_Name    : constant Name_Id   :=
                            New_Internal_Name ('R');
      Source_Partition  : constant Entity_Id :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('P'));
      Source_Receiver   : constant Entity_Id :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('S'));
      Source_Address    : constant Entity_Id :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('P'));
      Stream_Parameter  : constant Entity_Id :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('S'));
      Result            : constant Entity_Id  :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('P'));
      Stubbed_Result    : constant Entity_Id  :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('S'));
      Asynchronous_Flag : constant Entity_Id :=
                            Make_Defining_Identifier
                              (Loc, New_Internal_Name ('S'));
      Asynchronous_Node : constant Node_Id   :=
                            New_Occurrence_Of (Standard_False, Loc);

   begin
      --  Declare the asynchronous flag. This flag will be changed to True
      --  whenever it is known that the RACW type is asynchronous. Also, the
      --  node gets stored since it may be rewritten when we process the
      --  asynchronous pragma.

      Append_To (Declarations,
        Make_Object_Declaration (Loc,
          Defining_Identifier => Asynchronous_Flag,
          Constant_Present    => True,
          Object_Definition   => New_Occurrence_Of (Standard_Boolean, Loc),
          Expression          => Asynchronous_Node));

      Asynchronous_Flags_Table.Set (RACW_Type, Asynchronous_Node);

      --  Object declarations

      Decls := New_List (
        Make_Object_Declaration (Loc,
          Defining_Identifier => Source_Partition,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Partition_ID), Loc)),

        Make_Object_Declaration (Loc,
          Defining_Identifier => Source_Receiver,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)),

        Make_Object_Declaration (Loc,
          Defining_Identifier => Source_Address,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)),

        Make_Object_Declaration (Loc,
          Defining_Identifier => Stubbed_Result,
          Object_Definition   =>
            New_Occurrence_Of (Stub_Type_Access, Loc)));

      --  Read the source Partition_ID and RPC_Receiver from incoming stream

      Statements := New_List (
        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Partition_ID), Loc),
          Attribute_Name => Name_Read,
          Expressions    => New_List (
            New_Occurrence_Of (Stream_Parameter, Loc),
            New_Occurrence_Of (Source_Partition, Loc))),

        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Unsigned_64), Loc),
          Attribute_Name =>
            Name_Read,
          Expressions    => New_List (
            New_Occurrence_Of (Stream_Parameter, Loc),
            New_Occurrence_Of (Source_Receiver, Loc))),

        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Unsigned_64), Loc),
          Attribute_Name =>
            Name_Read,
          Expressions    => New_List (
            New_Occurrence_Of (Stream_Parameter, Loc),
            New_Occurrence_Of (Source_Address, Loc))));

      --  If the Address is Null_Address, then return a null object

      Append_To (Statements,
        Make_Implicit_If_Statement (RACW_Type,
          Condition       =>
            Make_Op_Eq (Loc,
              Left_Opnd  => New_Occurrence_Of (Source_Address, Loc),
              Right_Opnd => Make_Integer_Literal (Loc, Uint_0)),
          Then_Statements => New_List (
            Make_Assignment_Statement (Loc,
              Name       => New_Occurrence_Of (Result, Loc),
              Expression => Make_Null (Loc)),
            Make_Return_Statement (Loc))));

      --  If the RACW denotes an object created on the current partition, then
      --  Local_Statements will be executed. The real object will be used.

      Local_Statements := New_List (
        Make_Assignment_Statement (Loc,
          Name       => New_Occurrence_Of (Result, Loc),
          Expression =>
            Unchecked_Convert_To (RACW_Type,
              OK_Convert_To (RTE (RE_Address),
                New_Occurrence_Of (Source_Address, Loc)))));

      --  If the object is located on another partition, then a stub object
      --  will be created with all the information needed to rebuild the
      --  real object at the other end.

      Remote_Statements := New_List (

        Make_Assignment_Statement (Loc,
          Name       => New_Occurrence_Of (Stubbed_Result, Loc),
          Expression =>
            Make_Allocator (Loc,
              New_Occurrence_Of (Stub_Type, Loc))),

        Make_Assignment_Statement (Loc,
          Name       => Make_Selected_Component (Loc,
            Prefix        => New_Occurrence_Of (Stubbed_Result, Loc),
            Selector_Name => Make_Identifier (Loc, Name_Origin)),
          Expression =>
            New_Occurrence_Of (Source_Partition, Loc)),

        Make_Assignment_Statement (Loc,
          Name       => Make_Selected_Component (Loc,
            Prefix        => New_Occurrence_Of (Stubbed_Result, Loc),
            Selector_Name => Make_Identifier (Loc, Name_Receiver)),
          Expression =>
            New_Occurrence_Of (Source_Receiver, Loc)),

        Make_Assignment_Statement (Loc,
          Name       => Make_Selected_Component (Loc,
            Prefix        => New_Occurrence_Of (Stubbed_Result, Loc),
            Selector_Name => Make_Identifier (Loc, Name_Addr)),
          Expression =>
            New_Occurrence_Of (Source_Address, Loc)));

      Append_To (Remote_Statements,
        Make_Assignment_Statement (Loc,
          Name       => Make_Selected_Component (Loc,
            Prefix        => New_Occurrence_Of (Stubbed_Result, Loc),
            Selector_Name => Make_Identifier (Loc, Name_Asynchronous)),
          Expression =>
            New_Occurrence_Of (Asynchronous_Flag, Loc)));

      Append_To (Remote_Statements,
        Make_Procedure_Call_Statement (Loc,
          Name                   =>
            New_Occurrence_Of (RTE (RE_Get_Unique_Remote_Pointer), Loc),
          Parameter_Associations => New_List (
            Unchecked_Convert_To (RTE (RE_RACW_Stub_Type_Access),
              New_Occurrence_Of (Stubbed_Result, Loc)))));

      Append_To (Remote_Statements,
        Make_Assignment_Statement (Loc,
          Name       => New_Occurrence_Of (Result, Loc),
          Expression => Unchecked_Convert_To (RACW_Type,
            New_Occurrence_Of (Stubbed_Result, Loc))));

      --  Distinguish between the local and remote cases, and execute the
      --  appropriate piece of code.

      Append_To (Statements,
        Make_Implicit_If_Statement (RACW_Type,
          Condition       =>
            Make_Op_Eq (Loc,
              Left_Opnd  =>
                Make_Function_Call (Loc,
                  Name =>
                    New_Occurrence_Of (RTE (RE_Get_Local_Partition_Id), Loc)),
              Right_Opnd => New_Occurrence_Of (Source_Partition, Loc)),
          Then_Statements => Local_Statements,
          Else_Statements => Remote_Statements));

      Proc_Spec :=
        Make_Procedure_Specification (Loc,
          Defining_Unit_Name       =>
            Make_Defining_Identifier (Loc, Procedure_Name),

          Parameter_Specifications => New_List (
            Make_Parameter_Specification (Loc,
              Defining_Identifier => Stream_Parameter,
              Parameter_Type      =>
                Make_Access_Definition (Loc,
                  Subtype_Mark =>
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc),
                      Attribute_Name =>
                        Name_Class))),

            Make_Parameter_Specification (Loc,
              Defining_Identifier => Result,
              Out_Present         => True,
              Parameter_Type      =>
                New_Occurrence_Of (RACW_Type, Loc))));

      Proc_Body_Spec :=
        Make_Procedure_Specification (Loc,
          Defining_Unit_Name       =>
            Make_Defining_Identifier (Loc, Procedure_Name),

          Parameter_Specifications => New_List (
            Make_Parameter_Specification (Loc,
              Defining_Identifier =>
                Make_Defining_Identifier (Loc, Chars (Stream_Parameter)),
              Parameter_Type      =>
                Make_Access_Definition (Loc,
                  Subtype_Mark =>
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc),
                      Attribute_Name =>
                        Name_Class))),

            Make_Parameter_Specification (Loc,
              Defining_Identifier =>
                Make_Defining_Identifier (Loc, Chars (Result)),
              Out_Present         => True,
              Parameter_Type      =>
                New_Occurrence_Of (RACW_Type, Loc))));

      Body_Node :=
        Make_Subprogram_Body (Loc,
          Specification              => Proc_Body_Spec,
          Declarations               => Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => Statements));

      Proc_Decl :=
        Make_Subprogram_Declaration (Loc, Specification => Proc_Spec);

      Attr_Decl :=
        Make_Attribute_Definition_Clause (Loc,
          Name       => New_Occurrence_Of (RACW_Type, Loc),
          Chars      => Name_Read,
          Expression =>
            New_Occurrence_Of (Defining_Unit_Name (Proc_Spec), Loc));

      Insert_After (Declaration_Node (RACW_Type), Proc_Decl);
      Insert_After (Proc_Decl, Attr_Decl);
      Append_To (Declarations, Body_Node);
   end Add_RACW_Read_Attribute;

   ------------------------------------
   -- Add_RACW_Read_Write_Attributes --
   ------------------------------------

   procedure Add_RACW_Read_Write_Attributes
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Object_RPC_Receiver : in Entity_Id;
      Declarations        : in List_Id)
   is
   begin
      Add_RACW_Write_Attribute
        (RACW_Type           => RACW_Type,
         Stub_Type           => Stub_Type,
         Stub_Type_Access    => Stub_Type_Access,
         Object_RPC_Receiver => Object_RPC_Receiver,
         Declarations        => Declarations);

      Add_RACW_Read_Attribute
        (RACW_Type        => RACW_Type,
         Stub_Type        => Stub_Type,
         Stub_Type_Access => Stub_Type_Access,
         Declarations     => Declarations);
   end Add_RACW_Read_Write_Attributes;

   ------------------------------
   -- Add_RACW_Write_Attribute --
   ------------------------------

   procedure Add_RACW_Write_Attribute
     (RACW_Type           : in Entity_Id;
      Stub_Type           : in Entity_Id;
      Stub_Type_Access    : in Entity_Id;
      Object_RPC_Receiver : in Entity_Id;
      Declarations        : in List_Id)
   is
      Loc  : constant Source_Ptr := Sloc (RACW_Type);

      Proc_Spec      : Node_Id;

      Proc_Body_Spec : Node_Id;

      Body_Node      : Node_Id;

      Proc_Decl      : Node_Id;
      Attr_Decl      : Node_Id;

      Statements        : List_Id;
      Local_Statements  : List_Id;
      Remote_Statements : List_Id;
      Null_Statements   : List_Id;

      Procedure_Name    : constant Name_Id := New_Internal_Name ('R');

      Stream_Parameter : constant Entity_Id  :=
                           Make_Defining_Identifier
                             (Loc, New_Internal_Name ('S'));

      Object : constant Entity_Id   :=
                 Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

   begin
      --  Build the code fragment corresponding to the marshalling of a
      --  local object.

      Local_Statements := New_List (

        Pack_Entity_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => RTE (RE_Get_Local_Partition_Id)),

        Pack_Node_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => OK_Convert_To (RTE (RE_Unsigned_64),
            Make_Attribute_Reference (Loc,
              Prefix         => New_Occurrence_Of (Object_RPC_Receiver, Loc),
              Attribute_Name => Name_Address)),
          Etyp   => RTE (RE_Unsigned_64)),

        Pack_Node_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => OK_Convert_To (RTE (RE_Unsigned_64),
            Make_Attribute_Reference (Loc,
              Prefix         =>
                Make_Explicit_Dereference (Loc,
                  Prefix => New_Occurrence_Of (Object, Loc)),
              Attribute_Name => Name_Address)),
          Etyp   => RTE (RE_Unsigned_64)));

      --  Build the code fragment corresponding to the marshalling of
      --  a remote object.

      Remote_Statements := New_List (

        Pack_Node_Into_Stream_Access (Loc,
         Stream => Stream_Parameter,
         Object =>
            Make_Selected_Component (Loc,
              Prefix        => Unchecked_Convert_To (Stub_Type_Access,
                New_Occurrence_Of (Object, Loc)),
              Selector_Name =>
                Make_Identifier (Loc, Name_Origin)),
         Etyp   => RTE (RE_Partition_ID)),

        Pack_Node_Into_Stream_Access (Loc,
         Stream => Stream_Parameter,
         Object =>
            Make_Selected_Component (Loc,
              Prefix        => Unchecked_Convert_To (Stub_Type_Access,
                New_Occurrence_Of (Object, Loc)),
              Selector_Name =>
                Make_Identifier (Loc, Name_Receiver)),
         Etyp   => RTE (RE_Unsigned_64)),

        Pack_Node_Into_Stream_Access (Loc,
         Stream => Stream_Parameter,
         Object =>
            Make_Selected_Component (Loc,
              Prefix        => Unchecked_Convert_To (Stub_Type_Access,
                New_Occurrence_Of (Object, Loc)),
              Selector_Name =>
                Make_Identifier (Loc, Name_Addr)),
         Etyp   => RTE (RE_Unsigned_64)));

      --  Build the code fragment corresponding to the marshalling of a null
      --  object.

      Null_Statements := New_List (

        Pack_Entity_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => RTE (RE_Get_Local_Partition_Id)),

        Pack_Node_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => OK_Convert_To (RTE (RE_Unsigned_64),
            Make_Attribute_Reference (Loc,
              Prefix         => New_Occurrence_Of (Object_RPC_Receiver, Loc),
              Attribute_Name => Name_Address)),
          Etyp   => RTE (RE_Unsigned_64)),

        Pack_Node_Into_Stream_Access (Loc,
          Stream => Stream_Parameter,
          Object => Make_Integer_Literal (Loc, Uint_0),
          Etyp   => RTE (RE_Unsigned_64)));

      Statements := New_List (
        Make_Implicit_If_Statement (RACW_Type,
          Condition       =>
            Make_Op_Eq (Loc,
              Left_Opnd  => New_Occurrence_Of (Object, Loc),
              Right_Opnd => Make_Null (Loc)),
          Then_Statements => Null_Statements,
          Elsif_Parts     => New_List (
            Make_Elsif_Part (Loc,
              Condition       =>
                Make_Op_Eq (Loc,
                  Left_Opnd  =>
                    Make_Attribute_Reference (Loc,
                      Prefix         => New_Occurrence_Of (Object, Loc),
                      Attribute_Name => Name_Tag),
                  Right_Opnd =>
                    Make_Attribute_Reference (Loc,
                      Prefix         => New_Occurrence_Of (Stub_Type, Loc),
                      Attribute_Name => Name_Tag)),
              Then_Statements => Remote_Statements)),
          Else_Statements => Local_Statements));

      Proc_Spec :=
        Make_Procedure_Specification (Loc,
          Defining_Unit_Name       =>
            Make_Defining_Identifier (Loc, Procedure_Name),

          Parameter_Specifications => New_List (
            Make_Parameter_Specification (Loc,
              Defining_Identifier => Stream_Parameter,
              Parameter_Type      =>
                Make_Access_Definition (Loc,
                  Subtype_Mark =>
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc),
                      Attribute_Name =>
                        Name_Class))),

            Make_Parameter_Specification (Loc,
              Defining_Identifier => Object,
              In_Present          => True,
              Parameter_Type      =>
                New_Occurrence_Of (RACW_Type, Loc))));

      Proc_Decl :=
        Make_Subprogram_Declaration (Loc, Specification => Proc_Spec);

      Attr_Decl :=
        Make_Attribute_Definition_Clause (Loc,
          Name       => New_Occurrence_Of (RACW_Type, Loc),
          Chars      => Name_Write,
          Expression =>
            New_Occurrence_Of (Defining_Unit_Name (Proc_Spec), Loc));

      Proc_Body_Spec :=
        Make_Procedure_Specification (Loc,
          Defining_Unit_Name       =>
            Make_Defining_Identifier (Loc, Procedure_Name),

          Parameter_Specifications => New_List (
            Make_Parameter_Specification (Loc,
              Defining_Identifier =>
                Make_Defining_Identifier (Loc, Chars (Stream_Parameter)),
              Parameter_Type      =>
                Make_Access_Definition (Loc,
                  Subtype_Mark =>
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc),
                      Attribute_Name =>
                        Name_Class))),

            Make_Parameter_Specification (Loc,
              Defining_Identifier =>
                Make_Defining_Identifier (Loc, Chars (Object)),
              In_Present          => True,
              Parameter_Type      =>
                New_Occurrence_Of (RACW_Type, Loc))));

      Body_Node :=
        Make_Subprogram_Body (Loc,
          Specification              => Proc_Body_Spec,
          Declarations               => No_List,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => Statements));

      Insert_After (Declaration_Node (RACW_Type), Proc_Decl);
      Insert_After (Proc_Decl, Attr_Decl);
      Append_To (Declarations, Body_Node);
   end Add_RACW_Write_Attribute;

   ------------------------------
   -- Add_RAS_Access_Attribute --
   ------------------------------

   procedure Add_RAS_Access_Attribute (N : in Node_Id) is
      Ras_Type : constant Entity_Id := Defining_Identifier (N);
      Fat_Type : constant Entity_Id := Equivalent_Type (Ras_Type);
      --  Ras_Type is the access to subprogram type while Fat_Type points to
      --  the record type corresponding to a remote access to subprogram type.

      Proc_Decls        : constant List_Id := New_List;
      Proc_Statements   : constant List_Id := New_List;

      Proc_Spec : Node_Id;
      Proc_Body : Node_Id;

      Proc : Node_Id;

      Param        : Node_Id;
      Package_Name : Node_Id;
      Subp_Id      : Node_Id;
      Asynchronous : Node_Id;
      Return_Value : Node_Id;

      Loc : constant Source_Ptr := Sloc (N);

      procedure Set_Field (Field_Name : in Name_Id; Value : in Node_Id);
      --  Set a field name for the return value

      procedure Set_Field (Field_Name : in Name_Id; Value : in Node_Id)
      is
      begin
         Append_To (Proc_Statements,
           Make_Assignment_Statement (Loc,
             Name       =>
               Make_Selected_Component (Loc,
                 Prefix        => New_Occurrence_Of (Return_Value, Loc),
                 Selector_Name => Make_Identifier (Loc, Field_Name)),
             Expression => Value));
      end Set_Field;

   --  Start of processing for Add_RAS_Access_Attribute

   begin
      Param := Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
      Package_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      Subp_Id := Make_Defining_Identifier (Loc, New_Internal_Name ('N'));
      Asynchronous := Make_Defining_Identifier (Loc, New_Internal_Name ('B'));
      Return_Value := Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      --  Create the object which will be returned of type Fat_Type

      Append_To (Proc_Decls,
        Make_Object_Declaration (Loc,
          Defining_Identifier => Return_Value,
          Object_Definition   =>
            New_Occurrence_Of (Fat_Type, Loc)));

      --  Initialize the fields of the record type with the appropriate data

      Set_Field (Name_Ras,
        OK_Convert_To (RTE (RE_Unsigned_64), New_Occurrence_Of (Param, Loc)));

      Set_Field (Name_Origin,
        Unchecked_Convert_To (Standard_Integer,
          Make_Function_Call (Loc,
            Name                   =>
              New_Occurrence_Of (RTE (RE_Get_Active_Partition_Id), Loc),
            Parameter_Associations => New_List (
              New_Occurrence_Of (Package_Name, Loc)))));

      Set_Field (Name_Receiver,
        Make_Function_Call (Loc,
          Name                   =>
            New_Occurrence_Of (RTE (RE_Get_RCI_Package_Receiver), Loc),
          Parameter_Associations => New_List (
            New_Occurrence_Of (Package_Name, Loc))));

      Set_Field (Name_Subp_Id,
        New_Occurrence_Of (Subp_Id, Loc));

      Set_Field (Name_Async,
        New_Occurrence_Of (Asynchronous, Loc));

      --  Return the newly created value

      Append_To (Proc_Statements,
        Make_Return_Statement (Loc,
          Expression =>
            New_Occurrence_Of (Return_Value, Loc)));

      Proc := Make_Defining_Identifier (Loc, Name_uRAS_Access);

      Proc_Spec :=
        Make_Function_Specification (Loc,
          Defining_Unit_Name       => Proc,
          Parameter_Specifications => New_List (
            Make_Parameter_Specification (Loc,
              Defining_Identifier => Param,
              Parameter_Type      =>
                New_Occurrence_Of (RTE (RE_Address), Loc)),

            Make_Parameter_Specification (Loc,
              Defining_Identifier => Package_Name,
              Parameter_Type      =>
                New_Occurrence_Of (Standard_String, Loc)),

            Make_Parameter_Specification (Loc,
              Defining_Identifier => Subp_Id,
              Parameter_Type      =>
                New_Occurrence_Of (Standard_Natural, Loc)),

            Make_Parameter_Specification (Loc,
              Defining_Identifier => Asynchronous,
              Parameter_Type      =>
                New_Occurrence_Of (Standard_Boolean, Loc))),

         Subtype_Mark =>
           New_Occurrence_Of (Fat_Type, Loc));

      --  Set the kind and return type of the function to prevent ambiguities
      --  between Ras_Type and Fat_Type in subsequent analysis.

      Set_Ekind (Proc, E_Function);
      Set_Etype (Proc, New_Occurrence_Of (Fat_Type, Loc));

      Proc_Body :=
        Make_Subprogram_Body (Loc,
          Specification              => Proc_Spec,
          Declarations               => Proc_Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => Proc_Statements));

      Set_TSS (Fat_Type, Proc);

   end Add_RAS_Access_Attribute;

   -----------------------------------
   -- Add_RAS_Dereference_Attribute --
   -----------------------------------

   procedure Add_RAS_Dereference_Attribute (N : in Node_Id) is
      Loc : constant Source_Ptr := Sloc (N);

      Type_Def : constant Node_Id   := Type_Definition (N);

      Ras_Type : constant Entity_Id := Defining_Identifier (N);

      Fat_Type : constant Entity_Id := Equivalent_Type (Ras_Type);

      Proc_Decls      : constant List_Id := New_List;
      Proc_Statements : constant List_Id := New_List;

      Inner_Decls      : constant List_Id := New_List;
      Inner_Statements : constant List_Id := New_List;

      Direct_Statements : constant List_Id := New_List;

      Proc : Node_Id;

      Proc_Spec : Node_Id;
      Proc_Body : Node_Id;

      Param_Specs : constant List_Id := New_List;
      Param_Assoc : constant List_Id := New_List;

      Pointer : Node_Id;

      Converted_Ras    : Node_Id;
      Target_Partition : Node_Id;
      RPC_Receiver     : Node_Id;
      Subprogram_Id    : Node_Id;
      Asynchronous     : Node_Id;

      Is_Function : constant Boolean :=
                      Nkind (Type_Def) = N_Access_Function_Definition;

      Spec : constant Node_Id := Type_Def;

      Current_Parameter : Node_Id;

   begin
      --  The way to do it is test if the Ras field is non-null and then if
      --  the Origin field is equal to the current partition ID (which is in
      --  fact Current_Package'Partition_ID). If this is the case, then it
      --  is safe to dereference the Ras field directly rather than
      --  performing a remote call.

      Pointer :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      Target_Partition :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      Append_To (Proc_Decls,
        Make_Object_Declaration (Loc,
          Defining_Identifier => Target_Partition,
          Constant_Present    => True,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Partition_ID), Loc),
          Expression          =>
            Unchecked_Convert_To (RTE (RE_Partition_ID),
              Make_Selected_Component (Loc,
                Prefix        =>
                  New_Occurrence_Of (Pointer, Loc),
                Selector_Name =>
                  Make_Identifier (Loc, Name_Origin)))));

      RPC_Receiver :=
        Make_Selected_Component (Loc,
          Prefix        =>
            New_Occurrence_Of (Pointer, Loc),
          Selector_Name =>
            Make_Identifier (Loc, Name_Receiver));

      Subprogram_Id :=
        Unchecked_Convert_To (RTE (RE_Subprogram_Id),
          Make_Selected_Component (Loc,
            Prefix        =>
              New_Occurrence_Of (Pointer, Loc),
            Selector_Name =>
              Make_Identifier (Loc, Name_Subp_Id)));

      --  A function is never asynchronous. A procedure may or may not be
      --  asynchronous depending on whether a pragma Asynchronous applies
      --  on it. Since a RAST may point onto various subprograms, this is
      --  only known at runtime so both versions (synchronous and asynchronous)
      --  must be built every times it is not a function.

      if Is_Function then
         Asynchronous := Empty;

      else
         Asynchronous :=
           Make_Selected_Component (Loc,
             Prefix        =>
               New_Occurrence_Of (Pointer, Loc),
             Selector_Name =>
               Make_Identifier (Loc, Name_Async));

      end if;

      if Present (Parameter_Specifications (Type_Def)) then
         Current_Parameter := First (Parameter_Specifications (Type_Def));

         while Current_Parameter /= Empty loop
            Append_To (Param_Specs,
              Make_Parameter_Specification (Loc,
                Defining_Identifier =>
                  Make_Defining_Identifier (Loc,
                    Chars => Chars (Defining_Identifier (Current_Parameter))),
                In_Present        => In_Present (Current_Parameter),
                Out_Present       => Out_Present (Current_Parameter),
                Parameter_Type    =>
                  New_Occurrence_Of
                    (Etype (Parameter_Type (Current_Parameter)), Loc),
                Expression        =>
                  New_Copy_Tree (Expression (Current_Parameter))));

            Append_To (Param_Assoc,
              Make_Identifier (Loc,
                Chars => Chars (Defining_Identifier (Current_Parameter))));

            Next (Current_Parameter);
         end loop;
      end if;

      Proc := Make_Defining_Identifier (Loc, Name_uRAS_Dereference);

      if Is_Function then
         Proc_Spec :=
           Make_Function_Specification (Loc,
             Defining_Unit_Name       => Proc,
             Parameter_Specifications => Param_Specs,
             Subtype_Mark             =>
               New_Occurrence_Of (
                 Entity (Subtype_Mark (Spec)), Loc));

         Set_Ekind (Proc, E_Function);

         Set_Etype (Proc,
           New_Occurrence_Of (Entity (Subtype_Mark (Spec)), Loc));

      else
         Proc_Spec :=
           Make_Procedure_Specification (Loc,
             Defining_Unit_Name       => Proc,
             Parameter_Specifications => Param_Specs);

         Set_Ekind (Proc, E_Procedure);
         Set_Etype (Proc, Standard_Void_Type);
      end if;

      --  Build the calling stubs for the dereference of the RAS

      Build_General_Calling_Stubs
        (Decls                     => Inner_Decls,
         Statements                => Inner_Statements,
         Target_Partition          => Target_Partition,
         RPC_Receiver              => RPC_Receiver,
         Subprogram_Id             => Subprogram_Id,
         Asynchronous              => Asynchronous,
         Is_Known_Non_Asynchronous => Is_Function,
         Is_Function               => Is_Function,
         Spec                      => Proc_Spec,
         Nod                       => N);

      Converted_Ras :=
        Unchecked_Convert_To (Ras_Type,
          OK_Convert_To (RTE (RE_Address),
            Make_Selected_Component (Loc,
              Prefix        => New_Occurrence_Of (Pointer, Loc),
              Selector_Name => Make_Identifier (Loc, Name_Ras))));

      if Is_Function then
         Append_To (Direct_Statements,
           Make_Return_Statement (Loc,
             Expression =>
               Make_Function_Call (Loc,
                 Name                   =>
                   Make_Explicit_Dereference (Loc,
                     Prefix => Converted_Ras),
                 Parameter_Associations => Param_Assoc)));

      else
         Append_To (Direct_Statements,
           Make_Procedure_Call_Statement (Loc,
             Name                   =>
               Make_Explicit_Dereference (Loc,
                 Prefix => Converted_Ras),
             Parameter_Associations => Param_Assoc));
      end if;

      Prepend_To (Param_Specs,
        Make_Parameter_Specification (Loc,
          Defining_Identifier => Pointer,
          In_Present          => True,
          Parameter_Type      =>
            New_Occurrence_Of (Fat_Type, Loc)));

      Append_To (Proc_Statements,
        Make_Implicit_If_Statement (N,
          Condition =>
            Make_And_Then (Loc,
              Left_Opnd  =>
                Make_Op_Ne (Loc,
                  Left_Opnd  =>
                    Make_Selected_Component (Loc,
                      Prefix        => New_Occurrence_Of (Pointer, Loc),
                      Selector_Name => Make_Identifier (Loc, Name_Ras)),
                  Right_Opnd =>
                    Make_Integer_Literal (Loc, Uint_0)),

              Right_Opnd =>
                Make_Op_Eq (Loc,
                  Left_Opnd  =>
                    New_Occurrence_Of (Target_Partition, Loc),
                  Right_Opnd =>
                    Make_Function_Call (Loc,
                      New_Occurrence_Of (
                        RTE (RE_Get_Local_Partition_Id), Loc)))),

          Then_Statements =>
            Direct_Statements,

          Else_Statements => New_List (
            Make_Block_Statement (Loc,
              Declarations               => Inner_Decls,
              Handled_Statement_Sequence =>
                Make_Handled_Sequence_Of_Statements (Loc,
                  Statements => Inner_Statements)))));

      Proc_Body :=
        Make_Subprogram_Body (Loc,
          Specification              => Proc_Spec,
          Declarations               => Proc_Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => Proc_Statements));

      Set_TSS (Fat_Type, Defining_Unit_Name (Proc_Spec));

   end Add_RAS_Dereference_Attribute;

   -----------------------
   -- Add_RAST_Features --
   -----------------------

   procedure Add_RAST_Features (Vis_Decl : Node_Id) is
   begin
      --  Do not add attributes more than once in any case. This should
      --  be replaced by an assert or this comment removed if we decide
      --  that this is normal to be called several times ???

      if Present (TSS (Equivalent_Type (Defining_Identifier
           (Vis_Decl)), Name_uRAS_Access))
      then
         return;
      end if;

      Add_RAS_Dereference_Attribute (Vis_Decl);
      Add_RAS_Access_Attribute (Vis_Decl);
   end Add_RAST_Features;

   -----------------------------------------
   -- Add_Receiving_Stubs_To_Declarations --
   -----------------------------------------

   procedure Add_Receiving_Stubs_To_Declarations
     (Pkg_Spec : in Node_Id;
      Decls    : in List_Id)
   is
      Loc : constant Source_Ptr := Sloc (Pkg_Spec);

      Stream_Parameter : Node_Id;
      Result_Parameter : Node_Id;

      Pkg_RPC_Receiver            : Node_Id;
      Pkg_RPC_Receiver_Spec       : Node_Id;
      Pkg_RPC_Receiver_Formals    : List_Id;
      Pkg_RPC_Receiver_Decls      : List_Id;
      Pkg_RPC_Receiver_Statements : List_Id;
      Pkg_RPC_Receiver_Cases      : List_Id := New_List;
      Pkg_RPC_Receiver_Body       : Node_Id;
      --  A Pkg_RPC_Receiver is built to decode the request

      Subp_Id                     : Node_Id;
      --  Subprogram_Id as read from the incoming stream

      Current_Declaration       : Node_Id;
      Current_Subprogram_Number : Int := 0;
      Current_Stubs             : Node_Id;

      Actuals : List_Id;

      Dummy_Register_Name : Name_Id;
      Dummy_Register_Spec : Node_Id;
      Dummy_Register_Decl : Node_Id;
      Dummy_Register_Body : Node_Id;

   begin
      --  Building receiving stubs consist in several operations:

      --    - a package RPC receiver must be built. This subprogram
      --      will get a Subprogram_Id from the incoming stream
      --      and will dispatch the call to the right subprogram

      --    - a receiving stub for any subprogram visible in the package
      --      spec. This stub will read all the parameters from the stream,
      --      and put the result as well as the exception occurrence in the
      --      output stream

      --    - a dummy package with an empty spec and a body made of an
      --      elaboration part, whose job is to register the receiving
      --      part of this RCI package on the name server. This is done
      --      by calling System.Partition_Interface.Register_Receiving_Stub

      Stream_Parameter :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      Result_Parameter :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('R'));
      Subp_Id :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      Pkg_RPC_Receiver :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      --  The parameters of the package RPC receiver are made of two
      --  streams, an input one and an output one.

      Pkg_RPC_Receiver_Formals := New_List (
        Make_Parameter_Specification (Loc,
          Defining_Identifier => Stream_Parameter,
          Parameter_Type      =>
            Make_Access_Definition (Loc,
              Subtype_Mark =>
                New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))),
        Make_Parameter_Specification (Loc,
          Defining_Identifier => Result_Parameter,
          Parameter_Type      =>
            Make_Access_Definition (Loc,
              Subtype_Mark =>
                New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))));

      Pkg_RPC_Receiver_Spec :=
        Make_Procedure_Specification (Loc,
          Defining_Unit_Name       => Pkg_RPC_Receiver,
          Parameter_Specifications => Pkg_RPC_Receiver_Formals);

      Pkg_RPC_Receiver_Decls := New_List (
        Make_Object_Declaration (Loc,
          Defining_Identifier => Subp_Id,
          Object_Definition   =>
            New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc)));

      Pkg_RPC_Receiver_Statements := New_List (
        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc),
          Attribute_Name =>
            Name_Read,
          Expressions    => New_List (
            New_Occurrence_Of (Stream_Parameter, Loc),
            New_Occurrence_Of (Subp_Id, Loc))));

      --  For each subprogram, the receiving stub will be built and a
      --  case statement will be made on the Subprogram_Id to dispatch
      --  to the right subprogram.

      Current_Declaration := First (Visible_Declarations (Pkg_Spec));

      while Current_Declaration /= Empty loop

         if Nkind (Current_Declaration) = N_Subprogram_Declaration
           and then Comes_From_Source (Current_Declaration)
         then
            pragma Assert (Current_Subprogram_Number =
              Get_Subprogram_Id (Defining_Unit_Name (Specification (
                Current_Declaration))));

            Current_Stubs :=
              Build_Subprogram_Receiving_Stubs
                (Vis_Decl     => Current_Declaration,
                 Asynchronous =>
                   Nkind (Specification (Current_Declaration)) =
                       N_Procedure_Specification
                     and then Is_Asynchronous
                       (Defining_Unit_Name (Specification
                          (Current_Declaration))));

            Append_To (Decls, Current_Stubs);

            Analyze (Current_Stubs);

            Actuals := New_List (New_Occurrence_Of (Stream_Parameter, Loc));

            if Nkind (Specification (Current_Declaration))
                = N_Function_Specification
              or else
                not Is_Asynchronous (
                  Defining_Entity (Specification (Current_Declaration)))
            then
               --  An asynchronous procedure does not want an output parameter
               --  since no result and no exception will ever be returned.

               Append_To (Actuals,
                 New_Occurrence_Of (Result_Parameter, Loc));

            end if;

            Append_To (Pkg_RPC_Receiver_Cases,
              Make_Case_Statement_Alternative (Loc,
                Discrete_Choices =>
                  New_List (
                    Make_Integer_Literal (Loc, Current_Subprogram_Number)),

                Statements       =>
                  New_List (
                    Make_Procedure_Call_Statement (Loc,
                      Name                   =>
                        New_Occurrence_Of (
                          Defining_Entity (Current_Stubs), Loc),
                      Parameter_Associations =>
                        Actuals))));

            Current_Subprogram_Number := Current_Subprogram_Number + 1;
         end if;

         Next (Current_Declaration);
      end loop;

      --  If we receive an invalid Subprogram_Id, it is best to do nothing
      --  rather than raising an exception since we do not want someone
      --  to crash a remote partition by sending invalid subprogram ids.
      --  This is consistent with the other parts of the case statement
      --  since even in presence of incorrect parameters in the stream,
      --  every exception will be caught and (if the subprogram is not an
      --  APC) put into the result stream and sent away.

      Append_To (Pkg_RPC_Receiver_Cases,
        Make_Case_Statement_Alternative (Loc,
          Discrete_Choices =>
            New_List (Make_Others_Choice (Loc)),
          Statements       =>
            New_List (Make_Null_Statement (Loc))));

      Append_To (Pkg_RPC_Receiver_Statements,
        Make_Case_Statement (Loc,
          Expression   =>
            New_Occurrence_Of (Subp_Id, Loc),
          Alternatives => Pkg_RPC_Receiver_Cases));

      Pkg_RPC_Receiver_Body :=
        Make_Subprogram_Body (Loc,
          Specification              => Pkg_RPC_Receiver_Spec,
          Declarations               => Pkg_RPC_Receiver_Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => Pkg_RPC_Receiver_Statements));

      Append_To (Decls, Pkg_RPC_Receiver_Body);
      Analyze (Pkg_RPC_Receiver_Body);

      --  Construction of the dummy package used to register the package
      --  receiving stubs on the nameserver.

      Dummy_Register_Name := New_Internal_Name ('P');

      Dummy_Register_Spec :=
        Make_Package_Specification (Loc,
          Defining_Unit_Name   =>
            Make_Defining_Identifier (Loc, Dummy_Register_Name),
          Visible_Declarations => No_List,
          End_Label => Empty);

      Dummy_Register_Decl :=
        Make_Package_Declaration (Loc,
          Specification => Dummy_Register_Spec);

      Append_To (Decls,
        Dummy_Register_Decl);
      Analyze (Dummy_Register_Decl);

      Dummy_Register_Body :=
        Make_Package_Body (Loc,
          Defining_Unit_Name         =>
            Make_Defining_Identifier (Loc, Dummy_Register_Name),
          Declarations               => No_List,

          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements => New_List (
                Make_Procedure_Call_Statement (Loc,
                  Name                   =>
                    New_Occurrence_Of (RTE (RE_Register_Receiving_Stub), Loc),

                  Parameter_Associations => New_List (
                    Make_String_Literal (Loc,
                      Strval => Get_Pkg_Name_String_Id (Pkg_Spec)),
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (Pkg_RPC_Receiver, Loc),
                      Attribute_Name =>
                        Name_Unrestricted_Access),
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (Defining_Entity (Pkg_Spec), Loc),
                      Attribute_Name =>
                        Name_Version))))));

      Append_To (Decls, Dummy_Register_Body);
      Analyze (Dummy_Register_Body);
   end Add_Receiving_Stubs_To_Declarations;

   -------------------
   -- Add_Stub_Type --
   -------------------

   procedure Add_Stub_Type
     (Designated_Type     : in Entity_Id;
      RACW_Type           : in Entity_Id;
      Decls               : in List_Id;
      Stub_Type           : out Entity_Id;
      Stub_Type_Access    : out Entity_Id;
      Object_RPC_Receiver : out Entity_Id;
      Existing            : out Boolean)
   is
      Loc : constant Source_Ptr := Sloc (RACW_Type);

      Stub_Elements : constant Stub_Structure :=
                        Stubs_Table.Get (Designated_Type);

      Stub_Type_Declaration           : Node_Id;
      Stub_Type_Access_Declaration    : Node_Id;
      Object_RPC_Receiver_Declaration : Node_Id;

      RPC_Receiver_Stream             : Entity_Id;
      RPC_Receiver_Result             : Entity_Id;

   begin
      if Stub_Elements /= Empty_Stub_Structure then
         Stub_Type           := Stub_Elements.Stub_Type;
         Stub_Type_Access    := Stub_Elements.Stub_Type_Access;
         Object_RPC_Receiver := Stub_Elements.Object_RPC_Receiver;
         Existing            := True;
         return;
      end if;

      Existing            := False;
      Stub_Type           :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      Stub_Type_Access    :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      Object_RPC_Receiver :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
      RPC_Receiver_Stream :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      RPC_Receiver_Result :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      Stubs_Table.Set (Designated_Type,
        (Stub_Type           => Stub_Type,
         Stub_Type_Access    => Stub_Type_Access,
         Object_RPC_Receiver => Object_RPC_Receiver,
         RPC_Receiver_Stream => RPC_Receiver_Stream,
         RPC_Receiver_Result => RPC_Receiver_Result,
         RACW_Type           => RACW_Type));

      --  The stub type definition below must match exactly the one in
      --  s-parint.ads, since unchecked conversions will be used in
      --  s-parint.adb to modify pointers passed to Get_Unique_Remote_Pointer.

      Stub_Type_Declaration :=
        Make_Full_Type_Declaration (Loc,
          Defining_Identifier => Stub_Type,
          Type_Definition     =>
            Make_Record_Definition (Loc,
              Tagged_Present  => True,
              Limited_Present => True,
              Component_List  =>
                Make_Component_List (Loc,
                  Component_Items => New_List (

                    Make_Component_Declaration (Loc,
                      Defining_Identifier =>
                        Make_Defining_Identifier (Loc, Name_Origin),
                      Subtype_Indication  =>
                        New_Occurrence_Of (RTE (RE_Partition_ID), Loc)),

                    Make_Component_Declaration (Loc,
                      Defining_Identifier =>
                        Make_Defining_Identifier (Loc, Name_Receiver),
                      Subtype_Indication  =>
                        New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)),

                    Make_Component_Declaration (Loc,
                      Defining_Identifier =>
                        Make_Defining_Identifier (Loc, Name_Addr),
                      Subtype_Indication  =>
                        New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)),

                    Make_Component_Declaration (Loc,
                      Defining_Identifier =>
                        Make_Defining_Identifier (Loc, Name_Asynchronous),
                      Subtype_Indication  =>
                        New_Occurrence_Of (Standard_Boolean, Loc))))));

      Append_To (Decls, Stub_Type_Declaration);
      Analyze (Stub_Type_Declaration);

      --  This is in no way a type derivation, but we fake it to make
      --  sure that the dispatching table gets built with the corresponding
      --  primitive operations at the right place.

      Derive_Subprograms (Parent_Type  => Designated_Type,
                          Derived_Type => Stub_Type);

      Stub_Type_Access_Declaration :=
        Make_Full_Type_Declaration (Loc,
          Defining_Identifier => Stub_Type_Access,
          Type_Definition     =>
            Make_Access_To_Object_Definition (Loc,
              Subtype_Indication => New_Occurrence_Of (Stub_Type, Loc)));

      Append_To (Decls, Stub_Type_Access_Declaration);
      Analyze (Stub_Type_Access_Declaration);

      Object_RPC_Receiver_Declaration :=
        Make_Subprogram_Declaration (Loc,
          Make_Procedure_Specification (Loc,
            Defining_Unit_Name       => Object_RPC_Receiver,
            Parameter_Specifications => New_List (
              Make_Parameter_Specification (Loc,
                Defining_Identifier => RPC_Receiver_Stream,
                Parameter_Type      =>
                  Make_Access_Definition (Loc,
                    Subtype_Mark =>
                      New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))),

              Make_Parameter_Specification (Loc,
                Defining_Identifier => RPC_Receiver_Result,
                Parameter_Type      =>
                  Make_Access_Definition (Loc,
                    Subtype_Mark =>
                      New_Occurrence_Of
                        (RTE (RE_Params_Stream_Type), Loc))))));

      Append_To (Decls, Object_RPC_Receiver_Declaration);
   end Add_Stub_Type;

   ---------------------------------
   -- Build_General_Calling_Stubs --
   ---------------------------------

   procedure Build_General_Calling_Stubs
     (Decls                     : List_Id;
      Statements                : List_Id;
      Target_Partition          : Entity_Id;
      RPC_Receiver              : Node_Id;
      Subprogram_Id             : Node_Id;
      Asynchronous              : Node_Id   := Empty;
      Is_Known_Asynchronous     : Boolean   := False;
      Is_Known_Non_Asynchronous : Boolean   := False;
      Is_Function               : Boolean;
      Spec                      : Node_Id;
      Object_Type               : Entity_Id := Empty;
      Nod                       : Node_Id)
   is
      Loc : constant Source_Ptr := Sloc (Nod);

      Stream_Parameter : Node_Id;
      --  Name of the stream used to transmit parameters to the remote package

      Result_Parameter : Node_Id;
      --  Name of the result parameter (in non-APC cases) which get the
      --  result of the remote subprogram.

      Exception_Return_Parameter : Node_Id;
      --  Name of the parameter which will hold the exception sent by the
      --  remote subprogram.

      Current_Parameter : Node_Id;
      --  Current parameter being handled

      Ordered_Parameters_List : constant List_Id :=
                                  Build_Ordered_Parameters_List (Spec);

      Asynchronous_Statements     : List_Id := No_List;
      Non_Asynchronous_Statements : List_Id := No_List;
      --  Statements specifics to the Asynchronous/Non-Asynchronous cases.

      Extra_Formal_Statements : constant List_Id := New_List;
      --  List of statements for extra formal parameters. It will appear after
      --  the regular statements for writing out parameters.

   begin
      --  The general form of a calling stub for a given subprogram is:

      --    procedure X (...) is
      --      P : constant Partition_ID := RCI_Cache.Get_Active_Partition_ID;
      --      Stream, Result : aliased System.RPC.Params_Stream_Type (0);
      --    begin
      --       Put_Package_RPC_Receiver_In_Stream; (the package RPC receiver
      --                  comes from RCI_Cache.Get_RCI_Package_Receiver)
      --       Put_Subprogram_Id_In_Stream;
      --       Put_Parameters_In_Stream;
      --       Do_RPC (Stream, Result);
      --       Read_Exception_Occurrence_From_Result; Raise_It;
      --       Read_Out_Parameters_And_Function_Return_From_Stream;
      --    end X;

      --  There are some variations: Do_APC is called for an asynchronous
      --  procedure and the part after the call is completely ommitted
      --  as well as the declaration of Result. For a function call,
      --  'Input is always used to read the result even if it is constrained.

      Stream_Parameter :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));

      Append_To (Decls,
        Make_Object_Declaration (Loc,
          Defining_Identifier => Stream_Parameter,
          Aliased_Present     => True,
          Object_Definition   =>
            Make_Subtype_Indication (Loc,
              Subtype_Mark =>
                New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc),
              Constraint   =>
                Make_Index_Or_Discriminant_Constraint (Loc,
                  Constraints =>
                    New_List (Make_Integer_Literal (Loc, 0))))));

      if not Is_Known_Asynchronous then
         Result_Parameter :=
           Make_Defining_Identifier (Loc, New_Internal_Name ('R'));

         Append_To (Decls,
           Make_Object_Declaration (Loc,
             Defining_Identifier => Result_Parameter,
             Aliased_Present     => True,
             Object_Definition   =>
               Make_Subtype_Indication (Loc,
                 Subtype_Mark =>
                   New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc),
                 Constraint   =>
                   Make_Index_Or_Discriminant_Constraint (Loc,
                     Constraints =>
                       New_List (Make_Integer_Literal (Loc, 0))))));

         Exception_Return_Parameter :=
           Make_Defining_Identifier (Loc, New_Internal_Name ('E'));

         Append_To (Decls,
           Make_Object_Declaration (Loc,
             Defining_Identifier => Exception_Return_Parameter,
             Object_Definition   =>
               New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc)));

      else
         Result_Parameter := Empty;
         Exception_Return_Parameter := Empty;
      end if;

      --  Put first the RPC receiver corresponding to the remote package

      Append_To (Statements,
        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Unsigned_64), Loc),
          Attribute_Name => Name_Write,
          Expressions    => New_List (
            Make_Attribute_Reference (Loc,
              Prefix         =>
                New_Occurrence_Of (Stream_Parameter, Loc),
              Attribute_Name =>
                Name_Access),
            RPC_Receiver)));

      --  Then put the Subprogram_Id of the subprogram we want to call in
      --  the stream.

      Append_To (Statements,
        Make_Attribute_Reference (Loc,
          Prefix         =>
            New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc),
          Attribute_Name =>
            Name_Write,
          Expressions      => New_List (
            Make_Attribute_Reference (Loc,
              Prefix         =>
                New_Occurrence_Of (Stream_Parameter, Loc),
              Attribute_Name => Name_Access),
            Subprogram_Id)));

      Current_Parameter := First (Ordered_Parameters_List);

      while Current_Parameter /= Empty loop

         if Is_RACW_Controlling_Formal (Current_Parameter, Object_Type) then

            --  In the case of a controlling formal argument, we marshall
            --  its addr field rather than the local stub.

            Append_To (Statements,
               Pack_Node_Into_Stream (Loc,
                 Stream => Stream_Parameter,
                 Object =>
                   Make_Selected_Component (Loc,
                     Prefix        =>
                       New_Occurrence_Of (
                         Defining_Identifier (Current_Parameter), Loc),
                     Selector_Name =>
                       Make_Identifier (Loc, Name_Addr)),
                 Etyp   => RTE (RE_Unsigned_64)));

         else
            declare
               Etyp : constant Entity_Id :=
                        Etype (Parameter_Type (Current_Parameter));

               Constrained : constant Boolean :=
                               Is_Constrained (Etyp)
                                 or else Is_Elementary_Type (Etyp);

            begin
               if In_Present (Current_Parameter)
                 or else not Out_Present (Current_Parameter)
                 or else not Constrained
               then
                  Append_To (Statements,
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (Etyp, Loc),
                      Attribute_Name => Output_From_Constrained (Constrained),
                      Expressions    => New_List (
                        Make_Attribute_Reference (Loc,
                          Prefix         =>
                            New_Occurrence_Of (Stream_Parameter, Loc),
                          Attribute_Name => Name_Access),
                        New_Occurrence_Of (
                          Defining_Identifier (Current_Parameter), Loc))));
               end if;
            end;
         end if;

         --  If the current parameter has a dynamic constrained status,
         --  then this status is transmitted as well.
         --  This should be done for accessibility as well ???

         if Nkind (Parameter_Type (Current_Parameter)) /= N_Access_Definition
           and then Need_Extra_Constrained (Current_Parameter)
         then
            --  In this block, we do not use the extra formal that has been
            --  created because it does not exist at the time of expansion
            --  when building calling stubs for remote access to subprogram
            --  types. We create an extra variable of this type and push it
            --  in the stream after the regular parameters.

            declare
               Extra_Parameter : constant Entity_Id :=
                                   Make_Defining_Identifier
                                     (Loc, New_Internal_Name ('P'));

            begin
               Append_To (Decls,
                 Make_Object_Declaration (Loc,
                   Defining_Identifier => Extra_Parameter,
                   Constant_Present    => True,
                   Object_Definition   =>
                     New_Occurrence_Of (Standard_Boolean, Loc),
                   Expression          =>
                     Make_Attribute_Reference (Loc,
                       Prefix         =>
                         New_Occurrence_Of (
                           Defining_Identifier (Current_Parameter), Loc),
                       Attribute_Name => Name_Constrained)));

               Append_To (Extra_Formal_Statements,
                 Make_Attribute_Reference (Loc,
                   Prefix         =>
                     New_Occurrence_Of (Standard_Boolean, Loc),
                   Attribute_Name =>
                     Name_Write,
                   Expressions    => New_List (
                     Make_Attribute_Reference (Loc,
                       Prefix         =>
                         New_Occurrence_Of (Stream_Parameter, Loc),
                       Attribute_Name =>
                         Name_Access),
                     New_Occurrence_Of (Extra_Parameter, Loc))));
            end;
         end if;

         Next (Current_Parameter);
      end loop;

      --  Append the formal statements list to the statements

      Append_List_To (Statements, Extra_Formal_Statements);

      if not Is_Known_Non_Asynchronous then

         --  Build the call to System.RPC.Do_APC

         Asynchronous_Statements := New_List (
           Make_Procedure_Call_Statement (Loc,
             Name                   =>
               New_Occurrence_Of (RTE (RE_Do_Apc), Loc),
             Parameter_Associations => New_List (
               New_Occurrence_Of (Target_Partition, Loc),
               Make_Attribute_Reference (Loc,
                 Prefix         =>
                   New_Occurrence_Of (Stream_Parameter, Loc),
                 Attribute_Name =>
                   Name_Access))));
      else
         Asynchronous_Statements := No_List;
      end if;

      if not Is_Known_Asynchronous then

         --  Build the call to System.RPC.Do_RPC

         Non_Asynchronous_Statements := New_List (
           Make_Procedure_Call_Statement (Loc,
             Name                   =>
               New_Occurrence_Of (RTE (RE_Do_Rpc), Loc),
             Parameter_Associations => New_List (
               New_Occurrence_Of (Target_Partition, Loc),

               Make_Attribute_Reference (Loc,
                 Prefix         =>
                   New_Occurrence_Of (Stream_Parameter, Loc),
                 Attribute_Name =>
                   Name_Access),

               Make_Attribute_Reference (Loc,
                 Prefix         =>
                   New_Occurrence_Of (Result_Parameter, Loc),
                 Attribute_Name =>
                   Name_Access))));

         --  Read the exception occurrence from the result stream and
         --  reraise it. It does no harm if this is a Null_Occurrence since
         --  this does nothing.

         Append_To (Non_Asynchronous_Statements,
           Make_Attribute_Reference (Loc,
             Prefix         =>
               New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc),

             Attribute_Name =>
               Name_Read,

             Expressions    => New_List (
               Make_Attribute_Reference (Loc,
                 Prefix         =>
                   New_Occurrence_Of (Result_Parameter, Loc),
                 Attribute_Name =>
                   Name_Access),
               New_Occurrence_Of (Exception_Return_Parameter, Loc))));

         Append_To (Non_Asynchronous_Statements,
           Make_Procedure_Call_Statement (Loc,
             Name                   =>
               New_Occurrence_Of (RTE (RE_Reraise_Occurrence), Loc),
             Parameter_Associations => New_List (
               New_Occurrence_Of (Exception_Return_Parameter, Loc))));

         if Is_Function then

            --  If this is a function call, then read the value and return
            --  it. The return value is written/read using 'Output/'Input.

            Append_To (Non_Asynchronous_Statements,
              Make_Tag_Check (Loc,
                Make_Return_Statement (Loc,
                  Expression =>
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (
                          Etype (Subtype_Mark (Spec)), Loc),

                      Attribute_Name => Name_Input,

                      Expressions    => New_List (
                        Make_Attribute_Reference (Loc,
                          Prefix         =>
                            New_Occurrence_Of (Result_Parameter, Loc),
                          Attribute_Name => Name_Access))))));

         else
            --  Loop around parameters and assign out (or in out) parameters.
            --  In the case of RACW, controlling arguments cannot possibly
            --  have changed since they are remote, so we do not read them
            --  from the stream.

            Current_Parameter :=
              First (Ordered_Parameters_List);

            while Current_Parameter /= Empty loop

               if Out_Present (Current_Parameter)
                 and then
                   Etype (Parameter_Type (Current_Parameter)) /= Object_Type
               then
                  Append_To (Non_Asynchronous_Statements,
                    Make_Attribute_Reference (Loc,
                      Prefix         =>
                        New_Occurrence_Of (
                          Etype (Parameter_Type (Current_Parameter)), Loc),

                      Attribute_Name => Name_Read,

                      Expressions    => New_List (
                        Make_Attribute_Reference (Loc,
                          Prefix         =>
                            New_Occurrence_Of (Result_Parameter, Loc),
                          Attribute_Name =>
                            Name_Access),
                        New_Occurrence_Of (
                          Defining_Identifier (Current_Parameter), Loc))));
               end if;

               Next (Current_Parameter);
            end loop;
         end if;
      end if;

      if Is_Known_Asynchronous then
         Append_List_To (Statements, Asynchronous_Statements);

      elsif Is_Known_Non_Asynchronous then
         Append_List_To (Statements, Non_Asynchronous_Statements);

      else
         pragma Assert (Asynchronous /= Empty);
         Prepend_To (Asynchronous_Statements,
           Make_Attribute_Reference (Loc,
             Prefix         => New_Occurrence_Of (Standard_Boolean, Loc),
             Attribute_Name => Name_Write,
             Expressions    => New_List (
               Make_Attribute_Reference (Loc,
                 Prefix         => New_Occurrence_Of (Stream_Parameter, Loc),
                 Attribute_Name => Name_Access),
               New_Occurrence_Of (Standard_True, Loc))));
         Prepend_To (Non_Asynchronous_Statements,
           Make_Attribute_Reference (Loc,
             Prefix         => New_Occurrence_Of (Standard_Boolean, Loc),
             Attribute_Name => Name_Write,
             Expressions    => New_List (
               Make_Attribute_Reference (Loc,
                 Prefix         => New_Occurrence_Of (Stream_Parameter, Loc),
                 Attribute_Name => Name_Access),
               New_Occurrence_Of (Standard_False, Loc))));
         Append_To (Statements,
           Make_Implicit_If_Statement (Nod,
             Condition       => Asynchronous,
             Then_Statements => Asynchronous_Statements,
             Else_Statements => Non_Asynchronous_Statements));
      end if;
   end Build_General_Calling_Stubs;

   -----------------------------------
   -- Build_Ordered_Parameters_List --
   -----------------------------------

   function Build_Ordered_Parameters_List (Spec : Node_Id) return List_Id is
      Constrained_List   : List_Id;
      Unconstrained_List : List_Id;
      Current_Parameter  : Node_Id;

   begin
      if not Present (Parameter_Specifications (Spec)) then
         return New_List;
      end if;

      Constrained_List   := New_List;
      Unconstrained_List := New_List;

      --  Loop through the parameters and add them to the right list

      Current_Parameter := First (Parameter_Specifications (Spec));
      while Current_Parameter /= Empty loop

         if Nkind (Parameter_Type (Current_Parameter)) = N_Access_Definition
             or else
           Is_Constrained (Etype (Parameter_Type (Current_Parameter)))
             or else
           Is_Elementary_Type (Etype (Parameter_Type (Current_Parameter)))
         then
            Append_To (Constrained_List, New_Copy (Current_Parameter));
         else
            Append_To (Unconstrained_List, New_Copy (Current_Parameter));
         end if;

         Next (Current_Parameter);
      end loop;

      --  Unconstrained parameters are returned first

      Append_List_To (Unconstrained_List, Constrained_List);

      return Unconstrained_List;

   end Build_Ordered_Parameters_List;

   ----------------------------------
   -- Build_Passive_Partition_Stub --
   ----------------------------------

   procedure Build_Passive_Partition_Stub (U : Node_Id) is
      Pkg_Spec : Node_Id;
      L        : List_Id;
      Reg      : Node_Id;
      Loc      : constant Source_Ptr := Sloc (U);
      Dist_OK  : Entity_Id;

   begin
      --  Verify that the implementation supports distribution, by accessing
      --  a type defined in the proper version of system.rpc

      Dist_OK := RTE (RE_Params_Stream_Type);

      --  Use body if present, spec otherwise

      if Nkind (U) = N_Package_Declaration then
         Pkg_Spec := Specification (U);
         L := Visible_Declarations (Pkg_Spec);
      else
         Pkg_Spec := Parent (Corresponding_Spec (U));
         L := Declarations (U);
      end if;

      Reg :=
        Make_Procedure_Call_Statement (Loc,
          Name                   =>
            New_Occurrence_Of (RTE (RE_Register_Passive_Package), Loc),
          Parameter_Associations => New_List (
            Make_String_Literal (Loc, Get_Pkg_Name_String_Id (Pkg_Spec)),
            Make_Attribute_Reference (Loc,
              Prefix         =>
                New_Occurrence_Of (Defining_Entity (Pkg_Spec), Loc),
              Attribute_Name =>
                Name_Version)));
      Append_To (L, Reg);
      Analyze (Reg);
   end Build_Passive_Partition_Stub;

   ------------------------------------
   -- Build_Subprogram_Calling_Stubs --
   ------------------------------------

   function Build_Subprogram_Calling_Stubs
     (Vis_Decl                 : Node_Id;
      Subp_Id                  : Int;
      Asynchronous             : Boolean;
      Dynamically_Asynchronous : Boolean   := False;
      Stub_Type                : Entity_Id := Empty;
      Locator                  : Entity_Id := Empty;
      New_Name                 : Name_Id   := No_Name)
      return                     Node_Id
   is
      Loc : constant Source_Ptr := Sloc (Vis_Decl);

      Target_Partition : Node_Id;
      --  Contains the name of the target partition

      Decls      : constant List_Id := New_List;
      Statements : constant List_Id := New_List;

      Subp_Spec : Node_Id;
      --  The specification of the body

      Controlling_Parameter : Entity_Id := Empty;
      RPC_Receiver          : Node_Id;

      Asynchronous_Expr : Node_Id := Empty;

      RCI_Locator : Entity_Id;

      Spec_To_Use : Node_Id;

      procedure Insert_Partition_Check (Parameter : in Node_Id);
      --  Check that the parameter has been elaborated on the same partition
      --  than the controlling parameter (E.4(19)).

      ----------------------------
      -- Insert_Partition_Check --
      ----------------------------

      procedure Insert_Partition_Check (Parameter : in Node_Id) is
         Parameter_Entity  : constant Entity_Id :=
                               Defining_Identifier (Parameter);
         Designated_Object : Node_Id;
         Condition         : Node_Id;

      begin
         --  The expression that will be built is of the form:
         --    if not (Parameter in Stub_Type and then
         --            Parameter.Origin = Controlling.Origin)
         --    then
         --      raise Constraint_Error;
         --    end if;
         --
         --  Condition contains the reversed condition. Also, Parameter is
         --  dereferenced if it is an access type. We do not check that
         --  Parameter is in Stub_Type since such a check has been inserted
         --  at the point of call already (a tag check since we have multiple
         --  controlling operands).

         if Nkind (Parameter_Type (Parameter)) = N_Access_Definition then
            Designated_Object :=
              Make_Explicit_Dereference (Loc,
                Prefix => New_Occurrence_Of (Parameter_Entity, Loc));
         else
            Designated_Object := New_Occurrence_Of (Parameter_Entity, Loc);
         end if;

         Condition :=
           Make_Op_Eq (Loc,
             Left_Opnd  =>
               Make_Selected_Component (Loc,
                 Prefix        =>
                   New_Occurrence_Of (Parameter_Entity, Loc),
               Selector_Name =>
                 Make_Identifier (Loc, Name_Origin)),

             Right_Opnd =>
               Make_Selected_Component (Loc,
                 Prefix        =>
                   New_Occurrence_Of (Controlling_Parameter, Loc),
               Selector_Name =>
                 Make_Identifier (Loc, Name_Origin)));

         Append_To (Decls,
           Make_Raise_Constraint_Error (Loc,
             Condition       =>
               Make_Op_Not (Loc, Right_Opnd => Condition)));
      end Insert_Partition_Check;

   --  Start of processing for Build_Subprogram_Calling_Stubs

   begin
      Target_Partition :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('P'));

      Subp_Spec := Copy_Specification (Loc,
        Spec     => Specification (Vis_Decl),
        New_Name => New_Name);

      if Locator = Empty then
         RCI_Locator := RCI_Cache;
         Spec_To_Use := Specification (Vis_Decl);
      else
         RCI_Locator := Locator;
         Spec_To_Use := Subp_Spec;
      end if;

      --  Find a controlling argument if we have a stub type. Also check
      --  if this subprogram can be made asynchronous.

      if Stub_Type /= Empty
         and then Present (Parameter_Specifications (Spec_To_Use))
      then
         declare
            Current_Parameter : Node_Id :=
                                  First (Parameter_Specifications
                                           (Spec_To_Use));
         begin
            while Current_Parameter /= Empty loop

               if
                 Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type)
               then
                  if Controlling_Parameter = Empty then
                     Controlling_Parameter :=
                       Defining_Identifier (Current_Parameter);
                  else
                     Insert_Partition_Check (Current_Parameter);
                  end if;
               end if;

               Next (Current_Parameter);
            end loop;
         end;
      end if;

      if Stub_Type /= Empty then
         pragma Assert (Controlling_Parameter /= Empty);

         Append_To (Decls,
           Make_Object_Declaration (Loc,
             Defining_Identifier => Target_Partition,
             Constant_Present    => True,
             Object_Definition   =>
               New_Occurrence_Of (RTE (RE_Partition_ID), Loc),

             Expression          =>
               Make_Selected_Component (Loc,
                 Prefix        =>
                   New_Occurrence_Of (Controlling_Parameter, Loc),
                 Selector_Name =>
                   Make_Identifier (Loc, Name_Origin))));

         RPC_Receiver :=
           Make_Selected_Component (Loc,
             Prefix        =>
               New_Occurrence_Of (Controlling_Parameter, Loc),
             Selector_Name =>
               Make_Identifier (Loc, Name_Receiver));

      else
         Append_To (Decls,
           Make_Object_Declaration (Loc,
             Defining_Identifier => Target_Partition,
             Constant_Present    => True,
             Object_Definition   =>
               New_Occurrence_Of (RTE (RE_Partition_ID), Loc),

             Expression          =>
               Make_Function_Call (Loc,
                 Name => Make_Selected_Component (Loc,
                   Prefix        =>
                     Make_Identifier (Loc, Chars (RCI_Locator)),
                   Selector_Name =>
                     Make_Identifier (Loc, Name_Get_Active_Partition_ID)))));

         RPC_Receiver :=
           Make_Selected_Component (Loc,
             Prefix        =>
               Make_Identifier (Loc, Chars (RCI_Locator)),
             Selector_Name =>
               Make_Identifier (Loc, Name_Get_RCI_Package_Receiver));
      end if;

      if Dynamically_Asynchronous then
         Asynchronous_Expr :=
           Make_Selected_Component (Loc,
             Prefix        =>
               New_Occurrence_Of (Controlling_Parameter, Loc),
             Selector_Name =>
               Make_Identifier (Loc, Name_Asynchronous));
      end if;

      Build_General_Calling_Stubs
        (Decls                 => Decls,
         Statements            => Statements,
         Target_Partition      => Target_Partition,
         RPC_Receiver          => RPC_Receiver,
         Subprogram_Id         => Make_Integer_Literal (Loc, Subp_Id),
         Asynchronous          => Asynchronous_Expr,
         Is_Known_Asynchronous => Asynchronous
                                    and then not Dynamically_Asynchronous,
         Is_Known_Non_Asynchronous
                               => not Asynchronous
                                    and then not Dynamically_Asynchronous,
         Is_Function           => Nkind (Spec_To_Use) =
                                    N_Function_Specification,
         Spec                  => Spec_To_Use,
         Object_Type           => Stub_Type,
         Nod                   => Vis_Decl);

      RCI_Calling_Stubs_Table.Set
        (Defining_Unit_Name (Specification (Vis_Decl)),
         Defining_Unit_Name (Spec_To_Use));

      return
        Make_Subprogram_Body (Loc,
          Specification              => Subp_Spec,
          Declarations               => Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc, Statements));
   end Build_Subprogram_Calling_Stubs;

   --------------------------------------
   -- Build_Subprogram_Receiving_Stubs --
   --------------------------------------

   function Build_Subprogram_Receiving_Stubs
     (Vis_Decl                 : Node_Id;
      Asynchronous             : Boolean;
      Dynamically_Asynchronous : Boolean   := False;
      Stub_Type                : Entity_Id := Empty;
      RACW_Type                : Entity_Id := Empty;
      Parent_Primitive         : Entity_Id := Empty)
      return Node_Id
   is
      Loc : constant Source_Ptr := Sloc (Vis_Decl);

      Stream_Parameter : Node_Id;
      Result_Parameter : Node_Id;
      --  See explanations of those in Build_Subprogram_Calling_Stubs

      Decls : List_Id := New_List;
      --  All the parameters will get declared before calling the real
      --  subprograms. Also the out parameters will be declared.

      Statements : List_Id := New_List;

      Extra_Formal_Statements : List_Id := New_List;
      --  Statements concerning extra formal parameters

      After_Statements : List_Id := New_List;
      --  Statements to be executed after the subprogram call

      Inner_Decls : List_Id := No_List;
      --  In case of a function, the inner declarations are needed since
      --  the result may be unconstrained.

      Excep_Handler : Node_Id;
      Excep_Choice  : Entity_Id;
      Excep_Code    : List_Id;

      Parameter_List   : List_Id := New_List;
      --  List of parameters to be passed to the subprogram.

      Current_Parameter : Node_Id;

      Ordered_Parameters_List : constant List_Id :=
        Build_Ordered_Parameters_List (Specification (Vis_Decl));

      Subp_Spec : Node_Id;
      --  Subprogram specification

      Called_Subprogram : Node_Id;
      --  The subprogram to call

      Null_Raise_Statement : Node_Id;

      Dynamic_Async : Entity_Id;

   begin
      if RACW_Type /= Empty then
         Called_Subprogram :=
           New_Occurrence_Of (Parent_Primitive, Loc);
      else
         Called_Subprogram :=
           New_Occurrence_Of (
             Defining_Unit_Name (Specification (Vis_Decl)), Loc);
      end if;

      Stream_Parameter :=
        Make_Defining_Identifier (Loc, New_Internal_Name ('S'));

      if Dynamically_Asynchronous then
         Dynamic_Async :=
           Make_Defining_Identifier (Loc, New_Internal_Name ('S'));
      else
         Dynamic_Async := Empty;
      end if;

      if not Asynchronous or else Dynamically_Asynchronous then
         Result_Parameter :=
           Make_Defining_Identifier (Loc, New_Internal_Name ('S'));

         --  The first statement after the subprogram call is a statement to
         --  writes a Null_Occurrence into the result stream.

         Null_Raise_Statement :=
           Make_Attribute_Reference (Loc,
             Prefix         =>
               New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc),
             Attribute_Name => Name_Write,
             Expressions    => New_List (
               New_Occurrence_Of (Result_Parameter, Loc),
               New_Occurrence_Of (RTE (RE_Null_Occurrence), Loc)));

         if Dynamically_Asynchronous then
            Null_Raise_Statement :=
              Make_Implicit_If_Statement (Vis_Decl,
                Condition       =>
                  Make_Op_Not (Loc, New_Occurrence_Of (Dynamic_Async, Loc)),
                Then_Statements => New_List (Null_Raise_Statement));
         end if;

         Append_To (After_Statements, Null_Raise_Statement);

      else
         Result_Parameter := Empty;
      end if;

      --  Loop through every parameter and get its value from the stream. If
      --  the parameter is unconstrained, then the parameter is read using
      --  'Input at the point of declaration.

      Current_Parameter := First (Ordered_Parameters_List);

      while Current_Parameter /= Empty loop

         declare
            Etyp        : Entity_Id;
            Constrained : Boolean;
            Object      : Entity_Id;
            Expr        : Node_Id := Empty;

         begin
            Object := Make_Defining_Identifier (Loc, New_Internal_Name ('P'));
            Set_Ekind (Object, E_Variable);

            if
              Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type)
            then
               --  We have a controlling formal parameter. Read its address
               --  rather than a real object. The address is in Unsigned_64
               --  form.

               Etyp := RTE (RE_Unsigned_64);
            else
               Etyp := Etype (Parameter_Type (Current_Parameter));
            end if;

            Constrained :=
              Is_Constrained (Etyp) or else Is_Elementary_Type (Etyp);

            if In_Present (Current_Parameter)
               or else not Out_Present (Current_Parameter)
               or else not Constrained
            then
               --  If an input parameter is contrained, then its reading is
               --  deferred until the beginning of the subprogram body. If
               --  it is unconstrained, then an expression is built for
               --  the object declaration and the variable is set using
               --  'Input instead of 'Read.

               if Constrained then
                  Append_To (Statements,
                    Make_Attribute_Reference (Loc,
                      Prefix         => New_Occurrence_Of (Etyp, Loc),
                      Attribute_Name => Name_Read,
                      Expressions    => New_List (
                        New_Occurrence_Of (Stream_Parameter, Loc),
                        New_Occurrence_Of (Object, Loc))));

               else
                  Expr := Input_With_Tag_Check (Loc,
                    Var_Type => Etyp,
                    Stream   => Stream_Parameter);
                  Append_To (Decls, Expr);
                  Expr := Make_Function_Call (Loc,
                    New_Occurrence_Of (Defining_Unit_Name
                      (Specification (Expr)), Loc));
               end if;
            end if;

            --  If we do not have to output the current parameter, then
            --  it can well be flagged as constant. This may allow further
            --  optimizations done by the back end.

            Append_To (Decls,
              Make_Object_Declaration (Loc,
                Defining_Identifier => Object,
                Constant_Present    =>
                  not Constrained and then not Out_Present (Current_Parameter),
                Object_Definition   =>
                  New_Occurrence_Of (Etyp, Loc),
                Expression          => Expr));

            --  An out parameter may be written back using a 'Write
            --  attribute instead of a 'Output because it has been
            --  constrained by the parameter given to the caller. Note that
            --  out controlling arguments in the case of a RACW are not put
            --  back in the stream because the pointer on them has not
            --  changed.

            if Out_Present (Current_Parameter)
              and then
                Etype (Parameter_Type (Current_Parameter)) /= Stub_Type
            then
               Append_To (After_Statements,
                 Make_Attribute_Reference (Loc,
                   Prefix         => New_Occurrence_Of (Etyp, Loc),
                   Attribute_Name => Name_Write,
                   Expressions    => New_List (
                       New_Occurrence_Of (Result_Parameter, Loc),
                     New_Occurrence_Of (Object, Loc))));
            end if;

            if
              Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type)
            then

               if Nkind (Parameter_Type (Current_Parameter)) /=
                 N_Access_Definition
               then
                  Append_To (Parameter_List,
                    Make_Parameter_Association (Loc,
                      Selector_Name             =>
                        New_Occurrence_Of (
                          Defining_Identifier (Current_Parameter), Loc),
                      Explicit_Actual_Parameter =>
                        Make_Explicit_Dereference (Loc,
                          Unchecked_Convert_To (RACW_Type,
                            OK_Convert_To (RTE (RE_Address),
                              New_Occurrence_Of (Object, Loc))))));
               else
                  Append_To (Parameter_List,
                    Make_Parameter_Association (Loc,
                      Selector_Name             =>
                        New_Occurrence_Of (
                          Defining_Identifier (Current_Parameter), Loc),
                      Explicit_Actual_Parameter =>
                        Unchecked_Convert_To (RACW_Type,
                          OK_Convert_To (RTE (RE_Address),
                            New_Occurrence_Of (Object, Loc)))));
               end if;
            else
               Append_To (Parameter_List,
                 Make_Parameter_Association (Loc,
                   Selector_Name             =>
                     New_Occurrence_Of (
                       Defining_Identifier (Current_Parameter), Loc),
                   Explicit_Actual_Parameter =>
                     New_Occurrence_Of (Object, Loc)));
            end if;

            --  If the current parameter needs an extra formal, then read it
            --  from the stream and set the corresponding semantic field in
            --  the variable. If the kind of the parameter identifier is
            --  E_Void, then this is a compiler generated parameter that
            --  doesn't need an extra constrained status.

            --  The case of Extra_Accessibility should also be handled ???

            if Nkind (Parameter_Type (Current_Parameter)) /=
                                                      N_Access_Definition
              and then
                Ekind (Defining_Identifier (Current_Parameter)) /= E_Void
              and then
                Present (Extra_Constrained
                  (Defining_Identifier (Current_Parameter)))
            then
               declare
                  Extra_Parameter : constant Entity_Id :=
                                      Extra_Constrained
                                        (Defining_Identifier
                                          (Current_Parameter));

                  Formal_Entity : constant Entity_Id :=
                                    Make_Defining_Identifier
                                        (Loc, Chars (Extra_Parameter));

                  Formal_Type : constant Entity_Id :=
                                  Etype (Extra_Parameter);

               begin
                  Append_To (Decls,
                    Make_Object_Declaration (Loc,
                      Defining_Identifier => Formal_Entity,
                      Object_Definition   =>
                        New_Occurrence_Of (Formal_Type, Loc)));

                  Append_To (Extra_Formal_Statements,
                    Make_Attribute_Reference (Loc,
                      Prefix         => New_Occurrence_Of (Formal_Type, Loc),
                      Attribute_Name => Name_Read,
                      Expressions    => New_List (
                        New_Occurrence_Of (Stream_Parameter, Loc),
                        New_Occurrence_Of (Formal_Entity, Loc))));
                  Set_Extra_Constrained (Object, Formal_Entity);
               end;
            end if;
         end;

         Next (Current_Parameter);
      end loop;

      --  Append the formal statements list at the end of regular statements

      Append_List_To (Statements, Extra_Formal_Statements);

      if Nkind (Specification (Vis_Decl)) = N_Function_Specification then

         --  The remote subprogram is a function. We build an inner block to
         --  be able to hold a potentially unconstrained result in a variable.

         declare
            Etyp   : constant Entity_Id :=
                       Etype (Subtype_Mark (Specification (Vis_Decl)));
            Result : constant Node_Id   :=
                       Make_Defining_Identifier (Loc, New_Internal_Name ('R'));

         begin
            Inner_Decls := New_List (
              Make_Object_Declaration (Loc,
                Defining_Identifier => Result,
                Constant_Present    => True,
                Object_Definition   => New_Occurrence_Of (Etyp, Loc),
                Expression          =>
                  Make_Function_Call (Loc,
                    Name                   => Called_Subprogram,
                    Parameter_Associations => Parameter_List)));

            Append_To (After_Statements,
              Make_Attribute_Reference (Loc,
                Prefix         => New_Occurrence_Of (Etyp, Loc),
                Attribute_Name => Name_Output,
                Expressions    => New_List (
                  New_Occurrence_Of (Result_Parameter, Loc),
                  New_Occurrence_Of (Result, Loc))));
         end;

         Append_To (Statements,
           Make_Block_Statement (Loc,
             Declarations               => Inner_Decls,
             Handled_Statement_Sequence =>
               Make_Handled_Sequence_Of_Statements (Loc,
                 Statements => After_Statements)));

      else
         --  The remote subprogram is a procedure. We do not need any inner
         --  block in this case.

         if Dynamically_Asynchronous then
            Append_To (Decls,
              Make_Object_Declaration (Loc,
                Defining_Identifier => Dynamic_Async,
                Object_Definition   =>
                  New_Occurrence_Of (Standard_Boolean, Loc)));

            Append_To (Statements,
              Make_Attribute_Reference (Loc,
                Prefix         => New_Occurrence_Of (Standard_Boolean, Loc),
                Attribute_Name => Name_Read,
                Expressions    => New_List (
                  New_Occurrence_Of (Stream_Parameter, Loc),
                  New_Occurrence_Of (Dynamic_Async, Loc))));
         end if;

         Append_To (Statements,
           Make_Procedure_Call_Statement (Loc,
             Name                   => Called_Subprogram,
             Parameter_Associations => Parameter_List));

         Append_List_To (Statements, After_Statements);

      end if;

      if Asynchronous and then not Dynamically_Asynchronous then

         --  An asynchronous procedure does not want a Result
         --  parameter. Also, we put an exception handler with an others
         --  clause that does nothing.

         Subp_Spec :=
           Make_Procedure_Specification (Loc,
             Defining_Unit_Name       =>
               Make_Defining_Identifier (Loc, New_Internal_Name ('F')),
             Parameter_Specifications => New_List (
               Make_Parameter_Specification (Loc,
                 Defining_Identifier => Stream_Parameter,
                 Parameter_Type      =>
                   Make_Access_Definition (Loc,
                   Subtype_Mark =>
                     New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc)))));

         Excep_Handler :=
           Make_Exception_Handler (Loc,
             Exception_Choices =>
               New_List (Make_Others_Choice (Loc)),
             Statements        => New_List (
               Make_Null_Statement (Loc)));

      else
         --  In the other cases, if an exception is raised, then the
         --  exception occurrence is copied into the output stream and
         --  no other output parameter is written.

         Excep_Choice :=
           Make_Defining_Identifier (Loc, New_Internal_Name ('E'));

         Excep_Code := New_List (
           Make_Attribute_Reference (Loc,
             Prefix         =>
               New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc),
             Attribute_Name => Name_Write,
             Expressions    => New_List (
               New_Occurrence_Of (Result_Parameter, Loc),
               New_Occurrence_Of (Excep_Choice, Loc))));

         if Dynamically_Asynchronous then
            Excep_Code := New_List (
              Make_Implicit_If_Statement (Vis_Decl,
                Condition       => Make_Op_Not (Loc,
                  New_Occurrence_Of (Dynamic_Async, Loc)),
                Then_Statements => Excep_Code));
         end if;

         Excep_Handler :=
           Make_Exception_Handler (Loc,
             Choice_Parameter   => Excep_Choice,
             Exception_Choices  => New_List (Make_Others_Choice (Loc)),
             Statements         => Excep_Code);

         Subp_Spec :=
           Make_Procedure_Specification (Loc,
             Defining_Unit_Name       =>
               Make_Defining_Identifier (Loc, New_Internal_Name ('F')),

             Parameter_Specifications => New_List (
               Make_Parameter_Specification (Loc,
                 Defining_Identifier => Stream_Parameter,
                 Parameter_Type      =>
                   Make_Access_Definition (Loc,
                   Subtype_Mark =>
                     New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))),

               Make_Parameter_Specification (Loc,
                 Defining_Identifier => Result_Parameter,
                 Parameter_Type      =>
                   Make_Access_Definition (Loc,
                  Subtype_Mark =>
                  New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc)))));
      end if;

      return
        Make_Subprogram_Body (Loc,
          Specification              => Subp_Spec,
          Declarations               => Decls,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc,
              Statements         => Statements,
              Exception_Handlers => New_List (Excep_Handler)));

   end Build_Subprogram_Receiving_Stubs;

   ------------------------
   -- Copy_Specification --
   ------------------------

   function Copy_Specification
     (Loc         : Source_Ptr;
      Spec        : Node_Id;
      Object_Type : Entity_Id := Empty;
      Stub_Type   : Entity_Id := Empty;
      New_Name    : Name_Id   := No_Name)
      return        Node_Id
   is
      Parameters : List_Id := No_List;

      Current_Parameter : Node_Id;
      Current_Type      : Node_Id;

      Name_For_New_Spec : Name_Id;

      New_Identifier : Entity_Id;

   begin
      if New_Name = No_Name then
         Name_For_New_Spec := Chars (Defining_Unit_Name (Spec));
      else
         Name_For_New_Spec := New_Name;
      end if;

      if Present (Parameter_Specifications (Spec)) then

         Parameters        := New_List;
         Current_Parameter := First (Parameter_Specifications (Spec));

         while Current_Parameter /= Empty loop

            Current_Type := Parameter_Type (Current_Parameter);

            if Nkind (Current_Type) = N_Access_Definition then
               if Object_Type = Empty then
                  Current_Type :=
                    Make_Access_Definition (Loc,
                      Subtype_Mark =>
                        New_Occurrence_Of (Etype (
                          Subtype_Mark (Current_Type)), Loc));
               else
                  pragma Assert
                    (Root_Type (Etype (Subtype_Mark (Current_Type)))
                       = Root_Type (Object_Type));
                  Current_Type :=
                    Make_Access_Definition (Loc,
                      Subtype_Mark => New_Occurrence_Of (Stub_Type, Loc));
               end if;

            elsif Object_Type /= Empty
              and then Etype (Current_Type) = Object_Type
            then
               Current_Type := New_Occurrence_Of (Stub_Type, Loc);

            else
               Current_Type := New_Occurrence_Of (Etype (Current_Type), Loc);
            end if;

            New_Identifier := Make_Defining_Identifier (Loc,
              Chars (Defining_Identifier (Current_Parameter)));

            Append_To (Parameters,
              Make_Parameter_Specification (Loc,
                Defining_Identifier => New_Identifier,
                Parameter_Type      => Current_Type,
                In_Present          => In_Present (Current_Parameter),
                Out_Present         => Out_Present (Current_Parameter),
                Expression          =>
                  New_Copy_Tree (Expression (Current_Parameter))));

            Next (Current_Parameter);
         end loop;
      end if;

      if Nkind (Spec) = N_Function_Specification then
         return
           Make_Function_Specification (Loc,
             Defining_Unit_Name       =>
               Make_Defining_Identifier (Loc,
                 Chars => Name_For_New_Spec),
             Parameter_Specifications => Parameters,
             Subtype_Mark             =>
               New_Occurrence_Of (Etype (Subtype_Mark (Spec)), Loc));

      else
         return
           Make_Procedure_Specification (Loc,
             Defining_Unit_Name       =>
               Make_Defining_Identifier (Loc,
                 Chars => Name_For_New_Spec),
             Parameter_Specifications => Parameters);
      end if;

   end Copy_Specification;

   ---------------------------
   -- Could_Be_Asynchronous --
   ---------------------------

   function Could_Be_Asynchronous (Spec : Node_Id) return Boolean is
      Current_Parameter : Node_Id;

   begin
      if Present (Parameter_Specifications (Spec)) then
         Current_Parameter := First (Parameter_Specifications (Spec));
         while Current_Parameter /= Empty loop
            if Out_Present (Current_Parameter) then
               return False;
            end if;

            Next (Current_Parameter);
         end loop;
      end if;

      return True;
   end Could_Be_Asynchronous;

   ---------------------------------------------
   -- Expand_All_Calls_Remote_Subprogram_Call --
   ---------------------------------------------

   procedure Expand_All_Calls_Remote_Subprogram_Call (N : in Node_Id) is
      Called_Subprogram : constant Entity_Id  := Entity (Name (N));
      RCI_Package       : constant Entity_Id  := Scope (Called_Subprogram);
      Loc               : constant Source_Ptr := Sloc (N);
      RCI_Locator       : Node_Id;
      RCI_Cache         : Entity_Id;
      Calling_Stubs     : Node_Id;
      E_Calling_Stubs   : Entity_Id;

   begin
      E_Calling_Stubs := RCI_Calling_Stubs_Table.Get (Called_Subprogram);

      if E_Calling_Stubs = Empty then
         RCI_Cache := RCI_Locator_Table.Get (RCI_Package);

         if RCI_Cache = Empty then
            RCI_Locator :=
              RCI_Package_Locator
                (Loc, Specification (Unit_Declaration_Node (RCI_Package)));
            Prepend_To (Current_Sem_Unit_Declarations, RCI_Locator);

            --  The RCI_Locator package is inserted at the top level in the
            --  current unit, and must appear in the proper scope, so that it
            --  is not prematurely removed by the GCC back-end.

            declare
               Scop : Entity_Id := Cunit_Entity (Current_Sem_Unit);

            begin
               if Ekind (Scop) = E_Package_Body then
                  New_Scope (Spec_Entity (Scop));

               elsif Ekind (Scop) = E_Subprogram_Body then
                  New_Scope
                     (Corresponding_Spec (Unit_Declaration_Node (Scop)));

               else
                  New_Scope (Scop);
               end if;

               Analyze (RCI_Locator);
               Pop_Scope;
            end;

            RCI_Cache   := Defining_Unit_Name (RCI_Locator);

         else
            RCI_Locator := Parent (RCI_Cache);
         end if;

         Calling_Stubs := Build_Subprogram_Calling_Stubs
           (Vis_Decl               => Parent (Parent (Called_Subprogram)),
            Subp_Id                => Get_Subprogram_Id (Called_Subprogram),
            Asynchronous           => Nkind (N) = N_Procedure_Call_Statement
                                        and then
                                      Is_Asynchronous (Called_Subprogram),
            Locator                => RCI_Cache,
            New_Name               => New_Internal_Name ('S'));
         Insert_After (RCI_Locator, Calling_Stubs);
         Analyze (Calling_Stubs);
         E_Calling_Stubs := Defining_Unit_Name (Specification (Calling_Stubs));
      end if;

      Rewrite (Name (N), New_Occurrence_Of (E_Calling_Stubs, Loc));
   end Expand_All_Calls_Remote_Subprogram_Call;

   ---------------------------------
   -- Expand_Calling_Stubs_Bodies --
   ---------------------------------

   procedure Expand_Calling_Stubs_Bodies (Unit_Node : in Node_Id) is
      Spec  : constant Node_Id := Specification (Unit_Node);
      Decls : constant List_Id := Visible_Declarations (Spec);

   begin
      New_Scope (Scope_Of_Spec (Spec));
      Add_Calling_Stubs_To_Declarations (Specification (Unit_Node),
                                         Decls);
      Pop_Scope;
   end Expand_Calling_Stubs_Bodies;

   -----------------------------------
   -- Expand_Receiving_Stubs_Bodies --
   -----------------------------------

   procedure Expand_Receiving_Stubs_Bodies (Unit_Node : in Node_Id) is
      Spec  : Node_Id;
      Decls : List_Id;
      Temp  : List_Id;

   begin
      if Nkind (Unit_Node) = N_Package_Declaration then
         Spec  := Specification (Unit_Node);
         Decls := Visible_Declarations (Spec);
         New_Scope (Scope_Of_Spec (Spec));
         Add_Receiving_Stubs_To_Declarations (Spec, Decls);

      else
         Spec  :=
           Package_Specification_Of_Scope (Corresponding_Spec (Unit_Node));
         Decls := Declarations (Unit_Node);
         New_Scope (Scope_Of_Spec (Unit_Node));
         Temp := New_List;
         Add_Receiving_Stubs_To_Declarations (Spec, Temp);
         Insert_List_Before (First (Decls), Temp);
      end if;

      Pop_Scope;
   end Expand_Receiving_Stubs_Bodies;

   ----------------------------
   -- Get_Pkg_Name_string_Id --
   ----------------------------

   function Get_Pkg_Name_String_Id (Decl_Node : Node_Id) return String_Id is
      Unit_Name_Id : Unit_Name_Type := Get_Unit_Name (Decl_Node);

   begin
      Get_Unit_Name_String (Unit_Name_Id);

      --  Remove seven last character (" (spec)" or " (body)").

      Name_Len := Name_Len - 7;
      pragma Assert (Name_Buffer (Name_Len + 1) = ' ');

      return Get_String_Id (Name_Buffer (1 .. Name_Len));
   end Get_Pkg_Name_String_Id;

   -------------------
   -- Get_String_Id --
   -------------------

   function Get_String_Id (Val : String) return String_Id is
   begin
      Start_String;
      Store_String_Chars (Val);
      return End_String;
   end Get_String_Id;

   ----------
   -- Hash --
   ----------

   function Hash (F : Entity_Id) return Hash_Index is
   begin
      return Hash_Index (Natural (F) mod Positive (Hash_Index'Last + 1));
   end Hash;

   --------------------------
   -- Input_With_Tag_Check --
   --------------------------

   function Input_With_Tag_Check
     (Loc      : Source_Ptr;
      Var_Type : Entity_Id;
      Stream   : Entity_Id)
      return     Node_Id
   is
   begin
      return
        Make_Subprogram_Body (Loc,
          Specification              => Make_Function_Specification (Loc,
            Defining_Unit_Name =>
              Make_Defining_Identifier (Loc, New_Internal_Name ('S')),
            Subtype_Mark       => New_Occurrence_Of (Var_Type, Loc)),
          Declarations               => No_List,
          Handled_Statement_Sequence =>
            Make_Handled_Sequence_Of_Statements (Loc, New_List (
              Make_Tag_Check (Loc,
                Make_Return_Statement (Loc,
                  Make_Attribute_Reference (Loc,
                    Prefix         => New_Occurrence_Of (Var_Type, Loc),
                    Attribute_Name => Name_Input,
                    Expressions    =>
                      New_List (New_Occurrence_Of (Stream, Loc))))))));
   end Input_With_Tag_Check;

   --------------------------------
   -- Is_RACW_Controlling_Formal --
   --------------------------------

   function Is_RACW_Controlling_Formal
     (Parameter : Node_Id;
      Stub_Type : Entity_Id)
      return      Boolean
   is
      Typ : Entity_Id;

   begin
      --  If the kind of the parameter is E_Void, then it is not a
      --  controlling formal (this can happen in the context of RAS).

      if Ekind (Defining_Identifier (Parameter)) = E_Void then
         return False;
      end if;

      --  If the parameter is not a controlling formal, then it cannot
      --  be possibly a RACW_Controlling_Formal.

      if not Is_Controlling_Formal (Defining_Identifier (Parameter)) then
         return False;
      end if;

      Typ := Parameter_Type (Parameter);
      return (Nkind (Typ) = N_Access_Definition
               and then Etype (Subtype_Mark (Typ)) = Stub_Type)
        or else Etype (Typ) = Stub_Type;
   end Is_RACW_Controlling_Formal;

   --------------------
   -- Make_Tag_Check --
   --------------------

   function Make_Tag_Check (Loc : Source_Ptr; N : Node_Id) return Node_Id is
      Occ : constant Entity_Id :=
              Make_Defining_Identifier (Loc, New_Internal_Name ('E'));

   begin
      return Make_Block_Statement (Loc,
        Handled_Statement_Sequence =>
          Make_Handled_Sequence_Of_Statements (Loc,
            Statements         => New_List (N),

            Exception_Handlers => New_List (
              Make_Exception_Handler (Loc,
                Choice_Parameter => Occ,

                Exception_Choices =>
                  New_List (New_Occurrence_Of (RTE (RE_Tag_Error), Loc)),

                Statements =>
                  New_List (Make_Procedure_Call_Statement (Loc,
                    New_Occurrence_Of
                      (RTE (RE_Raise_Program_Error_Unknown_Tag), Loc),
                    New_List (New_Occurrence_Of (Occ, Loc))))))));
   end Make_Tag_Check;

   ----------------------------
   -- Need_Extra_Constrained --
   ----------------------------

   function Need_Extra_Constrained (Parameter : Node_Id) return Boolean is
      Etyp : constant Entity_Id := Etype (Parameter_Type (Parameter));

   begin
      return Out_Present (Parameter)
        and then Has_Discriminants (Etyp)
        and then not Is_Constrained (Etyp)
        and then not Is_Indefinite_Subtype (Etyp);
   end Need_Extra_Constrained;

   ------------------------------------
   -- Pack_Entity_Into_Stream_Access --
   ------------------------------------

   function Pack_Entity_Into_Stream_Access
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Entity_Id;
      Etyp   : Entity_Id := Empty)
      return   Node_Id
   is
      Typ : Entity_Id;

   begin
      if Etyp /= Empty then
         Typ := Etyp;
      else
         Typ := Etype (Object);
      end if;

      return
        Pack_Node_Into_Stream_Access (Loc,
          Stream => Stream,
          Object => New_Occurrence_Of (Object, Loc),
          Etyp   => Typ);
   end Pack_Entity_Into_Stream_Access;

   ---------------------------
   -- Pack_Node_Into_Stream --
   ---------------------------

   function Pack_Node_Into_Stream
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Node_Id;
      Etyp   : Entity_Id)
      return   Node_Id
   is
      Write_Attribute : Name_Id := Name_Write;

   begin
      if not Is_Constrained (Etyp) then
         Write_Attribute := Name_Output;
      end if;

      return
        Make_Attribute_Reference (Loc,
          Prefix         => New_Occurrence_Of (Etyp, Loc),
          Attribute_Name => Write_Attribute,
          Expressions    => New_List (
            Make_Attribute_Reference (Loc,
              Prefix         => New_Occurrence_Of (Stream, Loc),
              Attribute_Name => Name_Access),
            Object));
   end Pack_Node_Into_Stream;

   ----------------------------------
   -- Pack_Node_Into_Stream_Access --
   ----------------------------------

   function Pack_Node_Into_Stream_Access
     (Loc    : Source_Ptr;
      Stream : Entity_Id;
      Object : Node_Id;
      Etyp   : Entity_Id)
      return   Node_Id
   is
      Write_Attribute : Name_Id := Name_Write;

   begin
      if not Is_Constrained (Etyp) then
         Write_Attribute := Name_Output;
      end if;

      return
        Make_Attribute_Reference (Loc,
          Prefix         => New_Occurrence_Of (Etyp, Loc),
          Attribute_Name => Write_Attribute,
          Expressions    => New_List (
            New_Occurrence_Of (Stream, Loc),
            Object));
   end Pack_Node_Into_Stream_Access;

   -------------------------------
   -- RACW_Type_Is_Asynchronous --
   -------------------------------

   procedure RACW_Type_Is_Asynchronous (RACW_Type : in Entity_Id) is
      N : constant Node_Id := Asynchronous_Flags_Table.Get (RACW_Type);
      pragma Assert (N /= Empty);

   begin
      Replace (N, New_Occurrence_Of (Standard_True, Sloc (N)));
   end RACW_Type_Is_Asynchronous;

   -------------------------
   -- RCI_Package_Locator --
   -------------------------

   function RCI_Package_Locator
     (Loc          : Source_Ptr;
      Package_Spec : Node_Id)
      return         Node_Id
   is
      Inst : constant Node_Id :=
               Make_Package_Instantiation (Loc,
                 Defining_Unit_Name   =>
                   Make_Defining_Identifier (Loc, New_Internal_Name ('R')),
                 Name                 =>
                   New_Occurrence_Of (RTE (RE_RCI_Info), Loc),
                 Generic_Associations => New_List (
                   Make_Generic_Association (Loc,
                     Selector_Name                     =>
                       Make_Identifier (Loc, Name_RCI_Name),
                     Explicit_Generic_Actual_Parameter =>
                       Make_String_Literal (Loc,
                         Strval => Get_Pkg_Name_String_Id (Package_Spec)))));

   begin
      RCI_Locator_Table.Set (Defining_Unit_Name (Package_Spec),
        Defining_Unit_Name (Inst));
      return Inst;
   end RCI_Package_Locator;

   -----------------------------------------------
   -- Remote_Types_Tagged_Full_View_Encountered --
   -----------------------------------------------

   procedure Remote_Types_Tagged_Full_View_Encountered
     (Full_View : in Entity_Id)
   is
      Stub_Elements : constant Stub_Structure :=
                        Stubs_Table.Get (Full_View);

   begin
      if Stub_Elements /= Empty_Stub_Structure then
         Add_RACW_Primitive_Declarations_And_Bodies
           (Full_View,
            Parent (Declaration_Node (Stub_Elements.Object_RPC_Receiver)),
            List_Containing (Declaration_Node (Full_View)));
      end if;
   end Remote_Types_Tagged_Full_View_Encountered;

   -------------------
   -- Scope_Of_Spec --
   -------------------

   function Scope_Of_Spec (Spec : Node_Id) return Entity_Id is
      Unit_Name : Node_Id := Defining_Unit_Name (Spec);

   begin
      while Nkind (Unit_Name) /= N_Defining_Identifier loop
         Unit_Name := Defining_Identifier (Unit_Name);
      end loop;

      return Unit_Name;
   end Scope_Of_Spec;

end Exp_Dist;
