[multiple changes]
authorArnaud Charlet <charlet@gcc.gnu.org>
Mon, 18 Apr 2016 10:17:17 +0000 (12:17 +0200)
committerArnaud Charlet <charlet@gcc.gnu.org>
Mon, 18 Apr 2016 10:17:17 +0000 (12:17 +0200)
2016-04-18  Ed Schonberg  <schonberg@adacore.com>

* sem_ch6.adb (Analyze_Subprogram_Body_Helper): In GNATprove
mode, collect inherited class-wide conditions to generate the
corresponding pragmas.
* sem_prag.ads (Build_Pragma_Check_Equivalent): Moved from contracts
* contracts.adb (Collect_Inherited_Class_Wide_Conditions): New
procedure for overriding subprograms, used to generate the pragmas
corresponding to an inherited class- wide pre- or postcondition.
* sem_prag.adb (Build_Pragma_Check_Equivalent): moved here
from contracts.adb (Replace_Condition_Entities): Subsidiary
Build_Pragma_Check_Equivalent, to implement the proper semantics
of inherited class-wide conditions, as given in AI12-0113.
(Process_Class_Wide_Condition): Removed.
(Collect_Inherited_Class_Wide_Conditions): Iterate over pragmas
in contract of subprogram, to collect inherited class-wide
conditions.
(Build_Pragma_Check_Equivalent): Moved to sem_prag.adb

2016-04-18  Yannick Moy  <moy@adacore.com>

* a-calend.adb (Ada.Calendar): Mark package body as SPARK_Mode Off.
* a-calend.ads (Ada.Calendar): Mark package spec as
SPARK_Mode and add synchronous external abstract state Clock_Time.

From-SVN: r235113

gcc/ada/ChangeLog
gcc/ada/a-calend.adb
gcc/ada/a-calend.ads
gcc/ada/contracts.adb
gcc/ada/sem_ch6.adb
gcc/ada/sem_prag.adb
gcc/ada/sem_prag.ads

index c8e9141ff328d1edd12aecfafe9881cde4b36721..3e329a87b494f7248c2399354af2a255457e05c0 100644 (file)
@@ -1,3 +1,28 @@
+2016-04-18  Ed Schonberg  <schonberg@adacore.com>
+
+       * sem_ch6.adb (Analyze_Subprogram_Body_Helper): In GNATprove
+       mode, collect inherited class-wide conditions to generate the
+       corresponding pragmas.
+       * sem_prag.ads (Build_Pragma_Check_Equivalent): Moved from contracts
+       * contracts.adb (Collect_Inherited_Class_Wide_Conditions): New
+       procedure for overriding subprograms, used to generate the pragmas
+       corresponding to an inherited class- wide pre- or postcondition.
+       * sem_prag.adb (Build_Pragma_Check_Equivalent): moved here
+       from contracts.adb (Replace_Condition_Entities): Subsidiary
+       Build_Pragma_Check_Equivalent, to implement the proper semantics
+       of inherited class-wide conditions, as given in AI12-0113.
+       (Process_Class_Wide_Condition): Removed.
+       (Collect_Inherited_Class_Wide_Conditions): Iterate over pragmas
+       in contract of subprogram, to collect inherited class-wide
+       conditions.
+       (Build_Pragma_Check_Equivalent): Moved to sem_prag.adb
+
+2016-04-18  Yannick Moy  <moy@adacore.com>
+
+       * a-calend.adb (Ada.Calendar): Mark package body as SPARK_Mode Off.
+       * a-calend.ads (Ada.Calendar): Mark package spec as
+       SPARK_Mode and add synchronous external abstract state Clock_Time.
+
 2016-04-18  Yannick Moy  <moy@adacore.com>
 
        * sem_res.adb (Resolve_Call): Prevent inlining of
index 9fcc2996702c3007b8be9eb705673e208f441d95..f5076f23277f276ff2201c4f7e7a14059812d3fc 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2014, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -35,7 +35,9 @@ with Interfaces.C;
 
 with System.OS_Primitives;
 
-package body Ada.Calendar is
+package body Ada.Calendar with
+  SPARK_Mode => Off
+is
 
    --------------------------
    -- Implementation Notes --
index 55efe115f5dcd307e0101f076124dfb86a66af34..0eed8badf49aa3017730b066592c7516e25d048c 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 S p e c                                  --
 --                                                                          --
---          Copyright (C) 1992-2014, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
 --                                                                          --
 -- This specification is derived from the Ada Reference Manual for use with --
 -- GNAT. The copyright notice above, and the license provisions that follow --
 --                                                                          --
 ------------------------------------------------------------------------------
 
-package Ada.Calendar is
+package Ada.Calendar with
+  SPARK_Mode,
+  Abstract_State => (Clock_Time with Synchronous,
+                                     External => (Async_Readers,
+                                                  Async_Writers))
+is
 
    type Time is private;
 
@@ -49,7 +54,9 @@ package Ada.Calendar is
 
    subtype Day_Duration is Duration range 0.0 .. 86_400.0;
 
-   function Clock return Time;
+   function Clock return Time with
+     Volatile_Function,
+     Global => Clock_Time;
    --  The returned time value is the number of nanoseconds since the start
    --  of Ada time (1901-01-01 00:00:00.0 UTC). If leap seconds are enabled,
    --  the result will contain all elapsed leap seconds since the start of
@@ -108,6 +115,10 @@ package Ada.Calendar is
    Time_Error : exception;
 
 private
+   --  Mark private part as SPARK_Mode Off to avoid accounting for variable
+   --  Invalid_Time_Zone_Offset in abstract state.
+   pragma SPARK_Mode (Off);
+
    pragma Inline (Clock);
 
    pragma Inline (Year);
index ebaecc09512d8923c6d87f4e4bb54e204283edab..4eb6d26adbad59009e0b781807d5e39df9b5fbeb 100644 (file)
@@ -1432,15 +1432,6 @@ package body Contracts is
       --  of statements to be checked on exit. Parameter Result is the entity
       --  of parameter _Result when Subp_Id denotes a function.
 
-      function Build_Pragma_Check_Equivalent
-        (Prag     : Node_Id;
-         Subp_Id  : Entity_Id := Empty;
-         Inher_Id : Entity_Id := Empty) return Node_Id;
-      --  Transform a [refined] pre- or postcondition denoted by Prag into an
-      --  equivalent pragma Check. When the pre- or postcondition is inherited,
-      --  the routine corrects the references of all formals of Inher_Id to
-      --  point to the formals of Subp_Id.
-
       procedure Process_Contract_Cases (Stmts : in out List_Id);
       --  Process pragma Contract_Cases. This routine prepends items to the
       --  body declarations and appends items to list Stmts.
@@ -1860,155 +1851,6 @@ package body Contracts is
          Analyze (Proc_Bod);
       end Build_Postconditions_Procedure;
 
-      -----------------------------------
-      -- Build_Pragma_Check_Equivalent --
-      -----------------------------------
-
-      function Build_Pragma_Check_Equivalent
-        (Prag     : Node_Id;
-         Subp_Id  : Entity_Id := Empty;
-         Inher_Id : Entity_Id := Empty) return Node_Id
-      is
-         function Suppress_Reference (N : Node_Id) return Traverse_Result;
-         --  Detect whether node N references a formal parameter subject to
-         --  pragma Unreferenced. If this is the case, set Comes_From_Source
-         --  to False to suppress the generation of a reference when analyzing
-         --  N later on.
-
-         ------------------------
-         -- Suppress_Reference --
-         ------------------------
-
-         function Suppress_Reference (N : Node_Id) return Traverse_Result is
-            Formal : Entity_Id;
-
-         begin
-            if Is_Entity_Name (N) and then Present (Entity (N)) then
-               Formal := Entity (N);
-
-               --  The formal parameter is subject to pragma Unreferenced.
-               --  Prevent the generation of a reference by resetting the
-               --  Comes_From_Source flag.
-
-               if Is_Formal (Formal)
-                 and then Has_Pragma_Unreferenced (Formal)
-               then
-                  Set_Comes_From_Source (N, False);
-               end if;
-            end if;
-
-            return OK;
-         end Suppress_Reference;
-
-         procedure Suppress_References is
-           new Traverse_Proc (Suppress_Reference);
-
-         --  Local variables
-
-         Loc          : constant Source_Ptr := Sloc (Prag);
-         Prag_Nam     : constant Name_Id    := Pragma_Name (Prag);
-         Check_Prag   : Node_Id;
-         Formals_Map  : Elist_Id;
-         Inher_Formal : Entity_Id;
-         Msg_Arg      : Node_Id;
-         Nam          : Name_Id;
-         Subp_Formal  : Entity_Id;
-
-      --  Start of processing for Build_Pragma_Check_Equivalent
-
-      begin
-         Formals_Map := No_Elist;
-
-         --  When the pre- or postcondition is inherited, map the formals of
-         --  the inherited subprogram to those of the current subprogram.
-
-         if Present (Inher_Id) then
-            pragma Assert (Present (Subp_Id));
-
-            Formals_Map := New_Elmt_List;
-
-            --  Create a relation <inherited formal> => <subprogram formal>
-
-            Inher_Formal := First_Formal (Inher_Id);
-            Subp_Formal  := First_Formal (Subp_Id);
-            while Present (Inher_Formal) and then Present (Subp_Formal) loop
-               Append_Elmt (Inher_Formal, Formals_Map);
-               Append_Elmt (Subp_Formal, Formals_Map);
-
-               Next_Formal (Inher_Formal);
-               Next_Formal (Subp_Formal);
-            end loop;
-         end if;
-
-         --  Copy the original pragma while performing substitutions (if
-         --  applicable).
-
-         Check_Prag :=
-           New_Copy_Tree
-             (Source    => Prag,
-              Map       => Formals_Map,
-              New_Scope => Current_Scope);
-
-         --  Mark the pragma as being internally generated and reset the
-         --  Analyzed flag.
-
-         Set_Analyzed          (Check_Prag, False);
-         Set_Comes_From_Source (Check_Prag, False);
-
-         --  The tree of the original pragma may contain references to the
-         --  formal parameters of the related subprogram. At the same time
-         --  the corresponding body may mark the formals as unreferenced:
-
-         --     procedure Proc (Formal : ...)
-         --       with Pre => Formal ...;
-
-         --     procedure Proc (Formal : ...) is
-         --        pragma Unreferenced (Formal);
-         --     ...
-
-         --  This creates problems because all pragma Check equivalents are
-         --  analyzed at the end of the body declarations. Since all source
-         --  references have already been accounted for, reset any references
-         --  to such formals in the generated pragma Check equivalent.
-
-         Suppress_References (Check_Prag);
-
-         if Present (Corresponding_Aspect (Prag)) then
-            Nam := Chars (Identifier (Corresponding_Aspect (Prag)));
-         else
-            Nam := Prag_Nam;
-         end if;
-
-         --  Convert the copy into pragma Check by correcting the name and
-         --  adding a check_kind argument.
-
-         Set_Pragma_Identifier
-           (Check_Prag, Make_Identifier (Loc, Name_Check));
-
-         Prepend_To (Pragma_Argument_Associations (Check_Prag),
-           Make_Pragma_Argument_Association (Loc,
-             Expression => Make_Identifier (Loc, Nam)));
-
-         --  Update the error message when the pragma is inherited
-
-         if Present (Inher_Id) then
-            Msg_Arg := Last (Pragma_Argument_Associations (Check_Prag));
-
-            if Chars (Msg_Arg) = Name_Message then
-               String_To_Name_Buffer (Strval (Expression (Msg_Arg)));
-
-               --  Insert "inherited" to improve the error message
-
-               if Name_Buffer (1 .. 8) = "failed p" then
-                  Insert_Str_In_Name_Buffer ("inherited ", 8);
-                  Set_Strval (Expression (Msg_Arg), String_From_Name_Buffer);
-               end if;
-            end if;
-         end if;
-
-         return Check_Prag;
-      end Build_Pragma_Check_Equivalent;
-
       ----------------------------
       -- Process_Contract_Cases --
       ----------------------------
index a0a75b2ef8d311b37fcf79f0700985d1e9cf3f14..c1e57471c793ecc9e9d6fbec45b65e0ae7995b4a 100644 (file)
@@ -3754,6 +3754,17 @@ package body Sem_Ch6 is
          Build_Body_To_Inline (N, Spec_Id);
       end if;
 
+      --  When generating code, inherited pre/postconditions are handled
+      --  when expanding the corresponding contract. If GNATprove mode we
+      --  must process them when the body is analyzed.
+
+      if GNATprove_Mode
+        and then Present (Spec_Id)
+        and then Present (Overridden_Operation (Spec_Id))
+      then
+         Collect_Inherited_Class_Wide_Conditions (Spec_Id, N);
+      end if;
+
       --  Ada 2005 (AI-262): In library subprogram bodies, after the analysis
       --  of the specification we have to install the private withed units.
       --  This holds for child units as well.
index 1d64de503f480e340aecf04f5dd8e9ad9e28f327..01f498847bfd2efa42c363b88bc58ad850e43462 100644 (file)
@@ -23141,151 +23141,6 @@ package body Sem_Prag is
      (N         : Node_Id;
       Freeze_Id : Entity_Id := Empty)
    is
-      procedure Process_Class_Wide_Condition
-        (Expr      : Node_Id;
-         Spec_Id   : Entity_Id;
-         Subp_Decl : Node_Id);
-      --  Replace the type of all references to the controlling formal of
-      --  subprogram Spec_Id found in expression Expr with the corresponding
-      --  class-wide type. Subp_Decl is the subprogram [body] declaration
-      --  where the pragma resides.
-
-      ----------------------------------
-      -- Process_Class_Wide_Condition --
-      ----------------------------------
-
-      procedure Process_Class_Wide_Condition
-        (Expr      : Node_Id;
-         Spec_Id   : Entity_Id;
-         Subp_Decl : Node_Id)
-      is
-         Disp_Typ : constant Entity_Id := Find_Dispatching_Type (Spec_Id);
-
-         ACW : Entity_Id := Empty;
-         --  Access to Disp_Typ'Class, created if there is a controlling formal
-         --  that is an access parameter.
-
-         function Access_Class_Wide_Type return Entity_Id;
-         --  If expression Expr contains a reference to a controlling access
-         --  parameter, create an access to Disp_Typ'Class for the necessary
-         --  conversions if one does not exist.
-
-         function Replace_Type (N : Node_Id) return Traverse_Result;
-         --  ARM 6.1.1: Within the expression for a Pre'Class or Post'Class
-         --  aspect for a primitive subprogram of a tagged type Disp_Typ, a
-         --  name that denotes a formal parameter of type Disp_Typ is treated
-         --  as having type Disp_Typ'Class. Similarly, a name that denotes a
-         --  formal access parameter of type access-to-Disp_Typ is interpreted
-         --  as with type access-to-Disp_Typ'Class. This ensures the expression
-         --  is well defined for a primitive subprogram of a type descended
-         --  from Disp_Typ.
-
-         ----------------------------
-         -- Access_Class_Wide_Type --
-         ----------------------------
-
-         function Access_Class_Wide_Type return Entity_Id is
-            Loc : constant Source_Ptr := Sloc (N);
-
-         begin
-            if No (ACW) then
-               ACW := Make_Temporary (Loc, 'T');
-
-               Insert_Before_And_Analyze (Subp_Decl,
-                 Make_Full_Type_Declaration (Loc,
-                   Defining_Identifier => ACW,
-                   Type_Definition     =>
-                      Make_Access_To_Object_Definition (Loc,
-                        Subtype_Indication =>
-                          New_Occurrence_Of (Class_Wide_Type (Disp_Typ), Loc),
-                        All_Present        => True)));
-
-               Freeze_Before (Subp_Decl, ACW);
-            end if;
-
-            return ACW;
-         end Access_Class_Wide_Type;
-
-         ------------------
-         -- Replace_Type --
-         ------------------
-
-         function Replace_Type (N : Node_Id) return Traverse_Result is
-            Context : constant Node_Id    := Parent (N);
-            Loc     : constant Source_Ptr := Sloc (N);
-            CW_Typ  : Entity_Id := Empty;
-            Ent     : Entity_Id;
-            Typ     : Entity_Id;
-
-         begin
-            if Is_Entity_Name (N)
-              and then Present (Entity (N))
-              and then Is_Formal (Entity (N))
-            then
-               Ent := Entity (N);
-               Typ := Etype (Ent);
-
-               --  Do not perform the type replacement for selector names in
-               --  parameter associations. These carry an entity for reference
-               --  purposes, but semantically they are just identifiers.
-
-               if Nkind (Context) = N_Type_Conversion then
-                  null;
-
-               elsif Nkind (Context) = N_Parameter_Association
-                 and then Selector_Name (Context) = N
-               then
-                  null;
-
-               elsif Typ = Disp_Typ then
-                  CW_Typ := Class_Wide_Type (Typ);
-
-               elsif Is_Access_Type (Typ)
-                 and then Designated_Type (Typ) = Disp_Typ
-               then
-                  CW_Typ := Access_Class_Wide_Type;
-               end if;
-
-               if Present (CW_Typ) then
-                  Rewrite (N,
-                    Make_Type_Conversion (Loc,
-                      Subtype_Mark => New_Occurrence_Of (CW_Typ, Loc),
-                      Expression   => New_Occurrence_Of (Ent, Loc)));
-                  Set_Etype (N, CW_Typ);
-               end if;
-            end if;
-
-            return OK;
-         end Replace_Type;
-
-         procedure Replace_Types is new Traverse_Proc (Replace_Type);
-
-      --  Start of processing for Process_Class_Wide_Condition
-
-      begin
-         --  The subprogram subject to Pre'Class/Post'Class does not have a
-         --  dispatching type, therefore the aspect/pragma is illegal.
-
-         if No (Disp_Typ) then
-            Error_Msg_Name_1 := Original_Aspect_Pragma_Name (N);
-
-            if From_Aspect_Specification (N) then
-               Error_Msg_N
-                 ("aspect % can only be specified for a primitive operation "
-                  & "of a tagged type", Corresponding_Aspect (N));
-
-            --  The pragma is a source construct
-
-            else
-               Error_Msg_N
-                 ("pragma % can only be specified for a primitive operation "
-                  & "of a tagged type", N);
-            end if;
-         end if;
-
-         Replace_Types (Expr);
-      end Process_Class_Wide_Condition;
-
       --  Local variables
 
       Subp_Decl : constant Node_Id   := Find_Related_Declaration_Or_Body (N);
@@ -23295,6 +23150,7 @@ package body Sem_Prag is
       Save_Ghost_Mode : constant Ghost_Mode_Type := Ghost_Mode;
 
       Errors        : Nat;
+      Disp_Typ      : Entity_Id;
       Restore_Scope : Boolean := False;
 
    --  Start of processing for Analyze_Pre_Post_Condition_In_Decl_Part
@@ -23340,13 +23196,29 @@ package body Sem_Prag is
          Contract_Freeze_Error (Spec_Id, Freeze_Id);
       end if;
 
-      --  For a class-wide condition, a reference to a controlling formal must
-      --  be interpreted as having the class-wide type (or an access to such)
-      --  so that the inherited condition can be properly applied to any
-      --  overriding operation (see ARM12 6.6.1 (7)).
-
       if Class_Present (N) then
-         Process_Class_Wide_Condition (Expr, Spec_Id, Subp_Decl);
+
+         --  Verify that a class-wide condition is legal, i.e. the operation
+         --  is a primitive of a tagged type.
+
+         Disp_Typ := Find_Dispatching_Type (Spec_Id);
+
+         if No (Disp_Typ) then
+            Error_Msg_Name_1 := Original_Aspect_Pragma_Name (N);
+
+            if From_Aspect_Specification (N) then
+               Error_Msg_N
+                 ("aspect % can only be specified for a primitive operation "
+                  & "of a tagged type", Corresponding_Aspect (N));
+
+            --  The pragma is a source construct
+
+            else
+               Error_Msg_N
+                 ("pragma % can only be specified for a primitive operation "
+                  & "of a tagged type", N);
+            end if;
+         end if;
       end if;
 
       if Restore_Scope then
@@ -26164,6 +26036,294 @@ package body Sem_Prag is
       return False;
    end Appears_In;
 
+   -----------------------------------
+   -- Build_Pragma_Check_Equivalent --
+   -----------------------------------
+
+   function Build_Pragma_Check_Equivalent
+     (Prag     : Node_Id;
+      Subp_Id  : Entity_Id := Empty;
+      Inher_Id : Entity_Id := Empty) return Node_Id
+   is
+      function Suppress_Reference (N : Node_Id) return Traverse_Result;
+      --  Detect whether node N references a formal parameter subject to
+      --  pragma Unreferenced. If this is the case, set Comes_From_Source
+      --  to False to suppress the generation of a reference when analyzing
+      --  N later on.
+
+      ------------------------
+      -- Suppress_Reference --
+      ------------------------
+
+      function Suppress_Reference (N : Node_Id) return Traverse_Result is
+         Formal : Entity_Id;
+
+      begin
+         if Is_Entity_Name (N) and then Present (Entity (N)) then
+            Formal := Entity (N);
+
+            --  The formal parameter is subject to pragma Unreferenced.
+            --  Prevent the generation of a reference by resetting the
+            --  Comes_From_Source flag.
+
+            if Is_Formal (Formal)
+              and then Has_Pragma_Unreferenced (Formal)
+            then
+               Set_Comes_From_Source (N, False);
+            end if;
+         end if;
+
+         return OK;
+      end Suppress_Reference;
+
+      procedure Suppress_References is
+        new Traverse_Proc (Suppress_Reference);
+
+      --  Local variables
+
+      Loc          : constant Source_Ptr := Sloc (Prag);
+      Prag_Nam     : constant Name_Id    := Pragma_Name (Prag);
+      Check_Prag   : Node_Id;
+      Formals_Map  : Elist_Id;
+      Inher_Formal : Entity_Id;
+      Msg_Arg      : Node_Id;
+      Nam          : Name_Id;
+      Subp_Formal  : Entity_Id;
+
+      function Replace_Entity (N : Node_Id) return Traverse_Result;
+      --  Replace reference to formal of inherited operation or to primitive
+      --  operation of root type, with corresponding entity for derived type.
+
+      --------------------
+      -- Replace_Entity --
+      --------------------
+
+      function Replace_Entity (N : Node_Id) return Traverse_Result
+      is
+         Elmt  : Elmt_Id;
+         New_E : Entity_Id;
+
+      begin
+         if Nkind (N) = N_Identifier
+           and then Present (Entity (N))
+           and then
+             (Is_Formal (Entity (N)) or else Is_Subprogram (Entity (N)))
+           and then
+             (Nkind (Parent (N)) /= N_Attribute_Reference
+               or else Attribute_Name (Parent (N)) /= Name_Class)
+         then
+            --  The replacement does not apply to dispatching calls within
+            --  the condition, but only to calls whose static tag is that
+            --  of the parent type.
+
+            if Is_Subprogram (Entity (N))
+              and then Nkind (Parent (N)) = N_Function_Call
+              and then Present (Controlling_Argument (Parent (N)))
+            then
+               return OK;
+            end if;
+
+            --  Loop to find out if entity has a renaming
+
+            New_E := Empty;
+            Elmt := First_Elmt (Formals_Map);
+            while Present (Elmt) loop
+               if Node (Elmt) = Entity (N) then
+                  New_E := Node (Next_Elmt (Elmt));
+                  exit;
+               end if;
+
+               Next_Elmt (Elmt);
+            end loop;
+
+            if Present (New_E) then
+               Rewrite (N, New_Occurrence_Of (New_E, Sloc (N)));
+            end if;
+         end if;
+
+         if not Is_Abstract_Subprogram (Inher_Id)
+           and then  Nkind (N) = N_Function_Call
+           and then Present (Entity (Name (N)))
+           and then Is_Abstract_Subprogram (Entity (Name (N)))
+         then
+            Error_Msg_N ("cannot call abstract subprogram", N);
+
+         --  The whole expression will be reanalyzed
+
+         elsif Nkind (N) in N_Has_Etype then
+            Set_Analyzed (N, False);
+         end if;
+
+         return OK;
+      end Replace_Entity;
+
+      procedure Replace_Condition_Entities is
+        new Traverse_Proc (Replace_Entity);
+
+   --  Start of processing for Build_Pragma_Check_Equivalent
+
+   begin
+      Formals_Map := No_Elist;
+
+      --  When the pre- or postcondition is inherited, map the formals of
+      --  the inherited subprogram to those of the current subprogram.
+      --  In addition, map primitive operations of the parent type into the
+      --  corresponding primitive operations of the descendant.
+
+      if Present (Inher_Id) then
+         pragma Assert (Present (Subp_Id));
+
+         Formals_Map := New_Elmt_List;
+
+         --  Create a mapping  <inherited formal> => <subprogram formal>
+
+         Inher_Formal := First_Formal (Inher_Id);
+         Subp_Formal  := First_Formal (Subp_Id);
+         while Present (Inher_Formal) and then Present (Subp_Formal) loop
+            Append_Elmt (Inher_Formal, Formals_Map);
+            Append_Elmt (Subp_Formal, Formals_Map);
+
+            Next_Formal (Inher_Formal);
+            Next_Formal (Subp_Formal);
+         end loop;
+
+      --  Map primitive operations of the parent type into the corresponding
+      --  operations of the descendant. The descendant type might not be
+      --  frozen yet, so we cannot use the dispatch table directly.
+
+         declare
+            T     : constant Entity_Id := Find_Dispatching_Type (Subp_Id);
+            Old_T : constant Entity_Id := Find_Dispatching_Type (Inher_Id);
+            D     : Node_Id;
+            E     : Entity_Id;
+            Old_E : Entity_Id;
+
+         begin
+            D := First (List_Containing (Unit_Declaration_Node (Subp_Id)));
+
+            --  Look for primitive operations of the current type that have
+            --  overridden an operation of the type related to the original
+            --  class-wide precondition. There may be several intermediate
+            --  overridings between them.
+
+            while Present (D) loop
+               if Nkind (D) = N_Subprogram_Declaration then
+                  E := Defining_Entity (D);
+                  if Is_Subprogram (E)
+                    and then Present (Overridden_Operation (E))
+                    and then Find_Dispatching_Type (E) = T
+                  then
+                     Old_E := Overridden_Operation (E);
+                     while Present (Overridden_Operation (Old_E))
+                       and then Scope (Old_E) /= Scope (Inher_Id)
+                     loop
+                        Old_E := Overridden_Operation (Old_E);
+                     end loop;
+
+                     Append_Elmt (Old_E, Formals_Map);
+                     Append_Elmt (E, Formals_Map);
+                  end if;
+               end if;
+
+               Next (D);
+            end loop;
+
+            E := First_Entity (Scope (Subp_Id));
+            while Present (E) loop
+               if not Comes_From_Source (E)
+                 and then Ekind (E) = E_Function
+                 and then Present (Alias (E))
+               then
+                  Old_E := Alias (E);
+                  while Present (Alias (Old_E))
+                    and then Scope (Old_E) /= Scope (Inher_Id)
+                  loop
+                     Old_E := Alias (Old_E);
+                  end loop;
+
+                  Append_Elmt (Old_E, Formals_Map);
+                  Append_Elmt (E, Formals_Map);
+               end if;
+               Next_Entity (E);
+            end loop;
+
+            if Formals_Map /= No_Elist then
+               Append_Elmt (Old_T, Formals_Map);
+               Append_Elmt (T, Formals_Map);
+            end if;
+         end;
+      end if;
+
+      --  Copy the original pragma while performing substitutions (if
+      --  applicable).
+
+      Check_Prag := New_Copy_Tree (Source    => Prag);
+
+      if Formals_Map /= No_Elist then
+         Replace_Condition_Entities (Check_Prag);
+      end if;
+
+      --  Mark the pragma as being internally generated and reset the
+      --  Analyzed flag.
+
+      Set_Analyzed          (Check_Prag, False);
+      Set_Comes_From_Source (Check_Prag, False);
+      Set_Class_Present     (Check_Prag, False);
+
+      --  The tree of the original pragma may contain references to the
+      --  formal parameters of the related subprogram. At the same time
+      --  the corresponding body may mark the formals as unreferenced:
+
+      --     procedure Proc (Formal : ...)
+      --       with Pre => Formal ...;
+
+      --     procedure Proc (Formal : ...) is
+      --        pragma Unreferenced (Formal);
+      --     ...
+
+      --  This creates problems because all pragma Check equivalents are
+      --  analyzed at the end of the body declarations. Since all source
+      --  references have already been accounted for, reset any references
+      --  to such formals in the generated pragma Check equivalent.
+
+      Suppress_References (Check_Prag);
+
+      if Present (Corresponding_Aspect (Prag)) then
+         Nam := Chars (Identifier (Corresponding_Aspect (Prag)));
+      else
+         Nam := Prag_Nam;
+      end if;
+
+      --  Convert the copy into pragma Check by correcting the name and
+      --  adding a check_kind argument.
+
+      Set_Pragma_Identifier
+        (Check_Prag, Make_Identifier (Loc, Name_Check));
+
+      Prepend_To (Pragma_Argument_Associations (Check_Prag),
+        Make_Pragma_Argument_Association (Loc,
+          Expression => Make_Identifier (Loc, Nam)));
+
+      --  Update the error message when the pragma is inherited
+
+      if Present (Inher_Id) then
+         Msg_Arg := Last (Pragma_Argument_Associations (Check_Prag));
+
+         if Chars (Msg_Arg) = Name_Message then
+            String_To_Name_Buffer (Strval (Expression (Msg_Arg)));
+
+            --  Insert "inherited" to improve the error message
+
+            if Name_Buffer (1 .. 8) = "failed p" then
+               Insert_Str_In_Name_Buffer ("inherited ", 8);
+               Set_Strval (Expression (Msg_Arg), String_From_Name_Buffer);
+            end if;
+         end if;
+      end if;
+
+      return Check_Prag;
+   end Build_Pragma_Check_Equivalent;
+
    -----------------------------
    -- Check_Applicable_Policy --
    -----------------------------
@@ -26626,6 +26786,42 @@ package body Sem_Prag is
       end loop;
    end Check_State_And_Constituent_Use;
 
+   ---------------------------------------------
+   -- Collect_Inherited_Class_Wide_Conditions --
+   ---------------------------------------------
+
+   procedure Collect_Inherited_Class_Wide_Conditions
+     (Subp : Entity_Id;
+      Bod  : Node_Id)
+   is
+      Parent_Subp : constant Entity_Id := Overridden_Operation (Subp);
+      Prags       : constant Node_Id := Contract (Parent_Subp);
+      Prag        : Node_Id;
+
+   begin
+      --  Iterate over the contract to find inherited class-wide pre- and
+      --  postconditions.
+
+      if Present (Prags) then
+         Prag := Pre_Post_Conditions (Prags);
+
+         while Present (Prag) loop
+            if Pragma_Name (Prag) = Name_Precondition
+              or else Pragma_Name (Prag) = Name_Postcondition
+            then
+               if No (Declarations (Bod)) then
+                  Set_Declarations (Bod, Empty_List);
+               end if;
+
+               Append (Build_Pragma_Check_Equivalent (Prag, Subp, Parent_Subp),
+                 To => Declarations (Bod));
+            end if;
+
+            Prag := Next_Pragma (Prag);
+         end loop;
+      end if;
+   end Collect_Inherited_Class_Wide_Conditions;
+
    ---------------------------------------
    -- Collect_Subprogram_Inputs_Outputs --
    ---------------------------------------
index 3bc2f65ae92faabab72b7e0059d51edb9902db59..063e7df528fb72d2d1857d3f8fb4bcc2ac7e594e 100644 (file)
@@ -244,6 +244,16 @@ package Sem_Prag is
    procedure Analyze_Test_Case_In_Decl_Part (N : Node_Id);
    --  Perform preanalysis of pragma Test_Case
 
+   function Build_Pragma_Check_Equivalent
+     (Prag     : Node_Id;
+      Subp_Id  : Entity_Id := Empty;
+      Inher_Id : Entity_Id := Empty) return Node_Id;
+   --  Transform a [refined] pre- or postcondition denoted by Prag into an
+   --  equivalent pragma Check. When the pre- or postcondition is inherited,
+   --  the routine replaces the references of all formals of Inher_Id and
+   --  primitive operations of its controlling type by references to the
+   --  corresponding entities of Subp_Id and the descendant type.
+
    procedure Check_Applicable_Policy (N : Node_Id);
    --  N is either an N_Aspect or an N_Pragma node. There are two cases. If
    --  the name of the aspect or pragma is not one of those recognized as
@@ -301,6 +311,13 @@ package Sem_Prag is
    --  state, variable or package instantiation denoted by Item_Id requires the
    --  use of indicator/option Part_Of. If this is the case, emit an error.
 
+   procedure Collect_Inherited_Class_Wide_Conditions
+     (Subp : Entity_Id;
+      Bod  : Node_Id);
+   --  When analyzing an overriding subprogram, check whether the overridden
+   --  operations have class-wide pre/postconditions, and generate the
+   --  corresponding pragmas.
+
    procedure Collect_Subprogram_Inputs_Outputs
      (Subp_Id      : Entity_Id;
       Synthesize   : Boolean := False;