diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2018-12-11 11:10:27 +0000 |
---|---|---|
committer | Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> | 2018-12-11 11:10:27 +0000 |
commit | 504775519d3199ea89400f85a599cb791f736cb7 (patch) | |
tree | ccc7225b608c67e93265f33bc741e4dac5c7e268 /gcc/ada/gcc-interface | |
parent | f3e0577c2a2d3463ec8e05ec187ed7ad4f906159 (diff) | |
download | gcc-504775519d3199ea89400f85a599cb791f736cb7.zip gcc-504775519d3199ea89400f85a599cb791f736cb7.tar.gz gcc-504775519d3199ea89400f85a599cb791f736cb7.tar.bz2 |
[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
Diffstat (limited to 'gcc/ada/gcc-interface')
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 5caba99..c2553d8 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/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); |