diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-02-29 09:02:46 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-02-29 09:02:46 +0000 |
commit | 95164e7198c69e87adf63516993537c834b4512e (patch) | |
tree | 393bcdf9df2f8ceab15cb45aae341cbc2d86146c | |
parent | a890896f9d530c1501c3e053174a8f4bcb1478e8 (diff) | |
download | gcc-95164e7198c69e87adf63516993537c834b4512e.tar.gz |
* gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro.
* gcc-interface/gigi.h (gigi): Remove useless attribute.
(gnat_gimplify_expr): Likewise.
(gnat_to_gnu_external): Declare.
* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Constant>: Factor out
code dealing with the expression of external constants into...
Invoke gnat_to_gnu_external instead.
<E_Variable>: Invoke gnat_to_gnu_external to translate renamed objects
when not for a definition. Deal with COMPOUND_EXPR and variables with
DECL_RETURN_VALUE_P set for renamings and with the case of a dangling
'reference to a function call in a renaming. Remove obsolete test and
adjust associated comment.
* gcc-interface/trans.c (Call_to_gnu): Set DECL_RETURN_VALUE_P on the
temporaries created to hold the return value, if any.
(gnat_to_gnu_external): ...this. New function.
* gcc-interface/utils.c (create_var_decl): Detect a constant created
to hold 'reference to function call.
* gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Add folding
for COMPOUND_EXPR in the DECL_RETURN_VALUE_P case.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233804 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ada/ChangeLog | 22 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/ada-tree.h | 4 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/decl.c | 67 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/gigi.h | 14 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 41 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 16 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils2.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8.adb | 11 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8_pkg1.ads | 7 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8_pkg2.adb | 8 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8_pkg2.ads | 13 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8_pkg3.adb | 8 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/renaming8_pkg3.ads | 5 |
14 files changed, 190 insertions, 40 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 4868cae34a2..49c0632ef04 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,25 @@ +2016-02-29 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro. + * gcc-interface/gigi.h (gigi): Remove useless attribute. + (gnat_gimplify_expr): Likewise. + (gnat_to_gnu_external): Declare. + * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Constant>: Factor out + code dealing with the expression of external constants into... + Invoke gnat_to_gnu_external instead. + <E_Variable>: Invoke gnat_to_gnu_external to translate renamed objects + when not for a definition. Deal with COMPOUND_EXPR and variables with + DECL_RETURN_VALUE_P set for renamings and with the case of a dangling + 'reference to a function call in a renaming. Remove obsolete test and + adjust associated comment. + * gcc-interface/trans.c (Call_to_gnu): Set DECL_RETURN_VALUE_P on the + temporaries created to hold the return value, if any. + (gnat_to_gnu_external): ...this. New function. + * gcc-interface/utils.c (create_var_decl): Detect a constant created + to hold 'reference to function call. + * gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Add folding + for COMPOUND_EXPR in the DECL_RETURN_VALUE_P case. + 2016-02-17 Eric Botcazou <ebotcazou@adacore.com> * exp_ch4.adb (Expand_N_Indexed_Component): Active synchronization if diff --git a/gcc/ada/gcc-interface/ada-tree.h b/gcc/ada/gcc-interface/ada-tree.h index ceabd175ae4..ac4ec2f81c4 100644 --- a/gcc/ada/gcc-interface/ada-tree.h +++ b/gcc/ada/gcc-interface/ada-tree.h @@ -457,6 +457,10 @@ do { \ a discriminant of a discriminated type without default expression. */ #define DECL_INVARIANT_P(NODE) DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) +/* Nonzero in a VAR_DECL if it is a temporary created to hold the return + value of a function call or 'reference to a function call. */ +#define DECL_RETURN_VALUE_P(NODE) DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE)) + /* In a FIELD_DECL corresponding to a discriminant, contains the discriminant number. */ #define DECL_DISCRIMINANT_NUMBER(NODE) DECL_INITIAL (FIELD_DECL_CHECK (NODE)) diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 3f2358b7c6d..b4ba8e51bce 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -552,31 +552,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) && Present (Expression (Declaration_Node (gnat_entity))) && Nkind (Expression (Declaration_Node (gnat_entity))) != N_Allocator) - { - bool went_into_elab_proc = false; - int save_force_global = force_global; - /* The expression may contain N_Expression_With_Actions nodes and - thus object declarations from other units. In this case, even - though the expression will eventually be discarded since not a - constant, the declarations would be stuck either in the global - varpool or in the current scope. Therefore we force the local - context and create a fake scope that we'll zap at the end. */ - if (!current_function_decl) - { - current_function_decl = get_elaboration_procedure (); - went_into_elab_proc = true; - } - force_global = 0; - gnat_pushlevel (); - - gnu_expr = gnat_to_gnu (Expression (Declaration_Node (gnat_entity))); - - gnat_zaplevel (); - force_global = save_force_global; - if (went_into_elab_proc) - current_function_decl = NULL_TREE; - } + thus object declarations from other units. Discard them. */ + gnu_expr + = gnat_to_gnu_external (Expression (Declaration_Node (gnat_entity))); /* ... fall through ... */ @@ -611,13 +590,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) tree renamed_obj = NULL_TREE; tree gnu_object_size; + /* We need to translate the renamed object even though we are only + referencing the renaming. But it may contain a call for which + we'll generate a temporary to hold the return value and which + is part of the definition of the renaming, so discard it. */ if (Present (Renamed_Object (gnat_entity)) && !definition) { if (kind == E_Exception) gnu_expr = gnat_to_gnu_entity (Renamed_Entity (gnat_entity), NULL_TREE, 0); else - gnu_expr = gnat_to_gnu (Renamed_Object (gnat_entity)); + gnu_expr = gnat_to_gnu_external (Renamed_Object (gnat_entity)); } /* Get the type after elaborating the renamed object. */ @@ -976,14 +959,39 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) inner = TREE_OPERAND (inner, 0); /* Expand_Dispatching_Call can prepend a comparison of the tags before the call to "=". */ - if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR) + if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR + || TREE_CODE (inner) == COMPOUND_EXPR) inner = TREE_OPERAND (inner, 1); if ((TREE_CODE (inner) == CALL_EXPR && !call_is_atomic_load (inner)) || TREE_CODE (inner) == ADDR_EXPR || TREE_CODE (inner) == NULL_EXPR || TREE_CODE (inner) == CONSTRUCTOR - || CONSTANT_CLASS_P (inner)) + || CONSTANT_CLASS_P (inner) + /* We need to detect the case where a temporary is created to + hold the return value, since we cannot safely rename it at + top level as it lives only in the elaboration routine. */ + || (TREE_CODE (inner) == VAR_DECL + && DECL_RETURN_VALUE_P (inner)) + /* We also need to detect the case where the front-end creates + a dangling 'reference to a function call at top level and + substitutes it in the renaming, for example: + + q__b : boolean renames r__f.e (1); + + can be rewritten into: + + q__R1s : constant q__A2s := r__f'reference; + [...] + q__b : boolean renames q__R1s.all.e (1); + + We cannot safely rename the rewritten expression since the + underlying object lives only in the elaboration routine. */ + || (TREE_CODE (inner) == INDIRECT_REF + && (inner + = remove_conversions (TREE_OPERAND (inner, 0), true)) + && TREE_CODE (inner) == VAR_DECL + && DECL_RETURN_VALUE_P (inner))) ; /* Case 2: if the renaming entity need not be materialized, use @@ -991,8 +999,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) means that the caller is responsible for evaluating the address of the renaming in the correct place for the definition case to instantiate the SAVE_EXPRs. */ - else if (TREE_CODE (inner) != COMPOUND_EXPR - && !Materialize_Entity (gnat_entity)) + else if (!Materialize_Entity (gnat_entity)) { tree init = NULL_TREE; @@ -1001,7 +1008,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) &init); /* We cannot evaluate the first arm of a COMPOUND_EXPR in the - correct place for this case, hence the above test. */ + correct place for this case. */ gcc_assert (!init); /* No DECL_EXPR will be created so the expression needs to be diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 00b7c6a66be..2b58d4eadb9 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -246,7 +246,7 @@ extern "C" { structures and then generates code. */ extern void gigi (Node_Id gnat_root, int max_gnat_node, - int number_name ATTRIBUTE_UNUSED, + int number_name, struct Node *nodes_ptr, struct Flags *Flags_Ptr, Node_Id *next_node_ptr, @@ -270,17 +270,19 @@ extern void gigi (Node_Id gnat_root, #endif /* GNAT_NODE is the root of some GNAT tree. Return the root of the - GCC tree corresponding to that GNAT tree. Normally, no code is generated; - we just return an equivalent tree which is used elsewhere to generate - code. */ + GCC tree corresponding to that GNAT tree. */ extern tree gnat_to_gnu (Node_Id gnat_node); +/* Similar to gnat_to_gnu, but discard any object that might be created in + the course of the translation of GNAT_NODE, which must be an "external" + expression in the sense that it will be elaborated elsewhere. */ +extern tree gnat_to_gnu_external (Node_Id gnat_node); + /* GNU_STMT is a statement. We generate code for that statement. */ extern void gnat_expand_stmt (tree gnu_stmt); /* Generate GIMPLE in place for the expression at *EXPR_P. */ -extern int gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, - gimple_seq *post_p ATTRIBUTE_UNUSED); +extern int gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *); /* Do the processing for the declaration of a GNAT_ENTITY, a type. If a separate Freeze node exists, delay the bulk of the processing. Otherwise diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index fce3f0e2633..f830a3d2490 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -4336,7 +4336,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, && TREE_CODE (TYPE_SIZE (TREE_TYPE (gnu_target))) == INTEGER_CST)) && TREE_CODE (TYPE_SIZE (gnu_result_type)) != INTEGER_CST))) - gnu_retval = create_temporary ("R", gnu_result_type); + { + gnu_retval = create_temporary ("R", gnu_result_type); + DECL_RETURN_VALUE_P (gnu_retval) = 1; + } /* Create the list of the actual parameters as GCC expects it, namely a chain of TREE_LIST nodes in which the TREE_VALUE field of each node @@ -4461,7 +4464,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, we need to create a temporary for the return value because we must preserve it before copying back at the very end. */ if (!in_param && returning_value && !gnu_retval) - gnu_retval = create_temporary ("R", gnu_result_type); + { + gnu_retval = create_temporary ("R", gnu_result_type); + DECL_RETURN_VALUE_P (gnu_retval) = 1; + } /* If we haven't pushed a binding level, push a new one. This will narrow the lifetime of the temporary we are about to make as much @@ -7808,6 +7814,37 @@ gnat_to_gnu (Node_Id gnat_node) return gnu_result; } + +/* Similar to gnat_to_gnu, but discard any object that might be created in + the course of the translation of GNAT_NODE, which must be an "external" + expression in the sense that it will be elaborated elsewhere. */ + +tree +gnat_to_gnu_external (Node_Id gnat_node) +{ + const int save_force_global = force_global; + bool went_into_elab_proc = false; + + /* Force the local context and create a fake scope that we zap + at the end so declarations will not be stuck either in the + global varpool or in the current scope. */ + if (!current_function_decl) + { + current_function_decl = get_elaboration_procedure (); + went_into_elab_proc = true; + } + force_global = 0; + gnat_pushlevel (); + + tree gnu_result = gnat_to_gnu (gnat_node); + + gnat_zaplevel (); + force_global = save_force_global; + if (went_into_elab_proc) + current_function_decl = NULL_TREE; + + return gnu_result; +} /* Subroutine of above to push the exception label stack. GNU_STACK is a pointer to the stack to update and GNAT_LABEL, if present, is the diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index ff21e7b5ff0..6d4770df998 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -2464,6 +2464,22 @@ create_var_decl (tree name, tree asm_name, tree type, tree init, && !AGGREGATE_TYPE_P (type)) ? CONST_DECL : VAR_DECL, name, type); + /* Detect constants created by the front-end to hold 'reference to function + calls for stabilization purposes. This is needed for renaming. */ + if (const_flag && init && POINTER_TYPE_P (type)) + { + tree inner = init; + if (TREE_CODE (inner) == COMPOUND_EXPR) + inner = TREE_OPERAND (inner, 1); + inner = remove_conversions (inner, true); + if (TREE_CODE (inner) == ADDR_EXPR + && ((TREE_CODE (TREE_OPERAND (inner, 0)) == CALL_EXPR + && !call_is_atomic_load (TREE_OPERAND (inner, 0))) + || (TREE_CODE (TREE_OPERAND (inner, 0)) == VAR_DECL + && DECL_RETURN_VALUE_P (TREE_OPERAND (inner, 0))))) + DECL_RETURN_VALUE_P (var_decl) = 1; + } + /* If this is external, throw away any initializations (they will be done elsewhere) unless this is a constant for which we would like to remain able to get the initializer. If we are defining a global here, leave a diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index 44a05fb012d..c1bb74da287 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -1383,8 +1383,11 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) since the middle-end cannot handle it. But we don't it in the general case because it may introduce aliasing issues if the first operand is an indirect assignment and the second operand - the corresponding address, e.g. for an allocator. */ - if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE) + the corresponding address, e.g. for an allocator. However do + it for a return value to expose it for later recognition. */ + if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE + || (TREE_CODE (TREE_OPERAND (operand, 1)) == VAR_DECL + && DECL_RETURN_VALUE_P (TREE_OPERAND (operand, 1)))) { result = build_unary_op (ADDR_EXPR, result_type, TREE_OPERAND (operand, 1)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8347c677cd4..d6803dabd74 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2016-02-29 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/renaming8.adb: New test. + * gnat.dg/renaming8_pkg1.ads: New helper. + * gnat.dg/renaming8_pkg2.ad[sb]: Likewise. + * gnat.dg/renaming8_pkg3.ad[sb]: Likewise. + 2016-02-29 Richard Biener <rguenther@suse.de> PR tree-optimization/69720 diff --git a/gcc/testsuite/gnat.dg/renaming8.adb b/gcc/testsuite/gnat.dg/renaming8.adb new file mode 100644 index 00000000000..f41c8132ab0 --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8.adb @@ -0,0 +1,11 @@ +-- { dg-do run } +-- { dg-options "-gnatp" } + +with Renaming8_Pkg1; use Renaming8_Pkg1; + +procedure Renaming8 is +begin + if not B then + raise Program_Error; + end if; +end; diff --git a/gcc/testsuite/gnat.dg/renaming8_pkg1.ads b/gcc/testsuite/gnat.dg/renaming8_pkg1.ads new file mode 100644 index 00000000000..ff5768cc49a --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8_pkg1.ads @@ -0,0 +1,7 @@ +with Renaming8_Pkg2; use Renaming8_Pkg2; + +package Renaming8_Pkg1 is + + B: Boolean renames F.E(1); + +end Renaming8_Pkg1; diff --git a/gcc/testsuite/gnat.dg/renaming8_pkg2.adb b/gcc/testsuite/gnat.dg/renaming8_pkg2.adb new file mode 100644 index 00000000000..c135b392f0b --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8_pkg2.adb @@ -0,0 +1,8 @@ +package body Renaming8_Pkg2 is + + function F return Rec is + begin + return (E => (others => True)); + end; + +end Renaming8_Pkg2; diff --git a/gcc/testsuite/gnat.dg/renaming8_pkg2.ads b/gcc/testsuite/gnat.dg/renaming8_pkg2.ads new file mode 100644 index 00000000000..5d117dbfc26 --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8_pkg2.ads @@ -0,0 +1,13 @@ +with Renaming8_Pkg3; use Renaming8_Pkg3; + +package Renaming8_Pkg2 is + + type Arr is array (Positive range 1 .. Last_Index) of Boolean; + + type Rec is record + E : Arr; + end record; + + function F return Rec; + +end Renaming8_Pkg2; diff --git a/gcc/testsuite/gnat.dg/renaming8_pkg3.adb b/gcc/testsuite/gnat.dg/renaming8_pkg3.adb new file mode 100644 index 00000000000..c17786b4ef0 --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8_pkg3.adb @@ -0,0 +1,8 @@ +package body Renaming8_Pkg3 is + + function Last_Index return Integer is + begin + return 16; + end; + +end Renaming8_Pkg3; diff --git a/gcc/testsuite/gnat.dg/renaming8_pkg3.ads b/gcc/testsuite/gnat.dg/renaming8_pkg3.ads new file mode 100644 index 00000000000..dda81015189 --- /dev/null +++ b/gcc/testsuite/gnat.dg/renaming8_pkg3.ads @@ -0,0 +1,5 @@ +package Renaming8_Pkg3 is + + function Last_Index return Integer; + +end Renaming8_Pkg3; |