From: Raphaël AMIARD <ami...@adacore.com>

We want to allow statements lists with declarations *and* an exception
handler. What follows from this is that declarations declared in the
statement list are *not* visible from the exception handler, and that
the following code:

    declare
        A : Integer := 12;
    begin
        A : Integer := 15;

        <stmts>
    exception
        when others => ...

Roughly expands to:

    declare
        A : Integer := 12;
    begin
        declare
            A : Integer := 15;
        begin
            <stmts>
    exception
        when others => ...

As such, in the code above, there is no more error triggered for
conflicting declarations of `A`.

Move "Local declarations without block" into curated extensions

Restrict legal local decls in statement lists

Only accept object declarations & renamings, as well as use clauses for

gcc/ada/ChangeLog:

        * par-ch11.adb (P_Sequence_Of_Statements): Remove Handled
        parameter. Always wrap the statements in a block when there are
        declarations in it.
        * par-ch5.adb: Adapt call to P_Sequence_Of_Statements Update
        outdated comment, remove useless `Style_Checks` pragma.
        (P_Sequence_Of_Statements): Don't emit an error in core extensions
        mode. Emit an error when a non valid declaration is parsed in
        sequence of statements.
        * par.adb: Adapt P_Sequence_Of_Statements' signature
        * doc/gnat_rm/gnat_language_extensions.rst: Adapt documentation
        now.
        * gnat_rm.texi: Regenerate.
        * gnat_ugn.texi: Regenerate.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 .../doc/gnat_rm/gnat_language_extensions.rst  |  52 ++++++-
 gcc/ada/gnat_rm.texi                          |  60 +++++++-
 gcc/ada/gnat_ugn.texi                         |   2 +-
 gcc/ada/par-ch11.adb                          |   3 +-
 gcc/ada/par-ch5.adb                           | 129 +++++++++---------
 gcc/ada/par.adb                               |   2 +-
 6 files changed, 171 insertions(+), 77 deletions(-)

diff --git a/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst 
b/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
index b29f23c29ef..af0da983049 100644
--- a/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
+++ b/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
@@ -53,9 +53,12 @@ Features activated via ``-gnatX`` or
 Local Declarations Without Block
 --------------------------------
 
-A basic_declarative_item may appear at the place of any statement.
-This avoids the heavy syntax of block_statements just to declare
-something locally.
+A ``basic_declarative_item`` may appear at the place of any statement. This
+avoids the heavy syntax of block_statements just to declare something locally.
+
+The only valid kind of declarations for now are ``object_declaration``,
+``object_renaming_declaration``, ``use_package_clause`` and
+``use_type_clause``.
 
 For example:
 
@@ -69,6 +72,49 @@ For example:
       X := X + Squared;
    end if;
 
+.. attention::
+
+   Note that local declarations in statement lists have their own scope, which
+   means that:
+
+   1. Those declarations are not visible from the potential exception handler:
+
+      .. code-block:: ada
+
+         begin
+            A : Integer
+            ...
+         exception
+            when others =>
+                Put_Line (A'Image) --  ILLEGAL
+         end;
+
+   2. The following is legal
+
+      .. code-block:: ada
+
+         declare
+            A : Integer := 10;
+         begin
+            A : Integer := 12;
+         end;
+
+      because it is roughly expanded into
+
+      .. code-block:: ada
+
+         declare
+            A : Integer := 10;
+         begin
+            declare
+               A : Integer := 12;
+            begin
+               ...
+            end;
+         end;
+
+       And as such the second ``A`` declaration is hiding the first one.
+
 Link to the original RFC:
 
https://github.com/AdaCore/ada-spark-rfcs/blob/master/prototyped/rfc-local-vars-without-block.md
 
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index e2686b0a2c7..96f35f7edb8 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -28961,9 +28961,12 @@ Features activated via @code{-gnatX} or
 @subsection Local Declarations Without Block
 
 
-A basic_declarative_item may appear at the place of any statement.
-This avoids the heavy syntax of block_statements just to declare
-something locally.
+A @code{basic_declarative_item} may appear at the place of any statement. This
+avoids the heavy syntax of block_statements just to declare something locally.
+
+The only valid kind of declarations for now are @code{object_declaration},
+@code{object_renaming_declaration}, @code{use_package_clause} and
+@code{use_type_clause}.
 
 For example:
 
@@ -28977,6 +28980,57 @@ if X > 5 then
 end if;
 @end example
 
+@cartouche
+@quotation Attention 
+Note that local declarations in statement lists have their own scope, which
+means that:
+
+
+@enumerate 
+
+@item 
+Those declarations are not visible from the potential exception handler:
+
+@example
+begin
+   A : Integer
+   ...
+exception
+   when others =>
+       Put_Line (A'Image) --  ILLEGAL
+end;
+@end example
+
+@item 
+The following is legal
+
+@example
+declare
+   A : Integer := 10;
+begin
+   A : Integer := 12;
+end;
+@end example
+
+because it is roughly expanded into
+
+@example
+  declare
+     A : Integer := 10;
+  begin
+     declare
+        A : Integer := 12;
+     begin
+        ...
+     end;
+  end;
+
+And as such the second `@w{`}A`@w{`} declaration is hiding the first one.
+@end example
+@end enumerate
+@end quotation
+@end cartouche
+
 Link to the original RFC:
 
@indicateurl{https://github.com/AdaCore/ada-spark-rfcs/blob/master/prototyped/rfc-local-vars-without-block.md}
 
diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi
index 9ba898435f2..7e27b1c503f 100644
--- a/gcc/ada/gnat_ugn.texi
+++ b/gcc/ada/gnat_ugn.texi
@@ -29695,8 +29695,8 @@ to permit their use in free software.
 
 @printindex ge
 
-@anchor{d1}@w{                              }
 @anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{   
                           }
+@anchor{d1}@w{                              }
 
 @c %**end of body
 @bye
diff --git a/gcc/ada/par-ch11.adb b/gcc/ada/par-ch11.adb
index 8b51fc7e5b3..d935b58807e 100644
--- a/gcc/ada/par-ch11.adb
+++ b/gcc/ada/par-ch11.adb
@@ -61,8 +61,7 @@ package body Ch11 is
       Handled_Stmt_Seq_Node :=
         New_Node (N_Handled_Sequence_Of_Statements, Token_Ptr);
       Set_Statements
-        (Handled_Stmt_Seq_Node,
-         P_Sequence_Of_Statements (SS_Extm_Sreq, Handled => True));
+        (Handled_Stmt_Seq_Node, P_Sequence_Of_Statements (SS_Extm_Sreq));
 
       if Token = Tok_Exception then
          Scan; -- past EXCEPTION
diff --git a/gcc/ada/par-ch5.adb b/gcc/ada/par-ch5.adb
index a245fa1c08b..557aaf1ff68 100644
--- a/gcc/ada/par-ch5.adb
+++ b/gcc/ada/par-ch5.adb
@@ -23,10 +23,6 @@
 --                                                                          --
 ------------------------------------------------------------------------------
 
-pragma Style_Checks (All_Checks);
---  Turn off subprogram body ordering check. Subprograms are in order by RM
---  section rather than alphabetical.
-
 with Sinfo.CN;       use Sinfo.CN;
 
 separate (Par)
@@ -135,8 +131,7 @@ package body Ch5 is
    --  parsing a statement, then the scan pointer is advanced past the next
    --  semicolon and the parse continues.
 
-   function P_Sequence_Of_Statements
-     (SS_Flags : SS_Rec; Handled : Boolean := False) return List_Id
+   function P_Sequence_Of_Statements (SS_Flags : SS_Rec) return List_Id
    is
       Statement_Required : Boolean := SS_Flags.Sreq;
       --  This flag indicates if a subsequent statement (other than a pragma)
@@ -221,32 +216,57 @@ package body Ch5 is
    --  Start of processing for P_Sequence_Of_Statements
 
    begin
-      --  In Ada 2022, we allow declarative items to be mixed with
-      --  statements. The loop below alternates between calling
-      --  P_Declarative_Items to parse zero or more declarative items,
-      --  and parsing a statement.
+      --  When extensions are active, we allow declarative items to be mixed
+      --  with statements. The loop below alternates between calling
+      --  P_Declarative_Items to parse zero or more declarative items, and
+      --  parsing a statement.
 
       loop
          Ignore (Tok_Semicolon);
 
          declare
             Num_Statements : constant Nat := List_Length (Statement_List);
+            Decl           : Node_Id;
          begin
             P_Declarative_Items
               (Statement_List, Declare_Expression => False,
                In_Spec => False, In_Statements => True);
 
             --  Use the length of the list to determine whether we parsed
-            --  any declarative items. If so, it's an error unless language
-            --  extensions are enabled.
+            --  any declarative items.
 
             if List_Length (Statement_List) > Num_Statements then
+               Decl := Pick (Statement_List, Num_Statements + 1);
+
+               --  If so, it's an error unless language extensions are enabled.
+
                if All_Errors_Mode or else No (Decl_Loc) then
-                  Decl_Loc := Sloc (Pick (Statement_List, Num_Statements + 1));
+                  Decl_Loc := Sloc (Decl);
 
                   Error_Msg_GNAT_Extension
-                    ("declarations mixed with statements",
-                     Sloc (Pick (Statement_List, Num_Statements + 1)));
+                    ("declarations mixed with statements", Sloc (Decl),
+                     Is_Core_Extension => True);
+
+               end if;
+
+               --  Check every declaration added to the list, to see whether
+               --  it's part of the allowed subset of declarations. Only check
+               --  that if core extensions are allowed.
+
+               if Core_Extensions_Allowed then
+                  while Present (Decl) loop
+                     if not (Nkind (Decl) in
+                        N_Object_Declaration | N_Object_Renaming_Declaration |
+                        N_Use_Type_Clause | N_Use_Package_Clause |
+                        N_Representation_Clause)
+                     then
+                        Error_Msg
+                          ("Declaration kind not allowed in statements lists",
+                           Sloc (Decl));
+                     end if;
+
+                     Next (Decl);
+                  end loop;
                end if;
             end if;
          end;
@@ -937,12 +957,9 @@ package body Ch5 is
          exit when SS_Flags.Unco;
       end loop;
 
-      --  If there are no declarative items in the list, or if the list is part
-      --  of a handled sequence of statements, we just return the list.
-      --  Otherwise, we wrap the list in a block statement, so the declarations
-      --  will have a proper scope. In the Handled case, it would be wrong to
-      --  wrap, because we want the code before and after "begin" to be in the
-      --  same scope. Example:
+      --  If there are declarative items in the list, we always wrap it in a
+      --  block, so that anything declared in a statement list is not visible
+      --  from the exception handlers. Example:
       --
       --     if ... then
       --        use Some_Package;
@@ -958,17 +975,25 @@ package body Ch5 is
       --        end;
       --     end if;
       --
-      --  But we don't wrap this:
+      --  This:
       --
       --     declare
       --        X : Integer;
       --     begin
       --        X : Integer;
       --
-      --  Otherwise, we would fail to detect the error (conflicting X's).
-      --  Similarly, if a representation clause appears in the statement
-      --  part, we don't want it to appear more nested than the declarative
-      --  part -- that would cause an unwanted error.
+      --  is transformed into this:
+      --
+      --     declare
+      --        X : Integer;
+      --     begin
+      --        declare
+      --           X : Integer;
+      --        begin
+      --           ...
+      --
+      --  We hence don't try to detect this case, even though it can be
+      --  confusing to users, and might possibly deserve a warning.
 
       if Present (Decl_Loc) then
          --  Forbid labels and declarative items from coexisting. Otherwise,
@@ -983,47 +1008,17 @@ package body Ch5 is
             Error_Msg ("label in same list as declarative item", Label_Loc);
          end if;
 
-         --  Forbid exception handlers and declarative items from
-         --  coexisting. Example:
-         --
-         --     X : Integer := 123;
-         --     procedure P is
-         --     begin
-         --        X : Integer := 456;
-         --     exception
-         --        when Cain =>
-         --           Put(X);
-         --     end P;
-         --
-         --  It was proposed that in the handler, X should refer to the outer
-         --  X, but that's just confusing.
-
-         if Token = Tok_Exception then
-            Error_Msg
-              ("declarative item in statements conflicts with " &
-               "exception handler below",
-               Decl_Loc);
-            Error_Msg
-              ("exception handler conflicts with " &
-               "declarative item in statements above",
-               Token_Ptr);
-         end if;
-
-         if Handled then
-            return Statement_List;
-         else
-            declare
-               Loc : constant Source_Ptr := Sloc (First (Statement_List));
-               Block : constant Node_Id :=
-                 Make_Block_Statement
-                   (Loc,
-                    Handled_Statement_Sequence =>
-                      Make_Handled_Sequence_Of_Statements
-                        (Loc, Statements => Statement_List));
-            begin
-               return New_List (Block);
-            end;
-         end if;
+         declare
+            Loc : constant Source_Ptr := Sloc (First (Statement_List));
+            Block : constant Node_Id :=
+              Make_Block_Statement
+                (Loc,
+                 Handled_Statement_Sequence =>
+                   Make_Handled_Sequence_Of_Statements
+                     (Loc, Statements => Statement_List));
+         begin
+            return New_List (Block);
+         end;
       else
          return Statement_List;
       end if;
diff --git a/gcc/ada/par.adb b/gcc/ada/par.adb
index 9d502b23bc6..0df0c67daeb 100644
--- a/gcc/ada/par.adb
+++ b/gcc/ada/par.adb
@@ -886,7 +886,7 @@ function Par (Configuration_Pragmas : Boolean) return 
List_Id is
       --  Used in loop constructs and quantified expressions.
 
       function P_Sequence_Of_Statements
-        (SS_Flags : SS_Rec; Handled : Boolean := False) return List_Id;
+        (SS_Flags : SS_Rec) return List_Id;
       --  SS_Flags indicates the acceptable termination tokens; see body for
       --  details. Handled is true if we are parsing a handled sequence of
       --  statements.
-- 
2.43.0

Reply via email to