Commit 50477551 by Eric Botcazou Committed by Pierre-Marie de Rodat

[Ada] Complete implementation of RM C.6(19) clause

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.

2018-12-11  Eric Botcazou  <ebotcazou@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.

From-SVN: r266993
parent f3e0577c
2018-12-11 Eric Botcazou <ebotcazou@adacore.com>
* 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.
2018-12-11 Piotr Trojanek <trojanek@adacore.com> 2018-12-11 Piotr Trojanek <trojanek@adacore.com>
* sem_util.adb (Is_Subprogram_Stub_Without_Prior_Declaration): * sem_util.adb (Is_Subprogram_Stub_Without_Prior_Declaration):
......
...@@ -281,13 +281,17 @@ extern Boolean Is_OK_Static_Subtype (Entity_Id); ...@@ -281,13 +281,17 @@ extern Boolean Is_OK_Static_Subtype (Entity_Id);
#define Defining_Entity sem_util__defining_entity #define Defining_Entity sem_util__defining_entity
#define First_Actual sem_util__first_actual #define First_Actual sem_util__first_actual
#define Next_Actual sem_util__next_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_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 #define Requires_Transient_Scope sem_util__requires_transient_scope
extern Entity_Id Defining_Entity (Node_Id); extern Entity_Id Defining_Entity (Node_Id);
extern Node_Id First_Actual (Node_Id); extern Node_Id First_Actual (Node_Id);
extern Node_Id Next_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_Variable_Size_Record (Entity_Id Id);
extern Boolean Is_Volatile_Object (Node_Id);
extern Boolean Requires_Transient_Scope (Entity_Id); extern Boolean Requires_Transient_Scope (Entity_Id);
/* sinfo: */ /* sinfo: */
......
...@@ -4936,6 +4936,35 @@ create_init_temporary (const char *prefix, tree gnu_init, tree *gnu_init_stmt, ...@@ -4936,6 +4936,35 @@ create_init_temporary (const char *prefix, tree gnu_init, tree *gnu_init_stmt,
return gnu_temp; 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 /* 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. 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. 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, ...@@ -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); = build_compound_expr (TREE_TYPE (gnu_name), init, gnu_name);
} }
/* If we are passing a non-addressable parameter by reference, pass the /* If we are passing a non-addressable actual parameter by reference,
address of a copy. In the In Out or Out case, set up to copy back pass the address of a copy and, in the In Out or Out case, set up
out after the call. */ 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 if (is_by_ref_formal_parm
&& (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name))) && (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; tree gnu_orig = gnu_name, gnu_temp, gnu_stmt;
/* Do not issue warnings for CONSTRUCTORs since this is not a copy /* 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, ...@@ -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. */ /* Create an explicit temporary holding the copy. */
if (atomic_p)
gnu_name = build_atomic_load (gnu_name, sync);
gnu_temp gnu_temp
= create_init_temporary ("A", gnu_name, &gnu_stmt, gnat_actual); = 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, ...@@ -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))) (TREE_OPERAND (TREE_OPERAND (gnu_orig, 1), 1)))
gnu_orig = TREE_OPERAND (gnu_orig, 2); gnu_orig = TREE_OPERAND (gnu_orig, 2);
gnu_stmt if (atomic_p)
= build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_orig, gnu_temp); 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); set_expr_location_from_node (gnu_stmt, gnat_node);
append_to_statement_list (gnu_stmt, &gnu_after_list); append_to_statement_list (gnu_stmt, &gnu_after_list);
......
2018-12-11 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/atomic11.adb, gnat.dg/atomic11_pkg1.ads,
gnat.dg/atomic11_pkg2.ads: New testcase.
2018-12-11 Ed Schonberg <schonberg@adacore.com> 2018-12-11 Ed Schonberg <schonberg@adacore.com>
* gnat.dg/aspect1.adb, gnat.dg/aspect1_horizontal.adb, * gnat.dg/aspect1.adb, gnat.dg/aspect1_horizontal.adb,
......
-- { 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;
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;
package Atomic11_Pkg2 is
function Max return Positive;
end Atomic11_Pkg2;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment