From: Denis Mazzucato <mazzuc...@adacore.com>

This patch fixes the identification of inherited subprograms as primitive
operations via the Is_Primitive flag. This is essential in the context of the
new legality check which makes sure that, if any subprogram denoted by a
nonoverridable aspect of a type T with formal or return of either type T or
access T, then all denoted subprograms should be primitive operations. Note
that all valid interpretations of a subprogram are denoted by the aspect under
evaluation, all of these needs to be primitive then.

This is a respin of eng/toolchain/gnat!2039

gcc/ada/ChangeLog:

        * sem_ch13.adb (Check_Nonoverridable_Aspect_Subprograms): Add the new
        legality check in Check_Nonoverridable_Aspect_Subprograms for
        nonoverridable aspects to check whether the denoted subprograms satisfy
        MR 13.1.1(18.4/6), otherwise we emit an error. Fix spacing.
        * sem_ch6.adb (New_Overloaded_Entity): Set Is_Primitive flag
        for inherited primitives, and filter out homonym candidates without a
        function specification as parents.

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

---
 gcc/ada/sem_ch13.adb | 225 +++++++++++++++++++++++++++++++++++++++++--
 gcc/ada/sem_ch6.adb  |  19 ++--
 2 files changed, 230 insertions(+), 14 deletions(-)

diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index f0caf960269..727c92f5c7e 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -1002,6 +1002,17 @@ package body Sem_Ch13 is
       --  aspect has the proper profile. If the name is overloaded, check that
       --  some interpretation is legal.
 
+      procedure Check_Nonoverridable_Aspect_Subprograms
+        (ASN      : Node_Id;
+         E        : Entity_Id;
+         Original : Entity_Id := Empty);
+      --  RM 13.1.1(18.4/6) requires checking that if any of the subprograms
+      --  denoted by a nonoverridable aspect ASN has a parameter or result of
+      --  either type E or access E, then all denoted subprograms are
+      --  primitive. If missing, Original is initialized with ASN and will not
+      --  change during the recursive exploration of aggregate aspects, it is
+      --  used to improve the error message.
+
       procedure Make_Pragma_From_Boolean_Aspect (ASN : Node_Id);
       --  Given an aspect specification node ASN whose expression is an
       --  optional Boolean, this routines creates the corresponding pragma
@@ -1205,6 +1216,200 @@ package body Sem_Ch13 is
          end if;
       end Check_Indexing_Functions;
 
+      ---------------------------------------------
+      -- Check_Nonoverridable_Aspect_Subprograms --
+      ---------------------------------------------
+
+      procedure Check_Nonoverridable_Aspect_Subprograms
+        (ASN      : Node_Id;
+         E        : Entity_Id;
+         Original : Node_Id := Empty)
+      is
+         Expr : constant Node_Id   := Expression (ASN);
+         Kind : constant Node_Kind := Nkind (Expr);
+
+         function Required_To_Be_Primitive (Subp : Entity_Id) return Boolean;
+         --  This function returns True if Subp, belonging to a nonoverridable
+         --  aspect of the entity E, is required to be a primitive operation.
+         --  Specifically, whenever either its return type or any of its
+         --  formals are of either type E or access E.
+
+         function Required_To_Be_Primitive (Subp : Entity_Id) return Boolean is
+            Return_Typ  : constant Entity_Id := Etype (Subp);
+            Last_Formal : constant Entity_Id := Last_Entity (Subp);
+            Cursor      : Entity_Id          := First_Entity (Subp);
+         begin
+            if Return_Typ = E
+              or else (Ekind (Return_Typ) in Access_Kind
+                        and then Directly_Designated_Type (Return_Typ) = E)
+            then
+               return True;
+
+            elsif Present (Cursor) then
+               loop
+                  if Etype (Cursor) = E
+                    or else (Ekind (Cursor) in Access_Kind
+                              and then Directly_Designated_Type (Cursor) = E)
+                  then
+                     return True;
+                  end if;
+
+                  exit when Cursor = Last_Formal;
+
+                  Cursor := Next_Entity (Cursor);
+               end loop;
+            end if;
+
+            return False;
+         end Required_To_Be_Primitive;
+
+         --  Local Variables
+
+         Valid   : Boolean   := True;
+         Problem : Entity_Id := Empty;
+
+      --  Start of processing for Check_Nonoverridable_Aspect_Subprograms
+
+      begin
+         --  If the aspect specification was effectively inherited from the
+         --  parent type (so constructed anew by analysis), then no point
+         --  in validating.
+
+         if not Comes_From_Source (ASN) then
+            return;
+         end if;
+
+         --  If the expression is neither an aggregate nor a node denoting an
+         --  entity, then also no point in validating.
+
+         if Kind not in N_Aggregate | N_Has_Entity then
+            return;
+         end if;
+
+         --  Original should point to ASN if this is the first recursive call
+
+         if No (Original) then
+            Check_Nonoverridable_Aspect_Subprograms
+              (ASN => ASN,
+               E => E,
+               Original => ASN);
+            return;
+         end if;
+
+         if Kind = N_Aggregate then
+            declare
+               Aggregate_List : constant List_Id :=
+                 Component_Associations (Expr);
+               Current : Node_Id := First (Aggregate_List);
+            begin
+               --  Each component association must be checked separately
+
+               while Present (Current) loop
+
+                  Check_Nonoverridable_Aspect_Subprograms
+                    (ASN      => Current,
+                     E        => E,
+                     Original => Original);
+
+                  Next (Current);
+               end loop;
+            end;
+
+         else
+            --  Some expressions may be unanalyzed, as some nonoverridable
+            --  aspects allow forward references. For instance, when the type E
+            --  is defined inside a package body.
+
+            if No (Entity (Expr)) then
+               Analyze (Expr);
+            end if;
+
+            declare
+               Subp : constant Entity_Id := Entity (Expr);
+            begin
+
+               --  No point in validating a node that does not represent a
+               --  subprogram here.
+
+               if not Is_Subprogram (Subp) then
+                  return;
+               end if;
+
+               if not Is_Overloaded (Expr) then
+                  Valid := (if Required_To_Be_Primitive (Subp)
+                             then Is_Primitive (Subp));
+
+                  Problem := Subp;
+
+               else
+                  declare
+                     Found : Boolean := False;
+                     I     : Interp_Index;
+                     It    : Interp;
+                  begin
+                     --  Check whether there is at least one interpretation
+                     --  that is required to be primitive. We iterate over all
+                     --  possible interpretations, as some may be removed.
+
+                     Get_First_Interp (Expr, I, It);
+                     while Present (It.Nam) loop
+
+                        --  If the current interpretation is not declared
+                        --  within the scope of E, then it should not be
+                        --  considered, see RM 13.1.1(8/6).
+
+                        if not Within_Scope (It.Nam, Scope (E)) then
+                           Remove_Interp (I);
+
+                        else
+                           Found := Found
+                             or else Required_To_Be_Primitive (It.Nam);
+                        end if;
+
+                        Get_Next_Interp (I, It);
+                     end loop;
+
+                     if Found then
+
+                        --  To satisfy the legality rule in RM 13.1.1(18.2/5),
+                        --  if there's at least one interpretation that's
+                        --  primitive, then all of them must be primitive;
+                        --  otherwise we emit an error.
+
+                        Get_First_Interp (Expr, I, It);
+                        pragma Warnings (Off, Valid); -- Valid not always True
+                        while Valid and then Present (It.Nam) loop
+
+                           Valid := Valid and then Is_Primitive (It.Nam);
+                           Problem := It.Nam;
+
+                           Get_Next_Interp (I, It);
+                        end loop;
+                     end if;
+                  end;
+               end if;
+            end;
+         end if;
+
+         if not Valid then
+            declare
+               Operation_Kind : constant String :=
+                 (if Comes_From_Source (Problem)
+                   then "declared"
+                   else "inherited");
+            begin
+               Error_Msg_Name_1 := Chars (Identifier (Original));
+               Error_Msg_Name_2 := Chars (E);
+               Error_Msg_Name_3 := Chars (Problem);
+               Error_Msg_Sloc := Sloc (Problem);
+               Error_Msg_N ("nonoverridable aspect % of type % requires % "
+                            & Operation_Kind
+                            & "# to be a primitive operation",
+                            Original);
+            end;
+         end if;
+      end Check_Nonoverridable_Aspect_Subprograms;
+
       -------------------------------------
       -- Make_Pragma_From_Boolean_Aspect --
       -------------------------------------
@@ -1548,6 +1753,14 @@ package body Sem_Ch13 is
                if Present (Ritem) then
                   Analyze (Ritem);
                end if;
+
+               --  All nonoverriding aspects need further legality checks
+
+               if A_Id in Nonoverridable_Aspect_Id
+                 and then Ada_Version >= Ada_2022
+               then
+                  Check_Nonoverridable_Aspect_Subprograms (ASN, E);
+               end if;
             end if;
          end if;
 
@@ -12613,8 +12826,8 @@ package body Sem_Ch13 is
       elsif No (Next_Formal (First_Formal (Subp))) then
          Error_Msg_Sloc := Sloc (Subp);
          Illegal_Indexing
-            ("at least two parameters required for indexing function "
-             & "defined #");
+           ("at least two parameters required for indexing function "
+            & "defined #");
          return;
 
       elsif not Subp_Is_Dispatching_Op_Of_Typ
@@ -12625,7 +12838,7 @@ package body Sem_Ch13 is
       then
          Illegal_Indexing
            ("indexing aspect requires function with first formal "
-             & "applying to type& or its class-wide type");
+            & "applying to type& or its class-wide type");
          return;
 
       elsif Aspect = Aspect_Constant_Indexing
@@ -12634,7 +12847,7 @@ package body Sem_Ch13 is
       then
          Illegal_Indexing
            ("Constant_Indexing must apply to function with "
-             & "access-to-constant formal");
+            & "access-to-constant formal");
          return;
       end if;
 
@@ -12643,8 +12856,8 @@ package body Sem_Ch13 is
       if Aspect = Aspect_Variable_Indexing then
          if not Has_Implicit_Dereference (Ret_Type) then
             Illegal_Indexing
-               ("function for Variable_Indexing must return "
-                & "a reference type");
+              ("function for Variable_Indexing must return "
+               & "a reference type");
             return;
 
          elsif Is_Access_Constant
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index b7ddc4b7a6a..55c5e026ea0 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -7752,6 +7752,7 @@ package body Sem_Ch6 is
               or else not Is_Dispatching_Operation (Subp)
               or else No (Find_Dispatching_Type (Subp))
               or else not Is_Interface (Find_Dispatching_Type (Subp))
+              or else Parent (Subp) not in N_Subprogram_Specification_Id
             then
                null;
 
@@ -11772,16 +11773,18 @@ package body Sem_Ch6 is
          Is_Primitive := False;
 
          if not Comes_From_Source (S) then
+            if Present (Derived_Type) then
 
-            --  Add an inherited primitive for an untagged derived type to
-            --  Derived_Type's list of primitives. Tagged primitives are
-            --  dealt with in Check_Dispatching_Operation. Do this even when
-            --  Extensions_Allowed is False to issue better error messages.
+               --  Add an inherited primitive for an untagged derived type to
+               --  Derived_Type's list of primitives. Tagged primitives are
+               --  dealt with in Check_Dispatching_Operation. Do this even when
+               --  Extensions_Allowed is False to issue better error messages.
 
-            if Present (Derived_Type)
-              and then not Is_Tagged_Type (Derived_Type)
-            then
-               Append_Unique_Elmt (S, Primitive_Operations (Derived_Type));
+               if not Is_Tagged_Type (Derived_Type) then
+                  Append_Unique_Elmt (S, Primitive_Operations (Derived_Type));
+               end if;
+
+               Set_Is_Primitive (S);
             end if;
 
          --  If subprogram is at library level, it is not primitive operation
-- 
2.43.0

Reply via email to