]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
exp_ch6.adb (Add_Or_Save_Precondition): New routine.
authorHristian Kirtchev <kirtchev@adacore.com>
Tue, 25 Feb 2014 15:05:39 +0000 (15:05 +0000)
committerArnaud Charlet <charlet@gcc.gnu.org>
Tue, 25 Feb 2014 15:05:39 +0000 (16:05 +0100)
2014-02-25  Hristian Kirtchev  <kirtchev@adacore.com>

* exp_ch6.adb (Add_Or_Save_Precondition): New routine.
(Collect_Body_Postconditions_In_Decls): New routine.
(Collect_Body_Postconditions_Of_Kind): Factor out code. Handle
postcondition aspects or pragmas that appear on a subprogram
body stub.
(Collect_Spec_Preconditions): Factor out code. Handle
precondition aspects or pragmas that appear on a subprogram
body stub.
* sem_ch6.adb (Analyze_Subprogram_Body_Helper): The analysis of
aspects that apply to a subprogram body stub is no longer delayed,
the aspects are analyzed on the spot.
(SPARK_Aspect_Error):
Aspects that apply to a subprogram declaration cannot appear in
a subunit.
* sem_ch10.adb Remove with and use clause for Sem_Ch13.
(Analyze_Proper_Body): Add local variable Comp_Unit. Unum
is now a local variable. Code cleanup. Analysis related to
the aspects of a subprogram body stub is now carried out by
Analyze_Subprogram_Body_Helper. Do not propagate the aspects
and/or pragmas of a subprogram body stub to the proper body
as this is no longer needed. Do not analyze the aspects of a
subprogram stub when the corresponding source unit is missing.
(Analyze_Protected_Body_Stub): Flag the illegal use of aspects
on a stub.
(Analyze_Task_Body_Stub): Flag the illegal use of
aspects on a stub.
(Optional_Subunit): Add local variable Unum.
* sem_ch13.adb (Insert_Delayed_Pragma): Do not analyze a generated
pragma when it applies to a subprogram body stub.
* sem_prag.adb (Analyze_Pragma): Pragmas Contract_Cases,
Depends and Global can now apply to a subprogram body stub as
long as it acts as its own spec.
(Analyze_Refined_Pragma):
Code reformatting. Refinement pragmas cannot apply to a subunit.

From-SVN: r208134

gcc/ada/ChangeLog
gcc/ada/exp_ch6.adb
gcc/ada/sem_ch10.adb
gcc/ada/sem_ch13.adb
gcc/ada/sem_ch6.adb
gcc/ada/sem_prag.adb

index ed288b3d0532d41fd0934f80b648e2e572ad708b..ad3b82d2086bc278ad6c0e902f176771e7399e96 100644 (file)
@@ -1,3 +1,40 @@
+2014-02-25  Hristian Kirtchev  <kirtchev@adacore.com>
+
+       * exp_ch6.adb (Add_Or_Save_Precondition): New routine.
+       (Collect_Body_Postconditions_In_Decls): New routine.
+       (Collect_Body_Postconditions_Of_Kind): Factor out code. Handle
+       postcondition aspects or pragmas that appear on a subprogram
+       body stub.
+       (Collect_Spec_Preconditions): Factor out code. Handle
+       precondition aspects or pragmas that appear on a subprogram
+       body stub.
+       * sem_ch6.adb (Analyze_Subprogram_Body_Helper): The analysis of
+       aspects that apply to a subprogram body stub is no longer delayed,
+       the aspects are analyzed on the spot.
+       (SPARK_Aspect_Error):
+       Aspects that apply to a subprogram declaration cannot appear in
+       a subunit.
+       * sem_ch10.adb Remove with and use clause for Sem_Ch13.
+       (Analyze_Proper_Body): Add local variable Comp_Unit. Unum
+       is now a local variable. Code cleanup. Analysis related to
+       the aspects of a subprogram body stub is now carried out by
+       Analyze_Subprogram_Body_Helper. Do not propagate the aspects
+       and/or pragmas of a subprogram body stub to the proper body
+       as this is no longer needed. Do not analyze the aspects of a
+       subprogram stub when the corresponding source unit is missing.
+       (Analyze_Protected_Body_Stub): Flag the illegal use of aspects
+       on a stub.
+       (Analyze_Task_Body_Stub): Flag the illegal use of
+       aspects on a stub.
+       (Optional_Subunit): Add local variable Unum.
+       * sem_ch13.adb (Insert_Delayed_Pragma): Do not analyze a generated
+       pragma when it applies to a subprogram body stub.
+       * sem_prag.adb (Analyze_Pragma): Pragmas Contract_Cases,
+       Depends and Global can now apply to a subprogram body stub as
+       long as it acts as its own spec.
+       (Analyze_Refined_Pragma):
+       Code reformatting. Refinement pragmas cannot apply to a subunit.
+
 2014-02-25  Hristian Kirtchev  <kirtchev@adacore.com>
 
        * einfo.ads Update the usage of flag
index 5ffea6acc3f0bd04f8aeb5baaf0172fbff46b061..4aa43ba10d510992f1e033aceb925861b87b7d0d 100644 (file)
@@ -8671,58 +8671,100 @@ package body Exp_Ch6 is
 
       procedure Collect_Body_Postconditions (Stmts : in out List_Id) is
          procedure Collect_Body_Postconditions_Of_Kind (Post_Nam : Name_Id);
-         --  Process postconditions of a particular kind denoted by Post_Nam
+         --  Process all postconditions of a particular kind denoted by
+         --  Post_Nam.
 
          -----------------------------------------
          -- Collect_Body_Postconditions_Of_Kind --
          -----------------------------------------
 
          procedure Collect_Body_Postconditions_Of_Kind (Post_Nam : Name_Id) is
-            Check_Prag : Node_Id;
-            Decl       : Node_Id;
+            procedure Collect_Body_Postconditions_In_Decls
+              (First_Decl : Node_Id);
+            --  Process all postconditions found in a declarative list starting
+            --  with declaration First_Decl.
 
-         begin
-            pragma Assert (Nam_In (Post_Nam, Name_Postcondition,
-                                             Name_Refined_Post));
+            ------------------------------------------
+            -- Collect_Body_Postconditions_In_Decls --
+            ------------------------------------------
 
-            --  Inspect the declarations of the subprogram body looking for a
-            --  pragma that matches the desired name.
+            procedure Collect_Body_Postconditions_In_Decls
+              (First_Decl : Node_Id)
+            is
+               Check_Prag : Node_Id;
+               Decl       : Node_Id;
 
-            Decl := First (Declarations (N));
-            while Present (Decl) loop
-               if Nkind (Decl) = N_Pragma then
-                  if Pragma_Name (Decl) = Post_Nam then
-                     Analyze (Decl);
-                     Check_Prag := Build_Pragma_Check_Equivalent (Decl);
+            begin
+               --  Inspect the declarative list looking for a pragma that
+               --  matches the desired name.
 
-                     if Expander_Active then
-                        Append_Enabled_Item
-                          (Item => Check_Prag,
-                           List => Stmts);
+               Decl := First_Decl;
+               while Present (Decl) loop
 
-                     --  When analyzing a generic unit, save the pragma for
-                     --  later.
+                  --  Note that non-matching pragmas are skipped
 
-                     else
-                        Prepend_To_Declarations (Check_Prag);
+                  if Nkind (Decl) = N_Pragma then
+                     if Pragma_Name (Decl) = Post_Nam then
+                        if not Analyzed (Decl) then
+                           Analyze (Decl);
+                        end if;
+
+                        Check_Prag := Build_Pragma_Check_Equivalent (Decl);
+
+                        if Expander_Active then
+                           Append_Enabled_Item
+                             (Item => Check_Prag,
+                              List => Stmts);
+
+                        --  When analyzing a generic unit, save the pragma for
+                        --  later.
+
+                        else
+                           Prepend_To_Declarations (Check_Prag);
+                        end if;
                      end if;
+
+                  --  Skip internally generated code
+
+                  elsif not Comes_From_Source (Decl) then
+                     null;
+
+                  --  Postcondition pragmas are usually grouped together. There
+                  --  is no need to inspect the whole declarative list.
+
+                  else
+                     exit;
                   end if;
 
-               --  Skip internally generated code
+                  Next (Decl);
+               end loop;
+            end Collect_Body_Postconditions_In_Decls;
 
-               elsif not Comes_From_Source (Decl) then
-                  null;
+            --  Local variables
 
-               --  Postconditions in bodies are usually grouped at the top of
-               --  the declarations. There is no point in inspecting the whole
-               --  source list.
+            Unit_Decl : constant Node_Id := Parent (N);
 
-               else
-                  exit;
-               end if;
+         --  Start of processing for Collect_Body_Postconditions_Of_Kind
 
-               Next (Decl);
-            end loop;
+         begin
+            pragma Assert (Nam_In (Post_Nam, Name_Postcondition,
+                                             Name_Refined_Post));
+
+            --  Inspect the declarations of the subprogram body looking for a
+            --  pragma that matches the desired name.
+
+            Collect_Body_Postconditions_In_Decls
+              (First_Decl => First (Declarations (N)));
+
+            --  The subprogram body being processed is actually the proper body
+            --  of a stub with a corresponding spec. The subprogram stub may
+            --  carry a postcondition pragma in which case it must be taken
+            --  into account. The pragma appears after the stub.
+
+            if Present (Spec_Id) and then Nkind (Unit_Decl) = N_Subunit then
+               Collect_Body_Postconditions_In_Decls
+                 (First_Decl => Next (Corresponding_Stub (Unit_Decl)));
+            end if;
          end Collect_Body_Postconditions_Of_Kind;
 
       --  Start of processing for Collect_Body_Postconditions
@@ -8808,11 +8850,45 @@ package body Exp_Ch6 is
       --------------------------------
 
       procedure Collect_Spec_Preconditions (Subp_Id : Entity_Id) is
+         Class_Pre : Node_Id := Empty;
+         --  The sole class-wide precondition pragma that applies to the
+         --  subprogram.
+
+         procedure Add_Or_Save_Precondition (Prag : Node_Id);
+         --  Save a class-wide precondition or add a regulat precondition to
+         --  the declarative list of the body.
+
          procedure Merge_Preconditions (From : Node_Id; Into : Node_Id);
          --  Merge two class-wide preconditions by "or else"-ing them. The
          --  changes are accumulated in parameter Into. Update the error
          --  message of Into.
 
+         ------------------------------
+         -- Add_Or_Save_Precondition --
+         ------------------------------
+
+         procedure Add_Or_Save_Precondition (Prag : Node_Id) is
+            Check_Prag : Node_Id;
+
+         begin
+            Check_Prag := Build_Pragma_Check_Equivalent (Prag);
+
+            --  Save the sole class-wide precondition (if any) for the next
+            --  step where it will be merged with inherited preconditions.
+
+            if Class_Present (Prag) then
+               pragma Assert (No (Class_Pre));
+               Class_Pre := Check_Prag;
+
+            --  Accumulate the corresponding Check pragmas to the top of the
+            --  declarations. Prepending the items ensures that they will be
+            --  evaluated in their original order.
+
+            else
+               Prepend_To_Declarations (Check_Prag);
+            end if;
+         end Add_Or_Save_Precondition;
+
          -------------------------
          -- Merge_Preconditions --
          -------------------------
@@ -8889,8 +8965,9 @@ package body Exp_Ch6 is
 
          Inher_Subps   : constant Subprogram_List :=
                            Inherited_Subprograms (Subp_Id);
+         Subp_Decl     : constant Node_Id := Parent (Parent (Subp_Id));
          Check_Prag    : Node_Id;
-         Class_Pre     : Node_Id := Empty;
+         Decl          : Node_Id;
          Inher_Subp_Id : Entity_Id;
          Prag          : Node_Id;
 
@@ -8902,25 +8979,49 @@ package body Exp_Ch6 is
          Prag := Pre_Post_Conditions (Contract (Subp_Id));
          while Present (Prag) loop
             if Pragma_Name (Prag) = Name_Precondition then
-               Check_Prag := Build_Pragma_Check_Equivalent (Prag);
+               Add_Or_Save_Precondition (Prag);
+            end if;
 
-               --  Save the sole class-wide precondition (if any) for the next
-               --  step where it will be merged with inherited preconditions.
+            Prag := Next_Pragma (Prag);
+         end loop;
 
-               if Class_Present (Prag) then
-                  Class_Pre := Check_Prag;
+         --  The subprogram declaration being processed is actually a body
+         --  stub. The stub may carry a precondition pragma in which case it
+         --  must be taken into account. The pragma appears after the stub.
 
-               --  Accumulate the corresponding Check pragmas to the top of the
-               --  declarations. Prepending the items ensures that they will
-               --  be evaluated in their original order.
+         if Nkind (Subp_Decl) = N_Subprogram_Body_Stub then
+
+            --  Inspect the declarations following the body stub
+
+            Decl := Next (Subp_Decl);
+            while Present (Decl) loop
+
+               --  Note that non-matching pragmas are skipped
+
+               if Nkind (Decl) = N_Pragma then
+                  if Pragma_Name (Decl) = Name_Precondition then
+                     if not Analyzed (Decl) then
+                        Analyze (Decl);
+                     end if;
+
+                     Add_Or_Save_Precondition (Decl);
+                  end if;
+
+               --  Skip internally generated code
+
+               elsif not Comes_From_Source (Decl) then
+                  null;
+
+               --  Preconditions are usually grouped together. There is no need
+               --  to inspect the whole declarative list.
 
                else
-                  Prepend_To_Declarations (Check_Prag);
+                  exit;
                end if;
-            end if;
 
-            Prag := Next_Pragma (Prag);
-         end loop;
+               Next (Decl);
+            end loop;
+         end if;
 
          --  Process the contracts of all inherited subprograms, looking for
          --  class-wide preconditions.
index 7714526ae99ac5c8bd3438b4bacb4ab275af96a9..df4aacf6fc6b549b6047ad811fe6ba07008af050 100644 (file)
@@ -53,7 +53,6 @@ with Sem_Ch3;  use Sem_Ch3;
 with Sem_Ch6;  use Sem_Ch6;
 with Sem_Ch7;  use Sem_Ch7;
 with Sem_Ch8;  use Sem_Ch8;
-with Sem_Ch13; use Sem_Ch13;
 with Sem_Dist; use Sem_Dist;
 with Sem_Prag; use Sem_Prag;
 with Sem_Util; use Sem_Util;
@@ -1558,7 +1557,6 @@ package body Sem_Ch10 is
 
    procedure Analyze_Proper_Body (N : Node_Id; Nam : Entity_Id) is
       Subunit_Name : constant Unit_Name_Type := Get_Unit_Name (N);
-      Unum         : Unit_Number_Type;
 
       procedure Optional_Subunit;
       --  This procedure is called when the main unit is a stub, or when we
@@ -1573,6 +1571,7 @@ package body Sem_Ch10 is
 
       procedure Optional_Subunit is
          Comp_Unit : Node_Id;
+         Unum      : Unit_Number_Type;
 
       begin
          --  Try to load subunit, but ignore any errors that occur during the
@@ -1633,7 +1632,8 @@ package body Sem_Ch10 is
 
       --  Local variables
 
-      Stub_Id : Entity_Id;
+      Comp_Unit : Node_Id;
+      Unum      : Unit_Number_Type;
 
    --  Start of processing for Analyze_Proper_Body
 
@@ -1787,86 +1787,45 @@ package body Sem_Ch10 is
                   Write_Eol;
                end if;
 
-               declare
-                  Comp_Unit : constant Node_Id := Cunit (Unum);
-                  Prop_Body : Node_Id;
-
-               begin
-                  --  Check for child unit instead of subunit
-
-                  if Nkind (Unit (Comp_Unit)) /= N_Subunit then
-                     Error_Msg_N
-                       ("expected SEPARATE subunit, found child unit",
-                        Cunit_Entity (Unum));
-
-                  --  OK, we have a subunit
-
-                  else
-                     Prop_Body := Proper_Body (Unit (Comp_Unit));
-
-                     --  Set corresponding stub (even if errors)
+               Comp_Unit := Cunit (Unum);
 
-                     Set_Corresponding_Stub (Unit (Comp_Unit), N);
+               --  Check for child unit instead of subunit
 
-                     --  Collect SCO information for loaded subunit if we are
-                     --  in the main unit.
+               if Nkind (Unit (Comp_Unit)) /= N_Subunit then
+                  Error_Msg_N
+                    ("expected SEPARATE subunit, found child unit",
+                     Cunit_Entity (Unum));
 
-                     if Generate_SCO
-                       and then
-                         In_Extended_Main_Source_Unit
-                           (Cunit_Entity (Current_Sem_Unit))
-                     then
-                        SCO_Record (Unum);
-                     end if;
-
-                     --  Propagate all aspect specifications associated with
-                     --  the stub to the proper body.
-
-                     Move_Or_Merge_Aspects (From => N, To => Prop_Body);
-
-                     --  Move all source pragmas that follow the body stub and
-                     --  apply to it to the declarations of the proper body.
+               --  OK, we have a subunit
 
-                     if Nkind (N) = N_Subprogram_Body_Stub then
-                        Relocate_Pragmas_To_Body (N, Target_Body => Prop_Body);
-                     end if;
-
-                     --  Analyze the unit if semantics active
-
-                     if not Fatal_Error (Unum) or else Try_Semantics then
-                        Analyze_Subunit (Comp_Unit);
-                     end if;
+               else
+                  Set_Corresponding_Stub (Unit (Comp_Unit), N);
+                  Set_Library_Unit (N, Comp_Unit);
 
-                     --  Set the library unit pointer in any case
+                  --  We update the version. Although we are not technically
+                  --  semantically dependent on the subunit, given our approach
+                  --  of macro substitution of subunits, it makes sense to
+                  --  include it in the version identification.
 
-                     Set_Library_Unit (N, Comp_Unit);
+                  Version_Update (Cunit (Main_Unit), Comp_Unit);
 
-                     --  We update the version. Although we are not technically
-                     --  semantically dependent on the subunit, given our
-                     --  approach of macro substitution of subunits, it makes
-                     --  sense to include it in the version identification.
+                  --  Collect SCO information for loaded subunit if we are in
+                  --  the main unit.
 
-                     Version_Update (Cunit (Main_Unit), Comp_Unit);
+                  if Generate_SCO
+                    and then
+                      In_Extended_Main_Source_Unit
+                        (Cunit_Entity (Current_Sem_Unit))
+                  then
+                     SCO_Record (Unum);
                   end if;
-               end;
-
-            --  The unit which should contain the proper subprogram body does
-            --  not exist. Analyze the aspect specifications of the stub (if
-            --  any).
-
-            elsif Nkind (N) = N_Subprogram_Body_Stub
-              and then Has_Aspects (N)
-            then
-               Stub_Id := Defining_Unit_Name (Specification (N));
-
-               --  Restore the proper visibility of the stub and its formals
-
-               Push_Scope (Stub_Id);
-               Install_Formals (Stub_Id);
 
-               Analyze_Aspect_Specifications (N, Stub_Id);
+                  --  Analyze the unit if semantics active
 
-               Pop_Scope;
+                  if not Fatal_Error (Unum) or else Try_Semantics then
+                     Analyze_Subunit (Comp_Unit);
+                  end if;
+               end if;
             end if;
          end if;
 
@@ -1901,6 +1860,17 @@ package body Sem_Ch10 is
          Error_Msg_N ("missing specification for Protected body", N);
 
       else
+         --  Currently there are no language-defined aspects that can apply to
+         --  a protected body stub. Issue an error and remove the aspects to
+         --  prevent cascaded errors.
+
+         if Has_Aspects (N) then
+            Error_Msg_N
+              ("aspects on protected bodies are not allowed",
+               First (Aspect_Specifications (N)));
+            Remove_Aspects (N);
+         end if;
+
          Set_Scope (Defining_Entity (N), Current_Scope);
          Set_Has_Completion (Etype (Nam));
          Set_Corresponding_Spec_Of_Stub (N, Nam);
@@ -2351,7 +2321,19 @@ package body Sem_Ch10 is
 
       if No (Nam) or else not Is_Task_Type (Etype (Nam)) then
          Error_Msg_N ("missing specification for task body", N);
+
       else
+         --  Currently there are no language-defined aspects that can apply to
+         --  a task body stub. Issue an error and remove the aspects to prevent
+         --  cascaded errors.
+
+         if Has_Aspects (N) then
+            Error_Msg_N
+              ("aspects on task bodies are not allowed",
+               First (Aspect_Specifications (N)));
+            Remove_Aspects (N);
+         end if;
+
          Set_Scope (Defining_Entity (N), Current_Scope);
          Generate_Reference (Nam, Defining_Identifier (N), 'b');
          Set_Corresponding_Spec_Of_Stub (N, Nam);
index efa359fdb970323337410c30d82bfa9586ce4b59..d8c71d778cbde964e9ca4872cf607683c985f052 100644 (file)
@@ -1234,14 +1234,6 @@ package body Sem_Ch13 is
 
          else
             Insert_After (N, Prag);
-
-            --  Analyze the pragma before analyzing the proper body of a stub.
-            --  This ensures that the pragma will appear on the proper contract
-            --  list (see N_Contract).
-
-            if Nkind (N) = N_Subprogram_Body_Stub then
-               Analyze (Prag);
-            end if;
          end if;
       end Insert_Delayed_Pragma;
 
index ff3cbf25c2df840c94651864a74ee91ffbe43f7d..2433b32392d7cfc079cc1544b8bd15cf19d37b11 100644 (file)
@@ -2485,8 +2485,17 @@ package body Sem_Ch6 is
 
             if Has_Aspect (Spec_Id, Asp_Id) then
                Error_Msg_Name_1 := Asp_Nam;
-               Error_Msg_Name_2 := Ref_Nam;
-               Error_Msg_N ("aspect % should be %", Asp);
+
+               --  Subunits cannot carry aspects that apply to a subprogram
+               --  declaration.
+
+               if Nkind (Parent (N)) = N_Subunit then
+                  Error_Msg_N ("aspect % cannot apply to a subunit", Asp);
+
+               else
+                  Error_Msg_Name_2 := Ref_Nam;
+                  Error_Msg_N ("aspect % should be %", Asp);
+               end if;
 
             --  Otherwise the aspect must appear in the spec, not in the body:
 
@@ -2912,28 +2921,16 @@ package body Sem_Ch6 is
          end if;
       end if;
 
-      --  Language-defined aspects cannot appear in a subprogram body [stub] if
-      --  the subprogram has a separate spec. Certainly implementation-defined
-      --  aspects are allowed to appear (per Aspects_On_Body_Of_Stub_OK).
+      --  Language-defined aspects cannot appear on a subprogram body [stub] if
+      --  the subprogram has a spec. Certain implementation-defined aspects are
+      --  allowed to break this rule (see table Aspect_On_Body_Or_Stub_OK).
 
       if Has_Aspects (N) then
          if Present (Spec_Id)
            and then not Aspects_On_Body_Or_Stub_OK (N)
-
-            --  Do not emit an error on a subprogram body stub that act as
-            --  its own spec.
-
-           and then Nkind (Parent (Parent (Spec_Id))) /= N_Subprogram_Body_Stub
          then
             Diagnose_Misplaced_Aspect_Specifications;
 
-         --  Delay the analysis of aspect specifications that apply to a body
-         --  stub until the proper body is analyzed. If the corresponding body
-         --  is missing, the aspects are still analyzed in Analyze_Proper_Body.
-
-         elsif Nkind (N) in N_Body_Stub then
-            null;
-
          else
             Analyze_Aspect_Specifications (N, Body_Id);
          end if;
index 2b095eabbf699e28247b717dedbfab1ad5552d6c..a5eaf1304bd97f09fa912c5c0859b0fb0f53a416 100644 (file)
@@ -3601,40 +3601,42 @@ package body Sem_Prag is
 
          Body_Decl := Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
 
-         if not Nkind_In (Body_Decl, N_Subprogram_Body,
-                                     N_Subprogram_Body_Stub)
-         then
-            Pragma_Misplaced;
-            return;
-         end if;
-
-         Body_Id := Defining_Entity (Body_Decl);
-
-         --  The body [stub] must not act as a spec, in other words it has to
-         --  be paired with a corresponding spec.
+         --  Extract the entities of the spec and body
 
          if Nkind (Body_Decl) = N_Subprogram_Body then
+            Body_Id := Defining_Entity (Body_Decl);
             Spec_Id := Corresponding_Spec (Body_Decl);
-         else
+
+         elsif Nkind (Body_Decl) = N_Subprogram_Body_Stub then
+            Body_Id := Defining_Entity (Body_Decl);
             Spec_Id := Corresponding_Spec_Of_Stub (Body_Decl);
+
+         else
+            Pragma_Misplaced;
+            return;
          end if;
 
+         --  The pragma must apply to the second declaration of a subprogram.
+         --  In other words, the body [stub] cannot acts as a spec.
+
          if No (Spec_Id) then
             Error_Pragma ("pragma % cannot apply to a stand alone body");
             return;
+
+         --  Catch the case where the subprogram body is a subunit and acts as
+         --  the third declaration of the subprogram.
+
+         elsif Nkind (Parent (Body_Decl)) = N_Subunit then
+            Error_Pragma ("pragma % cannot apply to a subunit");
+            return;
          end if;
 
-         --  The pragma may only apply to the body [stub] of a subprogram
+         --  The pragma can only apply to the body [stub] of a subprogram
          --  declared in the visible part of a package. Retrieve the context of
          --  the subprogram declaration.
 
          Spec_Decl := Parent (Parent (Spec_Id));
 
-         pragma Assert
-           (Nkind_In (Spec_Decl, N_Abstract_Subprogram_Declaration,
-                                 N_Generic_Subprogram_Declaration,
-                                 N_Subprogram_Declaration));
-
          if Nkind (Parent (Spec_Decl)) /= N_Package_Specification then
             Error_Pragma
               ("pragma % must apply to the body of a subprogram declared in a "
@@ -12445,10 +12447,24 @@ package body Sem_Prag is
             Subp_Decl :=
               Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
 
-            if Nkind (Subp_Decl) /= N_Subprogram_Declaration
-              and then (Nkind (Subp_Decl) /= N_Subprogram_Body
-                         or else not Acts_As_Spec (Subp_Decl))
+            if Nkind (Subp_Decl) = N_Subprogram_Declaration then
+               null;
+
+            --  Body acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body
+              and then No (Corresponding_Spec (Subp_Decl))
+            then
+               null;
+
+            --  Body stub acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub
+              and then No (Corresponding_Spec_Of_Stub (Subp_Decl))
             then
+               null;
+
+            else
                Pragma_Misplaced;
                return;
             end if;
@@ -12969,10 +12985,24 @@ package body Sem_Prag is
             Subp_Decl :=
               Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
 
-            if Nkind (Subp_Decl) /= N_Subprogram_Declaration
-              and then (Nkind (Subp_Decl) /= N_Subprogram_Body
-                          or else not Acts_As_Spec (Subp_Decl))
+            if Nkind (Subp_Decl) = N_Subprogram_Declaration then
+               null;
+
+            --  Body acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body
+              and then No (Corresponding_Spec (Subp_Decl))
             then
+               null;
+
+            --  Body stub acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub
+              and then No (Corresponding_Spec_Of_Stub (Subp_Decl))
+            then
+               null;
+
+            else
                Pragma_Misplaced;
                return;
             end if;
@@ -14239,10 +14269,24 @@ package body Sem_Prag is
             Subp_Decl :=
               Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
 
-            if Nkind (Subp_Decl) /= N_Subprogram_Declaration
-              and then (Nkind (Subp_Decl) /= N_Subprogram_Body
-                          or else not Acts_As_Spec (Subp_Decl))
+            if Nkind (Subp_Decl) = N_Subprogram_Declaration then
+               null;
+
+            --  Body acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body
+              and then No (Corresponding_Spec (Subp_Decl))
             then
+               null;
+
+            --  Body stub acts as spec
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub
+              and then No (Corresponding_Spec_Of_Stub (Subp_Decl))
+            then
+               null;
+
+            else
                Pragma_Misplaced;
                return;
             end if;