exp_ch11.adb 83.8 KB
Newer Older
Richard Kenner committed
1 2 3 4 5 6 7 8
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                             E X P _ C H 1 1                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
9
--          Copyright (C) 1992-2019, Free Software Foundation, Inc.         --
Richard Kenner committed
10 11 12
--                                                                          --
-- 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- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
Richard Kenner committed
14 15 16 17
-- 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 --
18 19
-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
Richard Kenner committed
20 21
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
22
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
Richard Kenner committed
23 24 25 26 27 28
--                                                                          --
------------------------------------------------------------------------------

with Atree;    use Atree;
with Debug;    use Debug;
with Einfo;    use Einfo;
29
with Elists;   use Elists;
30
with Errout;   use Errout;
Richard Kenner committed
31
with Exp_Ch7;  use Exp_Ch7;
32
with Exp_Intr; use Exp_Intr;
Richard Kenner committed
33 34 35 36 37 38
with Exp_Util; use Exp_Util;
with Namet;    use Namet;
with Nlists;   use Nlists;
with Nmake;    use Nmake;
with Opt;      use Opt;
with Restrict; use Restrict;
Arnaud Charlet committed
39
with Rident;   use Rident;
Arnaud Charlet committed
40
with Rtsfind;  use Rtsfind;
Richard Kenner committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
with Sem;      use Sem;
with Sem_Ch8;  use Sem_Ch8;
with Sem_Res;  use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinfo;    use Sinfo;
with Sinput;   use Sinput;
with Snames;   use Snames;
with Stand;    use Stand;
with Stringt;  use Stringt;
with Targparm; use Targparm;
with Tbuild;   use Tbuild;
with Uintp;    use Uintp;

package body Exp_Ch11 is

56 57 58 59
   -----------------------
   -- Local Subprograms --
   -----------------------

60 61 62 63
   procedure Warn_No_Exception_Propagation_Active (N : Node_Id);
   --  Generates warning that pragma Restrictions (No_Exception_Propagation)
   --  is in effect. Caller then generates appropriate continuation message.
   --  N is the node on which the warning is placed.
64 65

   procedure Warn_If_No_Propagation (N : Node_Id);
66 67 68
   --  Called for an exception raise that is not a local raise (and thus cannot
   --  be optimized to a goto). Issues warning if No_Exception_Propagation
   --  restriction is set. N is the node for the raise or equivalent call.
69

Richard Kenner committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
   ---------------------------
   -- Expand_At_End_Handler --
   ---------------------------

   --  For a handled statement sequence that has a cleanup (At_End_Proc
   --  field set), an exception handler of the following form is required:

   --     exception
   --       when all others =>
   --          cleanup call
   --          raise;

   --  Note: this exception handler is treated rather specially by
   --  subsequent expansion in two respects:

   --    The normal call to Undefer_Abort is omitted
   --    The raise call does not do Defer_Abort

   --  This is because the current tasking code seems to assume that
   --  the call to the cleanup routine that is made from an exception
   --  handler for the abort signal is called with aborts deferred.

92 93 94 95 96 97 98 99 100 101
   --  This expansion is only done if we have front end exception handling.
   --  If we have back end exception handling, then the AT END handler is
   --  left alone, and cleanups (including the exceptional case) are handled
   --  by the back end.

   --  In the front end case, the exception handler described above handles
   --  the exceptional case. The AT END handler is left in the generated tree
   --  and the code generator (e.g. gigi) must still handle proper generation
   --  of cleanup calls for the non-exceptional case.

102
   procedure Expand_At_End_Handler (HSS : Node_Id; Blk_Id : Entity_Id) is
Richard Kenner committed
103 104 105 106
      Clean   : constant Entity_Id  := Entity (At_End_Proc (HSS));
      Ohandle : Node_Id;
      Stmnts  : List_Id;

Arnaud Charlet committed
107 108 109 110 111 112 113 114
      Loc : constant Source_Ptr := No_Location;
      --  Location used for expansion. We quite deliberately do not set a
      --  specific source location for the expanded handler. This makes
      --  sense since really the handler is not associated with specific
      --  source. We used to set this to Sloc (Clean), but that caused
      --  useless and annoying bouncing around of line numbers in the
      --  debugger in some circumstances.

Richard Kenner committed
115 116 117 118
   begin
      pragma Assert (Present (Clean));
      pragma Assert (No (Exception_Handlers (HSS)));

119 120
      --  Back end exception schemes don't need explicit handlers to
      --  trigger AT-END actions on exceptional paths.
121

122
      if Back_End_Exceptions then
123 124 125 126 127 128 129 130 131 132 133
         return;
      end if;

      --  Don't expand an At End handler if we have already had configurable
      --  run-time violations, since likely this will just be a matter of
      --  generating useless cascaded messages

      if Configurable_Run_Time_Violations > 0 then
         return;
      end if;

134 135 136 137 138
      --  Don't expand an At End handler if we are not allowing exceptions
      --  or if exceptions are transformed into local gotos, and never
      --  propagated (No_Exception_Propagation).

      if No_Exception_Handlers_Set then
Richard Kenner committed
139 140 141
         return;
      end if;

142 143
      if Present (Blk_Id) then
         Push_Scope (Blk_Id);
Richard Kenner committed
144 145 146 147 148 149 150 151
      end if;

      Ohandle :=
        Make_Others_Choice (Loc);
      Set_All_Others (Ohandle);

      Stmnts := New_List (
        Make_Procedure_Call_Statement (Loc,
152 153
          Name => New_Occurrence_Of (Clean, Loc)));

154 155 156 157 158 159 160
      --  Generate reraise statement as last statement of AT-END handler,
      --  unless we are under control of No_Exception_Propagation, in which
      --  case no exception propagation is possible anyway, so we do not need
      --  a reraise (the AT END handler in this case is only for normal exits
      --  not for exceptional exits). Also, we flag the Reraise statement as
      --  being part of an AT END handler to prevent signalling this reraise
      --  as a violation of the restriction when it is not set.
161 162

      if not Restriction_Active (No_Exception_Propagation) then
163 164 165 166 167 168
         declare
            Rstm : constant Node_Id := Make_Raise_Statement (Loc);
         begin
            Set_From_At_End (Rstm);
            Append_To (Stmnts, Rstm);
         end;
169
      end if;
Richard Kenner committed
170 171

      Set_Exception_Handlers (HSS, New_List (
172
        Make_Implicit_Exception_Handler (Loc,
Richard Kenner committed
173 174 175 176 177 178
          Exception_Choices => New_List (Ohandle),
          Statements        => Stmnts)));

      Analyze_List (Stmnts, Suppress => All_Checks);
      Expand_Exception_Handlers (HSS);

179
      if Present (Blk_Id) then
Richard Kenner committed
180 181 182 183 184 185 186 187 188
         Pop_Scope;
      end if;
   end Expand_At_End_Handler;

   -------------------------------
   -- Expand_Exception_Handlers --
   -------------------------------

   procedure Expand_Exception_Handlers (HSS : Node_Id) is
189 190
      Handlrs       : constant List_Id    := Exception_Handlers (HSS);
      Loc           : constant Source_Ptr := Sloc (HSS);
Richard Kenner committed
191 192 193
      Handler       : Node_Id;
      Others_Choice : Boolean;
      Obj_Decl      : Node_Id;
194 195 196 197 198
      Next_Handler  : Node_Id;

      procedure Expand_Local_Exception_Handlers;
      --  This procedure handles the expansion of exception handlers for the
      --  optimization of local raise statements into goto statements.
Richard Kenner committed
199 200 201 202 203 204 205

      procedure Prepend_Call_To_Handler
        (Proc : RE_Id;
         Args : List_Id := No_List);
      --  Routine to prepend a call to the procedure referenced by Proc at
      --  the start of the handler code for the current Handler.

206 207 208 209 210 211 212 213 214 215 216 217 218
      procedure Replace_Raise_By_Goto (Raise_S : Node_Id; Goto_L1 : Node_Id);
      --  Raise_S is a raise statement (possibly expanded, and possibly of the
      --  form of a Raise_xxx_Error node with a condition. This procedure is
      --  called to replace the raise action with the (already analyzed) goto
      --  statement passed as Goto_L1. This procedure also takes care of the
      --  requirement of inserting a Local_Raise call where possible.

      -------------------------------------
      -- Expand_Local_Exception_Handlers --
      -------------------------------------

      --  There are two cases for this transformation. First the case of
      --  explicit raise statements. For this case, the transformation we do
219
      --  looks like this. Right now we have for example (where L1, L2 are
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
      --  exception labels)

      --  begin
      --     ...
      --     raise_exception (excep1'identity);  -- was raise excep1
      --     ...
      --     raise_exception (excep2'identity);  -- was raise excep2
      --     ...
      --  exception
      --     when excep1 =>
      --        estmts1
      --     when excep2 =>
      --        estmts2
      --  end;

      --  This gets transformed into:

      --  begin
238 239 240
      --     L1 : label;                        -- marked Exception_Junk
      --     L2 : label;                        -- marked Exception_Junk
      --     L3 : label;                        -- marked Exception_Junk
241

242
      --     begin                              -- marked Exception_Junk
243
      --        ...
244
      --        local_raise (excep1'address);   -- was raise excep1
245 246
      --        goto L1;
      --        ...
247
      --        local_raise (excep2'address);   -- was raise excep2
248 249 250 251 252 253 254 255 256
      --        goto L2;
      --        ...
      --     exception
      --        when excep1 =>
      --           goto L1;
      --        when excep2 =>
      --           goto L2;
      --     end;

257
      --     goto L3;        -- skip handler if no raise, marked Exception_Junk
258

259 260 261 262 263
      --     <<L1>>          -- local excep target label, marked Exception_Junk
      --        begin        -- marked Exception_Junk
      --           estmts1
      --        end;
      --        goto L3;     -- marked Exception_Junk
264

265 266 267 268 269 270
      --     <<L2>>          -- marked Exception_Junk
      --        begin        -- marked Exception_Junk
      --           estmts2
      --        end;
      --        goto L3;     -- marked Exception_Junk
      --     <<L3>>          -- marked Exception_Junk
271 272 273 274 275 276 277 278 279
      --  end;

      --  Note: the reason we wrap the original statement sequence in an
      --  inner block is that there may be raise statements within the
      --  sequence of statements in the handlers, and we must ensure that
      --  these are properly handled, and in particular, such raise statements
      --  must not reenter the same exception handlers.

      --  If the restriction No_Exception_Propagation is in effect, then we
280
      --  can omit the exception handlers.
281 282

      --  begin
283 284 285
      --     L1 : label;                        -- marked Exception_Junk
      --     L2 : label;                        -- marked Exception_Junk
      --     L3 : label;                        -- marked Exception_Junk
286

287 288 289 290 291 292 293 294 295
      --     begin                              -- marked Exception_Junk
      --        ...
      --        local_raise (excep1'address);   -- was raise excep1
      --        goto L1;
      --        ...
      --        local_raise (excep2'address);   -- was raise excep2
      --        goto L2;
      --        ...
      --     end;
296

297
      --     goto L3;        -- skip handler if no raise, marked Exception_Junk
298

299 300 301 302 303
      --     <<L1>>          -- local excep target label, marked Exception_Junk
      --        begin        -- marked Exception_Junk
      --           estmts1
      --        end;
      --        goto L3;     -- marked Exception_Junk
304

305 306 307 308 309 310
      --     <<L2>>          -- marked Exception_Junk
      --        begin        -- marked Exception_Junk
      --           estmts2
      --        end;

      --     <<L3>>          -- marked Exception_Junk
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
      --  end;

      --  The second case is for exceptions generated by the back end in one
      --  of three situations:

      --    1. Front end generates N_Raise_xxx_Error node
      --    2. Front end sets Do_xxx_Check flag in subexpression node
      --    3. Back end detects a situation where an exception is appropriate

      --  In all these cases, the current processing in gigi is to generate a
      --  call to the appropriate Rcheck_xx routine (where xx encodes both the
      --  exception message and the exception to be raised, Constraint_Error,
      --  Program_Error, or Storage_Error.

      --  We could handle some subcases of 1 using the same front end expansion
      --  into gotos, but even for case 1, we can't handle all cases, since
      --  generating gotos in the middle of expressions is not possible (it's
      --  possible at the gigi/gcc level, but not at the level of the GNAT
      --  tree).

      --  In any case, it seems easier to have a scheme which handles all three
      --  cases in a uniform manner. So here is how we proceed in this case.

      --  This procedure detects all handlers for these three exceptions,
      --  Constraint_Error, Program_Error and Storage_Error (including WHEN
      --  OTHERS handlers that cover one or more of these cases).

      --  If the handler meets the requirements for being the target of a local
      --  raise, then the front end does the expansion described previously,
      --  creating a label to be used as a goto target to raise the exception.
      --  However, no attempt is made in the front end to convert any related
342 343
      --  raise statements into gotos, e.g. all N_Raise_xxx_Error nodes are
      --  left unchanged and passed to the back end.
344

Arnaud Charlet committed
345
      --  Instead, the front end generates three nodes
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

      --     N_Push_Constraint_Error_Label
      --     N_Push_Program_Error_Label
      --     N_Push_Storage_Error_Label

      --       The Push node is generated at the start of the statements
      --       covered by the handler, and has as a parameter the label to be
      --       used as the raise target.

      --     N_Pop_Constraint_Error_Label
      --     N_Pop_Program_Error_Label
      --     N_Pop_Storage_Error_Label

      --       The Pop node is generated at the end of the covered statements
      --       and undoes the effect of the preceding corresponding Push node.

      --  In the case where the handler does NOT meet the requirements, the
      --  front end will still generate the Push and Pop nodes, but the label
      --  field in the Push node will be empty signifying that for this region
      --  of code, no optimization is possible.

Arnaud Charlet committed
367 368 369 370
      --  These Push/Pop nodes are inhibited if No_Exception_Handlers is set
      --  since they are useless in this case, and in CodePeer mode, where
      --  they serve no purpose and can intefere with the analysis.

371
      --  The back end must maintain three stacks, one for each exception case,
372
      --  the Push node pushes an entry onto the corresponding stack, and Pop
373 374
      --  node pops off the entry. Then instead of calling Rcheck_nn, if the
      --  corresponding top stack entry has an non-empty label, a goto is
375 376
      --  generated. This goto should be preceded by a call to Local_Raise as
      --  described above.
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

      --  An example of this transformation is as follows, given:

      --  declare
      --    A : Integer range 1 .. 10;
      --  begin
      --    A := B + C;
      --  exception
      --    when Constraint_Error =>
      --       estmts
      --  end;

      --  gets transformed to:

      --  declare
      --    A : Integer range 1 .. 10;

      --  begin
      --     L1 : label;
      --     L2 : label;

      --     begin
399 400 401 402 403 404
      --        %push_constraint_error_label (L1)
      --        R1b : constant long_long_integer := long_long_integer?(b) +
      --          long_long_integer?(c);
      --        [constraint_error when
      --          not (R1b in -16#8000_0000# .. 16#7FFF_FFFF#)
      --          "overflow check failed"]
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
      --        a := integer?(R1b);
      --        %pop_constraint_error_Label

      --     exception
      --        ...
      --        when constraint_error =>
      --           goto L1;
      --     end;

      --     goto L2;       -- skip handler when exception not raised
      --     <<L1>>         -- target label for local exception
      --     estmts
      --     <<L2>>
      --  end;

420 421 422 423 424 425 426 427 428
      --  Note: the generated labels and goto statements all have the flag
      --  Exception_Junk set True, so that Sem_Ch6.Check_Returns will ignore
      --  this generated exception stuff when checking for missing return
      --  statements (see circuitry in Check_Statement_Sequence).

      --  Note: All of the processing described above occurs only if
      --  restriction No_Exception_Propagation applies or debug flag .g is
      --  enabled.

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
      CE_Locally_Handled : Boolean := False;
      SE_Locally_Handled : Boolean := False;
      PE_Locally_Handled : Boolean := False;
      --  These three flags indicate whether a handler for the corresponding
      --  exception (CE=Constraint_Error, SE=Storage_Error, PE=Program_Error)
      --  is present. If so the switch is set to True, the Exception_Label
      --  field of the corresponding handler is set, and appropriate Push
      --  and Pop nodes are inserted into the code.

      Local_Expansion_Required : Boolean := False;
      --  Set True if we have at least one handler requiring local raise
      --  expansion as described above.

      procedure Expand_Local_Exception_Handlers is
         procedure Add_Exception_Label (H : Node_Id);
         --  H is an exception handler. First check for an Exception_Label
445
         --  already allocated for H. If none, allocate one, set the field in
446
         --  the handler node, add the label declaration, and set the flag
447
         --  Local_Expansion_Required. Note: if Local_Raise_Not_OK is set
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
         --  the call has no effect and Exception_Label is left empty.

         procedure Add_Label_Declaration (L : Entity_Id);
         --  Add an implicit declaration of the given label to the declaration
         --  list in the parent of the current sequence of handled statements.

         generic
            Exc_Locally_Handled : in out Boolean;
            --  Flag indicating whether a local handler for this exception
            --  has already been generated.

            with function Make_Push_Label (Loc : Source_Ptr) return Node_Id;
            --  Function to create a Push_xxx_Label node

            with function Make_Pop_Label (Loc : Source_Ptr) return Node_Id;
            --  Function to create a Pop_xxx_Label node

         procedure Generate_Push_Pop (H : Node_Id);
         --  Common code for Generate_Push_Pop_xxx below, used to generate an
         --  exception label and Push/Pop nodes for Constraint_Error,
         --  Program_Error, or Storage_Error.

         -------------------------
         -- Add_Exception_Label --
         -------------------------

         procedure Add_Exception_Label (H : Node_Id) is
         begin
            if No (Exception_Label (H))
              and then not Local_Raise_Not_OK (H)
478
              and then not Special_Exception_Package_Used
479 480 481 482
            then
               Local_Expansion_Required := True;

               declare
483
                  L : constant Entity_Id := Make_Temporary (Sloc (H), 'L');
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
               begin
                  Set_Exception_Label (H, L);
                  Add_Label_Declaration (L);
               end;
            end if;
         end Add_Exception_Label;

         ---------------------------
         -- Add_Label_Declaration --
         ---------------------------

         procedure Add_Label_Declaration (L : Entity_Id) is
            P : constant Node_Id := Parent (HSS);

            Decl_L : constant Node_Id :=
                       Make_Implicit_Label_Declaration (Loc,
                         Defining_Identifier => L);

         begin
            if Declarations (P) = No_List then
               Set_Declarations (P, Empty_List);
            end if;

            Append (Decl_L, Declarations (P));
            Analyze (Decl_L);
         end Add_Label_Declaration;

         -----------------------
         -- Generate_Push_Pop --
         -----------------------

         procedure Generate_Push_Pop (H : Node_Id) is
         begin
Arnaud Charlet committed
517 518 519 520 521 522
            if Restriction_Active (No_Exception_Handlers)
              or else CodePeer_Mode
            then
               return;
            end if;

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
            if Exc_Locally_Handled then
               return;
            else
               Exc_Locally_Handled := True;
            end if;

            Add_Exception_Label (H);

            declare
               F : constant Node_Id := First (Statements (HSS));
               L : constant Node_Id := Last  (Statements (HSS));

               Push : constant Node_Id := Make_Push_Label (Sloc (F));
               Pop  : constant Node_Id := Make_Pop_Label  (Sloc (L));

            begin
539 540 541
               --  We make sure that a call to Get_Local_Raise_Call_Entity is
               --  made during front end processing, so that when we need it
               --  in the back end, it will already be available and loaded.
542

543 544 545 546 547
               Discard_Node (Get_Local_Raise_Call_Entity);

               --  Prepare and insert Push and Pop nodes

               Set_Exception_Label (Push, Exception_Label (H));
548 549 550 551 552 553 554 555 556 557 558
               Insert_Before (F, Push);
               Set_Analyzed (Push);

               Insert_After (L, Pop);
               Set_Analyzed (Pop);
            end;
         end Generate_Push_Pop;

         --  Local declarations

         Loc    : constant Source_Ptr := Sloc (HSS);
559
         Stmts  : List_Id := No_List;
560
         Choice : Node_Id;
561
         Excep  : Entity_Id;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592

         procedure Generate_Push_Pop_For_Constraint_Error is
           new Generate_Push_Pop
             (Exc_Locally_Handled => CE_Locally_Handled,
              Make_Push_Label     => Make_Push_Constraint_Error_Label,
              Make_Pop_Label      => Make_Pop_Constraint_Error_Label);
         --  If no Push/Pop has been generated for CE yet, then set the flag
         --  CE_Locally_Handled, allocate an Exception_Label for handler H (if
         --  not already done), and generate Push/Pop nodes for the exception
         --  label at the start and end of the statements of HSS.

         procedure Generate_Push_Pop_For_Program_Error is
           new Generate_Push_Pop
             (Exc_Locally_Handled => PE_Locally_Handled,
              Make_Push_Label     => Make_Push_Program_Error_Label,
              Make_Pop_Label      => Make_Pop_Program_Error_Label);
         --  If no Push/Pop has been generated for PE yet, then set the flag
         --  PE_Locally_Handled, allocate an Exception_Label for handler H (if
         --  not already done), and generate Push/Pop nodes for the exception
         --  label at the start and end of the statements of HSS.

         procedure Generate_Push_Pop_For_Storage_Error is
           new Generate_Push_Pop
             (Exc_Locally_Handled => SE_Locally_Handled,
              Make_Push_Label     => Make_Push_Storage_Error_Label,
              Make_Pop_Label      => Make_Pop_Storage_Error_Label);
         --  If no Push/Pop has been generated for SE yet, then set the flag
         --  SE_Locally_Handled, allocate an Exception_Label for handler H (if
         --  not already done), and generate Push/Pop nodes for the exception
         --  label at the start and end of the statements of HSS.

593 594
      --  Start of processing for Expand_Local_Exception_Handlers

595
      begin
596 597 598 599 600 601 602
         --  No processing if all exception handlers will get removed

         if Debug_Flag_Dot_X then
            return;
         end if;

         --  See for each handler if we have any local raises to expand
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

         Handler := First_Non_Pragma (Handlrs);
         while Present (Handler) loop

            --  Note, we do not test Local_Raise_Not_OK here, because in the
            --  case of Push/Pop generation we want to generate push with a
            --  null label. The Add_Exception_Label routine has no effect if
            --  Local_Raise_Not_OK is set, so this works as required.

            if Present (Local_Raise_Statements (Handler)) then
               Add_Exception_Label (Handler);
            end if;

            --  If we are doing local raise to goto optimization (restriction
            --  No_Exception_Propagation set or debug flag .g set), then check
618 619
            --  to see if handler handles CE, PE, SE and if so generate the
            --  appropriate push/pop sequence for the back end.
620

621 622 623
            if (Debug_Flag_Dot_G
                 or else Restriction_Active (No_Exception_Propagation))
              and then Has_Local_Raise (Handler)
624 625 626
            then
               Choice := First (Exception_Choices (Handler));
               while Present (Choice) loop
627 628 629
                  if Nkind (Choice) = N_Others_Choice
                    and then not All_Others (Choice)
                  then
630 631 632 633 634
                     Generate_Push_Pop_For_Constraint_Error (Handler);
                     Generate_Push_Pop_For_Program_Error    (Handler);
                     Generate_Push_Pop_For_Storage_Error    (Handler);

                  elsif Is_Entity_Name (Choice) then
635 636 637
                     Excep := Get_Renamed_Entity (Entity (Choice));

                     if Excep = Standard_Constraint_Error then
638
                        Generate_Push_Pop_For_Constraint_Error (Handler);
639 640 641 642
                     elsif Excep = Standard_Program_Error then
                        Generate_Push_Pop_For_Program_Error    (Handler);
                     elsif Excep = Standard_Storage_Error then
                        Generate_Push_Pop_For_Storage_Error    (Handler);
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
                     end if;
                  end if;

                  Next (Choice);
               end loop;
            end if;

            Next_Non_Pragma (Handler);
         end loop;

         --  Nothing to do if no handlers requiring the goto transformation

         if not (Local_Expansion_Required) then
            return;
         end if;

         --  Prepare to do the transformation

         declare
662 663
            --  L3 is the label to exit the HSS

664
            L3_Dent : constant Entity_Id := Make_Temporary (Loc, 'L');
665 666 667 668 669 670 671 672 673

            Labl_L3 : constant Node_Id :=
                        Make_Label (Loc,
                          Identifier => New_Occurrence_Of (L3_Dent, Loc));

            Blk_Stm : Node_Id;
            Relmt   : Elmt_Id;

         begin
674
            Set_Exception_Junk (Labl_L3);
675 676
            Add_Label_Declaration (L3_Dent);

677
            --  Wrap existing statements and handlers in an inner block
678

679 680 681 682
            Blk_Stm :=
              Make_Block_Statement (Loc,
                Handled_Statement_Sequence => Relocate_Node (HSS));
            Set_Exception_Junk (Blk_Stm);
683

684 685
            Rewrite (HSS,
              Make_Handled_Sequence_Of_Statements (Loc,
Arnaud Charlet committed
686 687
                Statements => New_List (Blk_Stm),
                End_Label  => Relocate_Node (End_Label (HSS))));
688

689 690 691
            --  Set block statement as analyzed, we don't want to actually call
            --  Analyze on this block, it would cause a recursion in exception
            --  handler processing which would mess things up.
692

693
            Set_Analyzed (Blk_Stm);
694 695 696 697 698 699 700 701 702 703 704 705 706

            --  Now loop through the exception handlers to deal with those that
            --  are targets of local raise statements.

            Handler := First_Non_Pragma (Handlrs);
            while Present (Handler) loop
               if Present (Exception_Label (Handler)) then

                  --  This handler needs the goto expansion

                  declare
                     Loc : constant Source_Ptr := Sloc (Handler);

707 708
                     --  L1 is the start label for this handler

709 710 711 712 713 714 715
                     L1_Dent : constant Entity_Id := Exception_Label (Handler);

                     Labl_L1 : constant Node_Id :=
                                 Make_Label (Loc,
                                   Identifier =>
                                     New_Occurrence_Of (L1_Dent, Loc));

716 717 718 719
                     --  Jump to L1 to be used as replacement for the original
                     --  handler (used in the case where exception propagation
                     --  may still occur).

720 721 722 723 724 725 726
                     Name_L1 : constant Node_Id :=
                                 New_Occurrence_Of (L1_Dent, Loc);

                     Goto_L1 : constant Node_Id :=
                                 Make_Goto_Statement (Loc,
                                   Name => Name_L1);

727 728
                     --  Jump to L3 to be used at the end of handler

729 730 731 732 733 734 735 736 737 738
                     Name_L3 : constant Node_Id :=
                                 New_Occurrence_Of (L3_Dent, Loc);

                     Goto_L3 : constant Node_Id :=
                                 Make_Goto_Statement (Loc,
                                   Name => Name_L3);

                     H_Stmts : constant List_Id := Statements (Handler);

                  begin
739 740 741 742 743 744 745
                     Set_Exception_Junk (Labl_L1);
                     Set_Exception_Junk (Goto_L3);

                     --  Note: we do NOT set Exception_Junk in Goto_L1, since
                     --  this is a real transfer of control that we want the
                     --  Sem_Ch6.Check_Returns procedure to recognize properly.

746 747
                     --  Replace handler by a goto L1. We can mark this as
                     --  analyzed since it is fully formed, and we don't
748 749 750
                     --  want it going through any further checks. We save
                     --  the last statement location in the goto L1 node for
                     --  the benefit of Sem_Ch6.Check_Returns.
751 752 753 754 755 756 757 758 759 760 761

                     Set_Statements (Handler, New_List (Goto_L1));
                     Set_Analyzed (Goto_L1);
                     Set_Etype (Name_L1, Standard_Void_Type);

                     --  Now replace all the raise statements by goto L1

                     if Present (Local_Raise_Statements (Handler)) then
                        Relmt := First_Elmt (Local_Raise_Statements (Handler));
                        while Present (Relmt) loop
                           declare
Arnaud Charlet committed
762 763
                              Raise_S : constant Node_Id    := Node (Relmt);
                              RLoc    : constant Source_Ptr := Sloc (Raise_S);
764 765 766
                              Name_L1 : constant Node_Id :=
                                          New_Occurrence_Of (L1_Dent, Loc);
                              Goto_L1 : constant Node_Id :=
Arnaud Charlet committed
767
                                          Make_Goto_Statement (RLoc,
768 769 770 771 772 773 774 775 776 777 778 779 780 781
                                            Name => Name_L1);

                           begin
                              --  Replace raise by goto L1

                              Set_Analyzed (Goto_L1);
                              Set_Etype (Name_L1, Standard_Void_Type);
                              Replace_Raise_By_Goto (Raise_S, Goto_L1);
                           end;

                           Next_Elmt (Relmt);
                        end loop;
                     end if;

782
                     --  Add a goto L3 at end of statement list in block. The
783 784
                     --  first time, this is what skips over the exception
                     --  handlers in the normal case. Subsequent times, it
785 786
                     --  terminates the execution of the previous handler code,
                     --  and skips subsequent handlers.
787 788 789 790 791 792 793 794 795 796 797 798 799

                     Stmts := Statements (HSS);

                     Insert_After (Last (Stmts), Goto_L3);
                     Set_Analyzed (Goto_L3);
                     Set_Etype (Name_L3, Standard_Void_Type);

                     --  Now we drop the label that marks the handler start,
                     --  followed by the statements of the handler.

                     Set_Etype (Identifier (Labl_L1), Standard_Void_Type);

                     Insert_After_And_Analyze (Last (Stmts), Labl_L1);
800 801 802 803 804 805 806 807 808 809 810 811

                     declare
                        Loc : constant Source_Ptr := Sloc (First (H_Stmts));
                        Blk : constant Node_Id :=
                                Make_Block_Statement (Loc,
                                  Handled_Statement_Sequence =>
                                    Make_Handled_Sequence_Of_Statements (Loc,
                                      Statements => H_Stmts));
                     begin
                        Set_Exception_Junk (Blk);
                        Insert_After_And_Analyze (Last (Stmts), Blk);
                     end;
812 813 814 815
                  end;

                  --  Here if we have local raise statements but the handler is
                  --  not suitable for processing with a local raise. In this
816
                  --  case we have to generate possible diagnostics.
817

818 819 820
               elsif Has_Local_Raise (Handler)
                 and then Local_Raise_Statements (Handler) /= No_Elist
               then
821 822 823 824 825 826 827 828 829 830 831 832 833
                  Relmt := First_Elmt (Local_Raise_Statements (Handler));
                  while Present (Relmt) loop
                     Warn_If_No_Propagation (Node (Relmt));
                     Next_Elmt (Relmt);
                  end loop;
               end if;

               Next (Handler);
            end loop;

            --  Only remaining step is to drop the L3 label and we are done

            Set_Etype (Identifier (Labl_L3), Standard_Void_Type);
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848

            --  If we had at least one handler, then we drop the label after
            --  the last statement of that handler.

            if Stmts /= No_List then
               Insert_After_And_Analyze (Last (Stmts), Labl_L3);

            --  Otherwise we have removed all the handlers (this results from
            --  use of pragma Restrictions (No_Exception_Propagation), and we
            --  drop the label at the end of the statements of the HSS.

            else
               Insert_After_And_Analyze (Last (Statements (HSS)), Labl_L3);
            end if;

849 850 851 852
            return;
         end;
      end Expand_Local_Exception_Handlers;

853 854 855 856
      -----------------------------
      -- Prepend_Call_To_Handler --
      -----------------------------

Richard Kenner committed
857 858 859 860
      procedure Prepend_Call_To_Handler
        (Proc : RE_Id;
         Args : List_Id := No_List)
      is
861
         Ent : constant Entity_Id := RTE (Proc);
Richard Kenner committed
862 863

      begin
Arnaud Charlet committed
864 865 866 867
         --  If we have no Entity, then we are probably in no run time mode or
         --  some weird error has occurred. In either case do nothing. Note use
         --  of No_Location to hide this code from the debugger, so single
         --  stepping doesn't jump back and forth.
868 869 870 871

         if Present (Ent) then
            declare
               Call : constant Node_Id :=
Arnaud Charlet committed
872 873
                        Make_Procedure_Call_Statement (No_Location,
                          Name => New_Occurrence_Of (RTE (Proc), No_Location),
874 875 876 877 878 879 880
                          Parameter_Associations => Args);

            begin
               Prepend_To (Statements (Handler), Call);
               Analyze (Call, Suppress => All_Checks);
            end;
         end if;
Richard Kenner committed
881 882
      end Prepend_Call_To_Handler;

883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
      ---------------------------
      -- Replace_Raise_By_Goto --
      ---------------------------

      procedure Replace_Raise_By_Goto (Raise_S : Node_Id; Goto_L1 : Node_Id) is
         Loc   : constant Source_Ptr := Sloc (Raise_S);
         Excep : Entity_Id;
         LR    : Node_Id;
         Cond  : Node_Id;
         Orig  : Node_Id;

      begin
         --  If we have a null statement, it means that there is no replacement
         --  needed (typically this results from a suppressed check).

         if Nkind (Raise_S) = N_Null_Statement then
            return;

         --  Test for Raise_xxx_Error

         elsif Nkind (Raise_S) = N_Raise_Constraint_Error then
            Excep := Standard_Constraint_Error;
            Cond  := Condition (Raise_S);

         elsif Nkind (Raise_S) = N_Raise_Storage_Error then
            Excep := Standard_Storage_Error;
            Cond := Condition (Raise_S);

         elsif Nkind (Raise_S) = N_Raise_Program_Error then
            Excep := Standard_Program_Error;
            Cond := Condition (Raise_S);

915
            --  The only other possibility is a node that is or used to be a
916 917
            --  simple raise statement. Note that the string expression in the
            --  original Raise statement is ignored.
918 919 920 921

         else
            Orig := Original_Node (Raise_S);
            pragma Assert (Nkind (Orig) = N_Raise_Statement
922
                             and then Present (Name (Orig)));
923 924 925 926 927
            Excep := Entity (Name (Orig));
            Cond := Empty;
         end if;

         --  Here Excep is the exception to raise, and Cond is the condition
928
         --  First prepare the call to Local_Raise (excep'address).
929 930 931 932 933 934

         if RTE_Available (RE_Local_Raise) then
            LR :=
              Make_Procedure_Call_Statement (Loc,
                Name => New_Occurrence_Of (RTE (RE_Local_Raise), Loc),
                Parameter_Associations => New_List (
935 936 937 938
                  Unchecked_Convert_To (RTE (RE_Address),
                    Make_Attribute_Reference (Loc,
                      Prefix         => New_Occurrence_Of (Excep, Loc),
                      Attribute_Name => Name_Identity))));
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959

            --  Use null statement if Local_Raise not available

         else
            LR :=
              Make_Null_Statement (Loc);
         end if;

         --  If there is no condition, we rewrite as

         --    begin
         --       Local_Raise (excep'Identity);
         --       goto L1;
         --    end;

         if No (Cond) then
            Rewrite (Raise_S,
              Make_Block_Statement (Loc,
                Handled_Statement_Sequence =>
                  Make_Handled_Sequence_Of_Statements (Loc,
                    Statements => New_List (LR, Goto_L1))));
960
            Set_Exception_Junk (Raise_S);
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978

         --  If there is a condition, we rewrite as

         --    if condition then
         --       Local_Raise (excep'Identity);
         --       goto L1;
         --    end if;

         else
            Rewrite (Raise_S,
              Make_If_Statement (Loc,
                Condition       => Cond,
                Then_Statements => New_List (LR, Goto_L1)));
         end if;

         Analyze (Raise_S);
      end Replace_Raise_By_Goto;

Richard Kenner committed
979 980 981
   --  Start of processing for Expand_Exception_Handlers

   begin
982 983
      Expand_Local_Exception_Handlers;

Richard Kenner committed
984 985 986
      --  Loop through handlers

      Handler := First_Non_Pragma (Handlrs);
987
      Handler_Loop : while Present (Handler) loop
Arnaud Charlet committed
988 989
         Process_Statements_For_Controlled_Objects (Handler);

990
         Next_Handler := Next_Non_Pragma (Handler);
Richard Kenner committed
991

992
         --  Remove source handler if gnat debug flag .x is set
993 994

         if Debug_Flag_Dot_X and then Comes_From_Source (Handler) then
995
            Remove (Handler);
Richard Kenner committed
996

997 998
         --  Remove handler if no exception propagation, generating a warning
         --  if a source generated handler was not the target of a local raise.
Richard Kenner committed
999

1000
         else
1001
            if not Has_Local_Raise (Handler)
1002 1003
              and then Comes_From_Source (Handler)
            then
1004
               Warn_If_No_Local_Raise (Handler);
1005
            end if;
Richard Kenner committed
1006

1007 1008
            if No_Exception_Propagation_Active then
               Remove (Handler);
Richard Kenner committed
1009

1010
            --  Exception handler is active and retained and must be processed
Richard Kenner committed
1011

1012 1013 1014
            else
               --  If an exception occurrence is present, then we must declare
               --  it and initialize it from the value stored in the TSD
Richard Kenner committed
1015

1016 1017 1018 1019 1020 1021
               --     declare
               --        name : Exception_Occurrence;
               --     begin
               --        Save_Occurrence (name, Get_Current_Excep.all)
               --        ...
               --     end;
1022

1023 1024 1025
               --  This expansion is only performed when using front-end
               --  exceptions. Gigi will insert a call to initialize the
               --  choice parameter.
Arnaud Charlet committed
1026 1027

               if Present (Choice_Parameter (Handler))
1028
                 and then (Front_End_Exceptions
Arnaud Charlet committed
1029
                            or else CodePeer_Mode)
Arnaud Charlet committed
1030
               then
1031 1032
                  declare
                     Cparm : constant Entity_Id  := Choice_Parameter (Handler);
1033 1034
                     Cloc  : constant Source_Ptr := Sloc (Cparm);
                     Hloc  : constant Source_Ptr := Sloc (Handler);
1035
                     Save  : Node_Id;
1036

1037
                  begin
Arnaud Charlet committed
1038 1039
                     --  Note: No_Location used to hide code from the debugger,
                     --  so single stepping doesn't jump back and forth.
Arnaud Charlet committed
1040

1041
                     Save :=
Arnaud Charlet committed
1042
                       Make_Procedure_Call_Statement (No_Location,
1043
                         Name                   =>
Arnaud Charlet committed
1044 1045
                           New_Occurrence_Of
                             (RTE (RE_Save_Occurrence), No_Location),
1046
                         Parameter_Associations => New_List (
Arnaud Charlet committed
1047
                           New_Occurrence_Of (Cparm, No_Location),
Arnaud Charlet committed
1048
                           Make_Explicit_Dereference (No_Location,
Arnaud Charlet committed
1049 1050 1051 1052 1053 1054 1055 1056
                             Prefix =>
                               Make_Function_Call (No_Location,
                                 Name =>
                                   Make_Explicit_Dereference (No_Location,
                                     Prefix =>
                                       New_Occurrence_Of
                                         (RTE (RE_Get_Current_Excep),
                                          No_Location))))));
1057 1058 1059 1060 1061

                     Mark_Rewrite_Insertion (Save);
                     Prepend (Save, Statements (Handler));

                     Obj_Decl :=
1062 1063 1064 1065 1066
                       Make_Object_Declaration (Cloc,
                         Defining_Identifier => Cparm,
                         Object_Definition   =>
                           New_Occurrence_Of
                             (RTE (RE_Exception_Occurrence), Cloc));
1067 1068 1069
                     Set_No_Initialization (Obj_Decl, True);

                     Rewrite (Handler,
1070 1071
                       Make_Exception_Handler (Hloc,
                         Choice_Parameter  => Empty,
1072
                         Exception_Choices => Exception_Choices (Handler),
1073
                         Statements        => New_List (
1074
                           Make_Block_Statement (Hloc,
1075 1076
                             Declarations => New_List (Obj_Decl),
                             Handled_Statement_Sequence =>
1077
                               Make_Handled_Sequence_Of_Statements (Hloc,
1078 1079
                                 Statements => Statements (Handler))))));

1080 1081 1082 1083 1084 1085 1086 1087
                     --  Local raise statements can't occur, since exception
                     --  handlers with choice parameters are not allowed when
                     --  No_Exception_Propagation applies, so set attributes
                     --  accordingly.

                     Set_Local_Raise_Statements (Handler, No_Elist);
                     Set_Local_Raise_Not_OK (Handler);

1088 1089 1090 1091
                     Analyze_List
                       (Statements (Handler), Suppress => All_Checks);
                  end;
               end if;
1092

1093 1094 1095 1096 1097 1098 1099 1100
               --  For the normal case, we have to worry about the state of
               --  abort deferral. Generally, we defer abort during runtime
               --  handling of exceptions. When control is passed to the
               --  handler, then in the normal case we undefer aborts. In
               --  any case this entire handling is relevant only if aborts
               --  are allowed.

               if Abort_Allowed
1101
                 and then not ZCX_Exceptions
Arnaud Charlet committed
1102
               then
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
                  --  There are some special cases in which we do not do the
                  --  undefer. In particular a finalization (AT END) handler
                  --  wants to operate with aborts still deferred.

                  --  We also suppress the call if this is the special handler
                  --  for Abort_Signal, since if we are aborting, we want to
                  --  keep aborts deferred (one abort is enough).

                  --  If abort really needs to be deferred the expander must
                  --  add this call explicitly, see
                  --  Expand_N_Asynchronous_Select.

                  Others_Choice :=
                    Nkind (First (Exception_Choices (Handler))) =
                                                         N_Others_Choice;

                  if (Others_Choice
                       or else Entity (First (Exception_Choices (Handler))) /=
                                                         Stand.Abort_Signal)
                    and then not
                      (Others_Choice
                        and then
                          All_Others (First (Exception_Choices (Handler))))
                  then
                     Prepend_Call_To_Handler (RE_Abort_Undefer);
                  end if;
1129
               end if;
Richard Kenner committed
1130 1131 1132
            end if;
         end if;

1133
         Handler := Next_Handler;
1134 1135
      end loop Handler_Loop;

1136 1137 1138
      --  If all handlers got removed, then remove the list. Note we cannot
      --  reference HSS here, since expanding local handlers may have buried
      --  the handlers in an inner block.
1139

1140 1141
      if Is_Empty_List (Handlrs) then
         Set_Exception_Handlers (Parent (Handlrs), No_List);
1142
      end if;
Richard Kenner committed
1143 1144 1145 1146 1147 1148 1149 1150
   end Expand_Exception_Handlers;

   ------------------------------------
   -- Expand_N_Exception_Declaration --
   ------------------------------------

   --  Generates:
   --     exceptE : constant String := "A.B.EXCEP";   -- static data
Arnaud Charlet committed
1151 1152 1153 1154 1155 1156 1157 1158
   --     except : exception_data :=
   --                (Handled_By_Other => False,
   --                 Lang             => 'A',
   --                 Name_Length      => exceptE'Length,
   --                 Full_Name        => exceptE'Address,
   --                 HTable_Ptr       => null,
   --                 Foreign_Data     => null,
   --                 Raise_Hook       => null);
Richard Kenner committed
1159 1160

   --  (protecting test only needed if not at library level)
Arnaud Charlet committed
1161

Richard Kenner committed
1162 1163 1164 1165 1166 1167 1168
   --     exceptF : Boolean := True --  static data
   --     if exceptF then
   --        exceptF := False;
   --        Register_Exception (except'Unchecked_Access);
   --     end if;

   procedure Expand_N_Exception_Declaration (N : Node_Id) is
Arnaud Charlet committed
1169 1170
      Id  : constant Entity_Id  := Defining_Identifier (N);
      Loc : constant Source_Ptr := Sloc (N);
Richard Kenner committed
1171

Arnaud Charlet committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
      procedure Force_Static_Allocation_Of_Referenced_Objects
        (Aggregate : Node_Id);
      --  A specialized solution to one particular case of an ugly problem
      --
      --  The given aggregate includes an Unchecked_Conversion as one of the
      --  component values. The call to Analyze_And_Resolve below ends up
      --  calling Exp_Ch4.Expand_N_Unchecked_Type_Conversion, which may decide
      --  to introduce a (constant) temporary and then obtain the component
      --  value by evaluating the temporary.
      --
      --  In the case of an exception declared within a subprogram (or any
      --  other dynamic scope), this is a bad transformation. The exception
      --  object is marked as being Statically_Allocated but the temporary is
      --  not. If the initial value of a Statically_Allocated declaration
      --  references a dynamically allocated object, this prevents static
      --  initialization of the object.
      --
      --  We cope with this here by marking the temporary Statically_Allocated.
      --  It might seem cleaner to generalize this utility and then use it to
      --  enforce a rule that the entities referenced in the declaration of any
      --  "hoisted" (i.e., Is_Statically_Allocated and not Is_Library_Level)
      --  entity must also be either Library_Level or hoisted. It turns out
      --  that this would be incompatible with the current treatment of an
      --  object which is local to a subprogram, subject to an Export pragma,
      --  not subject to an address clause, and whose declaration contains
      --  references to other local (non-hoisted) objects (e.g., in the initial
      --  value expression).

Arnaud Charlet committed
1200 1201 1202
      function Null_String return String_Id;
      --  Build a null-terminated empty string

Arnaud Charlet committed
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
      ---------------------------------------------------
      -- Force_Static_Allocation_Of_Referenced_Objects --
      ---------------------------------------------------

      procedure Force_Static_Allocation_Of_Referenced_Objects
        (Aggregate : Node_Id)
      is
         function Fixup_Node (N : Node_Id) return Traverse_Result;
         --  If the given node references a dynamically allocated object, then
         --  correct the declaration of the object.

         ----------------
         -- Fixup_Node --
         ----------------

         function Fixup_Node (N : Node_Id) return Traverse_Result is
         begin
            if Nkind (N) in N_Has_Entity
              and then Present (Entity (N))
              and then not Is_Library_Level_Entity (Entity (N))

              --  Note: the following test is not needed but it seems cleaner
              --  to do this test (this would be more important if procedure
              --  Force_Static_Allocation_Of_Referenced_Objects recursively
              --  traversed the declaration of an entity after marking it as
              --  statically allocated).

              and then not Is_Statically_Allocated (Entity (N))
            then
               Set_Is_Statically_Allocated (Entity (N));
            end if;

            return OK;
         end Fixup_Node;

         procedure Fixup_Tree is new Traverse_Proc (Fixup_Node);

      --  Start of processing for Force_Static_Allocation_Of_Referenced_Objects

      begin
         Fixup_Tree (Aggregate);
      end Force_Static_Allocation_Of_Referenced_Objects;

Arnaud Charlet committed
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
      -----------------
      -- Null_String --
      -----------------

      function Null_String return String_Id is
      begin
         Start_String;
         Store_String_Char (Get_Char_Code (ASCII.NUL));
         return End_String;
      end Null_String;

      --  Local variables

      Ex_Id   : Entity_Id;
      Ex_Val  : String_Id;
      Flag_Id : Entity_Id;
      L       : List_Id;

Arnaud Charlet committed
1264 1265
   --  Start of processing for Expand_N_Exception_Declaration

Richard Kenner committed
1266
   begin
Arnaud Charlet committed
1267 1268
      --  Nothing to do when generating C code

Arnaud Charlet committed
1269
      if Modify_Tree_For_C then
Arnaud Charlet committed
1270 1271 1272
         return;
      end if;

Richard Kenner committed
1273 1274
      --  Definition of the external name: nam : constant String := "A.B.NAME";

1275 1276 1277
      Ex_Id :=
        Make_Defining_Identifier (Loc, New_External_Name (Chars (Id), 'E'));

Arnaud Charlet committed
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
      --  Do not generate an external name if the exception declaration is
      --  subject to pragma Discard_Names. Use a null-terminated empty name
      --  to ensure that Ada.Exceptions.Exception_Name functions properly.

      if Global_Discard_Names or else Discard_Names (Ex_Id) then
         Ex_Val := Null_String;

      --  Otherwise generate the fully qualified name of the exception

      else
         Ex_Val := Fully_Qualified_Name_String (Id);
      end if;

Richard Kenner committed
1291 1292
      Insert_Action (N,
        Make_Object_Declaration (Loc,
1293
          Defining_Identifier => Ex_Id,
Richard Kenner committed
1294 1295
          Constant_Present    => True,
          Object_Definition   => New_Occurrence_Of (Standard_String, Loc),
Arnaud Charlet committed
1296
          Expression          => Make_String_Literal (Loc, Ex_Val)));
Richard Kenner committed
1297

1298
      Set_Is_Statically_Allocated (Ex_Id);
Richard Kenner committed
1299 1300 1301 1302

      --  Create the aggregate list for type Standard.Exception_Type:
      --  Handled_By_Other component: False

Arnaud Charlet committed
1303
      L := Empty_List;
Richard Kenner committed
1304 1305 1306 1307 1308
      Append_To (L, New_Occurrence_Of (Standard_False, Loc));

      --  Lang component: 'A'

      Append_To (L,
Robert Dewar committed
1309
        Make_Character_Literal (Loc,
1310 1311
          Chars              => Name_uA,
          Char_Literal_Value => UI_From_Int (Character'Pos ('A'))));
Richard Kenner committed
1312 1313 1314 1315 1316

      --  Name_Length component: Nam'Length

      Append_To (L,
        Make_Attribute_Reference (Loc,
1317
          Prefix         => New_Occurrence_Of (Ex_Id, Loc),
Richard Kenner committed
1318 1319 1320 1321
          Attribute_Name => Name_Length));

      --  Full_Name component: Standard.A_Char!(Nam'Address)

Arnaud Charlet committed
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
      --  The unchecked conversion causes capacity issues for CodePeer in some
      --  cases and is never useful, so we set the Full_Name component to null
      --  instead for CodePeer.

      if CodePeer_Mode then
         Append_To (L, Make_Null (Loc));
      else
         Append_To (L, Unchecked_Convert_To (Standard_A_Char,
           Make_Attribute_Reference (Loc,
             Prefix         => New_Occurrence_Of (Ex_Id, Loc),
             Attribute_Name => Name_Address)));
      end if;
Richard Kenner committed
1334 1335 1336 1337 1338

      --  HTable_Ptr component: null

      Append_To (L, Make_Null (Loc));

1339
      --  Foreign_Data component: null
Richard Kenner committed
1340

1341
      Append_To (L, Make_Null (Loc));
Richard Kenner committed
1342

1343 1344 1345 1346
      --  Raise_Hook component: null

      Append_To (L, Make_Null (Loc));

Richard Kenner committed
1347 1348 1349
      Set_Expression (N, Make_Aggregate (Loc, Expressions => L));
      Analyze_And_Resolve (Expression (N), Etype (Id));

Arnaud Charlet committed
1350 1351
      Force_Static_Allocation_Of_Referenced_Objects (Expression (N));

Richard Kenner committed
1352 1353
      --  Register_Exception (except'Unchecked_Access);

1354
      if not No_Exception_Handlers_Set
Arnaud Charlet committed
1355
        and then not Restriction_Active (No_Exception_Registration)
1356
      then
Richard Kenner committed
1357
         L := New_List (
1358 1359 1360 1361 1362 1363 1364 1365
           Make_Procedure_Call_Statement (Loc,
             Name                   =>
               New_Occurrence_Of (RTE (RE_Register_Exception), Loc),
             Parameter_Associations => New_List (
               Unchecked_Convert_To (RTE (RE_Exception_Data_Ptr),
                 Make_Attribute_Reference (Loc,
                   Prefix         => New_Occurrence_Of (Id, Loc),
                   Attribute_Name => Name_Unrestricted_Access)))));
Richard Kenner committed
1366 1367 1368 1369

         Set_Register_Exception_Call (Id, First (L));

         if not Is_Library_Level_Entity (Id) then
1370 1371 1372
            Flag_Id :=
              Make_Defining_Identifier (Loc,
                Chars => New_External_Name (Chars (Id), 'F'));
Richard Kenner committed
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405

            Insert_Action (N,
              Make_Object_Declaration (Loc,
                Defining_Identifier => Flag_Id,
                Object_Definition   =>
                  New_Occurrence_Of (Standard_Boolean, Loc),
                Expression          =>
                  New_Occurrence_Of (Standard_True, Loc)));

            Set_Is_Statically_Allocated (Flag_Id);

            Append_To (L,
              Make_Assignment_Statement (Loc,
                Name       => New_Occurrence_Of (Flag_Id, Loc),
                Expression => New_Occurrence_Of (Standard_False, Loc)));

            Insert_After_And_Analyze (N,
              Make_Implicit_If_Statement (N,
                Condition       => New_Occurrence_Of (Flag_Id, Loc),
                Then_Statements => L));

         else
            Insert_List_After_And_Analyze (N, L);
         end if;
      end if;
   end Expand_N_Exception_Declaration;

   ---------------------------------------------
   -- Expand_N_Handled_Sequence_Of_Statements --
   ---------------------------------------------

   procedure Expand_N_Handled_Sequence_Of_Statements (N : Node_Id) is
   begin
1406 1407
      --  Expand exception handlers

1408
      if Present (Exception_Handlers (N))
Arnaud Charlet committed
1409
        and then not Restriction_Active (No_Exception_Handlers)
1410
      then
Richard Kenner committed
1411 1412 1413
         Expand_Exception_Handlers (N);
      end if;

1414 1415 1416 1417 1418 1419 1420 1421
      --  If local exceptions are being expanded, the previous call will
      --  have rewritten the construct as a block and reanalyzed it. No
      --  further expansion is needed.

      if Analyzed (N) then
         return;
      end if;

1422 1423 1424 1425 1426 1427
      --  Add cleanup actions if required. No cleanup actions are needed in
      --  thunks associated with interfaces, because they only displace the
      --  pointer to the object. For extended return statements, we need
      --  cleanup actions if the Handled_Statement_Sequence contains generated
      --  objects of controlled types, for example. We do not want to clean up
      --  the return object.
Richard Kenner committed
1428

1429 1430 1431
      if not Nkind_In (Parent (N), N_Accept_Statement,
                                   N_Extended_Return_Statement,
                                   N_Package_Body)
Richard Kenner committed
1432
        and then not Delay_Cleanups (Current_Scope)
Arnaud Charlet committed
1433
        and then not Is_Thunk (Current_Scope)
Richard Kenner committed
1434 1435
      then
         Expand_Cleanup_Actions (Parent (N));
1436 1437 1438 1439 1440 1441 1442 1443

      elsif Nkind (Parent (N)) = N_Extended_Return_Statement
        and then Handled_Statement_Sequence (Parent (N)) = N
        and then not Delay_Cleanups (Current_Scope)
      then
         pragma Assert (not Is_Thunk (Current_Scope));
         Expand_Cleanup_Actions (Parent (N));

Richard Kenner committed
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
      else
         Set_First_Real_Statement (N, First (Statements (N)));
      end if;
   end Expand_N_Handled_Sequence_Of_Statements;

   -------------------------------------
   -- Expand_N_Raise_Constraint_Error --
   -------------------------------------

   procedure Expand_N_Raise_Constraint_Error (N : Node_Id) is
   begin
1455 1456 1457
      --  We adjust the condition to deal with the C/Fortran boolean case. This
      --  may well not be necessary, as all such conditions are generated by
      --  the expander and probably are all standard boolean, but who knows
1458
      --  what strange optimization in future may require this adjustment.
1459

Richard Kenner committed
1460
      Adjust_Condition (Condition (N));
1461 1462 1463 1464

      --  Now deal with possible local raise handling

      Possible_Local_Raise (N, Standard_Constraint_Error);
Richard Kenner committed
1465 1466
   end Expand_N_Raise_Constraint_Error;

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
   -------------------------------
   -- Expand_N_Raise_Expression --
   -------------------------------

   procedure Expand_N_Raise_Expression (N : Node_Id) is
      Loc : constant Source_Ptr := Sloc (N);
      Typ : constant Entity_Id  := Etype (N);
      RCE : Node_Id;

   begin
Arnaud Charlet committed
1477
      Possible_Local_Raise (N, Entity (Name (N)));
1478 1479 1480 1481 1482 1483 1484 1485

      --  Later we must teach the back end/gigi how to deal with this, but
      --  for now we will assume the type is Standard_Boolean and transform
      --  the node to:

      --     do
      --       raise X [with string]
      --     in
Arnaud Charlet committed
1486 1487 1488 1489 1490 1491 1492 1493 1494
      --       raise Constraint_Error;

      --  unless the flag Convert_To_Return_False is set, in which case
      --  the transformation is to:

      --     do
      --       return False;
      --     in
      --       raise Constraint_Error;
1495 1496 1497 1498 1499 1500 1501

      --  The raise constraint error can never be executed. It is just a dummy
      --  node that can be labeled with an arbitrary type.

      RCE := Make_Raise_Constraint_Error (Loc, Reason => CE_Explicit_Raise);
      Set_Etype (RCE, Typ);

Arnaud Charlet committed
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
      if Convert_To_Return_False (N) then
         Rewrite (N,
           Make_Expression_With_Actions (Loc,
             Actions     => New_List (
               Make_Simple_Return_Statement (Loc,
                 Expression => New_Occurrence_Of (Standard_False, Loc))),
              Expression => RCE));

      else
         Rewrite (N,
           Make_Expression_With_Actions (Loc,
             Actions     => New_List (
               Make_Raise_Statement (Loc,
                 Name       => Name (N),
                 Expression => Expression (N))),
              Expression => RCE));
      end if;
1519 1520 1521 1522

      Analyze_And_Resolve (N, Typ);
   end Expand_N_Raise_Expression;

Richard Kenner committed
1523 1524 1525 1526 1527 1528
   ----------------------------------
   -- Expand_N_Raise_Program_Error --
   ----------------------------------

   procedure Expand_N_Raise_Program_Error (N : Node_Id) is
   begin
1529 1530 1531
      --  We adjust the condition to deal with the C/Fortran boolean case. This
      --  may well not be necessary, as all such conditions are generated by
      --  the expander and probably are all standard boolean, but who knows
1532
      --  what strange optimization in future may require this adjustment.
1533

Richard Kenner committed
1534
      Adjust_Condition (Condition (N));
1535 1536 1537 1538

      --  Now deal with possible local raise handling

      Possible_Local_Raise (N, Standard_Program_Error);
Richard Kenner committed
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
   end Expand_N_Raise_Program_Error;

   ------------------------------
   -- Expand_N_Raise_Statement --
   ------------------------------

   procedure Expand_N_Raise_Statement (N : Node_Id) is
      Loc   : constant Source_Ptr := Sloc (N);
      Ehand : Node_Id;
      E     : Entity_Id;
      Str   : String_Id;
1550
      H     : Node_Id;
Arnaud Charlet committed
1551
      Src   : Boolean;
Richard Kenner committed
1552 1553

   begin
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
      --  Processing for locally handled exception (exclude reraise case)

      if Present (Name (N)) and then Nkind (Name (N)) = N_Identifier then
         if Debug_Flag_Dot_G
           or else Restriction_Active (No_Exception_Propagation)
         then
            --  If we have a local handler, then note that this is potentially
            --  able to be transformed into a goto statement.

            H := Find_Local_Handler (Entity (Name (N)), N);

            if Present (H) then
               if Local_Raise_Statements (H) = No_Elist then
                  Set_Local_Raise_Statements (H, New_Elmt_List);
               end if;

               --  Append the new entry if it is not there already. Sometimes
               --  we have situations where due to reexpansion, the same node
               --  is analyzed twice and would otherwise be added twice.

               Append_Unique_Elmt (N, Local_Raise_Statements (H));
1575 1576 1577 1578 1579 1580
               Set_Has_Local_Raise (H);

            --  If no local handler, then generate no propagation warning

            else
               Warn_If_No_Propagation (N);
1581 1582 1583 1584 1585
            end if;

         end if;
      end if;

1586 1587 1588
      --  If a string expression is present, then the raise statement is
      --  converted to a call:
      --     Raise_Exception (exception-name'Identity, string);
1589
      --  and there is nothing else to do.
1590 1591

      if Present (Expression (N)) then
Arnaud Charlet committed
1592

1593 1594 1595 1596 1597 1598 1599
         --  Adjust message to deal with Prefix_Exception_Messages. We only
         --  add the prefix to string literals, if the message is being
         --  constructed, we assume it already deals with uniqueness.

         if Prefix_Exception_Messages
           and then Nkind (Expression (N)) = N_String_Literal
         then
1600 1601 1602 1603 1604 1605 1606 1607 1608
            declare
               Buf : Bounded_String;
            begin
               Add_Source_Info (Buf, Loc, Name_Enclosing_Entity);
               Append (Buf, ": ");
               Append (Buf, Strval (Expression (N)));
               Rewrite (Expression (N), Make_String_Literal (Loc, +Buf));
               Analyze_And_Resolve (Expression (N), Standard_String);
            end;
1609 1610
         end if;

Arnaud Charlet committed
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636
         --  Avoid passing exception-name'identity in runtimes in which this
         --  argument is not used. This avoids generating undefined references
         --  to these exceptions when compiling with no optimization

         if Configurable_Run_Time_On_Target
           and then (Restriction_Active (No_Exception_Handlers)
                       or else
                     Restriction_Active (No_Exception_Propagation))
         then
            Rewrite (N,
              Make_Procedure_Call_Statement (Loc,
                Name => New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
                Parameter_Associations => New_List (
                  New_Occurrence_Of (RTE (RE_Null_Id), Loc),
                  Expression (N))));
         else
            Rewrite (N,
              Make_Procedure_Call_Statement (Loc,
                Name => New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
                Parameter_Associations => New_List (
                  Make_Attribute_Reference (Loc,
                    Prefix         => Name (N),
                    Attribute_Name => Name_Identity),
                  Expression (N))));
         end if;

1637 1638 1639 1640
         Analyze (N);
         return;
      end if;

Arnaud Charlet committed
1641 1642
      --  Remaining processing is for the case where no string expression is
      --  present.
1643

Arnaud Charlet committed
1644 1645 1646
      --  Don't expand a raise statement that does not come from source if we
      --  have already had configurable run-time violations, since most likely
      --  it will be junk cascaded nonsense.
1647 1648 1649 1650 1651 1652 1653

      if Configurable_Run_Time_Violations > 0
        and then not Comes_From_Source (N)
      then
         return;
      end if;

Richard Kenner committed
1654
      --  Convert explicit raise of Program_Error, Constraint_Error, and
1655 1656
      --  Storage_Error into the corresponding raise (in High_Integrity_Mode
      --  all other raises will get normal expansion and be disallowed,
Arnaud Charlet committed
1657 1658
      --  but this is also faster in all modes). Propagate Comes_From_Source
      --  flag to the new node.
Richard Kenner committed
1659 1660

      if Present (Name (N)) and then Nkind (Name (N)) = N_Identifier then
Arnaud Charlet committed
1661
         Src := Comes_From_Source (N);
Arnaud Charlet committed
1662

1663 1664
         if Entity (Name (N)) = Standard_Constraint_Error then
            Rewrite (N,
Arnaud Charlet committed
1665 1666
              Make_Raise_Constraint_Error (Loc, Reason => CE_Explicit_Raise));
            Set_Comes_From_Source (N, Src);
Richard Kenner committed
1667 1668 1669
            Analyze (N);
            return;

1670 1671
         elsif Entity (Name (N)) = Standard_Program_Error then
            Rewrite (N,
Arnaud Charlet committed
1672 1673
              Make_Raise_Program_Error (Loc, Reason => PE_Explicit_Raise));
            Set_Comes_From_Source (N, Src);
Richard Kenner committed
1674 1675 1676 1677
            Analyze (N);
            return;

         elsif Entity (Name (N)) = Standard_Storage_Error then
1678
            Rewrite (N,
Arnaud Charlet committed
1679 1680
              Make_Raise_Storage_Error (Loc, Reason => SE_Explicit_Raise));
            Set_Comes_From_Source (N, Src);
Richard Kenner committed
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694
            Analyze (N);
            return;
         end if;
      end if;

      --  Case of name present, in this case we expand raise name to

      --    Raise_Exception (name'Identity, location_string);

      --  where location_string identifies the file/line of the raise

      if Present (Name (N)) then
         declare
            Id : Entity_Id := Entity (Name (N));
1695
            Buf : Bounded_String;
Richard Kenner committed
1696 1697

         begin
1698
            Build_Location_String (Buf, Loc);
Richard Kenner committed
1699

1700 1701 1702 1703 1704 1705 1706
            --  If the exception is a renaming, use the exception that it
            --  renames (which might be a predefined exception, e.g.).

            if Present (Renamed_Object (Id)) then
               Id := Renamed_Object (Id);
            end if;

1707
            --  Build a C-compatible string in case of no exception handlers,
Richard Kenner committed
1708 1709
            --  since this is what the last chance handler is expecting.

1710
            if No_Exception_Handlers_Set then
Richard Kenner committed
1711

1712 1713 1714 1715
               --  Generate an empty message if configuration pragma
               --  Suppress_Exception_Locations is set for this unit.

               if Opt.Exception_Locations_Suppressed then
1716
                  Buf.Length := 0;
Richard Kenner committed
1717 1718
               end if;

1719
               Append (Buf, ASCII.NUL);
1720 1721 1722
            end if;

            if Opt.Exception_Locations_Suppressed then
1723
               Buf.Length := 0;
Richard Kenner committed
1724 1725
            end if;

1726
            Str := String_From_Name_Buffer (Buf);
Richard Kenner committed
1727

1728
            --  Convert raise to call to the Raise_Exception routine
Richard Kenner committed
1729

1730 1731 1732 1733 1734 1735 1736 1737 1738
            Rewrite (N,
              Make_Procedure_Call_Statement (Loc,
                 Name                   =>
                   New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
                 Parameter_Associations => New_List (
                   Make_Attribute_Reference (Loc,
                     Prefix         => Name (N),
                     Attribute_Name => Name_Identity),
                   Make_String_Literal (Loc, Strval => Str))));
Richard Kenner committed
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748
         end;

      --  Case of no name present (reraise). We rewrite the raise to:

      --    Reraise_Occurrence_Always (EO);

      --  where EO is the current exception occurrence. If the current handler
      --  does not have a choice parameter specification, then we provide one.

      else
Arnaud Charlet committed
1749
         --  Bypass expansion to a run-time call when back-end exception
1750 1751 1752 1753
         --  handling is active, unless the target is CodePeer or GNATprove.
         --  In CodePeer, raising an exception is treated as an error, while in
         --  GNATprove all code with exceptions falls outside the subset of
         --  code which can be formally analyzed.
Arnaud Charlet committed
1754

1755
         if not CodePeer_Mode
1756
           and then Back_End_Exceptions
Arnaud Charlet committed
1757 1758 1759 1760
         then
            return;
         end if;

Richard Kenner committed
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
         --  Find innermost enclosing exception handler (there must be one,
         --  since the semantics has already verified that this raise statement
         --  is valid, and a raise with no arguments is only permitted in the
         --  context of an exception handler.

         Ehand := Parent (N);
         while Nkind (Ehand) /= N_Exception_Handler loop
            Ehand := Parent (Ehand);
         end loop;

         --  Make exception choice parameter if none present. Note that we do
         --  not need to put the entity on the entity chain, since no one will
         --  be referencing this entity by normal visibility methods.

         if No (Choice_Parameter (Ehand)) then
1776
            E := Make_Temporary (Loc, 'E');
Richard Kenner committed
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
            Set_Choice_Parameter (Ehand, E);
            Set_Ekind (E, E_Variable);
            Set_Etype (E, RTE (RE_Exception_Occurrence));
            Set_Scope (E, Current_Scope);
         end if;

         --  Now rewrite the raise as a call to Reraise. A special case arises
         --  if this raise statement occurs in the context of a handler for
         --  all others (i.e. an at end handler). in this case we avoid
         --  the call to defer abort, cleanup routines are expected to be
         --  called in this case with aborts deferred.

         declare
            Ech : constant Node_Id := First (Exception_Choices (Ehand));
            Ent : Entity_Id;

         begin
            if Nkind (Ech) = N_Others_Choice
              and then All_Others (Ech)
            then
               Ent := RTE (RE_Reraise_Occurrence_No_Defer);
            else
               Ent := RTE (RE_Reraise_Occurrence_Always);
            end if;

            Rewrite (N,
              Make_Procedure_Call_Statement (Loc,
                Name => New_Occurrence_Of (Ent, Loc),
                Parameter_Associations => New_List (
                  New_Occurrence_Of (Choice_Parameter (Ehand), Loc))));
         end;
      end if;

      Analyze (N);
   end Expand_N_Raise_Statement;

   ----------------------------------
   -- Expand_N_Raise_Storage_Error --
   ----------------------------------

   procedure Expand_N_Raise_Storage_Error (N : Node_Id) is
   begin
1819 1820 1821
      --  We adjust the condition to deal with the C/Fortran boolean case. This
      --  may well not be necessary, as all such conditions are generated by
      --  the expander and probably are all standard boolean, but who knows
1822
      --  what strange optimization in future may require this adjustment.
1823

Richard Kenner committed
1824
      Adjust_Condition (Condition (N));
1825 1826 1827 1828

      --  Now deal with possible local raise handling

      Possible_Local_Raise (N, Standard_Storage_Error);
Richard Kenner committed
1829 1830
   end Expand_N_Raise_Storage_Error;

1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
   --------------------------
   -- Possible_Local_Raise --
   --------------------------

   procedure Possible_Local_Raise (N : Node_Id; E : Entity_Id) is
   begin
      --  Nothing to do if local raise optimization not active

      if not Debug_Flag_Dot_G
        and then not Restriction_Active (No_Exception_Propagation)
      then
         return;
      end if;

      --  Nothing to do if original node was an explicit raise, because in
      --  that case, we already generated the required warning for the raise.

      if Nkind (Original_Node (N)) = N_Raise_Statement then
         return;
      end if;

      --  Otherwise see if we have a local handler for the exception

      declare
         H : constant Node_Id := Find_Local_Handler (E, N);

      begin
         --  If so, mark that it has a local raise

         if Present (H) then
            Set_Has_Local_Raise (H, True);

         --  Otherwise, if the No_Exception_Propagation restriction is active
         --  and the warning is enabled, generate the appropriate warnings.

1866
         --  ??? Do not do it for the Call_Marker nodes inserted by the ABE
1867 1868
         --  mechanism because this generates too many false positives, or
         --  for generic instantiations for the same reason.
1869

1870 1871
         elsif Warn_On_Non_Local_Exception
           and then Restriction_Active (No_Exception_Propagation)
1872
           and then Nkind (N) /= N_Call_Marker
1873
           and then Nkind (N) not in N_Generic_Instantiation
1874 1875 1876 1877 1878
         then
            Warn_No_Exception_Propagation_Active (N);

            if Configurable_Run_Time_Mode then
               Error_Msg_NE
Arnaud Charlet committed
1879
                 ("\?X?& may call Last_Chance_Handler", N, E);
1880 1881
            else
               Error_Msg_NE
Arnaud Charlet committed
1882
                 ("\?X?& may result in unhandled exception", N, E);
1883 1884 1885 1886 1887
            end if;
         end if;
      end;
   end Possible_Local_Raise;

1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
   ------------------------
   -- Find_Local_Handler --
   ------------------------

   function Find_Local_Handler
     (Ename : Entity_Id;
      Nod   : Node_Id) return Node_Id
   is
      N : Node_Id;
      P : Node_Id;
      H : Node_Id;
      C : Node_Id;

1901 1902 1903
      SSE : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
      --  This is used to test for wrapped actions below

1904 1905 1906 1907 1908 1909
      ERaise  : Entity_Id;
      EHandle : Entity_Id;
      --  The entity Id's for the exception we are raising and handling, using
      --  the renamed exception if a Renamed_Entity is present.

   begin
1910 1911 1912 1913 1914 1915
      --  Never any local handler if all handlers removed

      if Debug_Flag_Dot_X then
         return Empty;
      end if;

1916 1917
      --  Get the exception we are raising, allowing for renaming

1918 1919 1920 1921
      ERaise := Get_Renamed_Entity (Ename);

      --  We need to check if the node we are looking at is contained in
      --
1922 1923 1924 1925 1926 1927 1928 1929

      --  Loop to search up the tree

      N := Nod;
      loop
         P := Parent (N);

         --  If we get to the top of the tree, or to a subprogram, task, entry,
1930 1931
         --  protected body, or accept statement without having found a
         --  matching handler, then there is no local handler.
1932 1933 1934 1935 1936 1937

         if No (P)
           or else Nkind (P) = N_Subprogram_Body
           or else Nkind (P) = N_Task_Body
           or else Nkind (P) = N_Protected_Body
           or else Nkind (P) = N_Entry_Body
1938
           or else Nkind (P) = N_Accept_Statement
1939 1940 1941
         then
            return Empty;

1942 1943
            --  Test for handled sequence of statements with at least one
            --  exception handler which might be the one we are looking for.
1944 1945

         elsif Nkind (P) = N_Handled_Sequence_Of_Statements
1946
           and then Present (Exception_Handlers (P))
1947
         then
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
            --  Before we proceed we need to check if the node N is covered
            --  by the statement part of P rather than one of its exception
            --  handlers (an exception handler obviously does not cover its
            --  own statements).

            --  This test is more delicate than might be thought. It is not
            --  just a matter of checking the Statements (P), because the node
            --  might be waiting to be wrapped in a transient scope, in which
            --  case it will end up in the block statements, even though it
            --  is not there now.

Arnaud Charlet committed
1959 1960 1961
            if Is_List_Member (N) then
               declare
                  LCN : constant List_Id := List_Containing (N);
1962

Arnaud Charlet committed
1963 1964 1965
               begin
                  if LCN = Statements (P)
                       or else
Arnaud Charlet committed
1966
                     LCN = SSE.Actions_To_Be_Wrapped (Before)
Arnaud Charlet committed
1967
                       or else
Arnaud Charlet committed
1968 1969 1970
                     LCN = SSE.Actions_To_Be_Wrapped (After)
                       or else
                     LCN = SSE.Actions_To_Be_Wrapped (Cleanup)
Arnaud Charlet committed
1971 1972
                  then
                     --  Loop through exception handlers
1973

Arnaud Charlet committed
1974 1975
                     H := First (Exception_Handlers (P));
                     while Present (H) loop
1976

Arnaud Charlet committed
1977 1978
                        --  Guard against other constructs appearing in the
                        --  list of exception handlers.
1979

Arnaud Charlet committed
1980
                        if Nkind (H) = N_Exception_Handler then
1981

Arnaud Charlet committed
1982
                           --  Loop through choices in one handler
1983

Arnaud Charlet committed
1984 1985
                           C := First (Exception_Choices (H));
                           while Present (C) loop
1986

Arnaud Charlet committed
1987
                              --  Deal with others case
1988

Arnaud Charlet committed
1989
                              if Nkind (C) = N_Others_Choice then
1990

Arnaud Charlet committed
1991 1992 1993 1994 1995
                                 --  Matching others handler, but we need
                                 --  to ensure there is no choice parameter.
                                 --  If there is, then we don't have a local
                                 --  handler after all (since we do not allow
                                 --  choice parameters for local handlers).
Arnaud Charlet committed
1996

Arnaud Charlet committed
1997 1998 1999 2000 2001
                                 if No (Choice_Parameter (H)) then
                                    return H;
                                 else
                                    return Empty;
                                 end if;
Arnaud Charlet committed
2002

Arnaud Charlet committed
2003
                                 --  If not others must be entity name
Arnaud Charlet committed
2004

Arnaud Charlet committed
2005 2006 2007
                              elsif Nkind (C) /= N_Others_Choice then
                                 pragma Assert (Is_Entity_Name (C));
                                 pragma Assert (Present (Entity (C)));
Arnaud Charlet committed
2008

Arnaud Charlet committed
2009 2010
                                 --  Get exception being handled, dealing with
                                 --  renaming.
Arnaud Charlet committed
2011

Arnaud Charlet committed
2012
                                 EHandle := Get_Renamed_Entity (Entity (C));
Arnaud Charlet committed
2013

Arnaud Charlet committed
2014 2015 2016 2017 2018 2019 2020 2021 2022
                                 --  If match, then check choice parameter

                                 if ERaise = EHandle then
                                    if No (Choice_Parameter (H)) then
                                       return H;
                                    else
                                       return Empty;
                                    end if;
                                 end if;
Arnaud Charlet committed
2023
                              end if;
Arnaud Charlet committed
2024 2025 2026

                              Next (C);
                           end loop;
2027 2028
                        end if;

Arnaud Charlet committed
2029
                        Next (H);
Arnaud Charlet committed
2030 2031
                     end loop;
                  end if;
Arnaud Charlet committed
2032
               end;
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
            end if;
         end if;

         N := P;
      end loop;
   end Find_Local_Handler;

   ---------------------------------
   -- Get_Local_Raise_Call_Entity --
   ---------------------------------

Arnaud Charlet committed
2044
   --  Note: this is primarily provided for use by the back end in generating
2045 2046 2047 2048 2049 2050 2051 2052
   --  calls to Local_Raise. But it would be too late in the back end to call
   --  RTE if this actually caused a load/analyze of the unit. So what we do
   --  is to ensure there is a dummy call to this function during front end
   --  processing so that the unit gets loaded then, and not later.

   Local_Raise_Call_Entity     : Entity_Id;
   Local_Raise_Call_Entity_Set : Boolean := False;

2053 2054
   function Get_Local_Raise_Call_Entity return Entity_Id is
   begin
2055 2056 2057 2058 2059 2060 2061 2062
      if not Local_Raise_Call_Entity_Set then
         Local_Raise_Call_Entity_Set := True;

         if RTE_Available (RE_Local_Raise) then
            Local_Raise_Call_Entity := RTE (RE_Local_Raise);
         else
            Local_Raise_Call_Entity := Empty;
         end if;
2063
      end if;
2064 2065

      return Local_Raise_Call_Entity;
2066 2067 2068 2069 2070 2071 2072 2073
   end Get_Local_Raise_Call_Entity;

   -----------------------------
   -- Get_RT_Exception_Entity --
   -----------------------------

   function Get_RT_Exception_Entity (R : RT_Exception_Code) return Entity_Id is
   begin
Arnaud Charlet committed
2074
      case Rkind (R) is
Arnaud Charlet committed
2075 2076 2077
         when CE_Reason => return Standard_Constraint_Error;
         when PE_Reason => return Standard_Program_Error;
         when SE_Reason => return Standard_Storage_Error;
2078 2079 2080
      end case;
   end Get_RT_Exception_Entity;

2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
   ---------------------------
   -- Get_RT_Exception_Name --
   ---------------------------

   procedure Get_RT_Exception_Name (Code : RT_Exception_Code) is
   begin
      case Code is
         when CE_Access_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Access_Check");
         when CE_Access_Parameter_Is_Null =>
            Add_Str_To_Name_Buffer ("CE_Null_Access_Parameter");
         when CE_Discriminant_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Discriminant_Check");
         when CE_Divide_By_Zero =>
            Add_Str_To_Name_Buffer ("CE_Divide_By_Zero");
         when CE_Explicit_Raise =>
            Add_Str_To_Name_Buffer ("CE_Explicit_Raise");
         when CE_Index_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Index_Check");
         when CE_Invalid_Data =>
            Add_Str_To_Name_Buffer ("CE_Invalid_Data");
         when CE_Length_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Length_Check");
         when CE_Null_Exception_Id =>
            Add_Str_To_Name_Buffer ("CE_Null_Exception_Id");
         when CE_Null_Not_Allowed =>
            Add_Str_To_Name_Buffer ("CE_Null_Not_Allowed");
         when CE_Overflow_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Overflow_Check");
         when CE_Partition_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Partition_Check");
         when CE_Range_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Range_Check");
         when CE_Tag_Check_Failed =>
            Add_Str_To_Name_Buffer ("CE_Tag_Check");

         when PE_Access_Before_Elaboration =>
            Add_Str_To_Name_Buffer ("PE_Access_Before_Elaboration");
         when PE_Accessibility_Check_Failed =>
            Add_Str_To_Name_Buffer ("PE_Accessibility_Check");
         when PE_Address_Of_Intrinsic =>
            Add_Str_To_Name_Buffer ("PE_Address_Of_Intrinsic");
Arnaud Charlet committed
2123 2124
         when PE_Aliased_Parameters =>
            Add_Str_To_Name_Buffer ("PE_Aliased_Parameters");
2125 2126 2127 2128
         when PE_All_Guards_Closed =>
            Add_Str_To_Name_Buffer ("PE_All_Guards_Closed");
         when PE_Bad_Predicated_Generic_Type =>
            Add_Str_To_Name_Buffer ("PE_Bad_Predicated_Generic_Type");
2129 2130
         when PE_Build_In_Place_Mismatch =>
            Add_Str_To_Name_Buffer ("PE_Build_In_Place_Mismatch");
2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
         when PE_Current_Task_In_Entry_Body =>
            Add_Str_To_Name_Buffer ("PE_Current_Task_In_Entry_Body");
         when PE_Duplicated_Entry_Address =>
            Add_Str_To_Name_Buffer ("PE_Duplicated_Entry_Address");
         when PE_Explicit_Raise =>
            Add_Str_To_Name_Buffer ("PE_Explicit_Raise");
         when PE_Finalize_Raised_Exception =>
            Add_Str_To_Name_Buffer ("PE_Finalize_Raised_Exception");
         when PE_Implicit_Return =>
            Add_Str_To_Name_Buffer ("PE_Implicit_Return");
         when PE_Misaligned_Address_Value =>
            Add_Str_To_Name_Buffer ("PE_Misaligned_Address_Value");
         when PE_Missing_Return =>
            Add_Str_To_Name_Buffer ("PE_Missing_Return");
Arnaud Charlet committed
2145 2146
         when PE_Non_Transportable_Actual =>
            Add_Str_To_Name_Buffer ("PE_Non_Transportable_Actual");
2147 2148 2149 2150
         when PE_Overlaid_Controlled_Object =>
            Add_Str_To_Name_Buffer ("PE_Overlaid_Controlled_Object");
         when PE_Potentially_Blocking_Operation =>
            Add_Str_To_Name_Buffer ("PE_Potentially_Blocking_Operation");
Arnaud Charlet committed
2151 2152
         when PE_Stream_Operation_Not_Allowed =>
            Add_Str_To_Name_Buffer ("PE_Stream_Operation_Not_Allowed");
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
         when PE_Stubbed_Subprogram_Called =>
            Add_Str_To_Name_Buffer ("PE_Stubbed_Subprogram_Called");
         when PE_Unchecked_Union_Restriction =>
            Add_Str_To_Name_Buffer ("PE_Unchecked_Union_Restriction");

         when SE_Empty_Storage_Pool =>
            Add_Str_To_Name_Buffer ("SE_Empty_Storage_Pool");
         when SE_Explicit_Raise =>
            Add_Str_To_Name_Buffer ("SE_Explicit_Raise");
         when SE_Infinite_Recursion =>
            Add_Str_To_Name_Buffer ("SE_Infinite_Recursion");
         when SE_Object_Too_Large =>
            Add_Str_To_Name_Buffer ("SE_Object_Too_Large");
      end case;
   end Get_RT_Exception_Name;

2169
   ----------------------------
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
   -- Warn_If_No_Local_Raise --
   ----------------------------

   procedure Warn_If_No_Local_Raise (N : Node_Id) is
   begin
      if Restriction_Active (No_Exception_Propagation)
        and then Warn_On_Non_Local_Exception
      then
         Warn_No_Exception_Propagation_Active (N);

         Error_Msg_N
           ("\?X?this handler can never be entered, and has been removed", N);
      end if;
   end Warn_If_No_Local_Raise;

   ----------------------------
2186 2187 2188 2189 2190
   -- Warn_If_No_Propagation --
   ----------------------------

   procedure Warn_If_No_Propagation (N : Node_Id) is
   begin
2191
      if Restriction_Check_Required (No_Exception_Propagation)
2192 2193
        and then Warn_On_Non_Local_Exception
      then
2194
         Warn_No_Exception_Propagation_Active (N);
2195 2196 2197

         if Configurable_Run_Time_Mode then
            Error_Msg_N
Arnaud Charlet committed
2198
              ("\?X?Last_Chance_Handler will be called on exception", N);
2199 2200
         else
            Error_Msg_N
Arnaud Charlet committed
2201
              ("\?X?execution may raise unhandled exception", N);
2202 2203 2204 2205
         end if;
      end if;
   end Warn_If_No_Propagation;

2206 2207 2208 2209 2210 2211 2212
   ------------------------------------------
   -- Warn_No_Exception_Propagation_Active --
   ------------------------------------------

   procedure Warn_No_Exception_Propagation_Active (N : Node_Id) is
   begin
      Error_Msg_N
Arnaud Charlet committed
2213
        ("?X?pragma Restrictions (No_Exception_Propagation) in effect", N);
2214 2215
   end Warn_No_Exception_Propagation_Active;

Richard Kenner committed
2216
end Exp_Ch11;