aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGary Dismukes <dismukes@adacore.com>2019-10-10 15:25:36 +0000
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>2019-10-10 15:25:36 +0000
commit7e536bfd0600341f83d85312cf9c909205ec4d18 (patch)
tree2081bd613368ceea2a041f343f4afb2d377eb20f /gcc
parentebeabe0454975d7600af111a9461a85e75863641 (diff)
downloadgcc-7e536bfd0600341f83d85312cf9c909205ec4d18.zip
gcc-7e536bfd0600341f83d85312cf9c909205ec4d18.tar.gz
gcc-7e536bfd0600341f83d85312cf9c909205ec4d18.tar.bz2
[Ada] Handling up-level references in loops within library-level declarations
2019-10-10 Gary Dismukes <dismukes@adacore.com> gcc/ada/ * exp_ch7.adb (Check_Unnesting_In_Decls_Or_Stmts): When encountering a loop at the top level of a package declaration list (that is, within the declarations of a package spec or body) that has nested subprograms, call Unnest_Loop to create a new library-level procedure that will contain the loop, to allow for proper handling of up-level references from within nested subprograms, such as to loop parameters. (Unnest_Loop): New procedure that takes a loop statement and creates a new procedure body to enclose the loop statement, along with generating a call to the procedure. From-SVN: r276836
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ada/ChangeLog14
-rw-r--r--gcc/ada/exp_ch7.adb86
2 files changed, 97 insertions, 3 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index b17b608..4b829cf 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,4 +1,12 @@
-2019-10-10 Arnaud Charlet <charlet@adacore.com>
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
- * freeze.adb (Freeze_Subprogram): Ensure constructor is a C++
- constructor. \ No newline at end of file
+ * exp_ch7.adb (Check_Unnesting_In_Decls_Or_Stmts): When
+ encountering a loop at the top level of a package declaration
+ list (that is, within the declarations of a package spec or
+ body) that has nested subprograms, call Unnest_Loop to create a
+ new library-level procedure that will contain the loop, to allow
+ for proper handling of up-level references from within nested
+ subprograms, such as to loop parameters.
+ (Unnest_Loop): New procedure that takes a loop statement and
+ creates a new procedure body to enclose the loop statement,
+ along with generating a call to the procedure. \ No newline at end of file
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index f1b7279..297e27d 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -398,6 +398,14 @@ package body Exp_Ch7 is
-- actions or secondary-stack management, in which case the nested
-- subprogram is a finalizer.
+ procedure Unnest_Loop (Loop_Stmt : Node_Id);
+ -- Top-level Loops that contain nested subprograms with up-level references
+ -- need to have activation records. We do this by rewriting the loop as a
+ -- procedure containing the loop, followed by a call to the procedure in
+ -- the same library-level declarative list, to replicate the semantics of
+ -- the original loop. Such loops can occur due to aggregate expansions and
+ -- other constructs.
+
procedure Check_Visibly_Controlled
(Prim : Final_Primitives;
Typ : Entity_Id;
@@ -4230,6 +4238,23 @@ package body Exp_Ch7 is
then
Unnest_Block (Decl_Or_Stmt);
+ elsif Nkind (Decl_Or_Stmt) = N_Loop_Statement then
+ declare
+ Id : constant Entity_Id :=
+ Entity (Identifier (Decl_Or_Stmt));
+
+ begin
+ -- When a top-level loop within declarations of a library
+ -- package spec or body contains nested subprograms, we wrap
+ -- it in a procedure to handle possible up-level references
+ -- to entities associated with the loop (such as loop
+ -- parameters).
+
+ if Present (Id) and then Contains_Subprogram (Id) then
+ Unnest_Loop (Decl_Or_Stmt);
+ end if;
+ end;
+
elsif Nkind (Decl_Or_Stmt) = N_Package_Declaration
and then not Modify_Tree_For_C
then
@@ -9256,6 +9281,67 @@ package body Exp_Ch7 is
end loop;
end Unnest_Block;
+ -----------------
+ -- Unnest_Loop --
+ -----------------
+
+ procedure Unnest_Loop (Loop_Stmt : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Loop_Stmt);
+ Ent : Entity_Id;
+ Local_Body : Node_Id;
+ Local_Call : Node_Id;
+ Local_Proc : Entity_Id;
+ Local_Scop : Entity_Id;
+ Loop_Copy : constant Node_Id :=
+ Relocate_Node (Loop_Stmt);
+ begin
+ Local_Scop := Entity (Identifier (Loop_Stmt));
+ Ent := First_Entity (Local_Scop);
+
+ Local_Proc :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_Internal_Name ('P'));
+
+ Local_Body :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Local_Proc),
+ Declarations => Empty_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (Loop_Copy)));
+
+ Set_First_Real_Statement
+ (Handled_Statement_Sequence (Local_Body), Loop_Copy);
+
+ Rewrite (Loop_Stmt, Local_Body);
+ Analyze (Loop_Stmt);
+
+ Set_Has_Nested_Subprogram (Local_Proc);
+
+ Local_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Local_Proc, Loc));
+
+ Insert_After (Loop_Stmt, Local_Call);
+ Analyze (Local_Call);
+
+ -- New procedure has the same scope as the original loop, and the scope
+ -- of the loop is the new procedure.
+
+ Set_Scope (Local_Proc, Scope (Local_Scop));
+ Set_Scope (Local_Scop, Local_Proc);
+
+ -- The entity list of the new procedure is that of the loop
+
+ Set_First_Entity (Local_Proc, Ent);
+
+ -- Note that the entities associated with the loop don't need to have
+ -- their Scope fields reset, since they're still associated with the
+ -- same loop entity that now belongs to the copied loop statement.
+ end Unnest_Loop;
+
--------------------------------
-- Wrap_Transient_Declaration --
--------------------------------