diff mbox

[Ada] Volatile functions

Message ID 20151020104416.GA17166@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Oct. 20, 2015, 10:44 a.m. UTC
This patch implements SPARK volatile functions described by the following
rules:

   A type is said to be effectively volatile if it is either a volatile
   type, an array type whose Volatile_Component aspect is True, or an
   array type whose component type is effectively volatile, a protected
   type, or a descendant of Ada.Synchronous_Task_Control.Suspension_Object.
   An effectively volatile object is a volatile object or an object of an
   effectively volatile type.

   The Boolean aspect Volatile_Function may be specified as part of
   the (explicit) initial declaration of a function. A function whose
   Volatile_Function aspect is True is said to be a volatile function.
   A protected function is also defined to be a volatile function.

   A subprogram whose Volatile_Function aspect is True shall not override an
   inherited primitive operation of a tagged type whose Volatile_Function
   aspect is False.

   A global_item of a nonvolatile function shall not denote either an
   effectively volatile object or an external state abstraction.

   A nonvolatile function shall not have a formal parameter (or result) of an
   effectively volatile type.

   Contrary to the general SPARK 2014 rule that expression evaluation cannot
   have side effects, a read of an effectively volatile object with the
   properties Async_Writers or Effective_Reads set to True is considered to
   have an effect when read. To reconcile this discrepancy, a name denoting
   such an object shall only occur in a non-interfering context. A name occurs
   in a non-interfering context if it is:

      the (protected) prefix of a name denoting a protected operation; or

      the return expression of a simple_return_statement which applies to a
      volatile function; or

      the initial value expression of the extended_return_object_declaration
      of an extended_return_statement which applies to a volatile function; or

The patch also changes the implementation of aspects/pragmas Async_Readers,
Async_Writers, Effective_Reads and Effective_Writes to remove their forward
referencing capabilities and require a static Boolean expression (if any).

------------
-- Source --
------------

--  volatile types.ads

with Ada.Synchronous_Task_Control; use Ada.Synchronous_Task_Control;

package Volatile_Types is
   type Vol_Typ_1 is null record with Volatile;
   type Vol_Typ_1_Ptr is access all Vol_Typ_1;

   type Vol_Typ_2 is array (1 .. 5) of Vol_Typ_1;

   type Vol_Typ_3 is array (1 .. 5) of Boolean with Volatile_Components;

   protected type Vol_Typ_4 is
      entry E;
      procedure P;
   end Vol_Typ_4;

   type Vol_Typ_5 is new Suspension_Object;
end Volatile_Types;

--  volatile types.adb

package body Volatile_Types is
   protected body Vol_Typ_4 is
      entry E when True is begin null; end E;
      procedure P is begin null; end P;
   end Vol_Typ_4;
end Volatile_Types;

--  lr712.ads

package LR712 is

   --  7.1.2 - The Boolean aspect Volatile_Function may be specified as part of
   --  the initial declaration of a function. Function whose Volatile_Function
   --  aspect is True is said to be a volatile function. A protected function
   --  is also defined to be a volatile function.

   function OK_1 return Boolean with Volatile_Function;              --  OK
   function OK_2 return Boolean is (True) with Volatile_Function;    --  OK
   function OK_3 return Boolean;
   pragma Volatile_Function;                                         --  OK

   function Error_1 return Boolean;
   function Error_2 return Boolean;
   function Error_3 return Boolean;
   function Error_4 return Boolean;
   function Error_4 return Boolean is (True)
     with Volatile_Function;                                         --  Error
   function Error_5 return Boolean
     with Volatile_Function => Junk;                                 --  Error
   function Error_6 return Boolean
     with Volatile_Function => "Junk";                               --  Error
   function Error_7 return Boolean;

   Obj : Integer := 1 with Volatile_Function;                        --  Error
end LR712;

--  lr712.adb

ckage body LR712 is
   function OK_1 return Boolean is begin return True; end OK_1;
   function OK_3 return Boolean is begin return True; end OK_3;

   function Error_1 return Boolean
     with Volatile_Function                                          --  Error
   is begin return True; end Error_1;
   function Error_2 return Boolean is (True) with Volatile_Function; --  Error
   function Error_3 return Boolean is separate;
   function Error_5 return Boolean is begin return True; end Error_5;
   function Error_6 return Boolean is begin return True; end Error_6;
   function Error_7 return Boolean is
      pragma Volatile_Function;                                      --  Error
   begin return True; end Error_7;
end LR712;

--  lr712-error_3.adb

separate (LR712)

function Error_3 return Boolean
  with Volatile_Function                                             --  Error
is begin return True; end Error_3;

--  lr71215.ads

package LR71215 is

   --  7.1.2(15) - A subprogram whose Volatile_Function aspect is True shall
   --  not override an inherited primitive operation of a tagged type whose
   --  Volatile_Function aspect is False.

   type Parent_Type is tagged null record;
   function Func_1 (Obj : Parent_Type) return Boolean;
   function Func_2 (Obj : Parent_Type) return Boolean
     with Volatile_Function;

   type Child_Type is new Parent_Type with null record;
   function Func_1 (Obj : Child_Type) return Boolean
     with Volatile_Function;                                         --  Error
   function Func_2 (Obj : Child_Type) return Boolean;                --  OK
end LR71215;

--  lr7138.ads

with Volatile_Types; use Volatile_Types;

package LR7138
  with SPARK_Mode,
       Abstract_State => (External_State with External)
is
   --  71.3(8) - A global_item of a nonvolatile function shall not denote
   --  either an effectively volatile object or an external state abstraction.

   Obj_1 : Vol_Typ_1 with Async_Readers;
   Obj_2 : Vol_Typ_2 with Async_Readers;
   Obj_3 : Vol_Typ_3 with Async_Readers;
   Obj_4 : Vol_Typ_4 with Async_Readers;
   Obj_5 : Vol_Typ_5 with Async_Readers;

   function OK return Boolean
     with Global =>
            (Input =>
              (External_State, Obj_1, Obj_2, Obj_3, Obj_4, Obj_5)),  --  all OK
          Volatile_Function;

   function Error return Boolean
     with Global => (Input => (External_State,                       --  Error
                               Obj_1,                                --  Error
                               Obj_2,                                --  Error
                               Obj_3,                                --  Error
                               Obj_4,                                --  Error
                               Obj_5));                              --  Error
end LR7138;

--  lr7139.ads

with Volatile_Types; use Volatile_Types;

package LR7139 with SPARK_Mode is

   --  7.1.3(9) - A nonvolatile function shall not have a formal parameter (or
   --  result) of an effectively volatile type.

   function OK_1 return Vol_Typ_1 with Volatile_Function;            --  OK
   function OK_2 return Vol_Typ_2 with Volatile_Function;            --  OK
   function OK_3 return Vol_Typ_3 with Volatile_Function;            --  OK
   function OK_4 return Vol_Typ_4 with Volatile_Function;            --  OK
   function OK_5 return Vol_Typ_5 with Volatile_Function;            --  OK
   function OK_6
     (Formal_1 : Vol_Typ_1;                                          --  OK
      Formal_2 : Vol_Typ_2;                                          --  OK
      Formal_3 : Vol_Typ_3;                                          --  OK
      Formal_4 : Vol_Typ_4;                                          --  OK
      Formal_5 : Vol_Typ_5) return Boolean                           --  OK
   with Volatile_Function;

   function Error_1 return Vol_Typ_1;                                --  Error
   function Error_2 return Vol_Typ_2;                                --  Error
   function Error_3 return Vol_Typ_3;                                --  Error
   function Error_4 return Vol_Typ_4;                                --  Error
   function Error_5 return Vol_Typ_5;                                --  Error
   function Error_6
     (Formal_1 : Vol_Typ_1;                                          --  Error
      Formal_2 : Vol_Typ_2;                                          --  Error
      Formal_3 : Vol_Typ_3;                                          --  Error
      Formal_4 : Vol_Typ_4;                                          --  Error
      Formal_5 : Vol_Typ_5) return Boolean;                          --  Error
end LR7139;

--  lr71312.ads

package LR71312 with SPARK_Mode is

   --  7.1.3(12) - Contrary to the general SPARK 2014 rule that expression
   --  evaluation cannot have side effects, a read of an effectively volatile
   --  object with the properties Async_Writers or Effective_Reads set to True
   --  is considered to have an effect when read. To reconcile this discrepancy
   --  a name denoting such an object shall only occur in a non-interfering
   --  context. A name occurs in a non-interfering context if it is:

   --    the (protected) prefix of a name denoting a protected operation

   --    the return expression of a simple_return_statement which applies to a
   --    volatile function

   --    the initial value expression of the extended_return_object_declaration
   --    of an extended_return_statement which applies to a volatile function

   function OK_1 return Integer with Volatile_Function;
   function OK_2 return Integer with Volatile_Function;
   procedure OK_3;

   function Error_1 return Integer;
   function Error_2 return Integer;
   procedure Error_3;
end LR71312;

--  lr71312.adb

with Volatile_Types; use Volatile_Types;

package body LR71312 with SPARK_Mode is
   Obj_1 : Integer with Async_Writers, Volatile;
   Obj_2 : Vol_Typ_4;

   function OK_1 return Integer is
   begin
      return Obj_1;                                                  --  OK
   end OK_1;

   function OK_2 return Integer is
   begin
      return Result : Integer := Obj_1;                              --  OK
   end OK_2;

   procedure OK_3 is
   begin
      Obj_2.E;                                                       --  OK
      Obj_2.P;                                                       --  OK
   end OK_3;

   function Error_1 return Integer is
   begin
      return Obj_1;                                                  --  Error
   end Error_1;

   function Error_2 return Integer is
   begin
      return Result : Integer := Obj_1;                              --  Error
   end Error_2;

   procedure Error_3 is
   begin
      if Obj_2 in Vol_Typ_4 then                                     --  Error
         null;
      end if;
   end Error_3;
end LR71312;

----------------------------
-- Compilation and output --
----------------------------

$ gcc -c lr712.adb
$ gcc -c lr71215.ads
$ gcc -c lr7138.ads
$ gcc -c lr7139.ads
$ gcc -c lr71312.adb
lr712.adb:6:11: aspect specification must appear in subprogram declaration
lr712.adb:8:51: aspect specification must appear in subprogram declaration
lr712.adb:13:07: incorrect placement of pragma "VOLATILE_FUNCTION"
lr712.ads:18:11: aspect specification must appear in subprogram declaration
lr712.ads:20:32: "Junk" is undefined
lr712.ads:22:32: expected type "Standard.Boolean"
lr712.ads:22:32: found a string type
lr712.ads:25:28: incorrect placement of aspect "VOLATILE_FUNCTION"
lr712-error_3.adb:4:08: aspect specification must appear in subprogram
  declaration
lr71215.ads:13:13: incompatible volatile function values in effect
lr71215.ads:13:13: "Func_1" declared at line 8 with Volatile_Function value
  "False"
lr71215.ads:13:13: overridden at line 13 with Volatile_Function value "True"
lr7138.ads:23:32: external state "External_State" cannot act as global item of
  nonvolatile function
lr7138.ads:24:32: volatile object "Obj_1" cannot act as global item of a
  function
lr7138.ads:25:32: volatile object "Obj_2" cannot act as global item of a
  function
lr7138.ads:26:32: volatile object "Obj_3" cannot act as global item of a
  function
lr7138.ads:27:32: volatile object "Obj_4" cannot act as global item of a
  function
lr7138.ads:28:32: volatile object "Obj_5" cannot act as global item of a
  function
lr7139.ads:21:13: nonvolatile function "Error_1" cannot have a volatile return
  type
lr7139.ads:22:13: nonvolatile function "Error_2" cannot have a volatile return
  type
lr7139.ads:23:13: nonvolatile function "Error_3" cannot have a volatile return
  type
lr7139.ads:24:13: nonvolatile function "Error_4" cannot have a volatile return
  type
lr7139.ads:25:13: nonvolatile function "Error_5" cannot have a volatile return
  type
lr7139.ads:27:07: nonvolatile function "Error_6" cannot have a volatile
  parameter
lr7139.ads:28:07: nonvolatile function "Error_6" cannot have a volatile
  parameter
lr7139.ads:29:07: nonvolatile function "Error_6" cannot have a volatile
  parameter
lr7139.ads:30:07: nonvolatile function "Error_6" cannot have a volatile
  parameter
lr7139.ads:31:07: nonvolatile function "Error_6" cannot have a volatile
  parameter
lr71312.adb:25:14: volatile object cannot appear in this context (SPARK RM
  7.1.3(12))
lr71312.adb:30:34: volatile object cannot appear in this context (SPARK RM
  7.1.3(12))
lr71312.adb:35:10: volatile object cannot appear in this context (SPARK RM
  7.1.3(12))

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

2015-10-20  Hristian Kirtchev  <kirtchev@adacore.com>

	* aspects.adb Add aspect Volatile_Function to table
	Canonical_Aspect.
	* aspect.ads Add aspect Volatile_Function to tables
	Aspect_Argument, Aspect_Delay, Aspect_Id, Aspect_Names
	and Implementation_Defined_Aspect.  Aspects Async_Readers,
	Async_Writers, Effective_Reads and Effective_Writes are no
	longer Boolean.
	* einfo.adb (Get_Pragma): Add an entry for pragma
	Volatile_Function.
	* par-prag.adb (Prag): Pragma Volatile_Function does not need
	special processing by the parser.
	* rtsfind.ads Add an entry for Ada.Synchronous_Task_Control in
	table RTU_Id. Add an entry for Suspension_Object in table RE_Id.
	* sem_ch3.adb Fix SPARK RM references.
	(Analyze_Object_Contract): Update the error guard.
	* sem_ch5.adb Fix SPARK RM references.
	* sem_ch6.adb (Analyze_Subprogram_Body_Contract): Ensure
	that a non-volatile function does not contain an effectively
	volatile parameter.
	(Analyze_Subprogram_Contract): Ensure
	that a non-volatile function does not contain an effectively
	volatile parameter.
	* sem_ch12.adb (Instantiate_Object): Remove the reference to
	the SPARK RM from the error message.
	* sem_ch13.adb (Analyze_Aspect_Specifications): Add
	processing for aspects Async_Readers, Async_Writers,
	Effective_Reads, Effective_Writes and Volatile_Function.
	(Check_Aspect_At_Freeze_Point): Aspects Async_Readers,
	Async_Writers, Effective_Reads, Effective_Writes and
	Volatile_Function do not need special processing at the freeze
	point.
	* sem_prag.adb Add an entry for pragma Volatile_Function in
	table Sig_Flags.
	(Analyze_External_Property_In_Decl_Part):
	Reimplemented as Async_Readers, Async_Writers, Effective_Reads
	and Effective_Writes are no longer Boolean pragmas.
	(Analyze_Global_Item): An external state or effectively
	volatile object cannot appear as an item in pragma
	[Refined_]Global.
	(Analyze_Pragma): Change the implementation
	of Async_Readers, Async_Writers, Effective_Reads and
	Effective_Writes as these are no longer Boolean pragmas.
	Use routine Check_Static_Boolean_Expression to verify the
	optional Boolean expression of Async_Readers, Async_Writers,
	Constant_After_Elaboration, Effective_Reads, Effective_Writes,
	Extensions_Visible and Volatile_Function.  Add processing for
	pragma Volatile_Function.
	(Check_Static_Boolean_Expression): New routine.
	(Find_Related_Context): Update the comment on usage.
	(Is_Enabled_Pragma): New routine.
	* sem_prag.ads (Is_Enabled_Pragma): New routine.
	* sem_res.adb Fix SPARK RM references.
	(Is_OK_Volatile_Context): Add detection for return statements.
	(Resolve_Actuals): Remove the check concerning an effectively volatile
	OUT actual parameter as this is now done by the SPARK flow analyzer.
	(Resolve_Entity_Name): Remove the check concerning an effectively
	volatile OUT formal parameter as this is now done by the SPARK
	flow analyzer.	(Within_Volatile_Function): New routine.
	* sem_util.adb (Add_Contract_Item): Add processing for pragma
	Volatile_Function.
	(Check_Nonvolatile_Function_Profile): New routine.
	(Is_Descendant_Of_Suspension_Object): New routine.
	(Is_Effectively_Volatile): Protected types and descendants of
	Suspension_Object are now treated as effectively volatile.
	(Is_Enabled): The optional Boolean expression of pragmas
	Async_Readers, Async_Writers, Effective_Reads and Effective_Writes
	now appears as the first argument.
	(Is_Volatile_Function): New routine.
	* sem_util.ads Add SPARK RM references.
	(Add_Contract_Item): Update the comment on usage.
	(Check_Nonvolatile_Function_Profile): New routine.
	(Is_Effectively_Volatile): Update the comment on usage.
	(Is_Volatile_Function): New routine.
	* snames.ads-tmpl Add a predefined name and pragma id for
	Volatile_Function.
diff mbox

Patch

Index: sem_ch3.adb
===================================================================
--- sem_ch3.adb	(revision 229028)
+++ sem_ch3.adb	(working copy)
@@ -3313,19 +3313,16 @@ 
 
       if Ekind (Obj_Id) = E_Constant then
 
-         --  A constant cannot be effectively volatile. This check is only
-         --  relevant with SPARK_Mode on as it is not a standard Ada legality
-         --  rule. Do not flag internally-generated constants that map generic
-         --  formals to actuals in instantiations (SPARK RM 7.1.3(6)).
+         --  A constant cannot be effectively volatile (SPARK RM 7.1.3(4)).
+         --  This check is relevant only when SPARK_Mode is on as it is not a
+         --  standard Ada legality rule. Internally-generated constants that
+         --  map generic formals to actuals in instantiations are allowed to
+         --  be volatile.
 
          if SPARK_Mode = On
+           and then Comes_From_Source (Obj_Id)
            and then Is_Effectively_Volatile (Obj_Id)
            and then No (Corresponding_Generic_Association (Parent (Obj_Id)))
-
-           --  Don't give this for internally generated entities (such as the
-           --  FIRST and LAST temporaries generated for bounds).
-
-           and then Comes_From_Source (Obj_Id)
          then
             Error_Msg_N ("constant cannot be volatile", Obj_Id);
          end if;
@@ -3334,7 +3331,7 @@ 
 
       else pragma Assert (Ekind (Obj_Id) = E_Variable);
 
-         --  The following checks are only relevant when SPARK_Mode is on as
+         --  The following checks are relevant only when SPARK_Mode is on as
          --  they are not standard Ada legality rules. Internally generated
          --  temporaries are ignored.
 
@@ -3342,7 +3339,7 @@ 
             if Is_Effectively_Volatile (Obj_Id) then
 
                --  The declaration of an effectively volatile object must
-               --  appear at the library level (SPARK RM 7.1.3(7), C.6(6)).
+               --  appear at the library level (SPARK RM 7.1.3(3), C.6(6)).
 
                if not Is_Library_Level_Entity (Obj_Id) then
                   Error_Msg_N
@@ -3367,7 +3364,7 @@ 
 
             else
                --  A non-effectively volatile object cannot have effectively
-               --  volatile components (SPARK RM 7.1.3(7)).
+               --  volatile components (SPARK RM 7.1.3(6)).
 
                if not Is_Effectively_Volatile (Obj_Id)
                  and then Has_Volatile_Component (Obj_Typ)
@@ -19282,9 +19279,9 @@ 
             end if;
          end if;
 
-         --  A discriminant cannot be effectively volatile. This check is only
-         --  relevant when SPARK_Mode is on as it is not standard Ada legality
-         --  rule (SPARK RM 7.1.3(6)).
+         --  A discriminant cannot be effectively volatile (SPARK RM 7.1.3(6)).
+         --  This check is relevant only when SPARK_Mode is on as it is not a
+         --  standard Ada legality rule.
 
          if SPARK_Mode = On
            and then Is_Effectively_Volatile (Defining_Identifier (Discr))
Index: sem_ch5.adb
===================================================================
--- sem_ch5.adb	(revision 229023)
+++ sem_ch5.adb	(working copy)
@@ -2279,9 +2279,9 @@ 
          end if;
       end if;
 
-      --  A loop parameter cannot be effectively volatile. This check is
-      --  peformed only when SPARK_Mode is on as it is not a standard Ada
-      --  legality check (SPARK RM 7.1.3(6)).
+      --  A loop parameter cannot be effectively volatile (SPARK RM 7.1.3(4)).
+      --  This check is relevant only when SPARK_Mode is on as it is not a
+      --  standard Ada legality check.
 
       --  Not clear whether this applies to element iterators, where the
       --  cursor is not an explicit entity ???
@@ -3037,9 +3037,9 @@ 
          end;
       end if;
 
-      --  A loop parameter cannot be effectively volatile. This check is
-      --  peformed only when SPARK_Mode is on as it is not a standard Ada
-      --  legality check (SPARK RM 7.1.3(6)).
+      --  A loop parameter cannot be effectively volatile (SPARK RM 7.1.3(4)).
+      --  This check is relevant only when SPARK_Mode is on as it is not a
+      --  standard Ada legality check.
 
       if SPARK_Mode = On and then Is_Effectively_Volatile (Id) then
          Error_Msg_N ("loop parameter cannot be volatile", Id);
Index: einfo.adb
===================================================================
--- einfo.adb	(revision 229034)
+++ einfo.adb	(working copy)
@@ -7000,7 +7000,8 @@ 
                  Id = Pragma_Part_Of                    or else
                  Id = Pragma_Refined_Depends            or else
                  Id = Pragma_Refined_Global             or else
-                 Id = Pragma_Refined_State;
+                 Id = Pragma_Refined_State              or else
+                 Id = Pragma_Volatile_Function;
 
       --  Contract / test case pragmas
 
Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 229040)
+++ sem_prag.adb	(working copy)
@@ -206,7 +206,8 @@ 
    function Find_Related_Context
      (Prag      : Node_Id;
       Do_Checks : Boolean := False) return Node_Id;
-   --  Subsidiaty to the analysis of pragmas Constant_After_Elaboration and
+   --  Subsidiaty to the analysis of pragmas Async_Readers, Async_Writers,
+   --  Constant_After_Elaboration, Effective_Reads, Effective_Writers and
    --  Part_Of. Find the first source declaration or statement found while
    --  traversing the previous node chain starting from pragma Prag. If flag
    --  Do_Checks is set, the routine reports duplicate pragmas. The routine
@@ -1720,19 +1721,12 @@ 
      (N        : Node_Id;
       Expr_Val : out Boolean)
    is
-      Arg1   : constant Node_Id   := First (Pragma_Argument_Associations (N));
-      Expr   : constant Node_Id   := Get_Pragma_Arg (Next (Arg1));
-      Obj_Id : constant Entity_Id := Entity (Get_Pragma_Arg (Arg1));
+      Arg1     : constant Node_Id := First (Pragma_Argument_Associations (N));
+      Obj_Decl : constant Node_Id := Find_Related_Context (N);
+      Obj_Id   : constant Entity_Id := Defining_Entity (Obj_Decl);
+      Expr     : Node_Id;
 
-      Save_Ghost_Mode : constant Ghost_Mode_Type := Ghost_Mode;
-
    begin
-      --  Set the Ghost mode in effect from the pragma. Due to the delayed
-      --  analysis of the pragma, the Ghost mode at point of declaration and
-      --  point of analysis may not necessarely be the same. Use the mode in
-      --  effect at the point of declaration.
-
-      Set_Ghost_Mode (N);
       Error_Msg_Name_1 := Pragma_Name (N);
 
       --  An external property pragma must apply to an effectively volatile
@@ -1754,17 +1748,13 @@ 
 
       Expr_Val := True;
 
-      if Present (Expr) then
-         Analyze_And_Resolve (Expr, Standard_Boolean);
+      if Present (Arg1) then
+         Expr := Get_Pragma_Arg (Arg1);
 
          if Is_OK_Static_Expression (Expr) then
             Expr_Val := Is_True (Expr_Value (Expr));
-         else
-            SPARK_Msg_N ("expression of % must be static", Expr);
          end if;
       end if;
-
-      Ghost_Mode := Save_Ghost_Mode;
    end Analyze_External_Property_In_Decl_Part;
 
    ---------------------------------
@@ -1924,6 +1914,18 @@ 
                      SPARK_Msg_N ("\use its constituents instead", Item);
                      return;
 
+                  --  An external state cannot appear as a global item of a
+                  --  nonvolatile function (SPARK RM 7.1.3(8)).
+
+                  elsif Is_External_State (Item_Id)
+                    and then Ekind_In (Spec_Id, E_Function, E_Generic_Function)
+                    and then not Is_Volatile_Function (Spec_Id)
+                  then
+                     SPARK_Msg_NE
+                       ("external state & cannot act as global item of "
+                        & "nonvolatile function", Item, Item_Id);
+                     return;
+
                   --  If the reference to the abstract state appears in an
                   --  enclosing package body that will eventually refine the
                   --  state, record the reference for future checks.
@@ -1956,9 +1958,11 @@ 
                  and then Is_Effectively_Volatile (Item_Id)
                then
                   --  An effectively volatile object cannot appear as a global
-                  --  item of a function (SPARK RM 7.1.3(9)).
+                  --  item of a nonvolatile function (SPARK RM 7.1.3(8)).
 
-                  if Ekind_In (Spec_Id, E_Function, E_Generic_Function) then
+                  if Ekind_In (Spec_Id, E_Function, E_Generic_Function)
+                    and then not Is_Volatile_Function (Spec_Id)
+                  then
                      Error_Msg_NE
                        ("volatile object & cannot act as global item of a "
                         & "function", Item, Item_Id);
@@ -2936,6 +2940,13 @@ 
       --  In this version of the procedure, the identifier name is given as
       --  a string with lower case letters.
 
+      procedure Check_Static_Boolean_Expression (Expr : Node_Id);
+      --  Subsidiary to the analysis of pragmas Async_Readers, Async_Writers,
+      --  Constant_After_Elaboration, Effective_Reads, Effective_Writes,
+      --  Extensions_Visible and Volatile_Function. Ensure that expression Expr
+      --  is an OK static boolean expression. Emit an error if this is not the
+      --  case.
+
       procedure Check_Static_Constraint (Constr : Node_Id);
       --  Constr is a constraint from an N_Subtype_Indication node from a
       --  component constraint in an Unchecked_Union type. This routine checks
@@ -5070,6 +5081,22 @@ 
          Check_Optional_Identifier (Arg, Name_Find);
       end Check_Optional_Identifier;
 
+      -------------------------------------
+      -- Check_Static_Boolean_Expression --
+      -------------------------------------
+
+      procedure Check_Static_Boolean_Expression (Expr : Node_Id) is
+      begin
+         if Present (Expr) then
+            Analyze_And_Resolve (Expr, Standard_Boolean);
+
+            if not Is_OK_Static_Expression (Expr) then
+               Error_Pragma_Arg
+                 ("expression of pragma % must be static", Expr);
+            end if;
+         end if;
+      end Check_Static_Boolean_Expression;
+
       -----------------------------
       -- Check_Static_Constraint --
       -----------------------------
@@ -11079,43 +11106,45 @@ 
          -- Async_Readers/Async_Writers/Effective_Reads/Effective_Writes --
          ------------------------------------------------------------------
 
-         --  pragma Asynch_Readers   ( object_LOCAL_NAME [, FLAG] );
-         --  pragma Asynch_Writers   ( object_LOCAL_NAME [, FLAG] );
-         --  pragma Effective_Reads  ( object_LOCAL_NAME [, FLAG] );
-         --  pragma Effective_Writes ( object_LOCAL_NAME [, FLAG] );
+         --  pragma Asynch_Readers   [ (boolean_EXPRESSION) ];
+         --  pragma Asynch_Writers   [ (boolean_EXPRESSION) ];
+         --  pragma Effective_Reads  [ (boolean_EXPRESSION) ];
+         --  pragma Effective_Writes [ (boolean_EXPRESSION) ];
 
-         --  FLAG ::= boolean_EXPRESSION
-
          when Pragma_Async_Readers    |
               Pragma_Async_Writers    |
               Pragma_Effective_Reads  |
               Pragma_Effective_Writes =>
          Async_Effective : declare
-            Duplic : Node_Id;
-            Expr   : Node_Id;
-            Obj    : Node_Id;
-            Obj_Id : Entity_Id;
+            Obj_Decl : Node_Id;
+            Obj_Id   : Entity_Id;
 
          begin
             GNAT_Pragma;
             Check_No_Identifiers;
-            Check_At_Least_N_Arguments (1);
-            Check_At_Most_N_Arguments  (2);
-            Check_Arg_Is_Local_Name (Arg1);
-            Error_Msg_Name_1 := Pname;
+            Check_At_Most_N_Arguments  (1);
 
-            Obj  := Get_Pragma_Arg (Arg1);
-            Expr := Get_Pragma_Arg (Arg2);
+            Obj_Decl := Find_Related_Context (N, Do_Checks => True);
 
+            --  Object declaration
+
+            if Nkind (Obj_Decl) = N_Object_Declaration then
+               null;
+
+            --  Otherwise the pragma is associated with an illegal construact
+
+            else
+               Pragma_Misplaced;
+               return;
+            end if;
+
+            Obj_Id := Defining_Entity (Obj_Decl);
+
             --  Perform minimal verification to ensure that the argument is at
             --  least a variable. Subsequent finer grained checks will be done
             --  at the end of the declarative region the contains the pragma.
 
-            if Is_Entity_Name (Obj)
-              and then Present (Entity (Obj))
-              and then Ekind (Entity (Obj)) = E_Variable
-            then
-               Obj_Id := Entity (Obj);
+            if Ekind (Obj_Id) = E_Variable then
 
                --  A pragma that applies to a Ghost entity becomes Ghost for
                --  the purposes of legality checks and removal of ignored Ghost
@@ -11123,30 +11152,19 @@ 
 
                Mark_Pragma_As_Ghost (N, Obj_Id);
 
-               --  Detect a duplicate pragma. Note that it is not efficient to
-               --  examine preceding statements as Boolean aspects may appear
-               --  anywhere between the related object declaration and its
-               --  freeze point. As an alternative, inspect the contents of the
-               --  variable contract.
+               --  Analyze the Boolean expression (if any)
 
-               Duplic := Get_Pragma (Obj_Id, Prag_Id);
+               if Present (Arg1) then
+                  Check_Static_Boolean_Expression (Get_Pragma_Arg (Arg1));
+               end if;
 
-               if Present (Duplic) then
-                  Error_Msg_Sloc := Sloc (Duplic);
-                  Error_Msg_N ("pragma % duplicates pragma declared #", N);
+               --  Chain the pragma on the contract for further processing by
+               --  Analyze_External_Property_In_Decl_Part.
 
-               --  No duplicate detected
+               Add_Contract_Item (N, Obj_Id);
 
-               else
-                  if Present (Expr) then
-                     Preanalyze_And_Resolve (Expr, Standard_Boolean);
-                  end if;
+            --  Otherwise the external property applies to a constant
 
-                  --  Chain the pragma on the contract for further processing
-                  --  by Analyze_External_Property_In_Decl_Part.
-
-                  Add_Contract_Item (N, Obj_Id);
-               end if;
             else
                Error_Pragma ("pragma % must apply to a volatile object");
             end if;
@@ -12150,7 +12168,6 @@ 
 
          when Pragma_Constant_After_Elaboration => Constant_After_Elaboration :
          declare
-            Expr     : Node_Id;
             Obj_Decl : Node_Id;
             Obj_Id   : Entity_Id;
 
@@ -12208,15 +12225,7 @@ 
             --  Analyze the Boolean expression (if any)
 
             if Present (Arg1) then
-               Expr := Get_Pragma_Arg (Arg1);
-
-               Analyze_And_Resolve (Expr, Standard_Boolean);
-
-               if not Is_OK_Static_Expression (Expr) then
-                  Error_Pragma_Arg
-                    ("expression of pragma % must be static", Expr);
-                  return;
-               end if;
+               Check_Static_Boolean_Expression (Get_Pragma_Arg (Arg1));
             end if;
 
             --  Chain the pragma on the contract for completeness
@@ -13950,7 +13959,6 @@ 
          --    the annotation must instantiate itself.
 
          when Pragma_Extensions_Visible => Extensions_Visible : declare
-            Expr          : Node_Id;
             Formal        : Entity_Id;
             Has_OK_Formal : Boolean := False;
             Spec_Id       : Entity_Id;
@@ -14043,15 +14051,8 @@ 
             --  Analyze the Boolean expression (if any)
 
             if Present (Arg1) then
-               Expr := Expression (Get_Argument (N, Spec_Id));
-
-               Analyze_And_Resolve (Expr, Standard_Boolean);
-
-               if not Is_OK_Static_Expression (Expr) then
-                  Error_Pragma_Arg
-                    ("expression of pragma % must be static", Expr);
-                  return;
-               end if;
+               Check_Static_Boolean_Expression
+                 (Expression (Get_Argument (N, Spec_Id)));
             end if;
 
             --  Chain the pragma on the contract for completeness
@@ -21486,6 +21487,14 @@ 
          when Pragma_Volatile =>
             Process_Atomic_Independent_Shared_Volatile;
 
+         -------------------------
+         -- Volatile_Components --
+         -------------------------
+
+         --  pragma Volatile_Components (array_LOCAL_NAME);
+
+         --  Volatile is handled by the same circuit as Atomic_Components
+
          --------------------------
          -- Volatile_Full_Access --
          --------------------------
@@ -21496,14 +21505,98 @@ 
             GNAT_Pragma;
             Process_Atomic_Independent_Shared_Volatile;
 
-         -------------------------
-         -- Volatile_Components --
-         -------------------------
+         -----------------------
+         -- Volatile_Function --
+         -----------------------
 
-         --  pragma Volatile_Components (array_LOCAL_NAME);
+         --  pragma Volatile_Function [ (boolean_EXPRESSION) ];
 
-         --  Volatile is handled by the same circuit as Atomic_Components
+         when Pragma_Volatile_Function => Volatile_Function : declare
+            Over_Id   : Entity_Id;
+            Spec_Id   : Entity_Id;
+            Subp_Decl : Node_Id;
 
+         begin
+            GNAT_Pragma;
+            Check_No_Identifiers;
+            Check_At_Most_N_Arguments (1);
+
+            Subp_Decl :=
+              Find_Related_Subprogram_Or_Body (N, Do_Checks => True);
+
+            --  Function instantiation
+
+            if Nkind (Subp_Decl) = N_Function_Instantiation then
+               null;
+
+            --  Generic subprogram
+
+            elsif Nkind (Subp_Decl) = N_Generic_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;
+
+            --  Subprogram
+
+            elsif Nkind (Subp_Decl) = N_Subprogram_Declaration then
+               null;
+
+            else
+               Pragma_Misplaced;
+               return;
+            end if;
+
+            Spec_Id := Corresponding_Spec_Of (Subp_Decl);
+            Over_Id := Overridden_Operation (Spec_Id);
+
+            --  A pragma that applies to a Ghost entity becomes Ghost for the
+            --  purposes of legality checks and removal of ignored Ghost code.
+
+            Mark_Pragma_As_Ghost (N, Spec_Id);
+
+            --  A volatile function cannot override a non-volatile function
+            --  (SPARK RM 7.1.2(15)). Overriding checks are usually performed
+            --  in New_Overloaded_Entity, however at that point the pragma has
+            --  not been processed yet.
+
+            if Present (Over_Id)
+              and then not Is_Volatile_Function (Over_Id)
+            then
+               Error_Msg_N
+                 ("incompatible volatile function values in effect", Spec_Id);
+
+               Error_Msg_Sloc := Sloc (Over_Id);
+               Error_Msg_N
+                 ("\& declared # with Volatile_Function value `False`",
+                  Spec_Id);
+
+               Error_Msg_Sloc := Sloc (Spec_Id);
+               Error_Msg_N
+                 ("\overridden # with Volatile_Function value `True`",
+                  Spec_Id);
+            end if;
+
+            --  Analyze the Boolean expression (if any)
+
+            if Present (Arg1) then
+               Check_Static_Boolean_Expression (Get_Pragma_Arg (Arg1));
+            end if;
+
+            Add_Contract_Item (N, Spec_Id);
+         end Volatile_Function;
+
          ----------------------
          -- Warning_As_Error --
          ----------------------
@@ -26278,6 +26371,33 @@ 
            and then Nkind (Parent (Parent (N))) = N_Package_Body;
    end Is_Elaboration_SPARK_Mode;
 
+   -----------------------
+   -- Is_Enabled_Pragma --
+   -----------------------
+
+   function Is_Enabled_Pragma (Prag : Node_Id) return Boolean is
+      Arg : Node_Id;
+
+   begin
+      if Present (Prag) then
+         Arg := First (Pragma_Argument_Associations (Prag));
+
+         if Present (Arg) then
+            return Is_True (Expr_Value (Get_Pragma_Arg (Arg)));
+
+         --  The lack of a Boolean argument automatically enables the pragma
+
+         else
+            return True;
+         end if;
+
+      --  The pragma is missing, therefore it is not enabled
+
+      else
+         return False;
+      end if;
+   end Is_Enabled_Pragma;
+
    -----------------------------------------
    -- Is_Non_Significant_Pragma_Reference --
    -----------------------------------------
@@ -26519,6 +26639,7 @@ 
       Pragma_Volatile                       =>  0,
       Pragma_Volatile_Components            =>  0,
       Pragma_Volatile_Full_Access           =>  0,
+      Pragma_Volatile_Function              =>  0,
       Pragma_Warning_As_Error               =>  0,
       Pragma_Warnings                       =>  0,
       Pragma_Weak_External                  =>  0,
Index: sem_prag.ads
===================================================================
--- sem_prag.ads	(revision 229023)
+++ sem_prag.ads	(working copy)
@@ -364,6 +364,23 @@ 
    --  Determine whether pragma SPARK_Mode appears in the statement part of a
    --  package body.
 
+   function Is_Enabled_Pragma (Prag : Node_Id) return Boolean;
+   --  Determine whether a Boolean-like SPARK pragma Prag is enabled. To be
+   --  considered enabled, the pragma must either:
+   --    * Appear without its Boolean expression
+   --    * The Boolean expression evaluates to "True"
+   --
+   --  Boolean-like SPARK pragmas differ from pure Boolean Ada pragmas in that
+   --  their optional Boolean expression must be static and cannot benefit from
+   --  forward references. The following are Boolean-like SPARK pragmas:
+   --    Async_Readers
+   --    Async_Writers
+   --    Constant_After_Elaboration
+   --    Effective_Reads
+   --    Effective_Writes
+   --    Extensions_Visible
+   --    Volatile_Function
+
    function Is_Non_Significant_Pragma_Reference (N : Node_Id) return Boolean;
    --  The node N is a node for an entity and the issue is whether the
    --  occurrence is a reference for the purposes of giving warnings about
Index: sem_ch12.adb
===================================================================
--- sem_ch12.adb	(revision 229040)
+++ sem_ch12.adb	(working copy)
@@ -5318,28 +5318,24 @@ 
             if Need_Subprogram_Instance_Body (N, Act_Decl_Id) then
                Check_Forward_Instantiation (Gen_Decl);
 
-               --  The wrapper package is always delayed, because it does not
-               --  constitute a freeze point, but to insure that the freeze
-               --  node is placed properly, it is created directly when
-               --  instantiating the body (otherwise the freeze node might
-               --  appear to early for nested instantiations).
+            --  The wrapper package is always delayed, because it does not
+            --  constitute a freeze point, but to insure that the freeze node
+            --  is placed properly, it is created directly when instantiating
+            --  the body (otherwise the freeze node might appear to early for
+            --  nested instantiations). For ASIS purposes, indicate that the
+            --  wrapper package has replaced the instantiation node.
 
             elsif Nkind (Parent (N)) = N_Compilation_Unit then
-
-               --  For ASIS purposes, indicate that the wrapper package has
-               --  replaced the instantiation node.
-
                Rewrite (N, Unit (Parent (N)));
                Set_Unit (Parent (N), N);
             end if;
 
-         elsif Nkind (Parent (N)) = N_Compilation_Unit then
+         --  Replace instance node for library-level instantiations of
+         --  intrinsic subprograms, for ASIS use.
 
-               --  Replace instance node for library-level instantiations of
-               --  intrinsic subprograms, for ASIS use.
-
-               Rewrite (N, Unit (Parent (N)));
-               Set_Unit (Parent (N), N);
+         elsif Nkind (Parent (N)) = N_Compilation_Unit then
+            Rewrite (N, Unit (Parent (N)));
+            Set_Unit (Parent (N), N);
          end if;
 
          if Parent_Installed then
@@ -5359,7 +5355,6 @@ 
          if SPARK_Mode = On then
             Dynamic_Elaboration_Checks := False;
          end if;
-
       end if;
 
    <<Leave>>
@@ -10663,17 +10658,18 @@ 
            ("actual must exclude null to match generic formal#", Actual);
       end if;
 
-      --  An effectively volatile object cannot be used as an actual in
-      --  a generic instance. The following check is only relevant when
-      --  SPARK_Mode is on as it is not a standard Ada legality rule.
+      --  An effectively volatile object cannot be used as an actual in a
+      --  generic instantiation (SPARK RM 7.1.3(7)). The following check is
+      --  relevant only when SPARK_Mode is on as it is not a standard Ada
+      --  legality rule.
 
       if SPARK_Mode = On
         and then Present (Actual)
         and then Is_Effectively_Volatile_Object (Actual)
       then
          Error_Msg_N
-           ("volatile object cannot act as actual in generic instantiation "
-            & "(SPARK RM 7.1.3(8))", Actual);
+           ("volatile object cannot act as actual in generic instantiation",
+            Actual);
       end if;
 
       return List;
Index: rtsfind.ads
===================================================================
--- rtsfind.ads	(revision 229023)
+++ rtsfind.ads	(working copy)
@@ -23,15 +23,15 @@ 
 --                                                                          --
 ------------------------------------------------------------------------------
 
-with Types; use Types;
-
-package Rtsfind is
-
 --  This package contains the routine that is used to obtain runtime library
 --  entities, loading in the required runtime library packages on demand. It
 --  is also used for such purposes as finding System.Address when System has
 --  not been explicitly With'ed.
 
+with Types; use Types;
+
+package Rtsfind is
+
    ------------------------
    -- Runtime Unit Table --
    ------------------------
@@ -131,6 +131,7 @@ 
       Ada_Real_Time,
       Ada_Streams,
       Ada_Strings,
+      Ada_Synchronous_Task_Control,
       Ada_Tags,
       Ada_Task_Identification,
       Ada_Task_Termination,
@@ -606,6 +607,8 @@ 
 
      RE_Unbounded_String,                -- Ada.Strings.Unbounded
 
+     RE_Suspension_Object,               -- Ada.Synchronous_Task_Control
+
      RE_Access_Level,                    -- Ada.Tags
      RE_Alignment,                       -- Ada.Tags
      RE_Address_Array,                   -- Ada.Tags
@@ -1837,6 +1840,8 @@ 
 
      RE_Unbounded_String                 => Ada_Strings_Unbounded,
 
+     RE_Suspension_Object                => Ada_Synchronous_Task_Control,
+
      RE_Access_Level                     => Ada_Tags,
      RE_Alignment                        => Ada_Tags,
      RE_Address_Array                    => Ada_Tags,
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 229029)
+++ sem_util.adb	(working copy)
@@ -375,6 +375,7 @@ 
       --    Postcondition
       --    Precondition
       --    Test_Case
+      --    Volatile_Function
 
       elsif Ekind_In (Id, E_Entry, E_Entry_Family)
         or else Is_Generic_Subprogram (Id)
@@ -392,6 +393,11 @@ 
          then
             Add_Classification;
 
+         elsif Prag_Nam = Name_Volatile_Function
+           and then Ekind_In (Id, E_Function, E_Generic_Function)
+         then
+            Add_Classification;
+
          --  The pragma is not a proper contract item
 
          else
@@ -3146,6 +3152,36 @@ 
       end if;
    end Check_No_Hidden_State;
 
+   ----------------------------------------
+   -- Check_Nonvolatile_Function_Profile --
+   ----------------------------------------
+
+   procedure Check_Nonvolatile_Function_Profile (Func_Id : Entity_Id) is
+      Formal : Entity_Id;
+
+   begin
+      --  Inspect all formal parameters
+
+      Formal := First_Formal (Func_Id);
+      while Present (Formal) loop
+         if Is_Effectively_Volatile (Etype (Formal)) then
+            Error_Msg_NE
+              ("nonvolatile function & cannot have a volatile parameter",
+               Formal, Func_Id);
+         end if;
+
+         Next_Formal (Formal);
+      end loop;
+
+      --  Inspect the return type
+
+      if Is_Effectively_Volatile (Etype (Func_Id)) then
+         Error_Msg_N
+           ("nonvolatile function & cannot have a volatile return type",
+            Func_Id);
+      end if;
+   end Check_Nonvolatile_Function_Profile;
+
    ------------------------------------------
    -- Check_Potentially_Blocking_Operation --
    ------------------------------------------
@@ -8577,18 +8613,18 @@ 
          ----------------
 
          function Is_Enabled (Prag : Node_Id) return Boolean is
-            Arg2 : Node_Id;
+            Arg1 : Node_Id;
 
          begin
             if Present (Prag) then
-               Arg2 := Next (First (Pragma_Argument_Associations (Prag)));
+               Arg1 := First (Pragma_Argument_Associations (Prag));
 
                --  The pragma has an optional Boolean expression, the related
                --  property is enabled only when the expression evaluates to
                --  True.
 
-               if Present (Arg2) then
-                  return Is_True (Expr_Value (Get_Pragma_Arg (Arg2)));
+               if Present (Arg1) then
+                  return Is_True (Expr_Value (Get_Pragma_Arg (Arg1)));
 
                --  Otherwise the lack of expression enables the property by
                --  default.
@@ -11358,6 +11394,66 @@ 
    -----------------------------
 
    function Is_Effectively_Volatile (Id : Entity_Id) return Boolean is
+      function Is_Descendant_Of_Suspension_Object
+        (Typ : Entity_Id) return Boolean;
+      --  Determine whether type Typ is a descendant of type Suspension_Object
+      --  defined in Ada.Synchronous_Task_Control. This routine is similar to
+      --  Sem_Util.Is_Descendent_Of, however this version does not load unit
+      --  Ada.Synchronous_Task_Control.
+
+      ----------------------------------------
+      -- Is_Descendant_Of_Suspension_Object --
+      ----------------------------------------
+
+      function Is_Descendant_Of_Suspension_Object
+        (Typ : Entity_Id) return Boolean
+      is
+         Cur_Typ : Entity_Id;
+         Par_Typ : Entity_Id;
+
+      begin
+         --  Do not attempt to load Ada.Synchronous_Task_Control in No_Run_Time
+         --  mode. The unit contains tagged types and those are not allowed in
+         --  this mode.
+
+         if No_Run_Time_Mode then
+            return False;
+
+         --  Unit Ada.Synchronous_Task_Control is not available, the type
+         --  cannot possibly be a descendant of Suspension_Object.
+
+         elsif not RTE_Available (RE_Suspension_Object) then
+            return False;
+         end if;
+
+         --  Climb the type derivation chain checking each parent type against
+         --  Suspension_Object.
+
+         Cur_Typ := Base_Type (Typ);
+         while Present (Cur_Typ) loop
+            Par_Typ := Etype (Cur_Typ);
+
+            --  The current type is a match
+
+            if Is_RTE (Cur_Typ, RE_Suspension_Object) then
+               return True;
+
+            --  Stop the traversal once the root of the derivation chain has
+            --  been reached. In that case the current type is its own base
+            --  type.
+
+            elsif Cur_Typ = Par_Typ then
+               exit;
+            end if;
+
+            Cur_Typ := Base_Type (Par_Typ);
+         end loop;
+
+         return False;
+      end Is_Descendant_Of_Suspension_Object;
+
+   --  Start of processing for Is_Effectively_Volatile
+
    begin
       if Is_Type (Id) then
 
@@ -11377,6 +11473,19 @@ 
                 or else
               Is_Effectively_Volatile (Component_Type (Base_Type (Id)));
 
+         --  A protected type is always volatile
+
+         elsif Is_Protected_Type (Id) then
+            return True;
+
+         --  A descendant of Ada.Synchronous_Task_Control.Suspension_Object is
+         --  automatically volatile.
+
+         elsif Is_Descendant_Of_Suspension_Object (Id) then
+            return True;
+
+         --  Otherwise the type is not effectively volatile
+
          else
             return False;
          end if;
@@ -13510,6 +13619,33 @@ 
         and then Scope (Scope (Scope (Root))) = Standard_Standard;
    end Is_Visibly_Controlled;
 
+   --------------------------
+   -- Is_Volatile_Function --
+   --------------------------
+
+   function Is_Volatile_Function (Func_Id : Entity_Id) return Boolean is
+   begin
+      --  The caller must ensure that Func_Id denotes a function
+
+      pragma Assert (Ekind_In (Func_Id, E_Function, E_Generic_Function));
+
+      --  A protected function is automatically volatile
+
+      if Is_Primitive (Func_Id)
+        and then Present (First_Formal (Func_Id))
+        and then Is_Protected_Type (Etype (First_Formal (Func_Id)))
+      then
+         return True;
+
+      --  Otherwise the function is treated as volatile if it is subject to
+      --  enabled pragma Volatile_Function.
+
+      else
+         return
+           Is_Enabled_Pragma (Get_Pragma (Func_Id, Pragma_Volatile_Function));
+      end if;
+   end Is_Volatile_Function;
+
    ------------------------
    -- Is_Volatile_Object --
    ------------------------
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 229029)
+++ sem_util.ads	(working copy)
@@ -73,6 +73,7 @@ 
    --    Refined_Post
    --    Refined_States
    --    Test_Case
+   --    Volatile_Function
 
    procedure Add_Global_Declaration (N : Node_Id);
    --  These procedures adds a declaration N at the library level, to be
@@ -313,6 +314,10 @@ 
    --  Determine whether object or state Id introduces a hidden state. If this
    --  is the case, emit an error.
 
+   procedure Check_Nonvolatile_Function_Profile (Func_Id : Entity_Id);
+   --  Verify that the profile of nonvolatile function Func_Id does not contain
+   --  effectively volatile parameters or return type.
+
    procedure Check_Potentially_Blocking_Operation (N : Node_Id);
    --  N is one of the statement forms that is a potentially blocking
    --  operation. If it appears within a protected action, emit warning.
@@ -533,7 +538,7 @@ 
 
    function Enclosing_Declaration (N : Node_Id) return Node_Id;
    --  Returns the declaration node enclosing N (including possibly N itself),
-   --  if any, or Empty otherwise
+   --  if any, or Empty otherwise.
 
    function Enclosing_Generic_Body
      (N : Node_Id) return Node_Id;
@@ -1285,13 +1290,17 @@ 
    --  . machine_emin = 3 - machine_emax
 
    function Is_Effectively_Volatile (Id : Entity_Id) return Boolean;
-   --  The SPARK property "effectively volatile" applies to both types and
-   --  objects. To qualify as such, an entity must be either volatile or be
-   --  (of) an array type subject to aspect Volatile_Components.
+   --  Determine whether a type or object denoted by entity Id is effectively
+   --  volatile (SPARK RM 7.1.2). To qualify as such, the entity must be either
+   --    * Volatile
+   --    * An array type subject to aspect Volatile_Components
+   --    * An array type whose component type is effectively volatile
+   --    * A protected type
+   --    * Descendant of type Ada.Synchronous_Task_Control.Suspension_Object
 
    function Is_Effectively_Volatile_Object (N : Node_Id) return Boolean;
    --  Determine whether an arbitrary node denotes an effectively volatile
-   --  object.
+   --  object (SPARK RM 7.1.2).
 
    function Is_Expression_Function (Subp : Entity_Id) return Boolean;
    --  Predicate to determine whether a scope entity comes from a rewritten
@@ -1301,8 +1310,8 @@ 
    function Is_EVF_Expression (N : Node_Id) return Boolean;
    --  Determine whether node N denotes a reference to a formal parameter of
    --  a specific tagged type whose related subprogram is subject to pragma
-   --  Extensions_Visible with value "False". Several other constructs fall
-   --  under this category:
+   --  Extensions_Visible with value "False" (SPARK RM 6.1.7). Several other
+   --  constructs fall under this category:
    --    1) A qualified expression whose operand is EVF
    --    2) A type conversion whose operand is EVF
    --    3) An if expression with at least one EVF dependent_expression
@@ -1550,6 +1559,11 @@ 
    --  Initialize/Adjust/Finalize subprogram does not override the inherited
    --  one.
 
+   function Is_Volatile_Function (Func_Id : Entity_Id) return Boolean;
+   --  Determine whether [generic] function Func_Id is subject to enabled
+   --  pragma Volatile_Function. Protected functions are treated as volatile
+   --  (SPARK RM 7.1.2).
+
    function Is_Volatile_Object (N : Node_Id) return Boolean;
    --  Determines if the given node denotes an volatile object in the sense of
    --  the legality checks described in RM C.6(12). Note that the test here is
Index: sem_res.adb
===================================================================
--- sem_res.adb	(revision 229023)
+++ sem_res.adb	(working copy)
@@ -4105,22 +4105,11 @@ 
                --  actual to a nested call, since this constitutes a reading of
                --  the parameter, which is not allowed.
 
-               if Is_Entity_Name (A)
+               if Ada_Version = Ada_83
+                 and then Is_Entity_Name (A)
                  and then Ekind (Entity (A)) = E_Out_Parameter
                then
-                  if Ada_Version = Ada_83 then
-                     Error_Msg_N
-                       ("(Ada 83) illegal reading of out parameter", A);
-
-                  --  An effectively volatile OUT parameter cannot act as IN or
-                  --  IN OUT actual in a call (SPARK RM 7.1.3(11)).
-
-                  elsif SPARK_Mode = On
-                    and then Is_Effectively_Volatile (Entity (A))
-                  then
-                     Error_Msg_N
-                       ("illegal reading of volatile OUT parameter", A);
-                  end if;
+                  Error_Msg_N ("(Ada 83) illegal reading of out parameter", A);
                end if;
             end if;
 
@@ -4472,8 +4461,8 @@ 
             --  temporaries are ignored.
 
             if SPARK_Mode = On
+              and then Comes_From_Source (A)
               and then Is_Effectively_Volatile_Object (A)
-              and then Comes_From_Source (A)
             then
                --  An effectively volatile object may act as an actual
                --  parameter when the corresponding formal is of a non-scalar
@@ -6792,7 +6781,7 @@ 
         (Context : Node_Id;
          Obj_Ref : Node_Id) return Boolean;
       --  Determine whether node Context denotes a "non-interfering context"
-      --  (as defined in SPARK RM 7.1.3(13)) where volatile reference Obj_Ref
+      --  (as defined in SPARK RM 7.1.3(12)) where volatile reference Obj_Ref
       --  can safely reside.
 
       ----------------------------------------
@@ -6851,6 +6840,10 @@ 
          function Within_Procedure_Call (Nod : Node_Id) return Boolean;
          --  Determine whether an arbitrary node appears in a procedure call
 
+         function Within_Volatile_Function (Id : Entity_Id) return Boolean;
+         --  Determine whether an arbitrary entity appears in a volatile
+         --  function.
+
          ------------------
          -- Within_Check --
          ------------------
@@ -6905,6 +6898,32 @@ 
             return False;
          end Within_Procedure_Call;
 
+         ------------------------------
+         -- Within_Volatile_Function --
+         ------------------------------
+
+         function Within_Volatile_Function (Id : Entity_Id) return Boolean is
+            Func_Id : Entity_Id;
+
+         begin
+            --  Traverse the scope stack looking for a [generic] function
+
+            Func_Id := Id;
+            while Present (Func_Id) and then Func_Id /= Standard_Standard loop
+               if Ekind_In (Func_Id, E_Function, E_Generic_Function) then
+                  return Is_Volatile_Function (Func_Id);
+               end if;
+
+               Func_Id := Scope (Func_Id);
+            end loop;
+
+            return False;
+         end Within_Volatile_Function;
+
+         --  Local variables
+
+         Obj_Id : Entity_Id;
+
       --  Start of processing for Is_OK_Volatile_Context
 
       begin
@@ -6914,15 +6933,27 @@ 
             return True;
 
          --  The volatile object is part of the initialization expression of
-         --  another object. Ensure that the climb of the parent chain came
-         --  from the expression side and not from the name side.
+         --  another object.
 
          elsif Nkind (Context) = N_Object_Declaration
            and then Present (Expression (Context))
            and then Expression (Context) = Obj_Ref
          then
-            return True;
+            Obj_Id := Defining_Entity (Context);
 
+            --  The volatile object acts as the initialization expression of an
+            --  extended return statement. This is valid context as long as the
+            --  function is volatile.
+
+            if Is_Return_Object (Obj_Id) then
+               return Within_Volatile_Function (Obj_Id);
+
+            --  Otherwise this is a normal object initialization
+
+            else
+               return True;
+            end if;
+
          --  The volatile object appears as an actual parameter in a call to an
          --  instance of Unchecked_Conversion whose result is renamed.
 
@@ -6932,6 +6963,15 @@ 
          then
             return True;
 
+         --  The volatile object appears as the expression of a simple return
+         --  statement that applies to a volatile function.
+
+         elsif Nkind (Context) = N_Simple_Return_Statement
+           and then Expression (Context) = Obj_Ref
+         then
+            return
+              Within_Volatile_Function (Return_Statement_Entity (Context));
+
          --  The volatile object appears as the prefix of a name occurring
          --  in a non-interfering context.
 
@@ -7057,14 +7097,6 @@ 
       then
          if Ada_Version = Ada_83 then
             Error_Msg_N ("(Ada 83) illegal reading of out parameter", N);
-
-         --  An effectively volatile OUT parameter cannot be read
-         --  (SPARK RM 7.1.3(11)).
-
-         elsif SPARK_Mode = On
-           and then Is_Effectively_Volatile (E)
-         then
-            Error_Msg_N ("illegal reading of volatile OUT parameter", N);
          end if;
 
       --  In all other cases, just do the possible static evaluation
@@ -7117,7 +7149,7 @@ 
         and then Comes_From_Source (N)
       then
          --  The effectively volatile objects appears in a "non-interfering
-         --  context" as defined in SPARK RM 7.1.3(13).
+         --  context" as defined in SPARK RM 7.1.3(12).
 
          if Is_OK_Volatile_Context (Par, N) then
             null;
@@ -7128,7 +7160,7 @@ 
          else
             SPARK_Msg_N
               ("volatile object cannot appear in this context "
-               & "(SPARK RM 7.1.3(13))", N);
+               & "(SPARK RM 7.1.3(12))", N);
          end if;
       end if;
 
Index: aspects.adb
===================================================================
--- aspects.adb	(revision 229023)
+++ aspects.adb	(working copy)
@@ -610,6 +610,7 @@ 
     Aspect_Volatile                     => Aspect_Volatile,
     Aspect_Volatile_Components          => Aspect_Volatile_Components,
     Aspect_Volatile_Full_Access         => Aspect_Volatile_Full_Access,
+    Aspect_Volatile_Function            => Aspect_Volatile_Function,
     Aspect_Warnings                     => Aspect_Warnings,
     Aspect_Write                        => Aspect_Write);
 
Index: aspects.ads
===================================================================
--- aspects.ads	(revision 229023)
+++ aspects.ads	(working copy)
@@ -78,6 +78,8 @@ 
       Aspect_Address,
       Aspect_Alignment,
       Aspect_Annotate,                      -- GNAT
+      Aspect_Async_Readers,                 -- GNAT
+      Aspect_Async_Writers,                 -- GNAT
       Aspect_Attach_Handler,
       Aspect_Bit_Order,
       Aspect_Component_Size,
@@ -96,6 +98,8 @@ 
       Aspect_Dimension_System,              -- GNAT
       Aspect_Dispatching_Domain,
       Aspect_Dynamic_Predicate,
+      Aspect_Effective_Reads,               -- GNAT
+      Aspect_Effective_Writes,              -- GNAT
       Aspect_Extensions_Visible,            -- GNAT
       Aspect_External_Name,
       Aspect_External_Tag,
@@ -145,6 +149,7 @@ 
       Aspect_Unsuppress,
       Aspect_Value_Size,                    -- GNAT
       Aspect_Variable_Indexing,
+      Aspect_Volatile_Function,             -- GNAT
       Aspect_Warnings,                      -- GNAT
       Aspect_Write,
 
@@ -167,15 +172,11 @@ 
       --  the aspect value is inherited from the parent, in which case, we do
       --  not allow False if we inherit a True value from the parent.
 
-      Aspect_Async_Readers,                 -- GNAT
-      Aspect_Async_Writers,                 -- GNAT
       Aspect_Asynchronous,
       Aspect_Atomic,
       Aspect_Atomic_Components,
       Aspect_Disable_Controlled,            -- GNAT
       Aspect_Discard_Names,
-      Aspect_Effective_Reads,               -- GNAT
-      Aspect_Effective_Writes,              -- GNAT
       Aspect_Export,
       Aspect_Favor_Top_Level,               -- GNAT
       Aspect_Independent,
@@ -264,6 +265,7 @@ 
       Aspect_Unreferenced               => True,
       Aspect_Unreferenced_Objects       => True,
       Aspect_Value_Size                 => True,
+      Aspect_Volatile_Function          => True,
       Aspect_Warnings                   => True,
       others                            => False);
 
@@ -291,7 +293,7 @@ 
    --  aspect is enabled. If it is False, the aspect is disabled.
 
    subtype Boolean_Aspects is
-     Aspect_Id range Aspect_Async_Readers .. Aspect_Id'Last;
+     Aspect_Id range Aspect_Asynchronous .. Aspect_Id'Last;
 
    subtype Pre_Post_Aspects is
      Aspect_Id range Aspect_Post .. Aspect_Precondition;
@@ -312,6 +314,8 @@ 
       Aspect_Address                    => Expression,
       Aspect_Alignment                  => Expression,
       Aspect_Annotate                   => Expression,
+      Aspect_Async_Readers              => Optional_Expression,
+      Aspect_Async_Writers              => Optional_Expression,
       Aspect_Attach_Handler             => Expression,
       Aspect_Bit_Order                  => Expression,
       Aspect_Component_Size             => Expression,
@@ -330,6 +334,8 @@ 
       Aspect_Dimension_System           => Expression,
       Aspect_Dispatching_Domain         => Expression,
       Aspect_Dynamic_Predicate          => Expression,
+      Aspect_Effective_Reads            => Optional_Expression,
+      Aspect_Effective_Writes           => Optional_Expression,
       Aspect_Extensions_Visible         => Optional_Expression,
       Aspect_External_Name              => Expression,
       Aspect_External_Tag               => Expression,
@@ -379,6 +385,7 @@ 
       Aspect_Unsuppress                 => Name,
       Aspect_Value_Size                 => Expression,
       Aspect_Variable_Indexing          => Name,
+      Aspect_Volatile_Function          => Optional_Expression,
       Aspect_Warnings                   => Name,
       Aspect_Write                      => Name,
 
@@ -511,6 +518,7 @@ 
       Aspect_Volatile                     => Name_Volatile,
       Aspect_Volatile_Components          => Name_Volatile_Components,
       Aspect_Volatile_Full_Access         => Name_Volatile_Full_Access,
+      Aspect_Volatile_Function            => Name_Volatile_Function,
       Aspect_Warnings                     => Name_Warnings,
       Aspect_Write                        => Name_Write);
 
@@ -731,6 +739,7 @@ 
       Aspect_Synchronization              => Never_Delay,
       Aspect_Test_Case                    => Never_Delay,
       Aspect_Unimplemented                => Never_Delay,
+      Aspect_Volatile_Function            => Never_Delay,
       Aspect_Warnings                     => Never_Delay,
 
       Aspect_Alignment                    => Rep_Aspect,
Index: sem_ch6.adb
===================================================================
--- sem_ch6.adb	(revision 229037)
+++ sem_ch6.adb	(working copy)
@@ -2228,6 +2228,19 @@ 
 
       Check_Result_And_Post_State (Body_Id);
 
+      --  A stand alone non-volatile function body cannot have an effectively
+      --  volatile formal parameter or return type (SPARK RM 7.1.3(9)). This
+      --  check is relevant only when SPARK_Mode is on as it is not a standard
+      --  legality rule. The check is performed here because Volatile_Function
+      --  is processed after the analysis of the related subprogram body.
+
+      if SPARK_Mode = On
+        and then Ekind_In (Body_Id, E_Function, E_Generic_Function)
+        and then not Is_Volatile_Function (Body_Id)
+      then
+         Check_Nonvolatile_Function_Profile (Body_Id);
+      end if;
+
       --  Restore the SPARK_Mode of the enclosing context after all delayed
       --  pragmas have been analyzed.
 
@@ -4086,6 +4099,19 @@ 
          Check_Result_And_Post_State (Subp_Id);
       end if;
 
+      --  A non-volatile function cannot have an effectively volatile formal
+      --  parameter or return type (SPARK RM 7.1.3(9)). This check is relevant
+      --  only when SPARK_Mode is on as it is not a standard legality rule. The
+      --  check is performed here because pragma Volatile_Function is processed
+      --  after the analysis of the related subprogram declaration.
+
+      if SPARK_Mode = On
+        and then Ekind_In (Subp_Id, E_Function, E_Generic_Function)
+        and then not Is_Volatile_Function (Subp_Id)
+      then
+         Check_Nonvolatile_Function_Profile (Subp_Id);
+      end if;
+
       --  Restore the SPARK_Mode of the enclosing context after all delayed
       --  pragmas have been analyzed.
 
@@ -4451,9 +4477,9 @@ 
          --  the check is applied later (see Analyze_Subprogram_Declaration).
 
          if not Nkind_In (Original_Node (Parent (N)),
-                          N_Subprogram_Renaming_Declaration,
                           N_Abstract_Subprogram_Declaration,
-                          N_Formal_Abstract_Subprogram_Declaration)
+                          N_Formal_Abstract_Subprogram_Declaration,
+                          N_Subprogram_Renaming_Declaration)
          then
             if Is_Abstract_Type (Etype (Designator))
               and then not Is_Interface (Etype (Designator))
@@ -4464,14 +4490,15 @@ 
             --  Ada 2012 (AI-0073): Extend this test to subprograms with an
             --  access result whose designated type is abstract.
 
-            elsif Nkind (Result_Definition (N)) = N_Access_Definition
+            elsif Ada_Version >= Ada_2012
+              and then Nkind (Result_Definition (N)) = N_Access_Definition
               and then
                 not Is_Class_Wide_Type (Designated_Type (Etype (Designator)))
               and then Is_Abstract_Type (Designated_Type (Etype (Designator)))
-              and then Ada_Version >= Ada_2012
             then
-               Error_Msg_N ("function whose access result designates "
-                            & "abstract type must be abstract", N);
+               Error_Msg_N
+                 ("function whose access result designates abstract type "
+                  & "must be abstract", N);
             end if;
          end if;
       end if;
@@ -9933,17 +9960,6 @@ 
      (T           : List_Id;
       Related_Nod : Node_Id)
    is
-      Context     : constant Node_Id := Parent (Parent (T));
-      Param_Spec  : Node_Id;
-      Formal      : Entity_Id;
-      Formal_Type : Entity_Id;
-      Default     : Node_Id;
-      Ptype       : Entity_Id;
-
-      Num_Out_Params  : Nat       := 0;
-      First_Out_Param : Entity_Id := Empty;
-      --  Used for setting Is_Only_Out_Parameter
-
       function Designates_From_Limited_With (Typ : Entity_Id) return Boolean;
       --  Determine whether an access type designates a type coming from a
       --  limited view.
@@ -9986,6 +10002,19 @@ 
                      and then Is_Class_Wide_Type (Etype (Prefix (D))));
       end Is_Class_Wide_Default;
 
+      --  Local variables
+
+      Context     : constant Node_Id := Parent (Parent (T));
+      Default     : Node_Id;
+      Formal      : Entity_Id;
+      Formal_Type : Entity_Id;
+      Param_Spec  : Node_Id;
+      Ptype       : Entity_Id;
+
+      Num_Out_Params  : Nat       := 0;
+      First_Out_Param : Entity_Id := Empty;
+      --  Used for setting Is_Only_Out_Parameter
+
    --  Start of processing for Process_Formals
 
    begin
@@ -10269,8 +10298,8 @@ 
             Null_Exclusion_Static_Checks (Param_Spec);
          end if;
 
-         --  The following checks are relevant when SPARK_Mode is on as these
-         --  are not standard Ada legality rules.
+         --  The following checks are relevant only when SPARK_Mode is on as
+         --  these are not standard Ada legality rules.
 
          if SPARK_Mode = On then
             if Ekind_In (Scope (Formal), E_Function, E_Generic_Function) then
@@ -10282,14 +10311,6 @@ 
                   Error_Msg_N
                     ("function cannot have parameter of mode `OUT` or "
                      & "`IN OUT`", Formal);
-
-               --  A function cannot have an effectively volatile formal
-               --  parameter (SPARK RM 7.1.3(10)).
-
-               elsif Is_Effectively_Volatile (Formal) then
-                  Error_Msg_N
-                    ("function cannot have a volatile formal parameter",
-                     Formal);
                end if;
 
             --  A procedure cannot have an effectively volatile formal
Index: par-prag.adb
===================================================================
--- par-prag.adb	(revision 229023)
+++ par-prag.adb	(working copy)
@@ -1486,6 +1486,7 @@ 
            Pragma_Volatile                       |
            Pragma_Volatile_Components            |
            Pragma_Volatile_Full_Access           |
+           Pragma_Volatile_Function              |
            Pragma_Warning_As_Error               |
            Pragma_Weak_External                  |
            Pragma_Validity_Checks                =>
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 229041)
+++ sem_ch13.adb	(working copy)
@@ -2284,6 +2284,36 @@ 
                   goto Continue;
                end Abstract_State;
 
+               --  Aspect Async_Readers is never delayed because it is
+               --  equivalent to a source pragma which appears after the
+               --  related object declaration.
+
+               when Aspect_Async_Readers =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Async_Readers);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
+               --  Aspect Async_Writers is never delayed because it is
+               --  equivalent to a source pragma which appears after the
+               --  related object declaration.
+
+               when Aspect_Async_Writers =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Async_Writers);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
                --  Aspect Constant_After_Elaboration is never delayed because
                --  it is equivalent to a source pragma which appears after the
                --  related object declaration.
@@ -2354,6 +2384,36 @@ 
                   Insert_Pragma (Aitem);
                   goto Continue;
 
+               --  Aspect Effecitve_Reads is never delayed because it is
+               --  equivalent to a source pragma which appears after the
+               --  related object declaration.
+
+               when Aspect_Effective_Reads =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Effective_Reads);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
+               --  Aspect Effective_Writes is never delayed because it is
+               --  equivalent to a source pragma which appears after the
+               --  related object declaration.
+
+               when Aspect_Effective_Writes =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Effective_Writes);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
                --  Aspect Extensions_Visible is never delayed because it is
                --  equivalent to a source pragma which appears after the
                --  related subprogram.
@@ -2779,6 +2839,21 @@ 
                      end;
                   end if;
 
+               --  Aspect Volatile_Function is never delayed because it is
+               --  equivalent to a source pragma which appears after the
+               --  related subprogram.
+
+               when Aspect_Volatile_Function =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Volatile_Function);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
                --  Case 2e: Annotate aspect
 
                when Aspect_Annotate =>
@@ -3234,47 +3309,10 @@ 
                      goto Continue;
                   end if;
 
-                  --  External property aspects are Boolean by nature, but
-                  --  their pragmas must contain two arguments, the second
-                  --  being the optional Boolean expression.
-
-                  if A_Id = Aspect_Async_Readers   or else
-                     A_Id = Aspect_Async_Writers   or else
-                     A_Id = Aspect_Effective_Reads or else
-                     A_Id = Aspect_Effective_Writes
-                  then
-                     declare
-                        Args : List_Id;
-
-                     begin
-                        --  The first argument of the external property pragma
-                        --  is the related object.
-
-                        Args :=
-                          New_List (
-                            Make_Pragma_Argument_Association (Sloc (Ent),
-                              Expression => Ent));
-
-                        --  The second argument is the optional Boolean
-                        --  expression which must be propagated even if it
-                        --  evaluates to False as this has special semantic
-                        --  meaning.
-
-                        if Present (Expr) then
-                           Append_To (Args,
-                             Make_Pragma_Argument_Association (Loc,
-                               Expression => Relocate_Node (Expr)));
-                        end if;
-
-                        Make_Aitem_Pragma
-                          (Pragma_Argument_Associations => Args,
-                           Pragma_Name                  => Nam);
-                     end;
-
                   --  Cases where we do not delay, includes all cases where the
                   --  expression is missing other than the above cases.
 
-                  elsif not Delay_Required or else No (Expr) then
+                  if not Delay_Required or else No (Expr) then
                      Make_Aitem_Pragma
                        (Pragma_Argument_Associations => New_List (
                           Make_Pragma_Argument_Association (Sloc (Ent),
@@ -9285,12 +9323,16 @@ 
 
          when Aspect_Abstract_State             |
               Aspect_Annotate                   |
+              Aspect_Async_Readers              |
+              Aspect_Async_Writers              |
               Aspect_Constant_After_Elaboration |
               Aspect_Contract_Cases             |
               Aspect_Default_Initial_Condition  |
               Aspect_Depends                    |
               Aspect_Dimension                  |
               Aspect_Dimension_System           |
+              Aspect_Effective_Reads            |
+              Aspect_Effective_Writes           |
               Aspect_Extensions_Visible         |
               Aspect_Ghost                      |
               Aspect_Global                     |
@@ -9309,7 +9351,8 @@ 
               Aspect_Refined_State              |
               Aspect_SPARK_Mode                 |
               Aspect_Test_Case                  |
-              Aspect_Unimplemented              =>
+              Aspect_Unimplemented              |
+              Aspect_Volatile_Function          =>
             raise Program_Error;
 
       end case;
Index: snames.ads-tmpl
===================================================================
--- snames.ads-tmpl	(revision 229023)
+++ snames.ads-tmpl	(working copy)
@@ -632,6 +632,7 @@ 
    Name_Volatile                       : constant Name_Id := N + $;
    Name_Volatile_Components            : constant Name_Id := N + $;
    Name_Volatile_Full_Access           : constant Name_Id := N + $; -- GNAT
+   Name_Volatile_Function              : constant Name_Id := N + $; -- GNAT
    Name_Weak_External                  : constant Name_Id := N + $; -- GNAT
    Last_Pragma_Name                    : constant Name_Id := N + $;
 
@@ -1937,6 +1938,7 @@ 
       Pragma_Volatile,
       Pragma_Volatile_Components,
       Pragma_Volatile_Full_Access,
+      Pragma_Volatile_Function,
       Pragma_Weak_External,
 
       --  The following pragmas are on their own, out of order, because of the