]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ada/par-ch6.adb
[Ada] Return when not working for procedures
[thirdparty/gcc.git] / gcc / ada / par-ch6.adb
index a5bdfbfaa78c323f2c35557d6dad58ce15c74734..23371756bafff7185e6e6e9ac4c27bf89418cc4e 100644 (file)
@@ -6,22 +6,20 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---                                                                          --
---          Copyright (C) 1992-2001 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2021, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
--- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
 -- for  more details.  You should have  received  a copy of the GNU General --
--- Public License  distributed with GNAT;  see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license.          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
--- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
 --                                                                          --
 ------------------------------------------------------------------------------
 
@@ -29,7 +27,7 @@ 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;
+with Sinfo.CN;       use Sinfo.CN;
 
 separate (Par)
 package body Ch6 is
@@ -38,12 +36,22 @@ package body Ch6 is
 
    function P_Defining_Designator        return Node_Id;
    function P_Defining_Operator_Symbol   return Node_Id;
+   function P_Return_Object_Declaration  return Node_Id;
+
+   procedure P_Return_Subtype_Indication (Decl_Node : Node_Id);
+   --  Decl_Node is a N_Object_Declaration. Set the Null_Exclusion_Present and
+   --  Object_Definition fields of Decl_Node.
 
    procedure Check_Junk_Semicolon_Before_Return;
    --  Check for common error of junk semicolon before RETURN keyword of
-   --  function specification. If present, skip over it with appropriate
-   --  error message, leaving Scan_Ptr pointing to the RETURN after. This
-   --  routine also deals with a possibly misspelled version of Return.
+   --  function specification. If present, skip over it with appropriate error
+   --  message, leaving Scan_Ptr pointing to the RETURN after. This routine
+   --  also deals with a possibly misspelled version of Return.
+
+   procedure No_Constraint_Maybe_Expr_Func;
+   --  Called after scanning return subtype to check for missing constraint,
+   --  taking into account the possibility of an occurrence of an expression
+   --  function where the IS has been forgotten.
 
    ----------------------------------------
    -- Check_Junk_Semicolon_Before_Return --
@@ -59,29 +67,76 @@ package body Ch6 is
 
          if Token = Tok_Return then
             Restore_Scan_State (Scan_State);
-            Error_Msg_SC ("Unexpected semicolon ignored");
+            Error_Msg_SC -- CODEFIX
+              ("|extra "";"" ignored");
             Scan; -- rescan past junk semicolon
-
          else
             Restore_Scan_State (Scan_State);
          end if;
-
-      elsif Bad_Spelling_Of (Tok_Return) then
-         null;
       end if;
    end Check_Junk_Semicolon_Before_Return;
 
+   -----------------------------------
+   -- No_Constraint_Maybe_Expr_Func --
+   -----------------------------------
+
+   procedure No_Constraint_Maybe_Expr_Func is
+   begin
+      --  If we have a left paren at the start of the line, then assume this is
+      --  the case of an expression function with missing IS. We do not have to
+      --  diagnose the missing IS, that is done elsewhere. We do this game in
+      --  Ada 2012 mode where expression functions are legal.
+
+      if Token = Tok_Left_Paren
+        and Ada_Version >= Ada_2012
+        and Token_Is_At_Start_Of_Line
+      then
+         --  One exception if we have "(token .." then this is a constraint
+
+         declare
+            Scan_State : Saved_Scan_State;
+
+         begin
+            Save_Scan_State (Scan_State);
+            Scan; -- past left paren
+            Scan; -- past following token
+
+            --  If we have "(token .." then restore scan state and treat as
+            --  unexpected constraint.
+
+            if Token = Tok_Dot_Dot then
+               Restore_Scan_State (Scan_State);
+               No_Constraint;
+
+            --  Otherwise we treat this as an expression function
+
+            else
+               Restore_Scan_State (Scan_State);
+            end if;
+         end;
+
+      --  Otherwise use standard routine to check for no constraint present
+
+      else
+         No_Constraint;
+      end if;
+   end No_Constraint_Maybe_Expr_Func;
+
    -----------------------------------------------------
    -- 6.1  Subprogram (Also 6.3, 8.5.4, 10.1.3, 12.3) --
    -----------------------------------------------------
 
    --  This routine scans out a subprogram declaration, subprogram body,
    --  subprogram renaming declaration or subprogram generic instantiation.
+   --  It also handles the new Ada 2012 expression function form
 
-   --  SUBPROGRAM_DECLARATION ::= SUBPROGRAM_SPECIFICATION;
+   --  SUBPROGRAM_DECLARATION ::=
+   --    SUBPROGRAM_SPECIFICATION
+   --     [ASPECT_SPECIFICATIONS];
 
    --  ABSTRACT_SUBPROGRAM_DECLARATION ::=
-   --    SUBPROGRAM_SPECIFICATION is abstract;
+   --    SUBPROGRAM_SPECIFICATION is abstract
+   --      [ASPECT_SPECIFICATIONS];
 
    --  SUBPROGRAM_SPECIFICATION ::=
    --      procedure DEFINING_PROGRAM_UNIT_NAME PARAMETER_PROFILE
@@ -92,23 +147,38 @@ package body Ch6 is
    --  PARAMETER_AND_RESULT_PROFILE ::= [FORMAL_PART] return SUBTYPE_MARK
 
    --  SUBPROGRAM_BODY ::=
-   --    SUBPROGRAM_SPECIFICATION is
+   --    SUBPROGRAM_SPECIFICATION [ASPECT_SPECIFICATIONS] is
    --      DECLARATIVE_PART
    --    begin
    --      HANDLED_SEQUENCE_OF_STATEMENTS
    --    end [DESIGNATOR];
 
    --  SUBPROGRAM_RENAMING_DECLARATION ::=
-   --    SUBPROGRAM_SPECIFICATION renames callable_entity_NAME;
+   --    SUBPROGRAM_SPECIFICATION renames callable_entity_NAME
+   --      [ASPECT_SPECIFICATIONS];
 
    --  SUBPROGRAM_BODY_STUB ::=
-   --    SUBPROGRAM_SPECIFICATION is separate;
+   --    SUBPROGRAM_SPECIFICATION is separate
+   --      [ASPECT_SPECIFICATIONS];
 
    --  GENERIC_INSTANTIATION ::=
    --    procedure DEFINING_PROGRAM_UNIT_NAME is
-   --      new generic_procedure_NAME [GENERIC_ACTUAL_PART];
+   --      new generic_procedure_NAME [GENERIC_ACTUAL_PART]
+   --        [ASPECT_SPECIFICATIONS];
    --  | function DEFINING_DESIGNATOR is
-   --      new generic_function_NAME [GENERIC_ACTUAL_PART];
+   --      new generic_function_NAME [GENERIC_ACTUAL_PART]
+   --        [ASPECT_SPECIFICATIONS];
+
+   --  NULL_PROCEDURE_DECLARATION ::=
+   --    SUBPROGRAM_SPECIFICATION is null;
+
+   --  Null procedures are an Ada 2005 feature. A null procedure declaration
+   --  is classified as a basic declarative item, but it is parsed here, with
+   --  other subprogram constructs.
+
+   --  EXPRESSION_FUNCTION ::=
+   --    FUNCTION SPECIFICATION IS (EXPRESSION)
+   --      [ASPECT_SPECIFICATIONS];
 
    --  The value in Pf_Flags indicates which of these possible declarations
    --  is acceptable to the caller:
@@ -118,42 +188,117 @@ package body Ch6 is
    --    Pf_Flags.Pbod                 Set if proper body OK
    --    Pf_Flags.Rnam                 Set if renaming declaration OK
    --    Pf_Flags.Stub                 Set if body stub OK
+   --    Pf_Flags.Pexp                 Set if expression function OK
 
    --  If an inappropriate form is encountered, it is scanned out but an
    --  error message indicating that it is appearing in an inappropriate
    --  context is issued. The only possible values for Pf_Flags are those
    --  defined as constants in the Par package.
 
-   --  The caller has checked that the initial token is FUNCTION or PROCEDURE
+   --  The caller has checked that the initial token is FUNCTION, PROCEDURE,
+   --  NOT or OVERRIDING.
 
    --  Error recovery: cannot raise Error_Resync
 
    function P_Subprogram (Pf_Flags : Pf_Rec) return Node_Id is
       Specification_Node : Node_Id;
-      Name_Node   : Node_Id;
-      Fpart_List  : List_Id;
-      Fpart_Sloc  : Source_Ptr;
-      Return_Node : Node_Id;
-      Inst_Node   : Node_Id;
-      Body_Node   : Node_Id;
-      Decl_Node   : Node_Id;
-      Rename_Node : Node_Id;
-      Absdec_Node : Node_Id;
-      Stub_Node   : Node_Id;
-      Fproc_Sloc  : Source_Ptr;
-      Func        : Boolean;
-      Scan_State  : Saved_Scan_State;
+      Name_Node          : Node_Id;
+      Aspects            : List_Id;
+      Fpart_List         : List_Id;
+      Fpart_Sloc         : Source_Ptr;
+      Result_Not_Null    : Boolean := False;
+      Result_Node        : Node_Id;
+      Inst_Node          : Node_Id;
+      Body_Node          : Node_Id;
+      Decl_Node          : Node_Id;
+      Rename_Node        : Node_Id;
+      Absdec_Node        : Node_Id;
+      Stub_Node          : Node_Id;
+      Fproc_Sloc         : Source_Ptr;
+      Func               : Boolean;
+      Scan_State         : Saved_Scan_State;
+
+      --  Flags for optional overriding indication. Two flags are needed,
+      --  to distinguish positive and negative overriding indicators from
+      --  the absence of any indicator.
+
+      Is_Overriding  : Boolean := False;
+      Not_Overriding : Boolean := False;
 
    begin
       --  Set up scope stack entry. Note that the Labl field will be set later
 
       SIS_Entry_Active := False;
+      SIS_Aspect_Import_Seen := False;
       SIS_Missing_Semicolon_Message := No_Error_Msg;
       Push_Scope_Stack;
-      Scope.Table (Scope.Last).Sloc := Token_Ptr;
-      Scope.Table (Scope.Last).Etyp := E_Name;
-      Scope.Table (Scope.Last).Ecol := Start_Column;
-      Scope.Table (Scope.Last).Lreq := False;
+      Scopes (Scope.Last).Sloc := Token_Ptr;
+      Scopes (Scope.Last).Etyp := E_Name;
+      Scopes (Scope.Last).Ecol := Start_Column;
+      Scopes (Scope.Last).Lreq := False;
+
+      Aspects := Empty_List;
+
+      --  Ada 2005: Scan leading NOT OVERRIDING indicator
+
+      if Token = Tok_Not then
+         Scan;  -- past NOT
+
+         if Token = Tok_Overriding then
+            Scan;  --  past OVERRIDING
+            Not_Overriding := True;
+
+         --  Overriding keyword used in non Ada 2005 mode
+
+         elsif Token = Tok_Identifier
+           and then Token_Name = Name_Overriding
+         then
+            Error_Msg_SC ("overriding indicator is an Ada 2005 extension");
+            Error_Msg_SC ("\unit must be compiled with -gnat05 switch");
+            Scan;  --  past Overriding
+            Not_Overriding := True;
+
+         else
+            Error_Msg_SC -- CODEFIX
+              ("OVERRIDING expected!");
+         end if;
+
+      --  Ada 2005: scan leading OVERRIDING indicator
+
+      --  Note: in the case of OVERRIDING keyword used in Ada 95 mode, the
+      --  declaration circuit already gave an error message and changed the
+      --  token to Tok_Overriding.
+
+      elsif Token = Tok_Overriding then
+         Scan;  --  past OVERRIDING
+         Is_Overriding := True;
+      end if;
+
+      if Is_Overriding or else Not_Overriding then
+
+         --  Note that if we are not in Ada_2005 mode, error messages have
+         --  already been given, so no need to give another message here.
+
+         --  An overriding indicator is allowed for subprogram declarations,
+         --  bodies (including subunits), renamings, stubs, and instantiations.
+         --  The test against Pf_Decl_Pbod is added to account for the case of
+         --  subprograms declared in a protected type, where only subprogram
+         --  declarations and bodies can occur. The Pf_Pbod case is for
+         --  subunits.
+
+         if Pf_Flags /= Pf_Decl_Gins_Pbod_Rnam_Stub_Pexp
+              and then
+            Pf_Flags /= Pf_Decl_Pbod_Pexp
+              and then
+            Pf_Flags /= Pf_Pbod_Pexp
+         then
+            Error_Msg_SC ("overriding indicator not allowed here!");
+
+         elsif Token /= Tok_Function and then Token /= Tok_Procedure then
+            Error_Msg_SC -- CODEFIX
+              ("FUNCTION or PROCEDURE expected!");
+         end if;
+      end if;
 
       Func := (Token = Tok_Function);
       Fproc_Sloc := Token_Ptr;
@@ -191,19 +336,16 @@ package body Ch6 is
          Name_Node := P_Defining_Program_Unit_Name;
       end if;
 
-      Scope.Table (Scope.Last).Labl := Name_Node;
-
-      if Token = Tok_Colon then
-         Error_Msg_SC ("redundant colon ignored");
-         Scan; -- past colon
-      end if;
+      Scopes (Scope.Last).Labl := Name_Node;
+      Current_Node := Name_Node;
+      Ignore (Tok_Colon);
 
       --  Deal with generic instantiation, the one case in which we do not
       --  have a subprogram specification as part of whatever we are parsing
 
       if Token = Tok_Is then
          Save_Scan_State (Scan_State); -- at the IS
-         T_Is; -- checks for redundant IS's
+         T_Is; -- checks for redundant IS
 
          if Token = Tok_New then
             if not Pf_Flags.Gins then
@@ -222,8 +364,16 @@ package body Ch6 is
 
             Set_Defining_Unit_Name (Inst_Node, Name_Node);
             Set_Generic_Associations (Inst_Node, P_Generic_Actual_Part_Opt);
-            TF_Semicolon;
+            P_Aspect_Specifications (Inst_Node);
             Pop_Scope_Stack; -- Don't need scope stack entry in this case
+
+            if Is_Overriding then
+               Set_Must_Override (Inst_Node);
+
+            elsif Not_Overriding then
+               Set_Must_Not_Override (Inst_Node);
+            end if;
+
             return Inst_Node;
 
          else
@@ -246,8 +396,8 @@ package body Ch6 is
       if Token = Tok_Identifier
         and then not Token_Is_At_Start_Of_Line
       then
-            T_Left_Paren; -- to generate message
-            Fpart_List := P_Formal_Part;
+         T_Left_Paren; -- to generate message
+         Fpart_List := P_Formal_Part;
 
       --  Otherwise scan out an optional formal part in the usual manner
 
@@ -260,29 +410,53 @@ package body Ch6 is
       --  since later RETURN statements will be valid in either case.
 
       Check_Junk_Semicolon_Before_Return;
-      Return_Node := Error;
+      Result_Node := Error;
 
       if Token = Tok_Return then
          if not Func then
-            Error_Msg ("PROCEDURE should be FUNCTION", Fproc_Sloc);
+            Error_Msg -- CODEFIX
+              ("PROCEDURE should be FUNCTION", Fproc_Sloc);
             Func := True;
          end if;
 
          Scan; -- past RETURN
-         Return_Node := P_Subtype_Mark;
-         No_Constraint;
+
+         Result_Not_Null := P_Null_Exclusion;     --  Ada 2005 (AI-231)
+
+         --  Ada 2005 (AI-318-02)
+
+         if Token = Tok_Access then
+            Error_Msg_Ada_2005_Extension ("anonymous access result type");
+
+            Result_Node := P_Access_Definition (Result_Not_Null);
+
+         else
+            Result_Node := P_Subtype_Mark;
+            No_Constraint_Maybe_Expr_Func;
+         end if;
 
       else
+         --  Skip extra parenthesis at end of formal part
+
+         Ignore (Tok_Right_Paren);
+
+         --  For function, scan result subtype
+
          if Func then
-            Ignore (Tok_Right_Paren);
             TF_Return;
+
+            if Prev_Token = Tok_Return then
+               Result_Node := P_Subtype_Mark;
+            end if;
          end if;
       end if;
 
       if Func then
          Specification_Node :=
            New_Node (N_Function_Specification, Fproc_Sloc);
-         Set_Subtype_Mark (Specification_Node, Return_Node);
+
+         Set_Null_Exclusion_Present (Specification_Node, Result_Not_Null);
+         Set_Result_Definition (Specification_Node, Result_Node);
 
       else
          Specification_Node :=
@@ -292,6 +466,13 @@ package body Ch6 is
       Set_Defining_Unit_Name (Specification_Node, Name_Node);
       Set_Parameter_Specifications (Specification_Node, Fpart_List);
 
+      if Is_Overriding then
+         Set_Must_Override (Specification_Node);
+
+      elsif Not_Overriding then
+         Set_Must_Not_Override (Specification_Node);
+      end if;
+
       --  Error check: barriers not allowed on protected functions/procedures
 
       if Token = Tok_When then
@@ -305,21 +486,42 @@ package body Ch6 is
          Discard_Junk_Node (P_Expression);
       end if;
 
-      --  Deal with case of semicolon ending a subprogram declaration
+      --  Deal with semicolon followed by IS. We want to treat this as IS
 
       if Token = Tok_Semicolon then
+         Save_Scan_State (Scan_State);
+         Scan; -- past semicolon
+
+         if Token = Tok_Is then
+            Error_Msg_SP -- CODEFIX
+              ("extra "";"" ignored");
+         else
+            Restore_Scan_State (Scan_State);
+         end if;
+      end if;
+
+      --  Subprogram declaration ended by aspect specifications
+
+      if Aspect_Specifications_Present then
+         goto Subprogram_Declaration;
+
+      --  Deal with case of semicolon ending a subprogram declaration
+
+      elsif Token = Tok_Semicolon then
          if not Pf_Flags.Decl then
             T_Is;
          end if;
 
+         Save_Scan_State (Scan_State);
          Scan; -- past semicolon
 
          --  If semicolon is immediately followed by IS, then ignore the
          --  semicolon, and go process the body.
 
          if Token = Tok_Is then
-            Error_Msg_SP ("unexpected semicolon ignored");
-            T_Is; -- ignroe redundant IS's
+            Error_Msg_SP -- CODEFIX
+              ("|extra "";"" ignored");
+            T_Is; -- scan past IS
             goto Subprogram_Body;
 
          --  If BEGIN follows in an appropriate column, we immediately
@@ -328,12 +530,14 @@ package body Ch6 is
          --  i.e. that the terminating semicolon should have been IS.
 
          elsif Token = Tok_Begin
-            and then Start_Column >= Scope.Table (Scope.Last).Ecol
+            and then Start_Column >= Scopes (Scope.Last).Ecol
          then
-            Error_Msg_SP (""";"" should be IS!");
+            Error_Msg_SP -- CODEFIX
+              ("|"";"" should be IS!");
             goto Subprogram_Body;
 
          else
+            Restore_Scan_State (Scan_State);
             goto Subprogram_Declaration;
          end if;
 
@@ -354,6 +558,7 @@ package body Ch6 is
             Scan; -- past RENAMES
             Set_Name (Rename_Node, P_Name);
             Set_Specification (Rename_Node, Specification_Node);
+            P_Aspect_Specifications (Rename_Node);
             TF_Semicolon;
             Pop_Scope_Stack;
             return Rename_Node;
@@ -370,7 +575,8 @@ package body Ch6 is
             --  Deal nicely with (now obsolete) use of <> in place of abstract
 
             if Token = Tok_Box then
-               Error_Msg_SC ("ABSTRACT expected");
+               Error_Msg_SC -- CODEFIX
+                 ("ABSTRACT expected");
                Token := Tok_Abstract;
             end if;
 
@@ -382,9 +588,26 @@ package body Ch6 is
                Set_Specification (Absdec_Node, Specification_Node);
                Pop_Scope_Stack; -- discard unneeded entry
                Scan; -- past ABSTRACT
-               TF_Semicolon;
+               P_Aspect_Specifications (Absdec_Node);
                return Absdec_Node;
 
+            --  Ada 2005 (AI-248): Parse a null procedure declaration
+
+            elsif Token = Tok_Null then
+               Error_Msg_Ada_2005_Extension ("null procedure");
+
+               Scan; -- past NULL
+
+               if Func then
+                  Error_Msg_SP ("only procedures can be null");
+               else
+                  Set_Null_Present (Specification_Node);
+                  Set_Null_Statement (Specification_Node,
+                    New_Node (N_Null_Statement, Prev_Token_Ptr));
+               end if;
+
+               goto Subprogram_Declaration;
+
             --  Check for IS NEW with Formal_Part present and handle nicely
 
             elsif Token = Tok_New then
@@ -410,23 +633,37 @@ package body Ch6 is
                goto Subprogram_Body;
             end if;
 
-         --  Here we have a missing IS or missing semicolon, we always guess
-         --  a missing semicolon, since we are pretty good at fixing up a
-         --  semicolon which should really be an IS
+         --  Aspect specifications present
 
-         else
-            Error_Msg_AP ("missing "";""");
-            SIS_Missing_Semicolon_Message := Get_Msg_Id;
+         elsif Aspect_Specifications_Present then
             goto Subprogram_Declaration;
+
+         --  Here we have a missing IS or missing semicolon
+
+         else
+            --  If the next token is a left paren at the start of a line, then
+            --  this is almost certainly the start of the expression for an
+            --  expression function, so in this case guess a missing IS.
+
+            if Token = Tok_Left_Paren and then Token_Is_At_Start_Of_Line then
+               Error_Msg_AP -- CODEFIX
+                 ("missing IS");
+
+            --  In all other cases, we guess a missing semicolon, since we are
+            --  good at fixing up a semicolon which should really be an IS.
+
+            else
+               Error_Msg_AP -- CODEFIX
+                 ("|missing "";""");
+               SIS_Missing_Semicolon_Message := Get_Msg_Id;
+               goto Subprogram_Declaration;
+            end if;
          end if;
       end if;
 
-      --  Processing for subprogram body
+      --  Processing for stub or subprogram body or expression function
 
       <<Subprogram_Body>>
-         if not Pf_Flags.Pbod then
-            Error_Msg_SP ("subprogram body not allowed here!");
-         end if;
 
          --  Subprogram body stub case
 
@@ -441,37 +678,265 @@ package body Ch6 is
                   Sloc (Name_Node));
             end if;
 
+            Scan; -- past SEPARATE
+
             Stub_Node :=
               New_Node (N_Subprogram_Body_Stub, Sloc (Specification_Node));
             Set_Specification (Stub_Node, Specification_Node);
-            Scan; -- past SEPARATE
-            Pop_Scope_Stack;
+
+            if Is_Non_Empty_List (Aspects) then
+               Error_Msg
+                 ("aspect specifications must come after SEPARATE",
+                  Sloc (First (Aspects)));
+            end if;
+
+            P_Aspect_Specifications (Stub_Node, Semicolon => False);
             TF_Semicolon;
+            Pop_Scope_Stack;
             return Stub_Node;
 
-         --  Subprogram body case
+         --  Subprogram body or expression function case
 
          else
-            --  Here is the test for a suspicious IS (i.e. one that looks
-            --  like it might more properly be a semicolon). See separate
-            --  section discussing use of IS instead of semicolon in
-            --  package Parse.
-
-            if (Token in Token_Class_Declk
-                  or else
-                Token = Tok_Identifier)
-              and then Start_Column <= Scope.Table (Scope.Last).Ecol
-              and then Scope.Last /= 1
-            then
-               Scope.Table (Scope.Last).Etyp := E_Suspicious_Is;
-               Scope.Table (Scope.Last).S_Is := Prev_Token_Ptr;
-            end if;
+            Scan_Body_Or_Expression_Function : declare
+
+               function Likely_Expression_Function return Boolean;
+               --  Returns True if we have a probable case of an expression
+               --  function omitting the parentheses, if so, returns True
+               --  and emits an appropriate error message, else returns False.
+
+               --------------------------------
+               -- Likely_Expression_Function --
+               --------------------------------
+
+               function Likely_Expression_Function return Boolean is
+               begin
+                  --  If currently pointing to BEGIN or a declaration keyword
+                  --  or a pragma, then we definitely have a subprogram body.
+                  --  This is a common case, so worth testing first.
+
+                  if Token = Tok_Begin
+                    or else Token in Token_Class_Declk
+                    or else Token = Tok_Pragma
+                  then
+                     return False;
+
+                  --  Test for tokens which could only start an expression and
+                  --  thus signal the case of a expression function.
+
+                  elsif Token     in Token_Class_Literal
+                    or else Token in Token_Class_Unary_Addop
+                    or else Token =  Tok_Left_Paren
+                    or else Token =  Tok_Abs
+                    or else Token =  Tok_Null
+                    or else Token =  Tok_New
+                    or else Token =  Tok_Not
+                  then
+                     null;
+
+                  --  Anything other than an identifier must be a body
+
+                  elsif Token /= Tok_Identifier then
+                     return False;
+
+                  --  Here for an identifier
+
+                  else
+                     --  If the identifier is the first token on its line, then
+                     --  let's assume that we have a missing begin and this is
+                     --  intended as a subprogram body. However, if the context
+                     --  is a function and the unit is a package declaration, a
+                     --  body would be illegal, so try for an unparenthesized
+                     --  expression function.
+
+                     if Token_Is_At_Start_Of_Line then
+                        declare
+                           --  The enclosing scope entry is a subprogram spec
+
+                           Spec_Node : constant Node_Id :=
+                                         Parent
+                                           (Scopes (Scope.Last).Labl);
+                           Lib_Node : Node_Id := Spec_Node;
+
+                        begin
+                           --  Check whether there is an enclosing scope that
+                           --  is a package declaration.
+
+                           if Scope.Last > 1 then
+                              Lib_Node  :=
+                                Parent (Scopes (Scope.Last - 1).Labl);
+                           end if;
+
+                           if Ada_Version >= Ada_2012
+                             and then
+                               Nkind (Lib_Node) = N_Package_Specification
+                             and then
+                               Nkind (Spec_Node) = N_Function_Specification
+                           then
+                              null;
+                           else
+                              return False;
+                           end if;
+                        end;
+
+                     --  Otherwise we have to scan ahead. If the identifier is
+                     --  followed by a colon or a comma, it is a declaration
+                     --  and hence we have a subprogram body. Otherwise assume
+                     --  a expression function.
+
+                     else
+                        declare
+                           Scan_State : Saved_Scan_State;
+                           Tok        : Token_Type;
+
+                        begin
+                           Save_Scan_State (Scan_State);
+                           Scan; -- past identifier
+                           Tok := Token;
+                           Restore_Scan_State (Scan_State);
+
+                           if Tok = Tok_Colon or else Tok = Tok_Comma then
+                              return False;
+                           end if;
+                        end;
+                     end if;
+                  end if;
+
+                  --  Fall through if we have a likely expression function.
+                  --  If the starting keyword is not "function" the error
+                  --  will be reported elsewhere.
+
+                  if Func then
+                     Error_Msg_SC
+                       ("expression function must be enclosed in parentheses");
+                  end if;
+
+                  return True;
+               end Likely_Expression_Function;
+
+            --  Start of processing for Scan_Body_Or_Expression_Function
+
+            begin
+               --  Expression_Function case
+
+               if Token = Tok_Left_Paren
+                 or else Likely_Expression_Function
+               then
+                  --  Check expression function allowed here
+
+                  if not Pf_Flags.Pexp then
+                     Error_Msg_SC ("expression function not allowed here!");
+                  end if;
+
+                  --  Check we are in Ada 2012 mode
+
+                  Error_Msg_Ada_2012_Feature
+                    ("!expression function", Token_Ptr);
+
+                  --  Catch an illegal placement of the aspect specification
+                  --  list:
+
+                  --    function_specification
+                  --      [aspect_specification] is (expression);
+
+                  --  This case is correctly processed by the parser because
+                  --  the expression function first appears as a subprogram
+                  --  declaration to the parser. The starting keyword may
+                  --  not have been "function" in which case the error is
+                  --  on a malformed procedure.
+
+                  if Is_Non_Empty_List (Aspects) then
+                     if Func then
+                        Error_Msg
+                          ("aspect specifications must come after "
+                           & "parenthesized expression",
+                           Sloc (First (Aspects)));
+                     else
+                        Error_Msg
+                          ("aspect specifications must come after subprogram "
+                           & "specification", Sloc (First (Aspects)));
+                     end if;
+                  end if;
+
+                  --  Parse out expression and build expression function
+
+                  Body_Node :=
+                    New_Node
+                      (N_Expression_Function, Sloc (Specification_Node));
+                  Set_Specification (Body_Node, Specification_Node);
+
+                  declare
+                     Expr : constant Node_Id := P_Expression;
+                  begin
+                     Set_Expression (Body_Node, Expr);
+
+                     --  Check that the full expression is properly
+                     --  parenthesized since we may have a left-operand that is
+                     --  parenthesized but that is not one of the allowed cases
+                     --  with syntactic parentheses.
+
+                     if not (Paren_Count (Expr) /= 0
+                              or else Nkind (Expr) in N_Aggregate
+                                                    | N_Extension_Aggregate
+                                                    | N_Quantified_Expression)
+                     then
+                        Error_Msg
+                          ("expression function must be enclosed in "
+                           & "parentheses", Sloc (Expr));
+                     end if;
+                  end;
+
+                  --  Expression functions can carry pre/postconditions
+
+                  P_Aspect_Specifications (Body_Node);
+                  Pop_Scope_Stack;
+
+               --  Subprogram body case
+
+               else
+                  --  Check body allowed here
+
+                  if not Pf_Flags.Pbod then
+                     Error_Msg_SP ("subprogram body not allowed here!");
+                  end if;
+
+                  --  Here is the test for a suspicious IS (i.e. one that
+                  --  looks like it might more properly be a semicolon).
+                  --  See separate section describing use of IS instead
+                  --  of semicolon in package Parse.
 
-            Body_Node :=
-              New_Node (N_Subprogram_Body, Sloc (Specification_Node));
-            Set_Specification (Body_Node, Specification_Node);
-            Parse_Decls_Begin_End (Body_Node);
-            return Body_Node;
+                  if (Token in Token_Class_Declk
+                        or else
+                      Token = Tok_Identifier)
+                    and then Start_Column <= Scopes (Scope.Last).Ecol
+                    and then Scope.Last /= 1
+                  then
+                     Scopes (Scope.Last).Etyp := E_Suspicious_Is;
+                     Scopes (Scope.Last).S_Is := Prev_Token_Ptr;
+                  end if;
+
+                  --  Build and return subprogram body, parsing declarations
+                  --  and statement sequence that belong to the body.
+
+                  Body_Node :=
+                    New_Node (N_Subprogram_Body, Sloc (Specification_Node));
+                  Set_Specification (Body_Node, Specification_Node);
+
+                  --  If aspects are present, the specification is parsed as
+                  --  a subprogram declaration, and we jump here after seeing
+                  --  the keyword IS. Attach asspects previously collected to
+                  --  the body.
+
+                  if Is_Non_Empty_List (Aspects) then
+                     Set_Parent (Aspects, Body_Node);
+                     Set_Aspect_Specifications (Body_Node, Aspects);
+                  end if;
+
+                  Parse_Decls_Begin_End (Body_Node);
+               end if;
+
+               return Body_Node;
+            end Scan_Body_Or_Expression_Function;
          end if;
 
       --  Processing for subprogram declaration
@@ -480,24 +945,63 @@ package body Ch6 is
          Decl_Node :=
            New_Node (N_Subprogram_Declaration, Sloc (Specification_Node));
          Set_Specification (Decl_Node, Specification_Node);
+         Aspects := Get_Aspect_Specifications (Semicolon => False);
+
+         --  Aspects may be present on a subprogram body. The source parsed
+         --  so far is that of its specification. Go parse the body and attach
+         --  the collected aspects, if any, to the body.
+
+         if Token = Tok_Is then
+
+            --  If the subprogram is a procedure and already has a
+            --  specification, we can't define another.
+
+            if Nkind (Specification (Decl_Node)) = N_Procedure_Specification
+              and then Null_Present (Specification (Decl_Node))
+            then
+               Error_Msg_AP ("null procedure cannot have a body");
+            end if;
+
+            Scan;
+            goto Subprogram_Body;
+
+         else
+            if Is_Non_Empty_List (Aspects) then
+               Set_Parent (Aspects, Decl_Node);
+               Set_Aspect_Specifications (Decl_Node, Aspects);
+            end if;
+
+            TF_Semicolon;
+         end if;
 
          --  If this is a context in which a subprogram body is permitted,
          --  set active SIS entry in case (see section titled "Handling
          --  Semicolon Used in Place of IS" in body of Parser package)
          --  Note that SIS_Missing_Semicolon_Message is already set properly.
 
-         if Pf_Flags.Pbod then
-            SIS_Labl := Scope.Table (Scope.Last).Labl;
-            SIS_Sloc := Scope.Table (Scope.Last).Sloc;
-            SIS_Ecol := Scope.Table (Scope.Last).Ecol;
+         if Pf_Flags.Pbod
+
+           --  Disconnect this processing if we have scanned a null procedure
+           --  because in this case the spec is complete anyway with no body.
+
+           and then (Nkind (Specification_Node) /= N_Procedure_Specification
+                      or else not Null_Present (Specification_Node))
+         then
+            SIS_Labl := Scopes (Scope.Last).Labl;
+            SIS_Sloc := Scopes (Scope.Last).Sloc;
+            SIS_Ecol := Scopes (Scope.Last).Ecol;
             SIS_Declaration_Node := Decl_Node;
             SIS_Semicolon_Sloc := Prev_Token_Ptr;
-            SIS_Entry_Active := True;
+
+            --  Do not activate the entry if we have "with Import"
+
+            if not SIS_Aspect_Import_Seen then
+               SIS_Entry_Active := True;
+            end if;
          end if;
 
          Pop_Scope_Stack;
          return Decl_Node;
-
    end P_Subprogram;
 
    ---------------------------------
@@ -534,6 +1038,8 @@ package body Ch6 is
 
    function P_Subprogram_Specification return Node_Id is
       Specification_Node : Node_Id;
+      Result_Not_Null    : Boolean;
+      Result_Node        : Node_Id;
 
    begin
       if Token = Tok_Function then
@@ -545,8 +1051,23 @@ package body Ch6 is
            (Specification_Node, P_Parameter_Profile);
          Check_Junk_Semicolon_Before_Return;
          TF_Return;
-         Set_Subtype_Mark (Specification_Node, P_Subtype_Mark);
-         No_Constraint;
+
+         Result_Not_Null := P_Null_Exclusion;     --  Ada 2005 (AI-231)
+
+         --  Ada 2005 (AI-318-02)
+
+         if Token = Tok_Access then
+            Error_Msg_Ada_2005_Extension ("anonymous access result type");
+
+            Result_Node := P_Access_Definition (Result_Not_Null);
+
+         else
+            Result_Node := P_Subtype_Mark;
+            No_Constraint_Maybe_Expr_Func;
+         end if;
+
+         Set_Null_Exclusion_Present (Specification_Node, Result_Not_Null);
+         Set_Result_Definition (Specification_Node, Result_Node);
          return Specification_Node;
 
       elsif Token = Tok_Procedure then
@@ -594,6 +1115,10 @@ package body Ch6 is
       --  True, a real dot has been scanned and we are positioned past it,
       --  if the result is False, the scan position is unchanged.
 
+      --------------
+      -- Real_Dot --
+      --------------
+
       function Real_Dot return Boolean is
          Scan_State  : Saved_Scan_State;
 
@@ -649,7 +1174,7 @@ package body Ch6 is
 
          --  On exit from the loop, Ident_Node is the last identifier scanned,
          --  i.e. the defining identifier, and Prefix_Node is a node for the
-         --  entire name, structured (incorrectly!) as a selected component.
+         --  entire name, structured (incorrectly) as a selected component.
 
          Name_Node := Prefix (Prefix_Node);
          Change_Node (Prefix_Node, N_Designator);
@@ -716,13 +1241,14 @@ package body Ch6 is
          Set_Identifier_Casing (Current_Source_File, Determine_Token_Casing);
       end if;
 
-      Ident_Node := P_Identifier;
+      Ident_Node := P_Identifier (C_Dot);
       Merge_Identifier (Ident_Node, Tok_Return);
 
       --  Normal case (not child library unit name)
 
       if Token /= Tok_Dot then
          Change_Identifier_To_Defining_Identifier (Ident_Node);
+         Warn_If_Standard_Redefinition (Ident_Node);
          return Ident_Node;
 
       --  Child library unit name case
@@ -732,7 +1258,7 @@ package body Ch6 is
             Error_Msg_SP ("child unit allowed only at library level");
             raise Error_Resync;
 
-         elsif Ada_83 then
+         elsif Ada_Version = Ada_83 then
             Error_Msg_SP ("(Ada 83) child unit not allowed!");
 
          end if;
@@ -747,19 +1273,20 @@ package body Ch6 is
             Name_Node := New_Node (N_Selected_Component, Token_Ptr);
             Scan; -- past period
             Set_Prefix (Name_Node, Prefix_Node);
-            Ident_Node := P_Identifier;
+            Ident_Node := P_Identifier (C_Dot);
             Set_Selector_Name (Name_Node, Ident_Node);
             Prefix_Node := Name_Node;
          end loop;
 
          --  On exit from the loop, Ident_Node is the last identifier scanned,
          --  i.e. the defining identifier, and Prefix_Node is a node for the
-         --  entire name, structured (incorrectly!) as a selected component.
+         --  entire name, structured (incorrectly) as a selected component.
 
          Name_Node := Prefix (Prefix_Node);
          Change_Node (Prefix_Node, N_Defining_Program_Unit_Name);
          Set_Name (Prefix_Node, Name_Node);
          Change_Identifier_To_Defining_Identifier (Ident_Node);
+         Warn_If_Standard_Redefinition (Ident_Node);
          Set_Defining_Identifier (Prefix_Node, Ident_Node);
 
          --  All set with unit name parsed
@@ -836,8 +1363,8 @@ package body Ch6 is
    --  FORMAL_PART ::= (PARAMETER_SPECIFICATION {; PARAMETER_SPECIFICATION})
 
    --  PARAMETER_SPECIFICATION ::=
-   --    DEFINING_IDENTIFIER_LIST : MODE SUBTYPE_MARK
-   --      [:= DEFAULT_EXPRESSION]
+   --    DEFINING_IDENTIFIER_LIST : [ALIASED] MODE [NULL_EXCLUSION]
+   --      SUBTYPE_MARK [:= DEFAULT_EXPRESSION]
    --  | DEFINING_IDENTIFIER_LIST : ACCESS_DEFINITION
    --      [:= DEFAULT_EXPRESSION]
 
@@ -845,6 +1372,8 @@ package body Ch6 is
    --  that the initial token is a left parenthesis, and skipped past it, so
    --  that on entry Token is the first token following the left parenthesis.
 
+   --  Note: The ALIASED keyword is allowed only in Ada 2012 mode (AI 142)
+
    --  Error recovery: cannot raise Error_Resync
 
    function P_Formal_Part return List_Id is
@@ -854,6 +1383,8 @@ package body Ch6 is
       Num_Idents         : Nat;
       Ident              : Nat;
       Ident_Sloc         : Source_Ptr;
+      Not_Null_Present   : Boolean := False;
+      Not_Null_Sloc      : Source_Ptr;
 
       Idents : array (Int range 1 .. 4096) of Entity_Id;
       --  This array holds the list of defining identifiers. The upper bound
@@ -862,16 +1393,16 @@ package body Ch6 is
 
    begin
       Specification_List := New_List;
-
       Specification_Loop : loop
          begin
             if Token = Tok_Pragma then
-               P_Pragmas_Misplaced;
+               Error_Msg_SC ("pragma not allowed in formal part");
+               Discard_Junk_Node (P_Pragma (Skipping => True));
             end if;
 
             Ignore (Tok_Left_Paren);
             Ident_Sloc := Token_Ptr;
-            Idents (1) := P_Defining_Identifier;
+            Idents (1) := P_Defining_Identifier (C_Comma_Colon);
             Num_Idents := 1;
 
             Ident_Loop : loop
@@ -883,9 +1414,11 @@ package body Ch6 is
 
                if Token /= Tok_Comma then
 
-                  --  Assume colon if IN or OUT keyword found
+                  --  Assume colon if ALIASED, IN or OUT keyword found
 
-                  exit Ident_Loop when Token = Tok_In or else Token = Tok_Out;
+                  exit Ident_Loop when Token = Tok_Aliased or else
+                                       Token = Tok_In      or else
+                                       Token = Tok_Out;
 
                   --  Otherwise scan ahead
 
@@ -893,8 +1426,8 @@ package body Ch6 is
                   Look_Ahead : loop
 
                      --  If we run into a semicolon, then assume that a
-                     --  colon was missing, e.g.  Parms (X Y; ...). Also
-                     --  assume missing colon on EOF (a real disaster!)
+                     --  colon was missing, e.g. Parms (X Y; ...). Also
+                     --  assume missing colon on EOF (a real disaster)
                      --  and on a right paren, e.g. Parms (X Y), and also
                      --  on an assignment symbol, e.g. Parms (X Y := ..)
 
@@ -925,7 +1458,7 @@ package body Ch6 is
 
                T_Comma;
                Num_Idents := Num_Idents + 1;
-               Idents (Num_Idents) := P_Defining_Identifier;
+               Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon);
             end loop Ident_Loop;
 
             --  Fall through the loop on encountering a colon, or deciding
@@ -951,16 +1484,65 @@ package body Ch6 is
                  New_Node (N_Parameter_Specification, Ident_Sloc);
                Set_Defining_Identifier (Specification_Node, Idents (Ident));
 
+               --  Scan possible ALIASED for Ada 2012 (AI-142)
+
+               if Token = Tok_Aliased then
+                  if Ada_Version < Ada_2012 then
+                     Error_Msg_Ada_2012_Feature
+                       ("ALIASED parameter", Token_Ptr);
+                  else
+                     Set_Aliased_Present (Specification_Node);
+                  end if;
+
+                  Scan; -- past ALIASED
+               end if;
+
+               --  Scan possible NOT NULL for Ada 2005 (AI-231, AI-447)
+
+               Not_Null_Sloc := Token_Ptr;
+               Not_Null_Present :=
+                 P_Null_Exclusion (Allow_Anonymous_In_95 => True);
+
+               --  Case of ACCESS keyword present
+
                if Token = Tok_Access then
-                  if Ada_83 then
+                  Set_Null_Exclusion_Present
+                    (Specification_Node, Not_Null_Present);
+
+                  if Ada_Version = Ada_83 then
                      Error_Msg_SC ("(Ada 83) access parameters not allowed");
                   end if;
 
                   Set_Parameter_Type
-                    (Specification_Node, P_Access_Definition);
+                    (Specification_Node,
+                     P_Access_Definition (Not_Null_Present));
+
+               --  Case of IN or OUT present
 
                else
-                  P_Mode (Specification_Node);
+                  if Token = Tok_In or else Token = Tok_Out then
+                     if Not_Null_Present then
+                        Error_Msg
+                          ("`NOT NULL` can only be used with `ACCESS`",
+                           Not_Null_Sloc);
+
+                        if Token = Tok_In then
+                           Error_Msg
+                             ("\`IN` not allowed together with `ACCESS`",
+                              Not_Null_Sloc);
+                        else
+                           Error_Msg
+                             ("\`OUT` not allowed together with `ACCESS`",
+                              Not_Null_Sloc);
+                        end if;
+                     end if;
+
+                     P_Mode (Specification_Node);
+                     Not_Null_Present := P_Null_Exclusion; -- Ada 2005 (AI-231)
+                  end if;
+
+                  Set_Null_Exclusion_Present
+                    (Specification_Node, Not_Null_Present);
 
                   if Token = Tok_Procedure
                        or else
@@ -1008,13 +1590,25 @@ package body Ch6 is
          end;
 
          if Token = Tok_Semicolon then
+            Save_Scan_State (Scan_State);
             Scan; -- past semicolon
 
             --  If we have RETURN or IS after the semicolon, then assume
             --  that semicolon should have been a right parenthesis and exit
 
             if Token = Tok_Is or else Token = Tok_Return then
-               Error_Msg_SP ("expected "")"" in place of "";""");
+               Error_Msg_SP -- CODEFIX
+                 ("|"";"" should be "")""");
+               exit Specification_Loop;
+            end if;
+
+            --  If we have a declaration keyword after the semicolon, then
+            --  assume we had a missing right parenthesis and terminate list
+
+            if Token in Token_Class_Declk then
+               Error_Msg_AP -- CODEFIX
+                 ("missing "")""");
+               Restore_Scan_State (Scan_State);
                exit Specification_Loop;
             end if;
 
@@ -1022,11 +1616,28 @@ package body Ch6 is
             Scan; -- past right paren
             exit Specification_Loop;
 
+         --  Support for aspects on formal parameters is a GNAT extension for
+         --  the time being.
+
+         elsif Token = Tok_With then
+            Error_Msg_Ada_2022_Feature
+              ("aspect on formal parameter", Token_Ptr);
+
+            P_Aspect_Specifications (Specification_Node, False);
+
+            if Token = Tok_Right_Paren then
+               Scan;  -- past right paren
+               exit Specification_Loop;
+
+            elsif Token = Tok_Semicolon then
+               Save_Scan_State (Scan_State);
+               Scan; -- past semicolon
+            end if;
+
          --  Special check for common error of using comma instead of semicolon
 
          elsif Token = Tok_Comma then
             T_Semicolon;
-            Scan; -- past comma
 
          --  Special check for omitted separator
 
@@ -1074,6 +1685,21 @@ package body Ch6 is
       if Token = Tok_In then
          Scan; -- past IN
          Set_In_Present (Node, True);
+
+         if Style.Mode_In_Check and then Token /= Tok_Out then
+            Error_Msg_SP -- CODEFIX
+              ("(style) IN should be omitted");
+         end if;
+
+         --  Since Ada 2005, formal objects can have an anonymous access type,
+         --  and of course carry a mode indicator.
+
+         if Token = Tok_Access
+           and then Nkind (Node) /= N_Formal_Object_Declaration
+         then
+            Error_Msg_SP ("IN not allowed together with ACCESS");
+            Scan; -- past ACCESS
+         end if;
       end if;
 
       if Token = Tok_Out then
@@ -1104,61 +1730,278 @@ package body Ch6 is
    -- 6.4  Function Call --
    ------------------------
 
-   --  Parsed by P_Call_Or_Name (4.1)
+   --  Parsed by P_Name (4.1)
 
    --------------------------------
    -- 6.4  Actual Parameter Part --
    --------------------------------
 
-   --  Parsed by P_Call_Or_Name (4.1)
+   --  Parsed by P_Name (4.1)
 
    --------------------------------
    -- 6.4  Parameter Association --
    --------------------------------
 
-   --  Parsed by P_Call_Or_Name (4.1)
+   --  Parsed by P_Name (4.1)
 
    ------------------------------------
    -- 6.4  Explicit Actual Parameter --
    ------------------------------------
 
-   --  Parsed by P_Call_Or_Name (4.1)
+   --  Parsed by P_Name (4.1)
 
    ---------------------------
    -- 6.5  Return Statement --
    ---------------------------
 
+   --  SIMPLE_RETURN_STATEMENT ::= return [EXPRESSION];
+   --
+   --  EXTENDED_RETURN_STATEMENT ::=
+   --    return DEFINING_IDENTIFIER : [aliased] RETURN_SUBTYPE_INDICATION
+   --                                           [:= EXPRESSION]
+   --                                           [ASPECT_SPECIFICATION] [do
+   --      HANDLED_SEQUENCE_OF_STATEMENTS
+   --    end return];
+   --
+   --  RETURN_SUBTYPE_INDICATION ::= SUBTYPE_INDICATION | ACCESS_DEFINITION
+
    --  RETURN_STATEMENT ::= return [EXPRESSION];
 
-   --  The caller has checked that the initial token is RETURN
+   --  Error recovery: can raise Error_Resync
+
+   procedure P_Return_Subtype_Indication (Decl_Node : Node_Id) is
+
+      --  Note: We don't need to check Ada_Version here, because this is
+      --  only called in >= Ada 2005 cases anyway.
+
+      Not_Null_Present : constant Boolean := P_Null_Exclusion;
+
+   begin
+      Set_Null_Exclusion_Present (Decl_Node, Not_Null_Present);
+
+      if Token = Tok_Access then
+         Set_Object_Definition
+           (Decl_Node, P_Access_Definition (Not_Null_Present));
+      else
+         Set_Object_Definition
+           (Decl_Node, P_Subtype_Indication (Not_Null_Present));
+      end if;
+   end P_Return_Subtype_Indication;
 
    --  Error recovery: can raise Error_Resync
 
-   function P_Return_Statement return Node_Id is
-      Return_Node : Node_Id;
+   function P_Return_Object_Declaration return Node_Id is
+      Return_Obj : Node_Id;
+      Decl_Node  : Node_Id;
 
    begin
-      Return_Node := New_Node (N_Return_Statement, Token_Ptr);
+      Return_Obj := Token_Node;
+      Change_Identifier_To_Defining_Identifier (Return_Obj);
+      Warn_If_Standard_Redefinition (Return_Obj);
+      Decl_Node := New_Node (N_Object_Declaration, Token_Ptr);
+      Set_Defining_Identifier (Decl_Node, Return_Obj);
+
+      Scan; -- past identifier
+      Scan; -- past :
+
+      --  First an error check, if we have two identifiers in a row, a likely
+      --  possibility is that the first of the identifiers is an incorrectly
+      --  spelled keyword. See similar check in P_Identifier_Declarations.
+
+      if Token = Tok_Identifier then
+         declare
+            SS : Saved_Scan_State;
+            I2 : Boolean;
+
+         begin
+            Save_Scan_State (SS);
+            Scan; -- past initial identifier
+            I2 := (Token = Tok_Identifier);
+            Restore_Scan_State (SS);
+
+            if I2
+              and then
+                (Bad_Spelling_Of (Tok_Access)   or else
+                 Bad_Spelling_Of (Tok_Aliased)  or else
+                 Bad_Spelling_Of (Tok_Constant))
+            then
+               null;
+            end if;
+         end;
+      end if;
+
+      --  We allow "constant" here (as in "return Result : constant
+      --  T..."). This is not in the latest RM, but the ARG is considering an
+      --  AI on the subject (see AI05-0015-1), which we expect to be approved.
+
+      if Token = Tok_Constant then
+         Scan; -- past CONSTANT
+         Set_Constant_Present (Decl_Node);
+
+         if Token = Tok_Aliased then
+            Error_Msg_SC -- CODEFIX
+              ("ALIASED should be before CONSTANT");
+            Scan; -- past ALIASED
+            Set_Aliased_Present (Decl_Node);
+         end if;
+
+      elsif Token = Tok_Aliased then
+         Scan; -- past ALIASED
+         Set_Aliased_Present (Decl_Node);
+
+         --  The restrictions on the use of aliased in an extended return
+         --  are semantic, not syntactic.
+
+         if Token = Tok_Constant then
+            Scan; -- past CONSTANT
+            Set_Constant_Present (Decl_Node);
+         end if;
+      end if;
+
+      P_Return_Subtype_Indication (Decl_Node);
+
+      if Token = Tok_Colon_Equal then
+         Scan; -- past :=
+         Set_Expression (Decl_Node, P_Expression_No_Right_Paren);
+         Set_Has_Init_Expression (Decl_Node);
+      end if;
+
+      return Decl_Node;
+   end P_Return_Object_Declaration;
+
+   --  Error recovery: can raise Error_Resync
+
+   function P_Return_Statement return Node_Id is
+      --  The caller has checked that the initial token is RETURN
+
+      type Return_Kind is (Simple_Return, Extended_Return, Return_When);
+
+      function Get_Return_Kind return Return_Kind;
+      --  Scan state is just after RETURN (and is left that way). Determine
+      --  whether this is a simple or extended return statement by looking
+      --  ahead for "identifier :", which implies extended.
 
-      --  Sloc points to RETURN
-      --  Expression (Op3)
+      ---------------------
+      -- Get_Return_Kind --
+      ---------------------
 
+      function Get_Return_Kind return Return_Kind is
+         Scan_State : Saved_Scan_State;
+         Result     : Return_Kind := Simple_Return;
+
+      begin
+         if Token = Tok_Identifier then
+            Save_Scan_State (Scan_State); -- at identifier
+            Scan; -- past identifier
+
+            if Token = Tok_Colon then
+               Result := Extended_Return; -- It's an extended_return_statement
+            elsif Token = Tok_When then
+               Error_Msg_GNAT_Extension ("return when statement");
+
+               Result := Return_When;
+            end if;
+
+            Restore_Scan_State (Scan_State); -- to identifier
+
+         elsif Token = Tok_When then
+            Error_Msg_GNAT_Extension ("return when statement");
+
+            Result := Return_When;
+         end if;
+
+         return Result;
+      end Get_Return_Kind;
+
+      Ret_Sloc : constant Source_Ptr := Token_Ptr;
+      Ret_Strt : constant Column_Number := Start_Column;
+      Ret_Node : Node_Id := New_Node (N_Simple_Return_Statement, Ret_Sloc);
+      Decl     : Node_Id;
+
+   --  Start of processing for P_Return_Statement
+
+   begin
       Scan; -- past RETURN
 
-      if Token /= Tok_Semicolon then
+      --  Simple_return_statement, no expression, return an
+      --  N_Simple_Return_Statement node with the expression field left Empty.
+
+      if Token = Tok_Semicolon then
+         Scan; -- past ;
+
+      --  Nontrivial case
+
+      else
+         --  Simple_return_statement with expression
 
-         --  If no semicolon, then scan an expression, except that
-         --  we avoid trying to scan an expression if we are at an
+         --  We avoid trying to scan an expression if we are at an
          --  expression terminator since in that case the best error
          --  message is probably that we have a missing semicolon.
 
-         if Token not in Token_Class_Eterm then
-            Set_Expression (Return_Node, P_Expression_No_Right_Paren);
-         end if;
+         case Get_Return_Kind is
+            --  Return_when_statement (Experimental only)
+
+            when Return_When =>
+               Ret_Node := New_Node (N_Return_When_Statement, Ret_Sloc);
+
+               if Token not in Token_Class_Eterm then
+                  Set_Expression (Ret_Node, P_Expression_No_Right_Paren);
+               end if;
+
+               if Token = Tok_When and then not Missing_Semicolon_On_When then
+                  Scan; -- past WHEN
+                  Set_Condition (Ret_Node, P_Condition);
+
+               --  Allow IF instead of WHEN, giving error message
+
+               elsif Token = Tok_If then
+                  T_When;
+                  Scan; -- past IF used in place of WHEN
+                  Set_Condition (Ret_Node, P_Expression_No_Right_Paren);
+               end if;
+
+            --  Simple_return_statement
+
+            when Simple_Return =>
+               Ret_Node := New_Node (N_Simple_Return_Statement, Ret_Sloc);
+
+               if Token not in Token_Class_Eterm then
+                  Set_Expression (Ret_Node, P_Expression_No_Right_Paren);
+               end if;
+
+            --  Extended_return_statement (Ada 2005 only -- AI-318):
+
+            when Extended_Return =>
+               Error_Msg_Ada_2005_Extension ("extended return statement");
+
+               Ret_Node := New_Node (N_Extended_Return_Statement, Ret_Sloc);
+               Decl := P_Return_Object_Declaration;
+               Set_Return_Object_Declarations (Ret_Node, New_List (Decl));
+
+               if Token = Tok_With then
+                  P_Aspect_Specifications (Decl, False);
+               end if;
+
+               if Token = Tok_Do then
+                  Push_Scope_Stack;
+                  Scopes (Scope.Last).Ecol := Ret_Strt;
+                  Scopes (Scope.Last).Etyp := E_Return;
+                  Scopes (Scope.Last).Labl := Error;
+                  Scopes (Scope.Last).Sloc := Ret_Sloc;
+
+                  Scan; -- past DO
+                  Set_Handled_Statement_Sequence
+                    (Ret_Node, P_Handled_Sequence_Of_Statements);
+                  End_Statements;
+
+                  --  Do we need to handle Error_Resync here???
+               end if;
+         end case;
+
+         TF_Semicolon;
       end if;
 
-      TF_Semicolon;
-      return Return_Node;
+      return Ret_Node;
    end P_Return_Statement;
 
 end Ch6;