From: Javier Miranda <mira...@adacore.com>

This patch adds support for a new GNAT aspect/pragma that modifies
the semantics of dispatching primitives. When a tagged type has
this aspect/pragma, only subprograms that have the first parameter
of this type will be considered dispatching primitives; this new
pragma/aspect is inherited by all descendant types.

gcc/ada/

        * aspects.ads (Aspect_First_Controlling_Parameter): New aspect.
        Defined as implementation defined aspect that has a static boolean
        value and it is converted to pragma when the value is True.
        * einfo.ads (Has_First_Controlling_Parameter): New attribute.
        * exp_ch9.adb (Build_Corresponding_Record): Propagate the aspect
        to the corresponding record type.
        (Expand_N_Protected_Type_Declaration): Analyze the inherited
        aspect to add the pragma.
        (Expand_N_Task_Type_Declaration): ditto.
        * freeze.adb (Warn_If_Implicitly_Inherited_Aspects): New
        subprogram.
        (Has_First_Ctrl_Param_Aspect): New subprogram.
        (Freeze_Record_Type): Call Warn_If_Implicitly_Inherited_Aspects.
        (Freeze_Subprogram): Check illegal subprograms of tagged types and
        interface types that have this new aspect.
        * gen_il-fields.ads (Has_First_Controlling_Parameter): New entity
        field.
        * gen_il-gen-gen_entities.adb (Has_First_Controlling_Parameter):
        The new field is a semantic flag.
        * gen_il-internals.adb (Image): Add
        Has_First_Controlling_Parameter.
        * par-prag.adb (Prag): No action for
        Pragma_First_Controlling_Parameter since processing is handled
        entirely in Sem_Prag.
        * sem_ch12.adb (Validate_Private_Type_Instance): When the generic
        formal has this new aspect, check that the actual type also has
        this aspect.
        * sem_ch13.adb (Analyze_One_Aspect): Check that the aspect is
        applied to a tagged type or a concurrent type.
        * sem_ch3.adb (Analyze_Full_Type_Declaration): Derived tagged
        types inherit this new aspect, and also from their implemented
        interface types.
        (Process_Full_View): Propagate the aspect to the full view.
        * sem_ch6.adb (Is_A_Primitive): New subprogram; used to factor
        code and also clarify detection of primitives.
        * sem_ch9.adb (Check_Interfaces): Propagate this new aspect to the
        type implementing interface types.
        * sem_disp.adb (Check_Controlling_Formals): Handle tagged type
        that has the aspect and has subprograms overriding primitives of
        tagged types that lack this aspect.
        (Check_Dispatching_Operation): Warn on dispatching primitives
        disallowed by this new aspect.
        (Has_Predefined_Dispatching_Operation_Name): New subprogram.
        (Find_Dispatching_Type): Handle dispatching functions of tagged
        types that have the new aspect.
        (Find_Primitive_Covering_Interface): For primitives of tagged
        types that have the aspect and override a primitive of a parent
        type that does not have the aspect, we must temporarily unset
        attribute First_Controlling_ Parameter to properly check
        conformance.
        * sem_prag.ads (Aspect_Specifying_Pragma): Add new pragma.
        * sem_prag.adb (Pragma_First_Controlling_Parameter): Handle new
        pragma.
        * snames.ads-tmpl (Name_First_Controlling_Parameter): New name.
        * warnsw.ads (Warn_On_Non_Dispatching_Primitives): New warning.
        * warnsw.adb (Warn_On_Non_Dispatching_Primitives): New warning;
        not set by default when GNAT_Mode warnings are enabled, nor when
        all warnings are enabled (-gnatwa).

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/aspects.ads                 |   5 +
 gcc/ada/einfo.ads                   |   9 +
 gcc/ada/exp_ch9.adb                 |  73 ++++++++
 gcc/ada/freeze.adb                  | 279 ++++++++++++++++++++++++++++
 gcc/ada/gen_il-fields.ads           |   1 +
 gcc/ada/gen_il-gen-gen_entities.adb |   3 +
 gcc/ada/gen_il-internals.adb        |   2 +
 gcc/ada/par-prag.adb                |   1 +
 gcc/ada/sem_ch12.adb                |  12 ++
 gcc/ada/sem_ch13.adb                |  52 ++++++
 gcc/ada/sem_ch3.adb                 |  48 +++++
 gcc/ada/sem_ch6.adb                 |  83 +++++++--
 gcc/ada/sem_ch9.adb                 |   8 +
 gcc/ada/sem_disp.adb                | 207 ++++++++++++++++++++-
 gcc/ada/sem_prag.adb                |  86 +++++++++
 gcc/ada/sem_prag.ads                |   1 +
 gcc/ada/snames.ads-tmpl             |   2 +
 gcc/ada/warnsw.adb                  |   4 +-
 gcc/ada/warnsw.ads                  |   7 +
 19 files changed, 860 insertions(+), 23 deletions(-)

diff --git a/gcc/ada/aspects.ads b/gcc/ada/aspects.ads
index 9d0a9eb0110..adaa11f8a93 100644
--- a/gcc/ada/aspects.ads
+++ b/gcc/ada/aspects.ads
@@ -198,6 +198,7 @@ package Aspects is
       Aspect_Export,
       Aspect_Extensions_Visible,            -- GNAT
       Aspect_Favor_Top_Level,               -- GNAT
+      Aspect_First_Controlling_Parameter,   -- GNAT
       Aspect_Full_Access_Only,
       Aspect_Ghost,                         -- GNAT
       Aspect_Import,
@@ -294,6 +295,7 @@ package Aspects is
       Aspect_Extensions_Visible         => True,
       Aspect_Favor_Top_Level            => True,
       Aspect_Finalizable                => True,
+      Aspect_First_Controlling_Parameter => True,
       Aspect_Ghost                      => True,
       Aspect_Ghost_Predicate            => True,
       Aspect_Global                     => True,
@@ -537,6 +539,7 @@ package Aspects is
       Aspect_External_Name                => False,
       Aspect_External_Tag                 => False,
       Aspect_Finalizable                  => False,
+      Aspect_First_Controlling_Parameter  => False,
       Aspect_Ghost_Predicate              => False,
       Aspect_Global                       => False,
       Aspect_GNAT_Annotate                => False,
@@ -712,6 +715,7 @@ package Aspects is
       Aspect_External_Tag                 => Name_External_Tag,
       Aspect_Favor_Top_Level              => Name_Favor_Top_Level,
       Aspect_Finalizable                  => Name_Finalizable,
+      Aspect_First_Controlling_Parameter  => Name_First_Controlling_Parameter,
       Aspect_Full_Access_Only             => Name_Full_Access_Only,
       Aspect_Ghost                        => Name_Ghost,
       Aspect_Ghost_Predicate              => Name_Ghost_Predicate,
@@ -1046,6 +1050,7 @@ package Aspects is
       Aspect_Exceptional_Cases            => Never_Delay,
       Aspect_Export                       => Never_Delay,
       Aspect_Extensions_Visible           => Never_Delay,
+      Aspect_First_Controlling_Parameter  => Never_Delay,
       Aspect_Ghost                        => Never_Delay,
       Aspect_Global                       => Never_Delay,
       Aspect_GNAT_Annotate                => Never_Delay,
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index 4486ab3636f..2fb45703a4f 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -1651,6 +1651,11 @@ package Einfo is
 --       that this does not imply a representation with holes, since the rep
 --       clause may merely confirm the default 0..N representation.
 
+--    Has_First_Controlling_Parameter_Aspect
+--       Defined in tagged types, concurrent types and concurrent record types.
+--       Set to indicate that the type has a First_Controlling_Parameter of
+--       True (whether by an aspect_specification, a pragma, or inheritance).
+
 --    Has_Exit
 --       Defined in loop entities. Set if the loop contains an exit statement.
 
@@ -5973,6 +5978,7 @@ package Einfo is
    --    First_Entity
    --    Corresponding_Record_Type
    --    Entry_Bodies_Array
+   --    Has_First_Controlling_Parameter_Aspect
    --    Last_Entity
    --    Discriminant_Constraint
    --    Scope_Depth_Value
@@ -6014,6 +6020,7 @@ package Einfo is
    --    Component_Alignment                  (special)  (base type only)
    --    C_Pass_By_Copy                       (base type only)
    --    Has_Dispatch_Table                   (base tagged type only)
+   --    Has_First_Controlling_Parameter_Aspect
    --    Has_Pragma_Pack                      (impl base type only)
    --    Has_Private_Ancestor
    --    Has_Private_Extension
@@ -6049,6 +6056,7 @@ package Einfo is
    --    Underlying_Record_View $$$           (base type only)
    --    Predicated_Parent                    (subtype only)
    --    Has_Completion
+   --    Has_First_Controlling_Parameter_Aspect
    --    Has_Private_Ancestor
    --    Has_Private_Extension
    --    Has_Record_Rep_Clause                (base type only)
@@ -6144,6 +6152,7 @@ package Einfo is
    --    Corresponding_Record_Type
    --    Last_Entity
    --    Discriminant_Constraint
+   --    Has_First_Controlling_Parameter_Aspect
    --    Scope_Depth_Value
    --    Stored_Constraint
    --    Task_Body_Procedure
diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb
index 939a8e25d5a..958657f298d 100644
--- a/gcc/ada/exp_ch9.adb
+++ b/gcc/ada/exp_ch9.adb
@@ -1344,6 +1344,9 @@ package body Exp_Ch9 is
       Rec_Ent  : constant Entity_Id :=
                    Make_Defining_Identifier
                      (Loc, New_External_Name (Chars (Ctyp), 'V'));
+      Alist    : List_Id;
+      Asp_Copy : Node_Id;
+      Aspect   : Node_Id;
       Disc     : Entity_Id;
       Dlist    : List_Id;
       New_Disc : Entity_Id;
@@ -1394,6 +1397,37 @@ package body Exp_Ch9 is
          Dlist := No_List;
       end if;
 
+      --  Propagate the aspect First_Controlling_Parameter to the corresponding
+      --  record to reuse the tagged types machinery. This is not needed if
+      --  the concurrent type does not implement interface types, as the
+      --  corresponding record will not be a tagged type in such case.
+
+      Alist := No_List;
+
+      if Present (Parent (Ctyp))
+        and then Present (Interface_List (Parent (Ctyp)))
+        and then Present (Aspect_Specifications (N))
+      then
+         Aspect := First (Aspect_Specifications (N));
+         while Present (Aspect) loop
+            if Chars (Identifier (Aspect))
+              = Name_First_Controlling_Parameter
+            then
+               Alist    := New_List;
+               Asp_Copy := New_Copy_Tree (Aspect);
+
+               --  Force its analysis in the corresponding record to add
+               --  the pragma.
+
+               Set_Analyzed (Asp_Copy, False);
+               Append_To (Alist, Asp_Copy);
+               exit;
+            end if;
+
+            Next (Aspect);
+         end loop;
+      end if;
+
       --  Now we can construct the record type declaration. Note that this
       --  record is "limited tagged". It is "limited" to reflect the underlying
       --  limitedness of the task or protected object that it represents, and
@@ -1405,6 +1439,7 @@ package body Exp_Ch9 is
       return
         Make_Full_Type_Declaration (Loc,
           Defining_Identifier => Rec_Ent,
+          Aspect_Specifications => Alist,
           Discriminant_Specifications => Dlist,
           Type_Definition =>
             Make_Record_Definition (Loc,
@@ -9257,6 +9292,25 @@ package body Exp_Ch9 is
 
       Analyze (Rec_Decl, Suppress => All_Checks);
 
+      --  Analyze aspects of the corresponding record type. They may have been
+      --  propagated to it and its analysis is required to add the pragma (see
+      --  propagation of aspect First_Controlling_Parameter in the subprogram
+      --  Build_Corresponding_Record).
+
+      if Has_Aspects (Rec_Decl) then
+         Analyze_Aspect_Specifications (Rec_Decl, Rec_Id);
+
+      --  Handle aspects that may have been implicitly inherited and must be
+      --  explicitly propagated to the corresponding record type. This applies
+      --  specifically when the First_Controlling_Parameter aspect has been
+      --  implicitly inherited from an implemented interface.
+
+      elsif Present (Interface_List (Parent (Prot_Typ)))
+        and then Has_First_Controlling_Parameter_Aspect (Prot_Typ)
+      then
+         Set_Has_First_Controlling_Parameter_Aspect (Rec_Id);
+      end if;
+
       --  Ada 2005 (AI-345): Construct the primitive entry wrappers before
       --  the corresponding record is frozen. If any wrappers are generated,
       --  Current_Node is updated accordingly.
@@ -12162,6 +12216,25 @@ package body Exp_Ch9 is
 
       Analyze (Rec_Decl);
 
+      --  Analyze aspects of the corresponding record type. They may have been
+      --  propagated to it and its analysis is required to add the pragma (see
+      --  propagation of aspect First_Controlling_Parameter in the subprogram
+      --  Build_Corresponding_Record).
+
+      if Has_Aspects (Rec_Decl) then
+         Analyze_Aspect_Specifications (Rec_Decl, Rec_Ent);
+
+      --  Handle aspects that may have been implicitly inherited and must be
+      --  explicitly propagated to the corresponding record type. This applies
+      --  specifically when the First_Controlling_Parameter aspect has been
+      --  implicitly inherited from an implemented interface.
+
+      elsif Present (Interface_List (Parent (Tasktyp)))
+        and then Has_First_Controlling_Parameter_Aspect (Tasktyp)
+      then
+         Set_Has_First_Controlling_Parameter_Aspect (Rec_Ent);
+      end if;
+
       --  Create the declaration of the task body procedure
 
       Proc_Spec := Build_Task_Proc_Specification (Tasktyp);
diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 7d5be6b6744..f8e8cf38bb6 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -5066,6 +5066,11 @@ package body Freeze is
          --  variants referenceed by the Variant_Part VP are frozen. This is
          --  a recursive routine to deal with nested variants.
 
+         procedure Warn_If_Implicitly_Inherited_Aspects (Tag_Typ : Entity_Id);
+         --  Report a warning for Tag_Typ when it implicitly inherits the
+         --  First_Controlling_Parameter aspect but does not explicitly
+         --  specify it.
+
          -----------------
          -- Check_Itype --
          -----------------
@@ -5144,6 +5149,193 @@ package body Freeze is
             end loop;
          end Freeze_Choices_In_Variant_Part;
 
+         ------------------------------------------
+         -- Warn_If_Implicitly_Inherited_Aspects --
+         ------------------------------------------
+
+         procedure Warn_If_Implicitly_Inherited_Aspects (Tag_Typ : Entity_Id)
+         is
+            function Has_First_Ctrl_Param_Aspect return Boolean;
+            --  Determines if Tag_Typ explicitly has the aspect/pragma
+            --  First_Controlling_Parameter.
+
+            ---------------------------------
+            -- Has_First_Ctrl_Param_Aspect --
+            ---------------------------------
+
+            function Has_First_Ctrl_Param_Aspect return Boolean is
+               Decl_Nod   : constant Node_Id := Parent (Tag_Typ);
+               Asp_Nod    : Node_Id;
+               Nod        : Node_Id;
+               Pragma_Arg : Node_Id;
+               Pragma_Ent : Entity_Id;
+
+            begin
+               pragma Assert (Nkind (Decl_Nod) = N_Full_Type_Declaration);
+
+               if Present (Aspect_Specifications (Decl_Nod)) then
+                  Asp_Nod := First (Aspect_Specifications (Decl_Nod));
+                  while Present (Asp_Nod) loop
+                     if Chars (Identifier (Asp_Nod))
+                       = Name_First_Controlling_Parameter
+                     then
+                        return True;
+                     end if;
+
+                     Next (Asp_Nod);
+                  end loop;
+               end if;
+
+               --  Search for the occurrence of the pragma
+
+               Nod := Next (Decl_Nod);
+               while Present (Nod) loop
+                  if Nkind (Nod) = N_Pragma
+                    and then Chars (Pragma_Identifier (Nod))
+                               = Name_First_Controlling_Parameter
+                    and then Present (Pragma_Argument_Associations (Nod))
+                  then
+                     Pragma_Arg :=
+                       Expression (First (Pragma_Argument_Associations (Nod)));
+
+                     if Nkind (Pragma_Arg) = N_Identifier
+                       and then Present (Entity (Pragma_Arg))
+                     then
+                        Pragma_Ent := Entity (Pragma_Arg);
+
+                        if Pragma_Ent = Tag_Typ
+                          or else
+                            (Is_Concurrent_Type (Pragma_Ent)
+                               and then
+                                 Corresponding_Record_Type (Pragma_Ent)
+                                   = Tag_Typ)
+                        then
+                           return True;
+                        end if;
+                     end if;
+                  end if;
+
+                  Next (Nod);
+               end loop;
+
+               return False;
+            end Has_First_Ctrl_Param_Aspect;
+
+            --  Local Variables
+
+            Has_Aspect_First_Ctrl_Param : constant Boolean :=
+                                            Has_First_Ctrl_Param_Aspect;
+
+         --  Start of processing for Warn_Implicitly_Inherited_Aspects
+
+         begin
+            --  Handle cases where reporting the warning is not needed
+
+            if not Warn_On_Non_Dispatching_Primitives then
+               return;
+
+            --  No check needed when this is the full view of a private type
+            --  declaration since the pragma/aspect must be placed and checked
+            --  in the partial view, and it is implicitly propagated to the
+            --  full view.
+
+            elsif Has_Private_Declaration (Tag_Typ)
+              and then Is_Tagged_Type (Incomplete_Or_Partial_View (Tag_Typ))
+            then
+               return;
+
+            --  Similar case but applied to concurrent types
+
+            elsif Is_Concurrent_Record_Type (Tag_Typ)
+              and then Has_Private_Declaration
+                         (Corresponding_Concurrent_Type (Tag_Typ))
+              and then Is_Tagged_Type
+                         (Incomplete_Or_Partial_View
+                           (Corresponding_Concurrent_Type (Tag_Typ)))
+            then
+               return;
+            end if;
+
+            if Etype (Tag_Typ) /= Tag_Typ
+              and then Has_First_Controlling_Parameter_Aspect (Etype (Tag_Typ))
+            then
+               --  The attribute was implicitly inherited
+               pragma Assert
+                 (Has_First_Controlling_Parameter_Aspect (Tag_Typ));
+
+               --  No warning needed when the current tagged type is not
+               --  an interface type since by definition the aspect is
+               --  implicitly propagated from its parent type; the warning
+               --  is reported on interface types since it may not be so
+               --  clear when some implemented interface types have the
+               --  aspect and other interface types don't have it. For
+               --  interface types, we don't report the warning when the
+               --  interface type is an extension of a single interface
+               --  type (for similarity with the behavior with regular
+               --  tagged types).
+
+               if not Has_Aspect_First_Ctrl_Param
+                 and then Is_Interface (Tag_Typ)
+                 and then not Is_Empty_Elmt_List (Interfaces (Tag_Typ))
+               then
+                  Error_Msg_N
+                    ("?_j?implicitly inherits aspect 'First_'Controlling_'"
+                     & "Parameter!", Tag_Typ);
+                  Error_Msg_NE
+                    ("\?_j?from & and must be confirmed explicitly!",
+                     Tag_Typ, Etype (Tag_Typ));
+               end if;
+
+            elsif Present (Interfaces (Tag_Typ))
+              and then not Is_Empty_Elmt_List (Interfaces (Tag_Typ))
+            then
+               --  To maintain consistency with the behavior when the aspect
+               --  is implicitly inherited from its parent type, we do not
+               --  report a warning for concurrent record types that implement
+               --  a single interface type. By definition, the aspect is
+               --  propagated from that interface type as if it were the parent
+               --  type. For example:
+
+               --     type Iface is interface with First_Controlling_Parameter;
+               --     task type T is new Iface with ...
+
+               if Is_Concurrent_Record_Type (Tag_Typ)
+                 and then No (Next_Elmt (First_Elmt (Interfaces (Tag_Typ))))
+               then
+                  null;
+
+               else
+                  declare
+                     Elmt  : Elmt_Id := First_Elmt (Interfaces (Tag_Typ));
+                     Iface : Entity_Id;
+
+                  begin
+                     while Present (Elmt) loop
+                        Iface := Node (Elmt);
+                        pragma Assert (Present (Iface));
+
+                        if Has_First_Controlling_Parameter_Aspect (Iface)
+                          and then not Has_Aspect_First_Ctrl_Param
+                        then
+                           pragma Assert
+                             (Has_First_Controlling_Parameter_Aspect
+                               (Tag_Typ));
+                           Error_Msg_N
+                             ("?_j?implicitly inherits aspect 'First_'"
+                              & "Controlling_'Parameter", Tag_Typ);
+                           Error_Msg_NE
+                             ("\?_j?from & and must be confirmed explicitly!",
+                              Tag_Typ, Iface);
+                           exit;
+                        end if;
+
+                        Next_Elmt (Elmt);
+                     end loop;
+                  end;
+               end if;
+            end if;
+         end Warn_If_Implicitly_Inherited_Aspects;
+
       --  Start of processing for Freeze_Record_Type
 
       begin
@@ -5919,6 +6111,13 @@ package body Freeze is
                end loop;
             end;
          end if;
+
+         --  For tagged types, warn on an implicitly inherited aspect/pragma
+         --  First_Controlling_Parameter that is not explicitly set.
+
+         if Is_Tagged_Type (Rec) then
+            Warn_If_Implicitly_Inherited_Aspects (Rec);
+         end if;
       end Freeze_Record_Type;
 
       -------------------------------
@@ -10276,6 +10475,86 @@ package body Freeze is
       then
          Check_Overriding_Indicator (E, Empty, Is_Primitive (E));
       end if;
+
+      --  Check illegal subprograms of tagged types and interface types that
+      --  have aspect/pragma First_Controlling_Parameter.
+
+      if Comes_From_Source (E)
+        and then Is_Abstract_Subprogram (E)
+      then
+         if Is_Dispatching_Operation (E) then
+            if Ekind (E) = E_Function
+              and then Is_Interface (Etype (E))
+              and then not Is_Class_Wide_Type (Etype (E))
+              and then Has_First_Controlling_Parameter_Aspect
+                         (Find_Dispatching_Type (E))
+            then
+               Error_Msg_NE
+                 ("'First_'Controlling_'Parameter disallows returning a "
+                  & "non-class-wide interface type",
+                  E, Etype (E));
+            end if;
+
+         else
+            --  The type of the formals cannot be an interface type
+
+            if Present (First_Formal (E)) then
+               declare
+                  Formal     : Entity_Id := First_Formal (E);
+                  Has_Aspect : Boolean := False;
+
+               begin
+                  --  Check if some formal has the aspect
+
+                  while Present (Formal) loop
+                     if Is_Tagged_Type (Etype (Formal))
+                       and then
+                         Has_First_Controlling_Parameter_Aspect
+                           (Etype (Formal))
+                     then
+                        Has_Aspect := True;
+                     end if;
+
+                     Next_Formal (Formal);
+                  end loop;
+
+                  --  If the aspect is present then report the error
+
+                  if Has_Aspect then
+                     Formal := First_Formal (E);
+
+                     while Present (Formal) loop
+                        if Is_Interface (Etype (Formal))
+                          and then not Is_Class_Wide_Type (Etype (Formal))
+                        then
+                           Error_Msg_NE
+                             ("not a dispatching primitive of interface type&",
+                              E, Etype (Formal));
+                           Error_Msg_N
+                             ("\disallowed by 'First_'Controlling_'Parameter "
+                              & "aspect", E);
+                        end if;
+
+                        Next_Formal (Formal);
+                     end loop;
+                  end if;
+               end;
+            end if;
+
+            if Ekind (E) = E_Function
+              and then Is_Interface (Etype (E))
+              and then not Is_Class_Wide_Type (Etype (E))
+              and then Has_First_Controlling_Parameter_Aspect (Etype (E))
+            then
+               Error_Msg_NE
+                 ("not a dispatching primitive of interface type&",
+                  E, Etype (E));
+               Error_Msg_N
+                 ("\disallowed by 'First_'Controlling_'Parameter "
+                  & "aspect", E);
+            end if;
+         end if;
+      end if;
    end Freeze_Subprogram;
 
    ----------------------
diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads
index 22fd1e372f6..8011fa31b23 100644
--- a/gcc/ada/gen_il-fields.ads
+++ b/gcc/ada/gen_il-fields.ads
@@ -575,6 +575,7 @@ package Gen_IL.Fields is
       Has_Enumeration_Rep_Clause,
       Has_Exit,
       Has_Expanded_Contract,
+      Has_First_Controlling_Parameter_Aspect,
       Has_Forward_Instantiation,
       Has_Fully_Qualified_Name,
       Has_Ghost_Predicate_Aspect,
diff --git a/gcc/ada/gen_il-gen-gen_entities.adb 
b/gcc/ada/gen_il-gen-gen_entities.adb
index 29b22c62587..4d2444ea347 100644
--- a/gcc/ada/gen_il-gen-gen_entities.adb
+++ b/gcc/ada/gen_il-gen-gen_entities.adb
@@ -478,6 +478,9 @@ begin -- Gen_IL.Gen.Gen_Entities
         Sm (Has_Dispatch_Table, Flag,
             Pre => "Is_Tagged_Type (N)"),
         Sm (Has_Dynamic_Predicate_Aspect, Flag),
+        Sm (Has_First_Controlling_Parameter_Aspect, Flag,
+            Pre => "Is_Tagged_Type (N) or else Is_Concurrent_Type (N)"
+                   & " or else Is_Concurrent_Record_Type (N)"),
         Sm (Has_Ghost_Predicate_Aspect, Flag),
         Sm (Has_Inheritable_Invariants, Flag, Base_Type_Only),
         Sm (Has_Inherited_DIC, Flag, Base_Type_Only),
diff --git a/gcc/ada/gen_il-internals.adb b/gcc/ada/gen_il-internals.adb
index e08397f7d4e..c26d3faaec4 100644
--- a/gcc/ada/gen_il-internals.adb
+++ b/gcc/ada/gen_il-internals.adb
@@ -279,6 +279,8 @@ package body Gen_IL.Internals is
             return "DT_Position";
          when Forwards_OK =>
             return "Forwards_OK";
+         when Has_First_Controlling_Parameter_Aspect =>
+            return "Has_First_Controlling_Parameter_Aspect";
          when Has_Inherited_DIC =>
             return "Has_Inherited_DIC";
          when Has_Own_DIC =>
diff --git a/gcc/ada/par-prag.adb b/gcc/ada/par-prag.adb
index 181b0d4c125..f464da9c436 100644
--- a/gcc/ada/par-prag.adb
+++ b/gcc/ada/par-prag.adb
@@ -1442,6 +1442,7 @@ begin
          | Pragma_Fast_Math
          | Pragma_Favor_Top_Level
          | Pragma_Finalize_Storage_Only
+         | Pragma_First_Controlling_Parameter
          | Pragma_Ghost
          | Pragma_Global
          | Pragma_GNAT_Annotate
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index bc0d34e871d..81068d0e6c0 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -14952,6 +14952,18 @@ package body Sem_Ch12 is
          then
             Error_Msg_NE
               ("actual for & must be a tagged type", Actual, Gen_T);
+
+         --  For generic formal tagged types with the First_Controlling_Param
+         --  aspect, ensure that the actual type also has this aspect.
+
+         elsif Is_Tagged_Type (Act_T)
+           and then Is_Tagged_Type (A_Gen_T)
+           and then not Has_First_Controlling_Parameter_Aspect (Act_T)
+           and then Has_First_Controlling_Parameter_Aspect (A_Gen_T)
+         then
+            Error_Msg_NE
+              ("actual for & must be a 'First_'Controlling_'Parameter tagged "
+               & "type", Actual, Gen_T);
          end if;
 
          Validate_Discriminated_Formal_Type;
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index 3fb0209f612..f4ff3a28273 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -4512,6 +4512,58 @@ package body Sem_Ch13 is
                            Pragma_Name                  => Nam);
                      end if;
 
+                     --  Minimum check of First_Controlling_Parameter aspect;
+                     --  the checks shared by the aspect and its corresponding
+                     --  pragma are performed when the pragma is analyzed.
+
+                     if A_Id = Aspect_First_Controlling_Parameter then
+                        if Present (Expr) then
+                           Analyze (Expr);
+                        end if;
+
+                        if (No (Expr) or else Entity (Expr) = Standard_True)
+                          and then not Core_Extensions_Allowed
+                        then
+                           Error_Msg_GNAT_Extension
+                             ("'First_'Controlling_'Parameter", Sloc (Aspect),
+                              Is_Core_Extension => True);
+                           goto Continue;
+                        end if;
+
+                        if not (Is_Type (E)
+                                  and then
+                                    (Is_Tagged_Type (E)
+                                       or else Is_Concurrent_Type (E)))
+                        then
+                           Error_Msg_N
+                             ("aspect 'First_'Controlling_'Parameter can only "
+                              & "apply to tagged type or concurrent type",
+                              Aspect);
+                           goto Continue;
+                        end if;
+
+                        --  If the aspect is specified for a derived type, the
+                        --  specified value shall be confirming.
+
+                        if Present (Expr)
+                          and then Is_Derived_Type (E)
+                          and then
+                            Has_First_Controlling_Parameter_Aspect (Etype (E))
+                          and then Entity (Expr) = Standard_False
+                        then
+                           Error_Msg_Name_1 := Nam;
+                           Error_Msg_N
+                             ("specification of inherited aspect% can only "
+                               & "confirm parent value", Id);
+                        end if;
+
+                        --  Given that the aspect has been explicitly given,
+                        --  we take note to avoid checking for its implicit
+                        --  inheritance (see Analyze_Full_Type_Declaration).
+
+                        Set_Has_First_Controlling_Parameter_Aspect (E);
+                     end if;
+
                   --  In general cases, the corresponding pragma/attribute
                   --  definition clause will be inserted later at the freezing
                   --  point, and we do not need to build it now.
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index ce3fe18080d..2b703dd13c0 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -3510,6 +3510,46 @@ package body Sem_Ch3 is
       then
          Check_Restriction (No_Local_Tagged_Types, T);
       end if;
+
+      --  Derived tagged types inherit aspect First_Controlling_Parameter
+      --  from their parent type and also from implemented interface types.
+      --  We implicitly perform inheritance here and will check for the
+      --  explicit confirming pragma or aspect in the sources when this type
+      --  is frozen (required for pragmas since they are placed at any place
+      --  after the type declaration; otherwise, when the pragma is used after
+      --  some non-first-controlling-parameter primitive, the reported errors
+      --  and warning would differ when the pragma is used).
+
+      if Is_Tagged_Type (T)
+        and then Is_Derived_Type (T)
+        and then not Has_First_Controlling_Parameter_Aspect (T)
+      then
+         pragma Assert (Etype (T) /= T);
+
+         if Has_First_Controlling_Parameter_Aspect (Etype (T)) then
+            Set_Has_First_Controlling_Parameter_Aspect (T);
+
+         elsif Present (Interfaces (T))
+           and then not Is_Empty_Elmt_List (Interfaces (T))
+         then
+            declare
+               Elmt  : Elmt_Id := First_Elmt (Interfaces (T));
+               Iface : Entity_Id;
+
+            begin
+               while Present (Elmt) loop
+                  Iface := Node (Elmt);
+
+                  if Has_First_Controlling_Parameter_Aspect (Iface) then
+                     Set_Has_First_Controlling_Parameter_Aspect (T);
+                     exit;
+                  end if;
+
+                  Next_Elmt (Elmt);
+               end loop;
+            end;
+         end if;
+      end if;
    end Analyze_Full_Type_Declaration;
 
    ----------------------------------
@@ -21870,6 +21910,14 @@ package body Sem_Ch3 is
          end;
       end if;
 
+      --  Propagate First_Controlling_Parameter aspect to the full type
+
+      if Is_Tagged_Type (Priv_T)
+        and then Has_First_Controlling_Parameter_Aspect (Priv_T)
+      then
+         Set_Has_First_Controlling_Parameter_Aspect (Full_T);
+      end if;
+
       --  Propagate predicates to full type, and predicate function if already
       --  defined. It is not clear that this can actually happen? the partial
       --  view cannot be frozen yet, and the predicate function has not been
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index 5735efb327c..fcd15445a07 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -11348,11 +11348,6 @@ package body Sem_Ch6 is
          --  replace the overridden primitive in Typ's primitives list with
          --  the new subprogram.
 
-         function Visible_Part_Type (T : Entity_Id) return Boolean;
-         --  Returns true if T is declared in the visible part of the current
-         --  package scope; otherwise returns false. Assumes that T is declared
-         --  in a package.
-
          procedure Check_Private_Overriding (T : Entity_Id);
          --  Checks that if a primitive abstract subprogram of a visible
          --  abstract type is declared in a private part, then it must override
@@ -11361,6 +11356,17 @@ package body Sem_Ch6 is
          --  in a private part, then it must override a function declared in
          --  the visible part.
 
+         function Is_A_Primitive
+           (Typ  : Entity_Id;
+            Subp : Entity_Id) return Boolean;
+         --  Typ is either the return type of function Subp or the type of one
+         --  of its formals; determine if Subp is a primitive of type Typ.
+
+         function Visible_Part_Type (T : Entity_Id) return Boolean;
+         --  Returns true if T is declared in the visible part of the current
+         --  package scope; otherwise returns false. Assumes that T is declared
+         --  in a package.
+
          ---------------------------------------
          -- Add_Or_Replace_Untagged_Primitive --
          ---------------------------------------
@@ -11529,7 +11535,9 @@ package body Sem_Ch6 is
                         --  operation. That's illegal in the tagged case
                         --  (but not if the private type is untagged).
 
-                        if T = Base_Type (Etype (S)) then
+                        if T = Base_Type (Etype (S))
+                          and then Has_Controlling_Result (S)
+                        then
                            Error_Msg_N
                              ("private function with controlling result must"
                               & " override visible-part function", S);
@@ -11542,6 +11550,7 @@ package body Sem_Ch6 is
 
                         elsif Ekind (Etype (S)) = E_Anonymous_Access_Type
                           and then T = Base_Type (Designated_Type (Etype (S)))
+                          and then Has_Controlling_Result (S)
                           and then Ada_Version >= Ada_2012
                         then
                            Error_Msg_N
@@ -11558,6 +11567,58 @@ package body Sem_Ch6 is
             end if;
          end Check_Private_Overriding;
 
+         --------------------
+         -- Is_A_Primitive --
+         --------------------
+
+         function Is_A_Primitive
+           (Typ  : Entity_Id;
+            Subp : Entity_Id) return Boolean is
+         begin
+            if Scope (Typ) /= Current_Scope
+              or else Is_Class_Wide_Type (Typ)
+              or else Is_Generic_Type (Typ)
+            then
+               return False;
+
+            --  Untagged type primitive
+
+            elsif not Is_Tagged_Type (Typ) then
+               return True;
+
+            --  Primitive of a tagged type without the First_Controlling_Param
+            --  aspect.
+
+            elsif not Has_First_Controlling_Parameter_Aspect (Typ) then
+               return True;
+
+            --  Non-overriding primitive of a tagged type with the
+            --  First_Controlling_Parameter aspect
+
+            elsif No (Overridden_Operation (Subp)) then
+               return Present (First_Formal (Subp))
+                 and then Etype (First_Formal (Subp)) = Typ;
+
+            --  Primitive of a tagged type with the First_Controlling_Parameter
+            --  aspect, overriding an inherited primitive of a tagged type
+            --  without this aspect.
+
+            else
+               if Ekind (Subp) = E_Function
+                 and then Has_Controlling_Result (Overridden_Operation (Subp))
+               then
+                  return True;
+
+               elsif Is_Dispatching_Operation
+                       (Overridden_Operation (Subp))
+               then
+                  return True;
+               end if;
+            end if;
+
+            return False;
+         end Is_A_Primitive;
+
          -----------------------
          -- Visible_Part_Type --
          -----------------------
@@ -11630,10 +11691,7 @@ package body Sem_Ch6 is
 
                B_Typ := Base_Type (F_Typ);
 
-               if Scope (B_Typ) = Current_Scope
-                 and then not Is_Class_Wide_Type (B_Typ)
-                 and then not Is_Generic_Type (B_Typ)
-               then
+               if Is_A_Primitive (B_Typ, S) then
                   Is_Primitive := True;
                   Set_Has_Primitive_Operations (B_Typ);
                   Set_Is_Primitive (S);
@@ -11673,10 +11731,7 @@ package body Sem_Ch6 is
                   B_Typ := Base_Type (B_Typ);
                end if;
 
-               if Scope (B_Typ) = Current_Scope
-                 and then not Is_Class_Wide_Type (B_Typ)
-                 and then not Is_Generic_Type (B_Typ)
-               then
+               if Is_A_Primitive (B_Typ, S) then
                   Is_Primitive := True;
                   Set_Is_Primitive (S);
                   Set_Has_Primitive_Operations (B_Typ);
diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb
index 391cbeb02a9..d52264a0278 100644
--- a/gcc/ada/sem_ch9.adb
+++ b/gcc/ada/sem_ch9.adb
@@ -3648,6 +3648,14 @@ package body Sem_Ch9 is
 
                Freeze_Before (N, Etype (Iface));
 
+               --  Implicit inheritance of attribute
+
+               if not Has_First_Controlling_Parameter_Aspect (T)
+                 and then Has_First_Controlling_Parameter_Aspect (Iface_Typ)
+               then
+                  Set_Has_First_Controlling_Parameter_Aspect (T);
+               end if;
+
                if Nkind (N) = N_Protected_Type_Declaration then
 
                   --  Ada 2005 (AI-345): Protected types can only implement
diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb
index 3c1c49f7064..203e9141624 100644
--- a/gcc/ada/sem_disp.adb
+++ b/gcc/ada/sem_disp.adb
@@ -305,7 +305,36 @@ package body Sem_Disp is
 
       Formal := First_Formal (Subp);
       while Present (Formal) loop
-         Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+         Ctrl_Type := Empty;
+
+         --  Common Ada case
+
+         if not Has_First_Controlling_Parameter_Aspect (Typ) then
+            Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+
+         --  Type with the First_Controlling_Parameter aspect: for overriding
+         --  primitives of a parent type that lacks this aspect, we cannot be
+         --  more restrictive than the overridden primitive. This also applies
+         --  to renamings of dispatching primitives. Dispatching operators can
+         --  have one or two controlling parameters, as long as one of them is
+         --  the first one, and none of the parameters have the same type as
+         --  the operator's result type.
+
+         --  Internal subprograms added by the frontend bypass the restrictions
+         --  of First_Controlling_Parameter aspect.
+
+         elsif Formal = First_Formal (Subp)
+           or else Is_Internal (Subp)
+           or else Present (Overridden_Operation (Subp))
+           or else
+             (Present (Alias (Subp))
+                and then Is_Dispatching_Operation (Ultimate_Alias (Subp)))
+           or else
+             (Ekind (Subp) = E_Function
+                and then Is_Operator_Name (Chars (Subp)))
+         then
+            Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp);
+         end if;
 
          if Present (Ctrl_Type) then
 
@@ -390,7 +419,24 @@ package body Sem_Disp is
          Next_Formal (Formal);
       end loop;
 
-      if Ekind (Subp) in E_Function | E_Generic_Function then
+      --  Functions overriding parent type primitives that lack the aspect
+      --  First_Controlling_Param cannot be more restrictive than the
+      --  overridden function. This also applies to renamings of dispatching
+      --  primitives. Internal subprograms added by the frontend bypass these
+      --  restrictions.
+
+      if Ekind (Subp) in E_Function | E_Generic_Function
+        and then (not Has_First_Controlling_Parameter_Aspect (Typ)
+                    or else Is_Internal (Subp)
+                    or else
+                      (Present (Overridden_Operation (Subp))
+                         and then
+                       Has_Controlling_Result (Overridden_Operation (Subp)))
+                    or else
+                      (Present (Alias (Subp))
+                         and then
+                       Has_Controlling_Result (Ultimate_Alias (Subp))))
+      then
          Ctrl_Type := Check_Controlling_Type (Etype (Subp), Subp);
 
          if Present (Ctrl_Type) then
@@ -1345,8 +1391,10 @@ package body Sem_Disp is
                   Typ := Etype (Subp);
                end if;
 
-               --  The following should be better commented, especially since
-               --  we just added several new conditions here ???
+               --  Report warning on non dispatching primitives of interface
+               --  type Typ; this warning is disabled when the type has the
+               --  aspect First_Controlling_Parameter because we will report
+               --  an error when the interface type is frozen.
 
                if Comes_From_Source (Subp)
                  and then Is_Interface (Typ)
@@ -1354,6 +1402,7 @@ package body Sem_Disp is
                  and then not Is_Derived_Type (Typ)
                  and then not Is_Generic_Type (Typ)
                  and then not In_Instance
+                 and then not Has_First_Controlling_Parameter_Aspect (Typ)
                then
                   Error_Msg_N ("??declaration of& is too late!", Subp);
                   Error_Msg_NE
@@ -1772,6 +1821,37 @@ package body Sem_Disp is
       --  cascaded errors.
 
       elsif not Error_Posted (Subp) then
+
+         --  When aspect First_Controlling_Parameter applies, check if the
+         --  subprogram is a primitive. Internal subprograms added by the
+         --  frontend bypass its restrictions.
+
+         if Has_First_Controlling_Parameter_Aspect (Tagged_Type)
+           and then not Is_Internal (Subp)
+           and then not
+             (Present (Overridden_Operation (Subp))
+                and then
+              Is_Dispatching_Operation (Overridden_Operation (Subp)))
+           and then not
+             (Present (Alias (Subp))
+                and then
+              Is_Dispatching_Operation (Ultimate_Alias (Subp)))
+           and then (No (First_Formal (Subp))
+                       or else not
+                     Is_Controlling_Formal (First_Formal (Subp)))
+         then
+            if Warn_On_Non_Dispatching_Primitives then
+               Error_Msg_NE
+                 ("?_j?not a dispatching primitive of tagged type&",
+                  Subp, Tagged_Type);
+               Error_Msg_NE
+                 ("\?_j?disallowed by 'First_'Controlling_'Parameter on &",
+                  Subp, Tagged_Type);
+            end if;
+
+            return;
+         end if;
+
          Add_Dispatching_Operation (Tagged_Type, Subp);
       end if;
 
@@ -2287,6 +2367,55 @@ package body Sem_Disp is
    ---------------------------
 
    function Find_Dispatching_Type (Subp : Entity_Id) return Entity_Id is
+
+      function Has_Predefined_Dispatching_Operation_Name return Boolean;
+      --  Determines if Subp has the name of a predefined dispatching
+      --  operation.
+
+      -----------------------------------------------
+      -- Has_Predefined_Dispatching_Operation_Name --
+      -----------------------------------------------
+
+      function Has_Predefined_Dispatching_Operation_Name return Boolean is
+         TSS_Name : TSS_Name_Type;
+
+      begin
+         Get_Name_String (Chars (Subp));
+
+         if Name_Len > TSS_Name_Type'Last then
+            TSS_Name :=
+              TSS_Name_Type
+                (Name_Buffer (Name_Len - TSS_Name'Length + 1 .. Name_Len));
+
+            if Chars (Subp) in Name_uAssign
+                             | Name_uSize
+                             | Name_Op_Eq
+              or else TSS_Name = TSS_Deep_Adjust
+              or else TSS_Name = TSS_Deep_Finalize
+              or else TSS_Name = TSS_Stream_Input
+              or else TSS_Name = TSS_Stream_Output
+              or else TSS_Name = TSS_Stream_Read
+              or else TSS_Name = TSS_Stream_Write
+              or else TSS_Name = TSS_Put_Image
+
+               --  Name of predefined interface type primitives
+
+              or else Chars (Subp) in Name_uDisp_Asynchronous_Select
+                                    | Name_uDisp_Conditional_Select
+                                    | Name_uDisp_Get_Prim_Op_Kind
+                                    | Name_uDisp_Get_Task_Id
+                                    | Name_uDisp_Requeue
+                                    | Name_uDisp_Timed_Select
+            then
+               return True;
+            end if;
+         end if;
+
+         return False;
+      end Has_Predefined_Dispatching_Operation_Name;
+
+      --  Local variables
+
       A_Formal  : Entity_Id;
       Formal    : Entity_Id;
       Ctrl_Type : Entity_Id;
@@ -2343,7 +2472,25 @@ package body Sem_Disp is
          --  The subprogram may also be dispatching on result
 
          if Present (Etype (Subp)) then
-            return Check_Controlling_Type (Etype (Subp), Subp);
+            if Is_Tagged_Type (Etype (Subp))
+              and then Has_First_Controlling_Parameter_Aspect (Etype (Subp))
+            then
+               if Present (Overridden_Operation (Subp))
+                 and then Has_Controlling_Result (Overridden_Operation (Subp))
+               then
+                  return Check_Controlling_Type (Etype (Subp), Subp);
+
+               --  Internal subprograms added by the frontend bypass the
+               --  restrictions of First_Controlling_Parameter aspect.
+
+               elsif Is_Internal (Subp)
+                 and then Has_Predefined_Dispatching_Operation_Name
+               then
+                  return Check_Controlling_Type (Etype (Subp), Subp);
+               end if;
+            else
+               return Check_Controlling_Type (Etype (Subp), Subp);
+            end if;
          end if;
       end if;
 
@@ -2444,6 +2591,8 @@ package body Sem_Disp is
      (Tagged_Type : Entity_Id;
       Iface_Prim  : Entity_Id) return Entity_Id
    is
+      Is_FCP_Type : constant Boolean :=
+                      Has_First_Controlling_Parameter_Aspect (Tagged_Type);
       E  : Entity_Id;
       El : Elmt_Id;
 
@@ -2462,9 +2611,30 @@ package body Sem_Disp is
       while Present (E) loop
          if Is_Subprogram (E)
            and then Is_Dispatching_Operation (E)
-           and then Is_Interface_Conformant (Tagged_Type, Iface_Prim, E)
          then
-            return E;
+            --  For overriding primitives of parent or interface types that
+            --  do not have the aspect First_Controlling_Parameter, we must
+            --  temporarily unset this attribute to check conformance.
+
+            if Ekind (E) = E_Function
+              and then Is_FCP_Type
+              and then Present (Overridden_Operation (E))
+              and then Has_Controlling_Result (Overridden_Operation (E))
+            then
+               Set_Has_First_Controlling_Parameter_Aspect (Tagged_Type, False);
+
+               if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+                  Set_Has_First_Controlling_Parameter_Aspect
+                    (Tagged_Type, Is_FCP_Type);
+                  return E;
+               end if;
+
+               Set_Has_First_Controlling_Parameter_Aspect
+                 (Tagged_Type, Is_FCP_Type);
+
+            elsif Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+               return E;
+            end if;
          end if;
 
          E := Homonym (E);
@@ -2501,7 +2671,28 @@ package body Sem_Disp is
             --  Check if E covers the interface primitive (includes case in
             --  which E is an inherited private primitive).
 
-            if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+            --  For overriding primitives of parent or interface types that
+            --  do not have the aspect First_Controlling_Parameter, we must
+            --  temporarily unset this attribute to check conformance.
+
+            if Present (Overridden_Operation (E))
+              and then Is_FCP_Type
+              and then not
+                Has_First_Controlling_Parameter_Aspect
+                  (Find_Dispatching_Type (Overridden_Operation (E)))
+            then
+               Set_Has_First_Controlling_Parameter_Aspect (Tagged_Type, False);
+
+               if Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
+                  Set_Has_First_Controlling_Parameter_Aspect
+                    (Tagged_Type, Is_FCP_Type);
+                  return E;
+               end if;
+
+               Set_Has_First_Controlling_Parameter_Aspect
+                 (Tagged_Type, Is_FCP_Type);
+
+            elsif Is_Interface_Conformant (Tagged_Type, Iface_Prim, E) then
                return E;
             end if;
 
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 3a0572c5a00..ce18ddca338 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -17756,6 +17756,91 @@ package body Sem_Prag is
             end if;
          end Finalize_Storage;
 
+         ----------------------------------------
+         -- Pragma_First_Controlling_Parameter --
+         ----------------------------------------
+
+         when Pragma_First_Controlling_Parameter => First_Ctrl_Param : declare
+            Arg : Node_Id;
+            E   : Entity_Id := Empty;
+
+         begin
+            if not Core_Extensions_Allowed then
+               return;
+            end if;
+
+            GNAT_Pragma;
+            Check_Arg_Count (1);
+
+            Arg := Get_Pragma_Arg (Arg1);
+
+            if Nkind (Arg) = N_Identifier then
+               Analyze (Arg);
+               E := Entity (Arg);
+            end if;
+
+            if No (E)
+              or else not Is_Type (E)
+              or else not (Is_Tagged_Type (E)
+                             or else Is_Concurrent_Type (E))
+            then
+               Error_Pragma
+                 ("pragma% must specify tagged type or concurrent type");
+            end if;
+
+            --  Check use of the pragma on private types
+
+            if Has_Private_Declaration (E) then
+               declare
+                  Prev_Id : constant Entity_Id :=
+                              Incomplete_Or_Partial_View (E);
+               begin
+                  if Is_Tagged_Type (Prev_Id) then
+                     if Has_First_Controlling_Parameter_Aspect (Prev_Id) then
+                        Error_Pragma
+                          ("pragma already specified in private declaration");
+                     else
+                        Error_Msg_N
+                          ("hidden 'First_'Controlling_'Parameter tagged type"
+                           & " not allowed", N);
+                     end if;
+
+                  --  No action needed if the partial view is not tagged. For
+                  --  example:
+
+                  --     package Example is
+                  --        type Private_Type is private;
+                  --     private
+                  --        type Private_Type is new ... with null record
+                  --          with First_Controlling_Parameter;      -- Legal
+                  --     end;
+
+                  else
+                     null;
+                  end if;
+               end;
+            end if;
+
+            --  The corresponding record type of concurrent types will not be
+            --  a tagged type when it does not implement some interface type.
+
+            if Is_Concurrent_Type (E)
+              and then Present (Parent (E))
+              and then No (Interface_List (Parent (E)))
+            then
+               if Warn_On_Non_Dispatching_Primitives then
+                  Error_Msg_N
+                    ("?_j?'First_'Controlling_'Parameter has no effect", N);
+                  Error_Msg_NE
+                    ("?_j?because & does not implement interface types",
+                     N, E);
+               end if;
+
+            else
+               Set_Has_First_Controlling_Parameter_Aspect (E);
+            end if;
+         end First_Ctrl_Param;
+
          -----------
          -- Ghost --
          -----------
@@ -32790,6 +32875,7 @@ package body Sem_Prag is
       Pragma_Fast_Math                      =>  0,
       Pragma_Favor_Top_Level                =>  0,
       Pragma_Finalize_Storage_Only          =>  0,
+      Pragma_First_Controlling_Parameter    =>  0,
       Pragma_Ghost                          =>  0,
       Pragma_Global                         => -1,
       Pragma_GNAT_Annotate                  => 93,
diff --git a/gcc/ada/sem_prag.ads b/gcc/ada/sem_prag.ads
index 557e0454870..48a16038f38 100644
--- a/gcc/ada/sem_prag.ads
+++ b/gcc/ada/sem_prag.ads
@@ -64,6 +64,7 @@ package Sem_Prag is
       Pragma_Export                       => True,
       Pragma_Extensions_Visible           => True,
       Pragma_Favor_Top_Level              => True,
+      Pragma_First_Controlling_Parameter  => True,
       Pragma_Ghost                        => True,
       Pragma_Global                       => True,
       Pragma_GNAT_Annotate                => True,
diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl
index 3ed4d3a6caa..12a14c8b396 100644
--- a/gcc/ada/snames.ads-tmpl
+++ b/gcc/ada/snames.ads-tmpl
@@ -567,6 +567,7 @@ package Snames is
    Name_Extensions_Visible             : constant Name_Id := N + $; -- GNAT
    Name_External                       : constant Name_Id := N + $; -- GNAT
    Name_Finalize_Storage_Only          : constant Name_Id := N + $; -- GNAT
+   Name_First_Controlling_Parameter    : constant Name_Id := N + $;
    Name_Ghost                          : constant Name_Id := N + $; -- GNAT
    Name_Global                         : constant Name_Id := N + $; -- GNAT
    Name_Ident                          : constant Name_Id := N + $; -- GNAT
@@ -1870,6 +1871,7 @@ package Snames is
       Pragma_Extensions_Visible,
       Pragma_External,
       Pragma_Finalize_Storage_Only,
+      Pragma_First_Controlling_Parameter,
       Pragma_Ghost,
       Pragma_Global,
       Pragma_Ident,
diff --git a/gcc/ada/warnsw.adb b/gcc/ada/warnsw.adb
index 4c6934df950..ea7e94c4114 100644
--- a/gcc/ada/warnsw.adb
+++ b/gcc/ada/warnsw.adb
@@ -92,12 +92,13 @@ package body Warnsw is
           'z' => X.Warn_On_Size_Alignment),
 
         '_' =>
-         ('b' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' |
+         ('b' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'k' | 'l' | 'm' |
           'n' | 'o' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' =>
            No_Such_Warning,
 
           'a' => X.Warn_On_Anonymous_Allocators,
           'c' => X.Warn_On_Unknown_Compile_Time_Warning,
+          'j' => X.Warn_On_Non_Dispatching_Primitives,
           'p' => X.Warn_On_Pedantic_Checks,
           'q' => X.Warn_On_Ignored_Equality,
           'r' => X.Warn_On_Component_Order,
@@ -190,6 +191,7 @@ package body Warnsw is
       --  These warnings are removed from the -gnatwa set
 
       Implementation_Unit_Warnings        := False;
+      Warn_On_Non_Dispatching_Primitives  := False;
       Warn_On_Non_Local_Exception         := False;
       No_Warn_On_Non_Local_Exception      := True;
       Warn_On_Reverse_Bit_Order           := False;
diff --git a/gcc/ada/warnsw.ads b/gcc/ada/warnsw.ads
index 5dab97070c9..10ec8a5700b 100644
--- a/gcc/ada/warnsw.ads
+++ b/gcc/ada/warnsw.ads
@@ -75,6 +75,7 @@ package Warnsw is
          Warn_On_Late_Primitives,
          Warn_On_Modified_Unread,
          Warn_On_No_Value_Assigned,
+         Warn_On_Non_Dispatching_Primitives,
          Warn_On_Non_Local_Exception,
          No_Warn_On_Non_Local_Exception,
          Warn_On_Object_Renames_Function,
@@ -159,6 +160,7 @@ package Warnsw is
       Warn_On_Ineffective_Predicate_Test |
       Warn_On_Late_Primitives |
       Warn_On_Modified_Unread |
+      Warn_On_Non_Dispatching_Primitives |
       Warn_On_Non_Local_Exception |
       No_Warn_On_Non_Local_Exception |
       Warn_On_Object_Renames_Function |
@@ -357,6 +359,11 @@ package Warnsw is
    --  suppress such warnings. The default is that such warnings are enabled.
    --  Modified by use of -gnatwv/V.
 
+   Warn_On_Non_Dispatching_Primitives : Boolean renames F 
(X.Warn_On_Non_Dispatching_Primitives);
+   --  Set to True to generate warnings for non dispatching primitives of 
tagged
+   --  types that have aspect/pragma First_Controlling_Parameter set to True.
+   --  This is turned on by -gnatw_j and turned off by -gnatw_J
+
    Warn_On_Non_Local_Exception : Boolean renames F 
(X.Warn_On_Non_Local_Exception);
    --  Set to True to generate warnings for non-local exception raises and also
    --  handlers that can never handle a local raise. This warning is only ever
-- 
2.45.2

Reply via email to