diff mbox

[Ada] Implement new pragmas Pre[_Class] and Post[_Class]

Message ID 20131013163407.GA22603@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Oct. 13, 2013, 4:34 p.m. UTC
This implements four new pragmas, Pre, Pre_Class, Post, Post_Class
that are intended to closely mirrir the four corresponding aspects
Pre, Pre'Class, Post, and Post'Class. They inherit the same set of
restrictions as these aspects. In particular, a given aspect can be
specified only once for a given entity (using either an aspect or
a pragma, but not both), and they can be given for a body only if
there is no separate specification. Unlike pragmas Precondition
and Postcondition, they take only one parameter (the expression)
and it must appear without an identifier.

The following example shows Pre and Post in action (and also shows
that they are controlled by assertion identifiers of the same name
(Pre_Class and Post_Class are controlled by Pre'Class/Post'Class).

      1. with Ada.Exceptions; use Ada.Exceptions;
      2. with Text_IO; use Text_IO;
      3. procedure PostPrePrag is
      4. begin
      5.    declare
      6.       pragma Assertion_Policy (Pre => Check, Post => Check);
      7.       function F (A : Integer) return Integer;
      8.       pragma Pre (A in 1 .. 10);
      9.       pragma Post (F'Result < 10);
     10.
     11.       function F (A : Integer) return Integer is
     12.       begin
     13.          return 2 * A;
     14.       end;
     15.
     16.       F1, F2, F3 : Integer;
     17.    begin
     18.       F1 := F (2);
     19.       Put_Line ("OK1");
     20.
     21.       begin
     22.          F2 := F (9);
     23.          Put_Line ("ERROR1");
     24.       exception
     25.          when M : others =>
     26.             Put_Line ("OK2 " & Exception_Message (M));
     27.       end;
     28.
     29.       begin
     30.          F3 := F (12);
     31.          Put_Line ("ERROR2");
     32.       exception
     33.          when M : others =>
     34.             Put_Line ("OK3 " & Exception_Message (M));
     35.       end;
     36.    end;
     37.
     38.    declare
     39.       pragma Assertion_Policy (Pre => Ignore, Post => Ignore);
     40.       function F (A : Integer) return Integer;
     41.       pragma Pre (A in 1 .. 10);
     42.       pragma Post (F'Result < 10);
     43.
     44.       function F (A : Integer) return Integer is
     45.       begin
     46.          return 2 * A;
     47.       end;
     48.
     49.       F1, F2, F3 : Integer;
     50.    begin
     51.       F1 := F (2);
     52.       Put_Line ("OK4");
     53.
     54.       begin
     55.          F2 := F (9);
     56.          Put_line ("OK5");
     57.       exception
     58.          when M : others =>
     59.             Put_Line ("ERROR3 " & Exception_Message (M));
     60.       end;
     61.
     62.       begin
     63.          F3 := F (12);
     64.          Put_Line ("OK6");
     65.       exception
     66.          when M : others =>
     67.             Put_Line ("ERROR4 " & Exception_Message (M));
     68.       end;
     69.    end;
     70.
     71. end PostPrePrag;

The output of the above example is:

OK1
OK2 failed postcondition from postpreprag.adb:9
OK3 failed precondition from postpreprag.adb:8
OK4
OK5
OK6

The following example shows additional error checking that
applies to these pragmas (if Precondition and Postcondition
were used in place of Pre and Post, these errors would not
be flagged):

      1. procedure PostPrePragE is
      2.    pragma Assertion_Policy (Pre => Check, Post => Check);
      3.    function F (A : Integer) return Integer
      4.      with Pre => A = 10;
      5.    pragma Pre (A in 1 .. 10);
            |
         >>> duplication of aspect for "F" given at line 4

      6.    pragma Pre (A = 5);
            |
         >>> duplication of aspect for "F" given at line 4

      7.    pragma Post (Check => F'Result = 2);
                         |
         >>> pragma "Post" does not permit identifier "Check" here

      8.    pragma Post (F'Result = 1, "message");
                                       |
         >>> too many arguments for pragma "Post"

      9.
     10.    function Q (M : Integer) return Integer;
     11.    pragma Pre_Class (M > 5);
     12.    pragma Pre (M > 10);
     13.    pragma Post (Q'Result < 10);
     14.    pragma Post (Q'Result < 5);
            |
         >>> duplication of aspect for "Q" given at line 13

     15.
     16.    package Inner is
     17.       type R is tagged null record;
     18.       procedure Prim (Arg : R);
     19.       pragma Pre_Class (True);
     20.       pragma Pre (False);
     21.    end Inner;
     22.
     23.    package body Inner is
     24.       procedure Prim (Arg : R) is
     25.       begin
     26.          null;
     27.       end Prim;
     28.    end Inner;
     29.
     30.    function F (A : Integer) return Integer is
     31.       pragma Post (F'Result = 3);
               |
         >>> pragma "Post" must apply to subprogram specification

     32.    begin
     33.       return 2 * A;
     34.    end;
     35.    function F1 (A : Integer) return Integer is
     36.       pragma Post (F1'Result = 3); -- OK no spec
     37.    begin
     38.       return 2 * A;
     39.    end;
     40.    function Q (M : Integer) return Integer is
     41.    begin
     42.       return 42;
     43.    end;
     44. begin
     45.    null;
     46. end PostPrePragE;

Tested on x86_64-pc-linux-gnu, committed on trunk

2013-10-13  Robert Dewar  <dewar@adacore.com>

	* gnat_rm.texi: Add documentation for pragmas Pre[_Class]
	Post[_Class].
	* par-ch2.adb (Skip_Pragma_Semicolon): Handle extra semicolon nicely.
	* par-prag.adb: Add entries for pragmas Pre[_Class] and
	Post[_Class].
	* sem_prag.adb: Add handling of pragmas Pre[_Class] and
	Post[_Class].
	* sem_util.adb (Original_Aspect_Name): Moved here from
	Sem_Prag.Original_Name, and modified to handle pragmas
	Pre/Post/Pre_Class/Post_Class.
	* sem_util.ads (Original_Aspect_Name): Moved here from
	Sem_Prag.Original_Name.
	* snames.ads-tmpl: Add entries for pragmas Pre[_Class] and
	Post[_Class].
diff mbox

Patch

Index: gnat_rm.texi
===================================================================
--- gnat_rm.texi	(revision 203500)
+++ gnat_rm.texi	(working copy)
@@ -206,11 +206,15 @@ 
 * Pragma Passive::
 * Pragma Persistent_BSS::
 * Pragma Polling::
+* Pragma Post::
 * Pragma Postcondition::
+* Pragma Post_Class::
+* Pragma Pre::
 * Pragma Precondition::
 * Pragma Predicate::
 * Pragma Preelaborable_Initialization::
 * Pragma Preelaborate_05::
+* Pragma Pre_Class::
 * Pragma Priority_Specific_Dispatching::
 * Pragma Profile::
 * Pragma Profile_Warnings::
@@ -1022,11 +1026,15 @@ 
 * Pragma Passive::
 * Pragma Persistent_BSS::
 * Pragma Polling::
+* Pragma Post::
 * Pragma Postcondition::
+* Pragma Post_Class::
+* Pragma Pre::
 * Pragma Precondition::
 * Pragma Predicate::
 * Pragma Preelaborable_Initialization::
 * Pragma Preelaborate_05::
+* Pragma Pre_Class::
 * Pragma Priority_Specific_Dispatching::
 * Pragma Profile::
 * Pragma Profile_Warnings::
@@ -1393,7 +1401,10 @@ 
 The pragma applies in both cases to pragmas and aspects with matching
 names, e.g. @code{Pre} applies to the Pre aspect, and @code{Precondition}
 applies to both the @code{Precondition} pragma
-and the aspect @code{Precondition}.
+and the aspect @code{Precondition}. Note that the identifiers for
+pragmas Pre_Class and Post_Class are Pre'Class and Post'Class (not
+Pre_Class and Post_Class), since these pragmas are intended to be
+identical to the corresponding aspects).
 
 If the policy is @code{CHECK}, then assertions are enabled, i.e.
 the corresponding pragma or aspect is activated.
@@ -5016,6 +5027,28 @@ 
 @xref{Switches for gcc,,, gnat_ugn, @value{EDITION} User's Guide}, for
 details.
 
+@node Pragma Post
+@unnumberedsec Pragma Post
+@cindex Post
+@cindex Checks, postconditions
+@findex Postconditions
+@noindent
+Syntax:
+
+@smallexample @c ada
+pragma Post (Boolean_Expression);
+@end smallexample
+
+@noindent
+The @code{Post} pragma is intended to be an exact replacement for
+the language-defined
+@code{Post} aspect, and shares its restrictions and semantics.
+It must appear either immediately following the corresponding
+subprogram declaration (only other pragmas may intervene), or
+if there is no separate subprogram declaration, then it can
+appear at the start of the declarations in a subprogram body
+(preceded only by other pragmas).
+
 @node Pragma Postcondition
 @unnumberedsec Pragma Postcondition
 @cindex Postcondition
@@ -5173,6 +5206,69 @@ 
 by the compiler, but are ignored at run-time even if postcondition
 checking is enabled.
 
+Note that pragma @code{Postcondition} differs from the language-defined
+@code{Post} aspect (and corresponding @code{Post} pragma) in allowing
+multiple occurrences, allowing occurences in the body even if there
+is a separate spec, and allowing a second string parameter, and the
+use of the pragma identifier @code{Check}. Historically, pragma
+@code{Postcondition} was implemented prior to the development of
+Ada 2012, and has been retained in its original form for
+compatibility purposes.
+
+@node Pragma Post_Class
+@unnumberedsec Pragma Post_Class
+@cindex Post
+@cindex Checks, postconditions
+@findex Postconditions
+@noindent
+Syntax:
+
+@smallexample @c ada
+pragma Post_Class (Boolean_Expression);
+@end smallexample
+
+@noindent
+The @code{Post_Class} pragma is intended to be an exact replacement for
+the language-defined
+@code{Post'Class} aspect, and shares its restrictions and semantics.
+It must appear either immediately following the corresponding
+subprogram declaration (only other pragmas may intervene), or
+if there is no separate subprogram declaration, then it can
+appear at the start of the declarations in a subprogram body
+(preceded only by other pragmas).
+
+Note: This pragma is called @code{Post_Class} rather than
+@code{Post'Class} because the latter would not be strictly
+conforming to the allowed syntax for pragmas. The motivation
+for provinding pragmas equivalent to the aspects is to allow a program
+to be written using the pragmas, and then compiled if necessary
+using an Ada compiler that does not recognize the pragmas or
+aspects, but is prepared to ignore the pragmas. The assertion
+policy that controls this pragma is @code{Post'Class}, not
+@code{Post_Class}.
+
+@node Pragma Pre
+@unnumberedsec Pragma Pre
+@cindex Pre
+@cindex Checks, preconditions
+@findex Preconditions
+@noindent
+Syntax:
+
+@smallexample @c ada
+pragma Pre (Boolean_Expression);
+@end smallexample
+
+@noindent
+The @code{Pre} pragma is intended to be an exact replacement for
+the language-defined
+@code{Pre} aspect, and shares its restrictions and semantics.
+It must appear either immediately following the corresponding
+subprogram declaration (only other pragmas may intervene), or
+if there is no separate subprogram declaration, then it can
+appear at the start of the declarations in a subprogram body
+(preceded only by other pragmas).
+
 @node Pragma Precondition
 @unnumberedsec Pragma Precondition
 @cindex Preconditions
@@ -5221,6 +5317,15 @@ 
 by the compiler, but are ignored at run-time even if precondition
 checking is enabled.
 
+Note that pragma @code{Precondition} differs from the language-defined
+@code{Pre} aspect (and corresponding @code{Pre} pragma) in allowing
+multiple occurrences, allowing occurences in the body even if there
+is a separate spec, and allowing a second string parameter, and the
+use of the pragma identifier @code{Check}. Historically, pragma
+@code{Precondition} was implemented prior to the development of
+Ada 2012, and has been retained in its original form for
+compatibility purposes.
+
 @node Pragma Predicate
 @unnumberedsec Pragma Predicate
 @findex Predicate
@@ -5295,6 +5400,38 @@ 
 Ada versions. This is used to handle some cases where packages
 not previously preelaborable became so in Ada 2005.
 
+@node Pragma Pre_Class
+@unnumberedsec Pragma Pre_Class
+@cindex Pre_Class
+@cindex Checks, preconditions
+@findex Preconditions
+@noindent
+Syntax:
+
+@smallexample @c ada
+pragma Pre_Class (Boolean_Expression);
+@end smallexample
+
+@noindent
+The @code{Pre_Class} pragma is intended to be an exact replacement for
+the language-defined
+@code{Pre'Class} aspect, and shares its restrictions and semantics.
+It must appear either immediately following the corresponding
+subprogram declaration (only other pragmas may intervene), or
+if there is no separate subprogram declaration, then it can
+appear at the start of the declarations in a subprogram body
+(preceded only by other pragmas).
+
+Note: This pragma is called @code{Pre_Class} rather than
+@code{Pre'Class} because the latter would not be strictly
+conforming to the allowed syntax for pragmas. The motivation
+for providing pragmas equivalent to the aspects is to allow a program
+to be written using the pragmas, and then compiled if necessary
+using an Ada compiler that does not recognize the pragmas or
+aspects, but is prepared to ignore the pragmas. The assertion
+policy that controls this pragma is @code{Pre'Class}, not
+@code{Pre_Class}.
+
 @node Pragma Priority_Specific_Dispatching
 @unnumberedsec Pragma Priority_Specific_Dispatching
 @findex Priority_Specific_Dispatching
Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 203504)
+++ sem_prag.adb	(working copy)
@@ -236,16 +236,6 @@ 
    --  Get_SPARK_Mode_Id. Convert a name into a corresponding value of type
    --  SPARK_Mode_Id.
 
-   function Original_Name (N : Node_Id) return Name_Id;
-   --  N is a pragma node or aspect specification node. This function returns
-   --  the name of the pragma or aspect in original source form, taking into
-   --  account possible rewrites, and also cases where a pragma comes from an
-   --  aspect (in such cases, the name can be different from the pragma name,
-   --  e.g. a Pre aspect generates a Precondition pragma). This also deals with
-   --  the presence of 'Class, which results in one of the special names
-   --  Name_uPre, Name_uPost, Name_uInvariant, or Name_uType_Invariant being
-   --  returned to represent the corresponding aspects with x'Class names.
-
    procedure Preanalyze_CTC_Args (N, Arg_Req, Arg_Ens : Node_Id);
    --  Preanalyze the boolean expressions in the Requires and Ensures arguments
    --  of a Test_Case pragma if present (possibly Empty). We treat these as
@@ -1979,6 +1969,13 @@ 
       --  In this version of the procedure, the identifier name is given as
       --  a string with lower case letters.
 
+      procedure Check_Pre_Post;
+      --  Called to perform checks for Pre, Pre_Class, Post, Post_Class
+      --  pragmas. These are processed by transformation to equivalent
+      --  Precondition and Postcondition pragmas, but Pre and Post need an
+      --  additional check that they are not used in a subprogram body when
+      --  there is a separate spec present.
+
       procedure Check_Precondition_Postcondition (In_Body : out Boolean);
       --  Called to process a precondition or postcondition pragma. There are
       --  three cases:
@@ -3392,6 +3389,97 @@ 
          Check_Optional_Identifier (Arg, Name_Find);
       end Check_Optional_Identifier;
 
+      --------------------
+      -- Check_Pre_Post --
+      --------------------
+
+      procedure Check_Pre_Post is
+         P  : Node_Id;
+         PO : Node_Id;
+
+      begin
+         if not Is_List_Member (N) then
+            Pragma_Misplaced;
+         end if;
+
+         --  If we are within an inlined body, the legality of the pragma
+         --  has been checked already.
+
+         if In_Inlined_Body then
+            return;
+         end if;
+
+         --  Search prior declarations
+
+         P := N;
+         while Present (Prev (P)) loop
+            P := Prev (P);
+
+            --  If the previous node is a generic subprogram, do not go to to
+            --  the original node, which is the unanalyzed tree: we need to
+            --  attach the pre/postconditions to the analyzed version at this
+            --  point. They get propagated to the original tree when analyzing
+            --  the corresponding body.
+
+            if Nkind (P) not in N_Generic_Declaration then
+               PO := Original_Node (P);
+            else
+               PO := P;
+            end if;
+
+            --  Skip past prior pragma
+
+            if Nkind (PO) = N_Pragma then
+               null;
+
+            --  Skip stuff not coming from source
+
+            elsif not Comes_From_Source (PO) then
+
+               --  The condition may apply to a subprogram instantiation
+
+               if Nkind (PO) = N_Subprogram_Declaration
+                 and then Present (Generic_Parent (Specification (PO)))
+               then
+                  return;
+
+               elsif Nkind (PO) = N_Subprogram_Declaration
+                 and then In_Instance
+               then
+                  return;
+
+               --  For all other cases of non source code, do nothing
+
+               else
+                  null;
+               end if;
+
+            --  Only remaining possibility is subprogram declaration
+
+            else
+               return;
+            end if;
+         end loop;
+
+         --  If we fall through loop, pragma is at start of list, so see if it
+         --  is at the start of declarations of a subprogram body.
+
+         PO := Parent (N);
+
+         if Nkind (PO) = N_Subprogram_Body
+           and then List_Containing (N) = Declarations (PO)
+         then
+            --  This is only allowed if there is no separate specification
+
+            if Present (Corresponding_Spec (PO)) then
+               Error_Pragma
+                 ("pragma% must apply to subprogram specification");
+            end if;
+
+            return;
+         end if;
+      end Check_Pre_Post;
+
       --------------------------------------
       -- Check_Precondition_Postcondition --
       --------------------------------------
@@ -3431,7 +3519,7 @@ 
             --  compatibility with earlier uses of the Ada pragma, apply this
             --  rule only to aspect specifications.
 
-            --  The above discrpency needs documentation. Robert is dubious
+            --  The above discrepency needs documentation. Robert is dubious
             --  about whether it is a good idea ???
 
             elsif Nkind (PO) = N_Subprogram_Declaration
@@ -4286,7 +4374,7 @@ 
 
             --  Get name from corresponding aspect
 
-            Error_Msg_Name_1 := Original_Name (N);
+            Error_Msg_Name_1 := Original_Aspect_Name (N);
          end if;
       end Fix_Error;
 
@@ -8180,7 +8268,7 @@ 
       --  Here to start processing for recognized pragma
 
       Prag_Id := Get_Pragma_Id (Pname);
-      Pname := Original_Name (N);
+      Pname := Original_Aspect_Name (N);
 
       --  Check applicable policy. We skip this if Is_Checked or Is_Ignored
       --  is already set, indicating that we have already checked the policy
@@ -15056,6 +15144,32 @@ 
             Check_Arg_Is_One_Of (Arg1, Name_On, Name_Off);
             Polling_Required := (Chars (Get_Pragma_Arg (Arg1)) = Name_On);
 
+         ------------------
+         -- Post[_Class] --
+         ------------------
+
+         --  pragma Post (Boolean_EXPRESSION);
+         --  pragma Post_Class (Boolean_EXPRESSION);
+
+         when Pragma_Post | Pragma_Post_Class => Post : declare
+            PC_Pragma : Node_Id;
+
+         begin
+            GNAT_Pragma;
+            Check_At_Least_N_Arguments (1);
+            Check_At_Most_N_Arguments (1);
+            Check_No_Identifiers;
+            Check_Pre_Post;
+
+            Set_Class_Present (N, Prag_Id = Pragma_Pre_Class);
+            PC_Pragma := New_Copy (N);
+            Set_Pragma_Identifier
+              (PC_Pragma, Make_Identifier (Loc, Name_Postcondition));
+            Rewrite (N, PC_Pragma);
+            Set_Analyzed (N, False);
+            Analyze (N);
+         end Post;
+
          -------------------
          -- Postcondition --
          -------------------
@@ -15090,6 +15204,32 @@ 
             end if;
          end Postcondition;
 
+         -----------------
+         -- Pre[_Class] --
+         -----------------
+
+         --  pragma Pre (Boolean_EXPRESSION);
+         --  pragma Pre_Class (Boolean_EXPRESSION);
+
+         when Pragma_Pre | Pragma_Pre_Class => Pre : declare
+            PC_Pragma : Node_Id;
+
+         begin
+            GNAT_Pragma;
+            Check_At_Least_N_Arguments (1);
+            Check_At_Most_N_Arguments (1);
+            Check_No_Identifiers;
+            Check_Pre_Post;
+
+            Set_Class_Present (N, Prag_Id = Pragma_Pre_Class);
+            PC_Pragma := New_Copy (N);
+            Set_Pragma_Identifier
+              (PC_Pragma, Make_Identifier (Loc, Name_Precondition));
+            Rewrite (N, PC_Pragma);
+            Set_Analyzed (N, False);
+            Analyze (N);
+         end Pre;
+
          ------------------
          -- Precondition --
          ------------------
@@ -18405,6 +18545,7 @@ 
       Subp_Id : Entity_Id)
    is
       Arg1 : constant Node_Id := First (Pragma_Argument_Associations (Prag));
+      Nam  : constant Name_Id := Original_Aspect_Name (Prag);
       Expr : Node_Id;
 
       Restore_Scope : Boolean := False;
@@ -18540,14 +18681,37 @@ 
 
          begin
             if not Present (T) then
-               Error_Msg_Name_1 :=
-                 Chars (Identifier (Corresponding_Aspect (Prag)));
 
-               Error_Msg_Name_2 := Name_Class;
+               --  Pre'Class/Post'Class aspect cases
 
-               Error_Msg_N
-                 ("aspect `%''%` can only be specified for a primitive "
-                  & "operation of a tagged type", Corresponding_Aspect (Prag));
+               if From_Aspect_Specification (Prag) then
+                  if Nam = Name_uPre then
+                     Error_Msg_Name_1 := Name_Pre;
+                  else
+                     Error_Msg_Name_1 := Name_Post;
+                  end if;
+
+                  Error_Msg_Name_2 := Name_Class;
+
+                  Error_Msg_N
+                    ("aspect `%''%` can only be specified for a primitive "
+                     & "operation of a tagged type",
+                     Corresponding_Aspect (Prag));
+
+               --  Pre_Class, Post_Class pragma cases
+
+               else
+                  if Nam = Name_uPre then
+                     Error_Msg_Name_1 := Name_Pre_Class;
+                  else
+                     Error_Msg_Name_1 := Name_Post_Class;
+                  end if;
+
+                  Error_Msg_N
+                    ("pragma% can only be specified for a primitive "
+                     & "operation of a tagged type",
+                     Corresponding_Aspect (Prag));
+               end if;
             end if;
 
             Replace_Type (Get_Pragma_Arg (Arg1));
@@ -20073,7 +20237,7 @@ 
       PP     : Node_Id;
       Policy : Name_Id;
 
-      Ename : constant Name_Id := Original_Name (N);
+      Ename : constant Name_Id := Original_Aspect_Name (N);
 
    begin
       --  No effect if not valid assertion kind name
@@ -20686,12 +20850,16 @@ 
       Pragma_Passive                        => -1,
       Pragma_Persistent_BSS                 =>  0,
       Pragma_Polling                        => -1,
+      Pragma_Post                           => -1,
       Pragma_Postcondition                  => -1,
+      Pragma_Post_Class                     => -1,
+      Pragma_Pre                            => -1,
       Pragma_Precondition                   => -1,
       Pragma_Predicate                      => -1,
       Pragma_Preelaborable_Initialization   => -1,
       Pragma_Preelaborate                   => -1,
       Pragma_Preelaborate_05                => -1,
+      Pragma_Pre_Class                      => -1,
       Pragma_Priority                       => -1,
       Pragma_Priority_Specific_Dispatching  => -1,
       Pragma_Profile                        =>  0,
@@ -21023,66 +21191,6 @@ 
       end if;
    end Make_Aspect_For_PPC_In_Gen_Sub_Decl;
 
-   -------------------
-   -- Original_Name --
-   -------------------
-
-   function Original_Name (N : Node_Id) return Name_Id is
-      Pras : Node_Id;
-      Name : Name_Id;
-
-   begin
-      pragma Assert (Nkind_In (N, N_Aspect_Specification, N_Pragma));
-      Pras := N;
-
-      if Is_Rewrite_Substitution (Pras)
-        and then Nkind (Original_Node (Pras)) = N_Pragma
-      then
-         Pras := Original_Node (Pras);
-      end if;
-
-      --  Case where we came from aspect specication
-
-      if Nkind (Pras) = N_Pragma and then From_Aspect_Specification (Pras) then
-         Pras := Corresponding_Aspect (Pras);
-      end if;
-
-      --  Get name from aspect or pragma
-
-      if Nkind (Pras) = N_Pragma then
-         Name := Pragma_Name (Pras);
-      else
-         Name := Chars (Identifier (Pras));
-      end if;
-
-      --  Deal with 'Class
-
-      if Class_Present (Pras) then
-         case Name is
-
-         --  Names that need converting to special _xxx form
-
-            when Name_Pre             => Name := Name_uPre;
-            when Name_Post            => Name := Name_uPost;
-            when Name_Invariant       => Name := Name_uInvariant;
-            when Name_Type_Invariant  => Name := Name_uType_Invariant;
-
-               --  Names already in special _xxx form (leave them alone)
-
-            when Name_uPre            => null;
-            when Name_uPost           => null;
-            when Name_uInvariant      => null;
-            when Name_uType_Invariant => null;
-
-               --  Anything else is impossible with Class_Present set True
-
-            when others               => raise Program_Error;
-         end case;
-      end if;
-
-      return Name;
-   end Original_Name;
-
    -------------------------
    -- Preanalyze_CTC_Args --
    -------------------------
Index: par-ch2.adb
===================================================================
--- par-ch2.adb	(revision 203500)
+++ par-ch2.adb	(working copy)
@@ -250,23 +250,15 @@ 
 
       procedure Skip_Pragma_Semicolon is
       begin
-         if Token /= Tok_Semicolon then
+         --  If skipping the pragma, ignore a missing semicolon
 
-            --  If skipping the pragma, ignore a missing semicolon
+         if Token /= Tok_Semicolon and then Skipping then
+            null;
 
-            if Skipping then
-               null;
+         --  Otherwise demand a semicolon
 
-            --  Otherwise demand a semicolon
-
-            else
-               T_Semicolon;
-            end if;
-
-         --  Scan past semicolon if present
-
          else
-            Scan;
+            T_Semicolon;
          end if;
       end Skip_Pragma_Semicolon;
 
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 203504)
+++ sem_util.adb	(working copy)
@@ -215,6 +215,7 @@ 
    procedure Add_Contract_Item (Prag : Node_Id; Subp_Id : Entity_Id) is
       Items : constant Node_Id := Contract (Subp_Id);
       Nam   : Name_Id;
+      N     : Node_Id;
 
    begin
       --  The related subprogram [body] must have a contract and the item to be
@@ -223,7 +224,7 @@ 
       pragma Assert (Present (Items));
       pragma Assert (Nkind (Prag) = N_Pragma);
 
-      Nam := Pragma_Name (Prag);
+      Nam := Original_Aspect_Name (Prag);
 
       --  Contract items related to subprogram bodies
 
@@ -241,7 +242,41 @@ 
       --  Contract items related to subprogram declarations
 
       else
-         if Nam_In (Nam, Name_Precondition, Name_Postcondition) then
+         if Nam_In (Nam, Name_Precondition,
+                         Name_Postcondition,
+                         Name_Pre,
+                         Name_Post,
+                         Name_uPre,
+                         Name_uPost)
+         then
+            --  Before we add a precondition or postcondition to the list,
+            --  make sure we do not have a disallowed duplicate, which can
+            --  happen if we use a pragma for Pre{_Class] or Post[_Class]
+            --  instead of the corresponding aspect.
+
+            if not From_Aspect_Specification (Prag)
+              and then Nam_In (Nam, Name_Pre_Class,
+                                    Name_Pre,
+                                    Name_uPre,
+                                    Name_Post_Class,
+                                    Name_Post,
+                                    Name_uPost)
+            then
+               N := Pre_Post_Conditions (Items);
+               while Present (N) loop
+                  if not Split_PPC (N)
+                    and then Original_Aspect_Name (N) = Nam
+                  then
+                     Error_Msg_Sloc := Sloc (N);
+                     Error_Msg_NE
+                       ("duplication of aspect for & given#", Prag, Subp_Id);
+                     return;
+                  else
+                     N := Next_Pragma (N);
+                  end if;
+               end loop;
+            end if;
+
             Set_Next_Pragma (Prag, Pre_Post_Conditions (Items));
             Set_Pre_Post_Conditions (Items, Prag);
 
@@ -4411,7 +4446,6 @@ 
 
    procedure Ensure_Freeze_Node (E : Entity_Id) is
       FN : Node_Id;
-
    begin
       if No (Freeze_Node (E)) then
          FN := Make_Freeze_Entity (Sloc (E));
@@ -4704,9 +4738,14 @@ 
       --  Inherited discriminants and components in derived record types are
       --  immediately visible. Itypes are not.
 
+      --  Unless the Itype is for a record type with a corresponding remote
+      --  type (what is that about, it was not commented ???)
+
       if Ekind_In (Def_Id, E_Discriminant, E_Component)
-        or else (No (Corresponding_Remote_Type (Def_Id))
-                 and then not Is_Itype (Def_Id))
+        or else
+          ((not Is_Record_Type (Def_Id)
+             or else No (Corresponding_Remote_Type (Def_Id)))
+            and then not Is_Itype (Def_Id))
       then
          Set_Is_Immediately_Visible (Def_Id);
          Set_Current_Entity         (Def_Id);
@@ -12833,6 +12872,71 @@ 
       end if;
    end Object_Access_Level;
 
+   --------------------------
+   -- Original_Aspect_Name --
+   --------------------------
+
+   function Original_Aspect_Name (N : Node_Id) return Name_Id is
+      Pras : Node_Id;
+      Name : Name_Id;
+
+   begin
+      pragma Assert (Nkind_In (N, N_Aspect_Specification, N_Pragma));
+      Pras := N;
+
+      if Is_Rewrite_Substitution (Pras)
+        and then Nkind (Original_Node (Pras)) = N_Pragma
+      then
+         Pras := Original_Node (Pras);
+      end if;
+
+      --  Case where we came from aspect specication
+
+      if Nkind (Pras) = N_Pragma and then From_Aspect_Specification (Pras) then
+         Pras := Corresponding_Aspect (Pras);
+      end if;
+
+      --  Get name from aspect or pragma
+
+      if Nkind (Pras) = N_Pragma then
+         Name := Pragma_Name (Pras);
+      else
+         Name := Chars (Identifier (Pras));
+      end if;
+
+      --  Deal with 'Class
+
+      if Class_Present (Pras) then
+         case Name is
+
+         --  Names that need converting to special _xxx form
+
+            when Name_Pre                  |
+                 Name_Pre_Class            =>
+               Name := Name_uPre;
+
+            when Name_Post                 |
+                 Name_Post_Class           =>
+               Name := Name_uPost;
+
+            when Name_Invariant            =>
+               Name := Name_uInvariant;
+
+            when Name_Type_Invariant       |
+                 Name_Type_Invariant_Class =>
+               Name := Name_uType_Invariant;
+
+            --  Nothing to do for other cases (e.g. a Check that derived
+            --  from Pre_Class and has the flag set). Also we do nothing
+            --  if the name is already in special _xxx form.
+
+            when others                    =>
+               null;
+         end case;
+      end if;
+
+      return Name;
+   end Original_Aspect_Name;
    --------------------------------------
    -- Original_Corresponding_Operation --
    --------------------------------------
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 203504)
+++ sem_util.ads	(working copy)
@@ -1365,6 +1365,16 @@ 
    --  convenience, qualified expressions applied to object names are also
    --  allowed as actuals for this function.
 
+   function Original_Aspect_Name (N : Node_Id) return Name_Id;
+   --  N is a pragma node or aspect specification node. This function returns
+   --  the name of the pragma or aspect in original source form, taking into
+   --  account possible rewrites, and also cases where a pragma comes from an
+   --  aspect (in such cases, the name can be different from the pragma name,
+   --  e.g. a Pre aspect generates a Precondition pragma). This also deals with
+   --  the presence of 'Class, which results in one of the special names
+   --  Name_uPre, Name_uPost, Name_uInvariant, or Name_uType_Invariant being
+   --  returned to represent the corresponding aspects with x'Class names.
+
    function Primitive_Names_Match (E1, E2 : Entity_Id) return Boolean;
    --  Returns True if the names of both entities correspond with matching
    --  primitives. This routine includes support for the case in which one
Index: par-prag.adb
===================================================================
--- par-prag.adb	(revision 203500)
+++ par-prag.adb	(working copy)
@@ -1234,11 +1234,15 @@ 
            Pragma_Preelaborable_Initialization   |
            Pragma_Polling                        |
            Pragma_Persistent_BSS                 |
+           Pragma_Post                           |
            Pragma_Postcondition                  |
+           Pragma_Post_Class                     |
+           Pragma_Pre                            |
            Pragma_Precondition                   |
            Pragma_Predicate                      |
            Pragma_Preelaborate                   |
            Pragma_Preelaborate_05                |
+           Pragma_Pre_Class                      |
            Pragma_Priority                       |
            Pragma_Priority_Specific_Dispatching  |
            Pragma_Profile                        |
Index: snames.ads-tmpl
===================================================================
--- snames.ads-tmpl	(revision 203500)
+++ snames.ads-tmpl	(working copy)
@@ -142,11 +142,10 @@ 
    Name_Dimension                      : constant Name_Id := N + $;
    Name_Dimension_System               : constant Name_Id := N + $;
    Name_Dynamic_Predicate              : constant Name_Id := N + $;
-   Name_Post                           : constant Name_Id := N + $;
-   Name_Pre                            : constant Name_Id := N + $;
    Name_Static_Predicate               : constant Name_Id := N + $;
    Name_Synchronization                : constant Name_Id := N + $;
    Name_Type_Invariant                 : constant Name_Id := N + $;
+   Name_Type_Invariant_Class           : constant Name_Id := N + $;
 
    --  Some special names used by the expander. Note that the lower case u's
    --  at the start of these names get translated to extra underscores. These
@@ -562,12 +561,16 @@ 
    Name_Pack                           : constant Name_Id := N + $;
    Name_Page                           : constant Name_Id := N + $;
    Name_Passive                        : constant Name_Id := N + $; -- GNAT
+   Name_Post                           : constant Name_Id := N + $; -- GNAT
    Name_Postcondition                  : constant Name_Id := N + $; -- GNAT
+   Name_Post_Class                     : constant Name_Id := N + $; -- GNAT
+   Name_Pre                            : constant Name_Id := N + $; -- GNAT
    Name_Precondition                   : constant Name_Id := N + $; -- GNAT
    Name_Predicate                      : constant Name_Id := N + $; -- GNAT
    Name_Preelaborable_Initialization   : constant Name_Id := N + $; -- Ada 05
    Name_Preelaborate                   : constant Name_Id := N + $;
    Name_Preelaborate_05                : constant Name_Id := N + $; -- GNAT
+   Name_Pre_Class                      : constant Name_Id := N + $; -- GNAT
 
    --  Note: Priority is not in this list because its name matches the name of
    --  the corresponding attribute. However, it is included in the definition
@@ -1860,12 +1863,16 @@ 
       Pragma_Pack,
       Pragma_Page,
       Pragma_Passive,
+      Pragma_Post,
       Pragma_Postcondition,
+      Pragma_Post_Class,
+      Pragma_Pre,
       Pragma_Precondition,
       Pragma_Predicate,
       Pragma_Preelaborable_Initialization,
       Pragma_Preelaborate,
       Pragma_Preelaborate_05,
+      Pragma_Pre_Class,
       Pragma_Psect_Object,
       Pragma_Pure,
       Pragma_Pure_05,