[Ada] Reject violation of SPARK 6.1.4(12) with enclosing task unit

Message ID 20180611092325.GA135030@adacore.com
State New
Headers show
Series
  • [Ada] Reject violation of SPARK 6.1.4(12) with enclosing task unit
Related show

Commit Message

Pierre-Marie de Rodat June 11, 2018, 9:23 a.m.
SPARK 6.1.4(12) applies both to enclosing subprograms and enclosing task
units, but the latter was not correctly rejected.

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

2018-06-11  Yannick Moy  <moy@adacore.com>

gcc/ada/

	* sem_prag.adb (Check_Mode_Restriction_In_Enclosing_Context): Adapt for
	possible task unit as the enclosing context.

gcc/testsuite/

	* gnat.dg/spark1.adb, gnat.dg/spark1.ads: New testcase.

Patch

--- gcc/ada/sem_prag.adb
+++ gcc/ada/sem_prag.adb
@@ -2128,10 +2128,10 @@  package body Sem_Prag is
          procedure Check_Mode_Restriction_In_Enclosing_Context
            (Item    : Node_Id;
             Item_Id : Entity_Id);
-         --  Verify that an item of mode In_Out or Output does not appear as an
-         --  input in the Global aspect of an enclosing subprogram. If this is
-         --  the case, emit an error. Item and Item_Id are respectively the
-         --  item and its entity.
+         --  Verify that an item of mode In_Out or Output does not appear as
+         --  an input in the Global aspect of an enclosing subprogram or task
+         --  unit. If this is the case, emit an error. Item and Item_Id are
+         --  respectively the item and its entity.
 
          procedure Check_Mode_Restriction_In_Function (Mode : Node_Id);
          --  Mode denotes either In_Out or Output. Depending on the kind of the
@@ -2483,12 +2483,24 @@  package body Sem_Prag is
             Outputs : Elist_Id := No_Elist;
 
          begin
-            --  Traverse the scope stack looking for enclosing subprograms
-            --  subject to pragma [Refined_]Global.
+            --  Traverse the scope stack looking for enclosing subprograms or
+            --  tasks subject to pragma [Refined_]Global.
 
             Context := Scope (Subp_Id);
             while Present (Context) and then Context /= Standard_Standard loop
-               if Is_Subprogram (Context)
+
+               --  For a single task type, retrieve the corresponding object to
+               --  which pragma [Refined_]Global is attached.
+
+               if Ekind (Context) = E_Task_Type
+                 and then Is_Single_Concurrent_Type (Context)
+               then
+                  Context := Anonymous_Object (Context);
+               end if;
+
+               if (Is_Subprogram (Context)
+                   or else Ekind (Context) = E_Task_Type
+                   or else Is_Single_Task_Object (Context))
                  and then
                    (Present (Get_Pragma (Context, Pragma_Global))
                       or else
@@ -2501,7 +2513,8 @@  package body Sem_Prag is
                      Global_Seen  => Dummy);
 
                   --  The item is classified as In_Out or Output but appears as
-                  --  an Input in an enclosing subprogram (SPARK RM 6.1.4(12)).
+                  --  an Input in an enclosing subprogram or task unit (SPARK
+                  --  RM 6.1.4(12)).
 
                   if Appears_In (Inputs, Item_Id)
                     and then not Appears_In (Outputs, Item_Id)
@@ -2510,9 +2523,15 @@  package body Sem_Prag is
                        ("global item & cannot have mode In_Out or Output",
                         Item, Item_Id);
 
-                     SPARK_Msg_NE
-                       (Fix_Msg (Subp_Id, "\item already appears as input of "
-                        & "subprogram &"), Item, Context);
+                     if Is_Subprogram (Context) then
+                        SPARK_Msg_NE
+                          (Fix_Msg (Subp_Id, "\item already appears as input "
+                           & "of subprogram &"), Item, Context);
+                     else
+                        SPARK_Msg_NE
+                          (Fix_Msg (Subp_Id, "\item already appears as input "
+                           & "of task &"), Item, Context);
+                     end if;
 
                      --  Stop the traversal once an error has been detected
 

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/spark1.adb
@@ -0,0 +1,22 @@ 
+--  { dg-do compile }
+
+package body Spark1 is
+
+   task body Worker is
+
+      procedure Update with
+        Global => (In_Out => Mailbox) --  { dg-error "global item \"Mailbox\" cannot have mode In_Out or Output|item already appears as input of task \"Worker\"" }
+      is
+         Tmp : Integer := Mailbox;
+      begin
+         Mailbox := Tmp + 1;
+      end Update;
+
+      X : Integer := Mailbox;
+   begin
+      loop
+         Update;
+      end loop;
+   end;
+
+end;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/spark1.ads
@@ -0,0 +1,8 @@ 
+package Spark1 is
+
+   Mailbox : Integer with Atomic, Async_Writers, Async_Readers;
+
+   task Worker
+     with Global => (Input => Mailbox);
+
+end;