This ensures that the compiler fully implements the C.6(19) clause of
the Ada Reference Manual and gives a warning when the clause does change
the passing mechanism of the affected parameter.

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

2018-12-11  Eric Botcazou  <ebotca...@adacore.com>

gcc/ada/

        * fe.h (Is_Atomic_Object): Declare.
        (Is_Volatile_Object): Likewise.
        * gcc-interface/trans.c (atomic_or_volatile_copy_required_p):
        New.
        (Call_to_gnu): Generate a copy for an actual parameter passed by
        reference if the conditions set forth by RM C.6(19) are met and
        specificially deal with an atomic actual parameter.

gcc/testsuite/

        * gnat.dg/atomic11.adb, gnat.dg/atomic11_pkg1.ads,
        gnat.dg/atomic11_pkg2.ads: New testcase.
--- gcc/ada/fe.h
+++ gcc/ada/fe.h
@@ -281,13 +281,17 @@ extern Boolean Is_OK_Static_Subtype	(Entity_Id);
 #define Defining_Entity			sem_util__defining_entity
 #define First_Actual			sem_util__first_actual
 #define Next_Actual			sem_util__next_actual
+#define Is_Atomic_Object		sem_util__is_atomic_object
 #define Is_Variable_Size_Record 	sem_util__is_variable_size_record
+#define Is_Volatile_Object		sem_util__is_volatile_object
 #define Requires_Transient_Scope	sem_util__requires_transient_scope
 
 extern Entity_Id Defining_Entity	(Node_Id);
 extern Node_Id First_Actual		(Node_Id);
 extern Node_Id Next_Actual		(Node_Id);
+extern Boolean Is_Atomic_Object 	(Node_Id);
 extern Boolean Is_Variable_Size_Record 	(Entity_Id Id);
+extern Boolean Is_Volatile_Object 	(Node_Id);
 extern Boolean Requires_Transient_Scope	(Entity_Id);
 
 /* sinfo: */

--- gcc/ada/gcc-interface/trans.c
+++ gcc/ada/gcc-interface/trans.c
@@ -4936,6 +4936,35 @@ create_init_temporary (const char *prefix, tree gnu_init, tree *gnu_init_stmt,
   return gnu_temp;
 }
 
+/* Return whether ACTUAL parameter corresponding to FORMAL_TYPE must be passed
+   by copy in a call as per RM C.6(19).  Note that we use the same predicates
+   as in the front-end for RM C.6(12) because it's purely a legality issue.  */
+
+static bool
+atomic_or_volatile_copy_required_p (Node_Id actual, Entity_Id formal_type)
+{
+  /* We should not have a scalar type here because such a type is passed
+     by copy.  But the Interlocked routines in System.Aux_DEC force some
+     of the their scalar parameters to be passed by reference so we need
+     to preserve that if we do not want to break the interface.  */
+  if (Is_Scalar_Type (formal_type))
+    return false;
+
+  if (Is_Atomic_Object (actual) && !Is_Atomic (formal_type))
+    {
+      post_error ("?atomic actual passed by copy (RM C.6(19))", actual);
+      return true;
+    }
+
+  if (Is_Volatile_Object (actual) && !Is_Volatile (formal_type))
+    {
+      post_error ("?volatile actual passed by copy (RM C.6(19))", actual);
+      return true;
+    }
+
+  return false;
+}
+
 /* Subroutine of gnat_to_gnu to translate gnat_node, either an N_Function_Call
    or an N_Procedure_Call_Statement, to a GCC tree, which is returned.
    GNU_RESULT_TYPE_P is a pointer to where we should place the result type.
@@ -5150,13 +5179,18 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
 	      = build_compound_expr (TREE_TYPE (gnu_name), init, gnu_name);
 	}
 
-      /* If we are passing a non-addressable parameter by reference, pass the
-	 address of a copy.  In the In Out or Out case, set up to copy back
-	 out after the call.  */
+      /* If we are passing a non-addressable actual parameter by reference,
+	 pass the address of a copy and, in the In Out or Out case, set up
+	 to copy back after the call.  We also need to do that if the actual
+	 parameter is atomic or volatile but the formal parameter is not.  */
       if (is_by_ref_formal_parm
 	  && (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)))
-	  && !addressable_p (gnu_name, gnu_name_type))
+	  && (!addressable_p (gnu_name, gnu_name_type)
+	      || (Comes_From_Source (gnat_node)
+		  && atomic_or_volatile_copy_required_p (gnat_actual,
+							 gnat_formal_type))))
 	{
+	  const bool atomic_p = atomic_access_required_p (gnat_actual, &sync);
 	  tree gnu_orig = gnu_name, gnu_temp, gnu_stmt;
 
 	  /* Do not issue warnings for CONSTRUCTORs since this is not a copy
@@ -5236,6 +5270,8 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
 	    }
 
 	  /* Create an explicit temporary holding the copy.  */
+	  if (atomic_p)
+	    gnu_name = build_atomic_load (gnu_name, sync);
 	  gnu_temp
 	    = create_init_temporary ("A", gnu_name, &gnu_stmt, gnat_actual);
 
@@ -5256,8 +5292,13 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
 		     (TREE_OPERAND (TREE_OPERAND (gnu_orig, 1), 1)))
 		gnu_orig = TREE_OPERAND (gnu_orig, 2);
 
-	      gnu_stmt
-		= build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_orig, gnu_temp);
+	      if (atomic_p)
+		gnu_stmt
+		  = build_atomic_store (gnu_orig, gnu_temp, sync);
+	      else
+		gnu_stmt
+		  = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_orig,
+				     gnu_temp);
 	      set_expr_location_from_node (gnu_stmt, gnat_node);
 
 	      append_to_statement_list (gnu_stmt, &gnu_after_list);

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/atomic11.adb
@@ -0,0 +1,19 @@
+--  { dg-do compile }
+
+with Atomic11_Pkg1; use Atomic11_Pkg1;
+
+procedure Atomic11 is
+
+  R1 : Rec1;
+  pragma Atomic (R1);
+
+  R2 : Rec2;
+  pragma Volatile (R2);
+
+begin
+  R1.I := 0;
+  Proc1 (R1);    -- { dg-warning "atomic actual passed by copy" }
+  R2.A(1) := 0;
+  Proc1 (R1);    -- { dg-warning "atomic actual passed by copy" }
+  Proc2 (R2);    -- { dg-warning "volatile actual passed by copy" }
+end;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/atomic11_pkg1.ads
@@ -0,0 +1,20 @@
+with Atomic11_Pkg2;
+
+package Atomic11_Pkg1 is
+
+  type Rec1 is record
+    I : Integer;
+  end record;
+
+  procedure Proc1 (R : Rec1);
+  pragma Import (C, Proc1);
+
+  type Arr is array (Positive range <>) of Integer;
+
+  type Rec2 is record
+    A : Arr (1 .. Atomic11_Pkg2.Max);
+  end record;
+
+  procedure Proc2 (R : Rec2);
+
+end Atomic11_Pkg1;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/atomic11_pkg2.ads
@@ -0,0 +1,5 @@
+package Atomic11_Pkg2 is
+
+  function Max return Positive;
+
+end Atomic11_Pkg2;

Reply via email to