diff gcc/ada/sem_elab.adb @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
line wrap: on
line diff
--- a/gcc/ada/sem_elab.adb	Fri Oct 27 22:46:09 2017 +0900
+++ b/gcc/ada/sem_elab.adb	Thu Oct 25 07:37:49 2018 +0900
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1997-2017, Free Software Foundation, Inc.         --
+--          Copyright (C) 1997-2018, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -24,28 +24,34 @@
 ------------------------------------------------------------------------------
 
 with Atree;    use Atree;
+with Checks;   use Checks;
 with Debug;    use Debug;
 with Einfo;    use Einfo;
+with Elists;   use Elists;
 with Errout;   use Errout;
 with Exp_Ch11; use Exp_Ch11;
 with Exp_Tss;  use Exp_Tss;
 with Exp_Util; use Exp_Util;
+with Expander; use Expander;
 with Lib;      use Lib;
 with Lib.Load; use Lib.Load;
 with Namet;    use Namet;
 with Nlists;   use Nlists;
 with Nmake;    use Nmake;
 with Opt;      use Opt;
+with Output;   use Output;
 with Restrict; use Restrict;
 with Rident;   use Rident;
 with Rtsfind;  use Rtsfind;
 with Sem;      use Sem;
 with Sem_Aux;  use Sem_Aux;
+with Sem_Cat;  use Sem_Cat;
 with Sem_Ch7;  use Sem_Ch7;
 with Sem_Ch8;  use Sem_Ch8;
 with Sem_Prag; use Sem_Prag;
 with Sem_Util; use Sem_Util;
 with Sinfo;    use Sinfo;
+with Sinput;   use Sinput;
 with Snames;   use Snames;
 with Stand;    use Stand;
 with Table;
@@ -67,7 +73,7 @@
    --    * Diagnose at compile-time or install run-time checks to prevent ABE
    --      access to data and behaviour.
    --
-   --      The high level idea is to accurately diagnose ABE issues within a
+   --      The high-level idea is to accurately diagnose ABE issues within a
    --      single unit because the ABE mechanism can inspect the whole unit.
    --      As soon as the elaboration graph extends to an external unit, the
    --      diagnostics stop because the body of the unit may not be available.
@@ -111,6 +117,9 @@
    -- Terminology --
    -----------------
 
+   --  * ABE - An attempt to activate, call, or instantiate a scenario which
+   --    has not been fully elaborated.
+   --
    --  * Bridge target - A type of target. A bridge target is a link between
    --    scenarios. It is usually a byproduct of expansion and does not have
    --    any direct ABE ramifications.
@@ -127,7 +136,12 @@
    --  * Declaration level - A type of enclosing level. A scenario or target is
    --    at the declaration level when it appears within the declarations of a
    --    block statement, entry body, subprogram body, or task body, ignoring
-   --    enclosing packges.
+   --    enclosing packages.
+   --
+   --  * Early call region - A section of code which ends at a subprogram body
+   --    and starts from the nearest non-preelaborable construct which precedes
+   --    the subprogram body. The early call region extends from a package body
+   --    to a package spec when the spec carries pragma Elaborate_Body.
    --
    --  * Generic library level - A type of enclosing level. A scenario or
    --    target is at the generic library level if it appears in a generic
@@ -145,8 +159,8 @@
    --    the library level if it appears in a package library unit, ignoring
    --    enclosng packages.
    --
-   --  * Non-library level encapsulator - A construct that cannot be elaborated
-   --    on its own and requires elaboration by a top level scenario.
+   --  * Non-library-level encapsulator - A construct that cannot be elaborated
+   --    on its own and requires elaboration by a top-level scenario.
    --
    --  * Scenario - A construct or context which may be elaborated or executed
    --    by elaboration code. The scenarios recognized by the ABE mechanism are
@@ -154,15 +168,19 @@
    --
    --      - '[Unrestricted_]Access of entries, operators, and subprograms
    --
-   --      -  Assignments to variables
-   --
-   --      -  Calls to entries, operators, and subprograms
-   --
-   --      -  Instantiations
-   --
-   --      -  Reads of variables
-   --
-   --      -  Task activation
+   --      - Assignments to variables
+   --
+   --      - Calls to entries, operators, and subprograms
+   --
+   --      - Derived type declarations
+   --
+   --      - Instantiations
+   --
+   --      - Pragma Refined_State
+   --
+   --      - Reads of variables
+   --
+   --      - Task activation
    --
    --  * Target - A construct referenced by a scenario. The targets recognized
    --    by the ABE mechanism are as follows:
@@ -174,13 +192,17 @@
    --
    --      - For calls, the target is the entry, operator, or subprogram
    --
+   --      - For derived type declarations, the target is the derived type
+   --
    --      - For instantiations, the target is the generic template
    --
+   --      - For pragma Refined_State, the targets are the constituents
+   --
    --      - For reads of variables, the target is the variable
    --
    --      - For task activation, the target is the task body
    --
-   --  * Top level scenario - A scenario which appears in a non-generic main
+   --  * Top-level scenario - A scenario which appears in a non-generic main
    --    unit. Depending on the elaboration model is in effect, the following
    --    addotional restrictions apply:
    --
@@ -197,13 +219,20 @@
    --  The Recording phase coincides with the analysis/resolution phase of the
    --  compiler. It has the following objectives:
    --
-   --    * Record all top level scenarios for examination by the Processing
+   --    * Record all top-level scenarios for examination by the Processing
    --      phase.
    --
    --      Saving only a certain number of nodes improves the performance of
    --      the ABE mechanism. This eliminates the need to examine the whole
    --      tree in a separate pass.
    --
+   --    * Record certain SPARK scenarios which are not necessarily executable
+   --      during elaboration, but still require elaboration-related checks.
+   --
+   --      Saving only a certain number of nodes improves the performance of
+   --      the ABE mechanism. This eliminates the need to examine the whole
+   --      tree in a separate pass.
+   --
    --    * Detect and diagnose calls in preelaborable or pure units, including
    --      generic bodies.
    --
@@ -230,23 +259,24 @@
    --  and/or inlining of bodies, but before the removal of Ghost code. It has
    --  the following objectives:
    --
-   --    * Examine all top level scenarios saved during the Recording phase
-   --
-   --      The top level scenarios act as roots for depth-first traversal of
+   --    * Examine all top-level scenarios saved during the Recording phase
+   --
+   --      The top-level scenarios act as roots for depth-first traversal of
    --      the call/instantiation/task activation graph. The traversal stops
    --      when an outgoing edge leaves the main unit.
    --
+   --    * Examine all SPARK scenarios saved during the Recording phase
+   --
    --    * Depending on the elaboration model in effect, perform the following
    --      actions:
    --
-   --        - Dynamic model - Diagnose guaranteed ABEs and install run-time
-   --          conditional ABE checks.
+   --        - Dynamic model - Install run-time conditional ABE checks.
    --
    --        - SPARK model - Enforce the SPARK elaboration rules
    --
-   --        - Static model - Diagnose conditional/guaranteed ABEs, install
-   --          run-time conditional ABE checks, and guarantee the elaboration
-   --          of external units.
+   --        - Static model - Diagnose conditional ABEs, install run-time
+   --          conditional ABE checks, and guarantee the elaboration of
+   --          external units.
    --
    --    * Examine nested scenarios
    --
@@ -258,44 +288,72 @@
    -- Architecture --
    ------------------
 
-   --  +------------------------ Recording phase ---------------------------+
+   --     Analysis/Resolution
+   --     |
+   --     +- Build_Call_Marker
+   --     |
+   --     +- Build_Variable_Reference_Marker
+   --     |
+   --  +- | -------------------- Recording phase ---------------------------+
+   --  |  v                                                                 |
+   --  |  Record_Elaboration_Scenario                                       |
+   --  |  |                                                                 |
+   --  |  +--> Check_Preelaborated_Call                                     |
+   --  |  |                                                                 |
+   --  |  +--> Process_Guaranteed_ABE                                       |
+   --  |  |    |                                                            |
+   --  |  |    +--> Process_Guaranteed_ABE_Activation                       |
+   --  |  |    |                                                            |
+   --  |  |    +--> Process_Guaranteed_ABE_Call                             |
+   --  |  |    |                                                            |
+   --  |  |    +--> Process_Guaranteed_ABE_Instantiation                    |
+   --  |  |                                                                 |
+   --  +- | ----------------------------------------------------------------+
+   --     |
+   --     |
+   --     +--> SPARK_Scenarios
+   --     |    +-----------+-----------+ .. +-----------+
+   --     |    | Scenario1 | Scenario2 | .. | ScenarioN |
+   --     |    +-----------+-----------+ .. +-----------+
+   --     |
+   --     +--> Top_Level_Scenarios
+   --     |    +-----------+-----------+ .. +-----------+
+   --     |    | Scenario1 | Scenario2 | .. | ScenarioN |
+   --     |    +-----------+-----------+ .. +-----------+
+   --     |
+   --     End of Compilation
+   --     |
+   --  +- | --------------------- Processing phase -------------------------+
+   --  |  v                                                                 |
+   --  |  Check_Elaboration_Scenarios                                       |
+   --  |  |                                                                 |
+   --  |  +--> Check_SPARK_Scenario                                         |
+   --  |  |    |                                                            |
+   --  |  |    +--> Check_SPARK_Derived_Type                                |
+   --  |  |    |                                                            |
+   --  |  |    +--> Check_SPARK_Instantiation                               |
+   --  |  |    |                                                            |
+   --  |  |    +--> Check_SPARK_Refined_State_Pragma                        |
+   --  |  |                                                                 |
+   --  |  +--> Process_Conditional_ABE <---------------------------+        |
+   --  |       |                                                   |        |
+   --  |       +--> Process_Conditional_ABE_Access    Is_Suitable_Scenario  |
+   --  |       |                                                   ^        |
+   --  |       +--> Process_Conditional_ABE_Activation             |        |
+   --  |       |    |                                              |        |
+   --  |       |    +-----------------------------+                |        |
+   --  |       |                                  |                |        |
+   --  |       +--> Process_Conditional_ABE_Call  +--------> Traverse_Body  |
+   --  |       |    |                             |                         |
+   --  |       |    +-----------------------------+                         |
+   --  |       |                                                            |
+   --  |       +--> Process_Conditional_ABE_Instantiation                   |
+   --  |       |                                                            |
+   --  |       +--> Process_Conditional_ABE_Variable_Assignment             |
+   --  |       |                                                            |
+   --  |       +--> Process_Conditional_ABE_Variable_Reference              |
    --  |                                                                    |
-   --  |              Record_Elaboration_Scenario                           |
-   --  |                           |                                        |
-   --  |                           +--> Check_Preelaborated_Call            |
-   --  |                           |                                        |
-   --  |                           +--> Process_Guaranteed_ABE              |
-   --  |                           |                                        |
-   --  +-------------------------  |  --------------------------------------+
-   --                              |
-   --                              |
-   --                              v
-   --                    Top_Level_Scenarios
-   --          +-----------+-----------+ .. +-----------+
-   --          | Scenario1 | Scenario2 | .. | ScenarioN |
-   --          +-----------+-----------+ .. +-----------+
-   --                              |
-   --                              |
-   --  +-------------------------  |  --------------------------------------+
-   --  |                           |                                        |
-   --  |              Check_Elaboration_Scenarios                           |
-   --  |                           |                                        |
-   --  |                           v                                        |
-   --  |       +----------- Process_Scenario <-----------+                  |
-   --  |       |                                         |                  |
-   --  |       +--> Process_Access               Is_Suitable_Scenario       |
-   --  |       |                                         ^                  |
-   --  |       +--> Process_Activation_Call --+          |                  |
-   --  |       |                              +---> Traverse_Body           |
-   --  |       +--> Process_Call -------------+                             |
-   --  |       |                                                            |
-   --  |       +--> Process_Instantiation                                   |
-   --  |       |                                                            |
-   --  |       +--> Process_Variable_Assignment                             |
-   --  |       |                                                            |
-   --  |       +--> Process_Variable_Read                                   |
-   --  |                                                                    |
-   --  +------------------------- Processing phase -------------------------+
+   --  +--------------------------------------------------------------------+
 
    ----------------------
    -- Important points --
@@ -314,6 +372,61 @@
    --  The diagnostics of the ABE mechanism depend on accurate source locations
    --  to determine the spacial relation of nodes.
 
+   -----------------------------------------
+   -- Suppression of elaboration warnings --
+   -----------------------------------------
+
+   --  Elaboration warnings along multiple traversal paths rooted at a scenario
+   --  are suppressed when the scenario has elaboration warnings suppressed.
+   --
+   --    Root scenario
+   --    |
+   --    +-- Child scenario 1
+   --    |   |
+   --    |   +-- Grandchild scenario 1
+   --    |   |
+   --    |   +-- Grandchild scenario N
+   --    |
+   --    +-- Child scenario N
+   --
+   --  If the root scenario has elaboration warnings suppressed, then all its
+   --  child, grandchild, etc. scenarios will have their elaboration warnings
+   --  suppressed.
+   --
+   --  In addition to switch -gnatwL, pragma Warnings may be used to suppress
+   --  elaboration-related warnings when used in the following manner:
+   --
+   --    pragma Warnings ("L");
+   --    <scenario-or-target>
+   --
+   --    <target>
+   --    pragma Warnings (Off, target);
+   --
+   --    pragma Warnings (Off);
+   --    <scenario-or-target>
+   --
+   --  * To suppress elaboration warnings for '[Unrestricted_]Access of
+   --    entries, operators, and subprograms, either:
+   --
+   --      - Suppress the entry, operator, or subprogram, or
+   --      - Suppress the attribute, or
+   --      - Use switch -gnatw.f
+   --
+   --  * To suppress elaboration warnings for calls to entries, operators,
+   --    and subprograms, either:
+   --
+   --      - Suppress the entry, operator, or subprogram, or
+   --      - Suppress the call
+   --
+   --  * To suppress elaboration warnings for instantiations, suppress the
+   --    instantiation.
+   --
+   --  * To suppress elaboration warnings for task activations, either:
+   --
+   --      - Suppress the task object, or
+   --      - Suppress the task type, or
+   --      - Suppress the activation call
+
    --------------
    -- Switches --
    --------------
@@ -321,6 +434,20 @@
    --  The following switches may be used to control the behavior of the ABE
    --  mechanism.
    --
+   --  -gnatd_a stop elaboration checks on accept or select statement
+   --
+   --           The ABE mechanism stops the traversal of a task body when it
+   --           encounters an accept or a select statement. This behavior is
+   --           equivalent to restriction No_Entry_Calls_In_Elaboration_Code,
+   --           but without penalizing actual entry calls during elaboration.
+   --
+   --  -gnatd_e ignore entry calls and requeue statements for elaboration
+   --
+   --           The ABE mechanism does not generate N_Call_Marker nodes for
+   --           protected or task entry calls as well as requeue statements.
+   --           As a result, the calls and requeues are not recorded or
+   --           processed.
+   --
    --  -gnatdE  elaboration checks on predefined units
    --
    --           The ABE mechanism considers scenarios which appear in internal
@@ -333,9 +460,11 @@
    --           actual subprograms through generic formal subprograms. As a
    --           result, the calls are not recorded or processed.
    --
-   --           If switches -gnatd.G and -gnatdL are used together, then the
-   --           ABE mechanism effectively ignores all calls which cause the
-   --           elaboration flow to "leave" the instance.
+   --  -gnatd_i ignore activations and calls to instances for elaboration
+   --
+   --           The ABE mechanism ignores calls and task activations when they
+   --           target a subprogram or task type defined an external instance.
+   --           As a result, the calls and task activations are not processed.
    --
    --  -gnatdL  ignore external calls from instances for elaboration
    --
@@ -345,10 +474,6 @@
    --           is external to the instance. As a result, the calls are not
    --           recorded or processed.
    --
-   --           If switches -gnatd.G and -gnatdL are used together, then the
-   --           ABE mechanism effectively ignores all calls which cause the
-   --           elaboration flow to "leave" the instance.
-   --
    --  -gnatd.o conservative elaboration order for indirect calls
    --
    --           The ABE mechanism treats '[Unrestricted_]Access of an entry,
@@ -356,6 +481,33 @@
    --           target. As a result, it performs ABE checks and diagnostics on
    --           the immediate call.
    --
+   --  -gnatd_p ignore assertion pragmas for elaboration
+   --
+   --           The ABE mechanism does not generate N_Call_Marker nodes for
+   --           calls to subprograms which verify the run-time semantics of
+   --           the following assertion pragmas:
+   --
+   --              Default_Initial_Condition
+   --              Initial_Condition
+   --              Invariant
+   --              Invariant'Class
+   --              Post
+   --              Post'Class
+   --              Postcondition
+   --              Type_Invariant
+   --              Type_Invariant_Class
+   --
+   --           As a result, the assertion expressions of the pragmas are not
+   --           processed.
+   --
+   --  -gnatd_s stop elaboration checks on synchronous suspension
+   --
+   --           The ABE mechanism stops the traversal of a task body when it
+   --           encounters a call to one of the following routines:
+   --
+   --             Ada.Synchronous_Barriers.Wait_For_Release
+   --             Ada.Synchronous_Task_Control.Suspend_Until_True
+   --
    --  -gnatd.U ignore indirect calls for static elaboration
    --
    --           The ABE mechanism does not consider '[Unrestricted_]Access of
@@ -391,16 +543,32 @@
    --
    --  -gnateL  turn off info messages on generated Elaborate[_All] pragmas
    --
-   --           The complimentary switch for -gnatel.
-   --
-   --  -gnatwl  turn on warnings for elaboration problems
-   --
-   --           The ABE mechanism produces warnings on detected ABEs along with
-   --           traceback showing the graph of the ABE.
-   --
-   --  -gnatwL  turn off warnings for elaboration problems
-   --
-   --           The complimentary switch for -gnatwl.
+   --           The complementary switch for -gnatel.
+   --
+   --  -gnatH   legacy elaboration checking mode enabled
+   --
+   --           When this switch is in effect, the pre-18.x ABE model becomes
+   --           the defacto ABE model. This ammounts to cutting off all entry
+   --           points into the new ABE mechanism, and giving full control to
+   --           the old ABE mechanism.
+   --
+   --  -gnatJ   permissive elaboration checking mode enabled
+   --
+   --           This switch activates the following switches:
+   --
+   --              -gnatd_a
+   --              -gnatd_e
+   --              -gnatd.G
+   --              -gnatd_i
+   --              -gnatdL
+   --              -gnatd_p
+   --              -gnatd_s
+   --              -gnatd.U
+   --              -gnatd.y
+   --
+   --           IMPORTANT: The behavior of the ABE mechanism becomes more
+   --           permissive at the cost of accurate diagnostics and runtime
+   --           ABE checks.
    --
    --  -gnatw.f turn on warnings for suspicious Subp'Access
    --
@@ -410,45 +578,69 @@
    --
    --  -gnatw.F turn off warnings for suspicious Subp'Access
    --
-   --           The complimentary switch for -gnatw.f.
+   --           The complementary switch for -gnatw.f.
+   --
+   --  -gnatwl  turn on warnings for elaboration problems
+   --
+   --           The ABE mechanism produces warnings on detected ABEs along with
+   --           a traceback showing the graph of the ABE.
+   --
+   --  -gnatwL  turn off warnings for elaboration problems
+   --
+   --           The complementary switch for -gnatwl.
 
    ---------------------------
    -- Adding a new scenario --
    ---------------------------
 
    --  The following steps describe how to add a new elaboration scenario and
-   --  preserve the existing architecture.
-   --
-   --    1) If necessary, update predicates Is_Check_Emitting_Scenario and
-   --       Is_Scenario.
+   --  preserve the existing architecture. Note that not all of the steps may
+   --  need to be carried out.
+   --
+   --    1) Update predicate Is_Scenario
    --
    --    2) Add predicate Is_Suitable_xxx. Include a call to it in predicate
    --       Is_Suitable_Scenario.
    --
    --    3) Update routine Record_Elaboration_Scenario
    --
-   --    4) Add routine Process_xxx. Include a call to it in Process_Scenario.
-   --
-   --    5) Add routine Info_xxx. Include a call to it in Process_xxx.
-   --
-   --    6) Add routine Output_xxx. Include a call to it in routine
+   --    4) Add routine Process_Conditional_ABE_xxx. Include a call to it in
+   --       routine Process_Conditional_ABE.
+   --
+   --    5) Add routine Process_Guaranteed_ABE_xxx. Include a call to it in
+   --       routine Process_Guaranteed_ABE.
+   --
+   --    6) Add routine Check_SPARK_xxx. Include a call to it in routine
+   --       Check_SPARK_Scenario.
+   --
+   --    7) Add routine Info_xxx. Include a call to it in routine
+   --       Process_Conditional_ABE_xxx.
+   --
+   --    8) Add routine Output_xxx. Include a call to it in routine
    --       Output_Active_Scenarios.
    --
-   --    7) If necessary, add a new Extract_xxx_Attributes routine
-   --
-   --    8) If necessary, update routine Is_Potential_Scenario
+   --    9) Add routine Extract_xxx_Attributes
+   --
+   --   10) Update routine Is_Potential_Scenario
 
    -------------------------
    -- Adding a new target --
    -------------------------
 
    --  The following steps describe how to add a new elaboration target and
-   --  preserve the existing architecture.
+   --  preserve the existing architecture. Note that not all of the steps may
+   --  need to be carried out.
    --
    --    1) Add predicate Is_xxx.
    --
-   --    2) Update predicates Is_Ada_Semantic_Target, Is_Bridge_Target, or
-   --       Is_SPARK_Semantic_Target. If necessary, create a new category.
+   --    2) Update the following predicates
+   --
+   --         Is_Ada_Semantic_Target
+   --         Is_Assertion_Pragma_Target
+   --         Is_Bridge_Target
+   --         Is_SPARK_Semantic_Target
+   --
+   --       If necessary, create a new category.
    --
    --    3) Update the appropriate Info_xxx routine.
    --
@@ -473,7 +665,8 @@
    --    body. The routines of interest are
    --
    --      Record_Elaboration_Scenario
-   --      Process_Scenario
+   --      Process_Conditional_ABE
+   --      Process_Guaranteed_ABE
    --      Traverse_Body
 
    --  * If the issue involves a circularity in the elaboration order, examine
@@ -496,12 +689,19 @@
    -- Attributes --
    ----------------
 
+   --  To minimize the amount of code within routines, the ABE mechanism relies
+   --  on "attribute" records to capture relevant information for a scenario or
+   --  a target.
+
    --  The following type captures relevant attributes which pertain to a call
 
    type Call_Attributes is record
       Elab_Checks_OK : Boolean;
       --  This flag is set when the call has elaboration checks enabled
 
+      Elab_Warnings_OK : Boolean;
+      --  This flag is set when the call has elaboration warnings elabled
+
       From_Source : Boolean;
       --  This flag is set when the call comes from source
 
@@ -557,6 +757,10 @@
       --  This flag is set when the instantiation has elaboration checks
       --  enabled.
 
+      Elab_Warnings_OK : Boolean;
+      --  This flag is set when the instantiation has elaboration warnings
+      --  enabled.
+
       Ghost_Mode_Ignore : Boolean;
       --  This flag is set when the instantiation appears in a region subject
       --  to pragma Ghost with policy ignore, or starts one such region.
@@ -570,6 +774,43 @@
       --  to pragma SPARK_Mode with value On, or starts one such region.
    end record;
 
+   --  The following type captures relevant attributes which pertain to the
+   --  state of the Processing phase.
+
+   type Processing_Attributes is record
+      Suppress_Implicit_Pragmas : Boolean;
+      --  This flag is set when the Processing phase must not generate any
+      --  implicit Elaborate[_All] pragmas.
+
+      Suppress_Warnings : Boolean;
+      --  This flag is set when the Processing phase must not emit any warnings
+      --  on elaboration problems.
+
+      Within_Initial_Condition : Boolean;
+      --  This flag is set when the Processing phase is currently examining a
+      --  scenario which was reached from an initial condition procedure.
+
+      Within_Instance : Boolean;
+      --  This flag is set when the Processing phase is currently examining a
+      --  scenario which was reached from a scenario defined in an instance.
+
+      Within_Partial_Finalization : Boolean;
+      --  This flag is set when the Processing phase is currently examining a
+      --  scenario which was reached from a partial finalization procedure.
+
+      Within_Task_Body : Boolean;
+      --  This flag is set when the Processing phase is currently examining a
+      --  scenario which was reached from a task body.
+   end record;
+
+   Initial_State : constant Processing_Attributes :=
+     (Suppress_Implicit_Pragmas   => False,
+      Suppress_Warnings           => False,
+      Within_Initial_Condition    => False,
+      Within_Instance             => False,
+      Within_Partial_Finalization => False,
+      Within_Task_Body            => False);
+
    --  The following type captures relevant attributes which pertain to a
    --  target.
 
@@ -577,6 +818,9 @@
       Elab_Checks_OK : Boolean;
       --  This flag is set when the target has elaboration checks enabled
 
+      Elab_Warnings_OK : Boolean;
+      --  This flag is set when the target has elaboration warnings enabled
+
       From_Source : Boolean;
       --  This flag is set when the target comes from source
 
@@ -659,6 +903,9 @@
       Elab_Checks_OK : Boolean;
       --  This flag is set when the task type has elaboration checks enabled
 
+      Elab_Warnings_OK : Boolean;
+      --  This flag is set when the task type has elaboration warnings enabled
+
       Ghost_Mode_Ignore : Boolean;
       --  This flag is set when the task type appears in a region subject to
       --  pragma Ghost with policy ignore, or starts one such region.
@@ -683,10 +930,6 @@
    --  variable.
 
    type Variable_Attributes is record
-      SPARK_Mode_On : Boolean;
-      --  This flag is set when the variable appears in a region subject to
-      --  pragma SPARK_Mode with value On, or starts one such region.
-
       Unit_Id : Entity_Id;
       --  This attribute denotes the entity of the compilation unit where the
       --  variable resides.
@@ -696,27 +939,117 @@
    -- Data structures --
    ---------------------
 
+   --  The ABE mechanism employs lists and hash tables to store information
+   --  pertaining to scenarios and targets, as well as the Processing phase.
+   --  The need for data structures comes partly from the size limitation of
+   --  nodes. Note that the use of hash tables is conservative and operations
+   --  are carried out only when a particular hash table has at least one key
+   --  value pair (see xxx_In_Use flags).
+
+   --  The following table stores the early call regions of subprogram bodies
+
+   Early_Call_Regions_Max : constant := 101;
+
+   type Early_Call_Regions_Index is range 0 .. Early_Call_Regions_Max - 1;
+
+   function Early_Call_Regions_Hash
+     (Key : Entity_Id) return Early_Call_Regions_Index;
+   --  Obtain the hash value of entity Key
+
+   Early_Call_Regions_In_Use : Boolean := False;
+   --  This flag determines whether table Early_Call_Regions contains at least
+   --  least one key/value pair.
+
+   Early_Call_Regions_No_Element : constant Node_Id := Empty;
+
+   package Early_Call_Regions is new Simple_HTable
+     (Header_Num => Early_Call_Regions_Index,
+      Element    => Node_Id,
+      No_Element => Early_Call_Regions_No_Element,
+      Key        => Entity_Id,
+      Hash       => Early_Call_Regions_Hash,
+      Equal      => "=");
+
    --  The following table stores the elaboration status of all units withed by
    --  the main unit.
 
-   Elaboration_Context_Max : constant := 1009;
-
-   type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1;
-
-   function Elaboration_Context_Hash
-     (Key : Entity_Id) return Elaboration_Context_Index;
+   Elaboration_Statuses_Max : constant := 1009;
+
+   type Elaboration_Statuses_Index is range 0 .. Elaboration_Statuses_Max - 1;
+
+   function Elaboration_Statuses_Hash
+     (Key : Entity_Id) return Elaboration_Statuses_Index;
    --  Obtain the hash value of entity Key
 
-   package Elaboration_Context is new Simple_HTable
-     (Header_Num => Elaboration_Context_Index,
+   Elaboration_Statuses_In_Use : Boolean := False;
+   --  This flag flag determines whether table Elaboration_Statuses contains at
+   --  least one key/value pair.
+
+   Elaboration_Statuses_No_Element : constant Elaboration_Attributes :=
+                                       No_Elaboration_Attributes;
+
+   package Elaboration_Statuses is new Simple_HTable
+     (Header_Num => Elaboration_Statuses_Index,
       Element    => Elaboration_Attributes,
-      No_Element => No_Elaboration_Attributes,
+      No_Element => Elaboration_Statuses_No_Element,
       Key        => Entity_Id,
-      Hash       => Elaboration_Context_Hash,
+      Hash       => Elaboration_Statuses_Hash,
+      Equal      => "=");
+
+   --  The following table stores a status flag for each SPARK scenario saved
+   --  in table SPARK_Scenarios.
+
+   Recorded_SPARK_Scenarios_Max : constant := 127;
+
+   type Recorded_SPARK_Scenarios_Index is
+     range 0 .. Recorded_SPARK_Scenarios_Max - 1;
+
+   function Recorded_SPARK_Scenarios_Hash
+     (Key : Node_Id) return Recorded_SPARK_Scenarios_Index;
+   --  Obtain the hash value of Key
+
+   Recorded_SPARK_Scenarios_In_Use : Boolean := False;
+   --  This flag flag determines whether table Recorded_SPARK_Scenarios
+   --  contains at least one key/value pair.
+
+   Recorded_SPARK_Scenarios_No_Element : constant Boolean := False;
+
+   package Recorded_SPARK_Scenarios is new Simple_HTable
+     (Header_Num => Recorded_SPARK_Scenarios_Index,
+      Element    => Boolean,
+      No_Element => Recorded_SPARK_Scenarios_No_Element,
+      Key        => Node_Id,
+      Hash       => Recorded_SPARK_Scenarios_Hash,
+      Equal      => "=");
+
+   --  The following table stores a status flag for each top-level scenario
+   --  recorded in table Top_Level_Scenarios.
+
+   Recorded_Top_Level_Scenarios_Max : constant := 503;
+
+   type Recorded_Top_Level_Scenarios_Index is
+     range 0 .. Recorded_Top_Level_Scenarios_Max - 1;
+
+   function Recorded_Top_Level_Scenarios_Hash
+     (Key : Node_Id) return Recorded_Top_Level_Scenarios_Index;
+   --  Obtain the hash value of entity Key
+
+   Recorded_Top_Level_Scenarios_In_Use : Boolean := False;
+   --  This flag flag determines whether table Recorded_Top_Level_Scenarios
+   --  contains at least one key/value pair.
+
+   Recorded_Top_Level_Scenarios_No_Element : constant Boolean := False;
+
+   package Recorded_Top_Level_Scenarios is new Simple_HTable
+     (Header_Num => Recorded_Top_Level_Scenarios_Index,
+      Element    => Boolean,
+      No_Element => Recorded_Top_Level_Scenarios_No_Element,
+      Key        => Node_Id,
+      Hash       => Recorded_Top_Level_Scenarios_Hash,
       Equal      => "=");
 
    --  The following table stores all active scenarios in a recursive traversal
-   --  starting from a top level scenario. This table must be maintained in a
+   --  starting from a top-level scenario. This table must be maintained in a
    --  FIFO fashion.
 
    package Scenario_Stack is new Table.Table
@@ -727,7 +1060,19 @@
       Table_Increment      => 100,
       Table_Name           => "Scenario_Stack");
 
-   --  The following table stores all top level scenario saved during the
+   --  The following table stores SPARK scenarios which are not necessarily
+   --  executable during elaboration, but still require elaboration-related
+   --  checks.
+
+   package SPARK_Scenarios is new Table.Table
+     (Table_Component_Type => Node_Id,
+      Table_Index_Type     => Int,
+      Table_Low_Bound      => 1,
+      Table_Initial        => 50,
+      Table_Increment      => 100,
+      Table_Name           => "SPARK_Scenarios");
+
+   --  The following table stores all top-level scenario saved during the
    --  Recording phase. The contents of this table act as traversal roots
    --  later in the Processing phase. This table must be maintained in a
    --  LIFO fashion.
@@ -741,7 +1086,7 @@
       Table_Name           => "Top_Level_Scenarios");
 
    --  The following table stores the bodies of all eligible scenarios visited
-   --  during a traversal starting from a top level scenario. The contents of
+   --  during a traversal starting from a top-level scenario. The contents of
    --  this table must be reset upon each new traversal.
 
    Visited_Bodies_Max : constant := 511;
@@ -751,10 +1096,16 @@
    function Visited_Bodies_Hash (Key : Node_Id) return Visited_Bodies_Index;
    --  Obtain the hash value of node Key
 
+   Visited_Bodies_In_Use : Boolean := False;
+   --  This flag determines whether table Visited_Bodies contains at least one
+   --  key/value pair.
+
+   Visited_Bodies_No_Element : constant Boolean := False;
+
    package Visited_Bodies is new Simple_HTable
      (Header_Num => Visited_Bodies_Index,
       Element    => Boolean,
-      No_Element => False,
+      No_Element => Visited_Bodies_No_Element,
       Key        => Node_Id,
       Hash       => Visited_Bodies_Hash,
       Equal      => "=");
@@ -763,15 +1114,52 @@
    -- Local subprograms --
    -----------------------
 
+   --  Multiple local subprograms are utilized to lower the semantic complexity
+   --  of the Recording and Processing phase.
+
    procedure Check_Preelaborated_Call (Call : Node_Id);
-   --  Determine whether entry, operator, or subprogram call Call appears at
-   --  the library level of a preelaborated unit. Emit an error if this is the
-   --  case.
+   pragma Inline (Check_Preelaborated_Call);
+   --  Verify that entry, operator, or subprogram call Call does not appear at
+   --  the library level of a preelaborated unit.
+
+   procedure Check_SPARK_Derived_Type (Typ_Decl : Node_Id);
+   pragma Inline (Check_SPARK_Derived_Type);
+   --  Verify that the freeze node of a derived type denoted by declaration
+   --  Typ_Decl is within the early call region of each overriding primitive
+   --  body that belongs to the derived type (SPARK RM 7.7(8)).
+
+   procedure Check_SPARK_Instantiation (Exp_Inst : Node_Id);
+   pragma Inline (Check_SPARK_Instantiation);
+   --  Verify that expanded instance Exp_Inst does not precede the generic body
+   --  it instantiates (SPARK RM 7.7(6)).
+
+   procedure Check_SPARK_Model_In_Effect (N : Node_Id);
+   pragma Inline (Check_SPARK_Model_In_Effect);
+   --  Determine whether a suitable elaboration model is currently in effect
+   --  for verifying the SPARK rules of scenario N. Emit a warning if this is
+   --  not the case.
+
+   procedure Check_SPARK_Scenario (N : Node_Id);
+   pragma Inline (Check_SPARK_Scenario);
+   --  Top-level dispatcher for verifying SPARK scenarios which are not always
+   --  executable during elaboration but still need elaboration-related checks.
+
+   procedure Check_SPARK_Refined_State_Pragma (N : Node_Id);
+   pragma Inline (Check_SPARK_Refined_State_Pragma);
+   --  Verify that each constituent of Refined_State pragma N which belongs to
+   --  an abstract state mentioned in pragma Initializes has prior elaboration
+   --  with respect to the main unit (SPARK RM 7.7.1(7)).
 
    function Compilation_Unit (Unit_Id : Entity_Id) return Node_Id;
    pragma Inline (Compilation_Unit);
    --  Return the N_Compilation_Unit node of unit Unit_Id
 
+   function Early_Call_Region (Body_Id : Entity_Id) return Node_Id;
+   pragma Inline (Early_Call_Region);
+   --  Return the early call region associated with entry or subprogram body
+   --  Body_Id. IMPORTANT: This routine does not find the early call region.
+   --  To compute it, use routine Find_Early_Call_Region.
+
    procedure Elab_Msg_NE
      (Msg      : String;
       N        : Node_Id;
@@ -784,13 +1172,20 @@
    --  message, otherwise it emits an error. If flag In_SPARK is set, then
    --  string " in SPARK" is added to the end of the message.
 
+   function Elaboration_Status
+     (Unit_Id : Entity_Id) return Elaboration_Attributes;
+   pragma Inline (Elaboration_Status);
+   --  Return the set of elaboration attributes associated with unit Unit_Id
+
    procedure Ensure_Prior_Elaboration
-     (N            : Node_Id;
-      Unit_Id      : Entity_Id;
-      In_Task_Body : Boolean);
-   --  Guarantee the elaboration of unit Unit_Id with respect to the main unit.
-   --  N denotes the related scenario. Flag In_Task_Body should be set when the
-   --  need for elaboration is initiated from a task body.
+     (N        : Node_Id;
+      Unit_Id  : Entity_Id;
+      Prag_Nam : Name_Id;
+      State    : Processing_Attributes);
+   --  Guarantee the elaboration of unit Unit_Id with respect to the main unit
+   --  by installing pragma Elaborate or Elaborate_All denoted by Prag_Nam. N
+   --  denotes the related scenario. State denotes the current state of the
+   --  Processing phase.
 
    procedure Ensure_Prior_Elaboration_Dynamic
      (N        : Node_Id;
@@ -867,10 +1262,22 @@
    --  Return the code unit which contains arbitrary node or entity N. This
    --  is the unit of the file which physically contains the related construct
    --  denoted by N except when N is within an instantiation. In that case the
-   --  unit is that of the top level instantiation.
+   --  unit is that of the top-level instantiation.
+
+   function Find_Early_Call_Region
+     (Body_Decl        : Node_Id;
+      Assume_Elab_Body : Boolean := False;
+      Skip_Memoization : Boolean := False) return Node_Id;
+   --  Find the start of the early call region which belongs to subprogram body
+   --  Body_Decl as defined in SPARK RM 7.7. The behavior of the routine is to
+   --  find the early call region, memoize it, and return it, but this behavior
+   --  can be altered. Flag Assume_Elab_Body should be set when a package spec
+   --  may lack pragma Elaborate_Body, but the routine must still examine that
+   --  spec. Flag Skip_Memoization should be set when the routine must avoid
+   --  memoizing the region.
 
    procedure Find_Elaborated_Units;
-   --  Populate table Elaboration_Context with all units which have prior
+   --  Populate table Elaboration_Statuses with all units which have prior
    --  elaboration with respect to the main unit.
 
    function Find_Enclosing_Instance (N : Node_Id) return Node_Id;
@@ -941,6 +1348,10 @@
    --  context ignoring enclosing library levels. Nested_OK should be set when
    --  the context of N1 can enclose that of N2.
 
+   function In_Task_Body (N : Node_Id) return Boolean;
+   pragma Inline (In_Task_Body);
+   --  Determine whether arbitrary node N appears within a task body
+
    procedure Info_Call
      (Call      : Node_Id;
       Target_Id : Entity_Id;
@@ -962,16 +1373,16 @@
    --  information message, otherwise it emits an error. If flag In_SPARK
    --  is set, then string " in SPARK" is added to the end of the message.
 
-   procedure Info_Variable_Read
+   procedure Info_Variable_Reference
      (Ref      : Node_Id;
       Var_Id   : Entity_Id;
       Info_Msg : Boolean;
       In_SPARK : Boolean);
-   pragma Inline (Info_Variable_Read);
-   --  Output information concerning reference Ref which reads variable Var_Id.
-   --  If flag Info_Msg is set, the routine emits an information message,
-   --  otherwise it emits an error. If flag In_SPARK is set, then string " in
-   --  SPARK" is added to the end of the message.
+   pragma Inline (Info_Variable_Reference);
+   --  Output information concerning reference Ref which mentions variable
+   --  Var_Id. If flag Info_Msg is set, the routine emits an information
+   --  message, otherwise it emits an error. If flag In_SPARK is set, then
+   --  string " in SPARK" is added to the end of the message.
 
    function Insertion_Node (N : Node_Id; Ins_Nod : Node_Id) return Node_Id;
    pragma Inline (Insertion_Node);
@@ -1012,18 +1423,18 @@
 
    function Is_Ada_Semantic_Target (Id : Entity_Id) return Boolean;
    pragma Inline (Is_Ada_Semantic_Target);
-   --  Determine whether arbitrary entity Id nodes a source or internally
+   --  Determine whether arbitrary entity Id denodes a source or internally
    --  generated subprogram which emulates Ada semantics.
 
+   function Is_Assertion_Pragma_Target (Id : Entity_Id) return Boolean;
+   pragma Inline (Is_Assertion_Pragma_Target);
+   --  Determine whether arbitrary entity Id denotes a procedure which varifies
+   --  the run-time semantics of an assertion pragma.
+
    function Is_Bodiless_Subprogram (Subp_Id : Entity_Id) return Boolean;
    pragma Inline (Is_Bodiless_Subprogram);
    --  Determine whether subprogram Subp_Id will never have a body
 
-   function Is_Check_Emitting_Scenario (N : Node_Id) return Boolean;
-   pragma Inline (Is_Check_Emitting_Scenario);
-   --  Determine whether arbitrary node N denotes a scenario which may emit a
-   --  conditional ABE check.
-
    function Is_Controlled_Proc
      (Subp_Id  : Entity_Id;
       Subp_Nam : Name_Id) return Boolean;
@@ -1101,6 +1512,16 @@
    --  Determine whether entity Id denotes the protected or unprotected version
    --  of a protected subprogram.
 
+   function Is_Recorded_SPARK_Scenario (N : Node_Id) return Boolean;
+   pragma Inline (Is_Recorded_SPARK_Scenario);
+   --  Determine whether arbitrary node N is a recorded SPARK scenario which
+   --  appears in table SPARK_Scenarios.
+
+   function Is_Recorded_Top_Level_Scenario (N : Node_Id) return Boolean;
+   pragma Inline (Is_Recorded_Top_Level_Scenario);
+   --  Determine whether arbitrary node N is a recorded top-level scenario
+   --  which appears in table Top_Level_Scenarios.
+
    function Is_Safe_Activation
      (Call      : Node_Id;
       Task_Decl : Node_Id) return Boolean;
@@ -1158,15 +1579,39 @@
    --  Determine whether arbitrary node N is a suitable scenario for ABE
    --  processing.
 
+   function Is_Suitable_SPARK_Derived_Type (N : Node_Id) return Boolean;
+   pragma Inline (Is_Suitable_SPARK_Derived_Type);
+   --  Determine whether arbitrary node N denotes a suitable derived type
+   --  declaration for ABE processing using the SPARK rules.
+
+   function Is_Suitable_SPARK_Instantiation (N : Node_Id) return Boolean;
+   pragma Inline (Is_Suitable_SPARK_Instantiation);
+   --  Determine whether arbitrary node N denotes a suitable instantiation for
+   --  ABE processing using the SPARK rules.
+
+   function Is_Suitable_SPARK_Refined_State_Pragma
+     (N : Node_Id) return Boolean;
+   pragma Inline (Is_Suitable_SPARK_Refined_State_Pragma);
+   --  Determine whether arbitrary node N denotes a suitable Refined_State
+   --  pragma for ABE processing using the SPARK rules.
+
    function Is_Suitable_Variable_Assignment (N : Node_Id) return Boolean;
    pragma Inline (Is_Suitable_Variable_Assignment);
    --  Determine whether arbitrary node N denotes a suitable assignment for ABE
    --  processing.
 
-   function Is_Suitable_Variable_Read (N : Node_Id) return Boolean;
-   pragma Inline (Is_Suitable_Variable_Read);
-   --  Determine whether arbitrary node N is a suitable variable read for ABE
-   --  processing.
+   function Is_Suitable_Variable_Reference (N : Node_Id) return Boolean;
+   pragma Inline (Is_Suitable_Variable_Reference);
+   --  Determine whether arbitrary node N is a suitable variable reference for
+   --  ABE processing.
+
+   function Is_Synchronous_Suspension_Call (N : Node_Id) return Boolean;
+   pragma Inline (Is_Synchronous_Suspension_Call);
+   --  Determine whether arbitrary node N denotes a call to one the following
+   --  routines:
+   --
+   --    Ada.Synchronous_Barriers.Wait_For_Release
+   --    Ada.Synchronous_Task_Control.Suspend_Until_True
 
    function Is_Task_Entry (Id : Entity_Id) return Boolean;
    pragma Inline (Is_Task_Entry);
@@ -1179,6 +1624,11 @@
    --  Target_Decl is within a context which encloses the current root or is in
    --  a different unit.
 
+   function Is_Visited_Body (Body_Decl : Node_Id) return Boolean;
+   pragma Inline (Is_Visited_Body);
+   --  Determine whether subprogram body Body_Decl is already visited during a
+   --  recursive traversal started from a top-level scenario.
+
    procedure Meet_Elaboration_Requirement
      (N         : Node_Id;
       Target_Id : Entity_Id;
@@ -1202,88 +1652,154 @@
    --  Pop the top of the scenario stack. A check is made to ensure that the
    --  scenario being removed is the same as N.
 
-   procedure Process_Access (Attr : Node_Id; In_Task_Body : Boolean);
-   --  Perform ABE checks and diagnostics for 'Access to entry, operator, or
-   --  subprogram denoted by Attr. Flag In_Task_Body should be set when the
-   --  processing is initiated from a task body.
-
    generic
       with procedure Process_Single_Activation
-        (Call         : Node_Id;
-         Call_Attrs   : Call_Attributes;
-         Obj_Id       : Entity_Id;
-         Task_Attrs   : Task_Attributes;
-         In_Task_Body : Boolean);
+        (Call       : Node_Id;
+         Call_Attrs : Call_Attributes;
+         Obj_Id     : Entity_Id;
+         Task_Attrs : Task_Attributes;
+         State      : Processing_Attributes);
       --  Perform ABE checks and diagnostics for task activation call Call
       --  which activates task Obj_Id. Call_Attrs are the attributes of the
       --  activation call. Task_Attrs are the attributes of the task type.
-      --  Flag In_Task_Body should be set when the processing is initiated
-      --  from a task body.
-
-   procedure Process_Activation_Call
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      In_Task_Body : Boolean);
+      --  State is the current state of the Processing phase.
+
+   procedure Process_Activation_Generic
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      State      : Processing_Attributes);
    --  Perform ABE checks and diagnostics for activation call Call by invoking
    --  routine Process_Single_Activation on each task object being activated.
-   --  Call_Attrs are the attributes of the activation call. Flag In_Task_Body
-   --  should be set when the processing is initiated from a task body.
-
-   procedure Process_Activation_Conditional_ABE_Impl
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Obj_Id       : Entity_Id;
-      Task_Attrs   : Task_Attributes;
-      In_Task_Body : Boolean);
+   --  Call_Attrs are the attributes of the activation call. State is the
+   --  current state of the Processing phase.
+
+   procedure Process_Conditional_ABE
+     (N     : Node_Id;
+      State : Processing_Attributes := Initial_State);
+   --  Top-level dispatcher for processing of various elaboration scenarios.
+   --  Perform conditional ABE checks and diagnostics for scenario N. State
+   --  is the current state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Access
+     (Attr  : Node_Id;
+      State : Processing_Attributes);
+   --  Perform ABE checks and diagnostics for 'Access to entry, operator, or
+   --  subprogram denoted by Attr. State is the current state of the Processing
+   --  phase.
+
+   procedure Process_Conditional_ABE_Activation_Impl
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Obj_Id     : Entity_Id;
+      Task_Attrs : Task_Attributes;
+      State      : Processing_Attributes);
    --  Perform common conditional ABE checks and diagnostics for call Call
-   --  which activates task Obj_Id ignoring the Ada or SPARK rules. CAll_Attrs
+   --  which activates task Obj_Id ignoring the Ada or SPARK rules. Call_Attrs
    --  are the attributes of the activation call. Task_Attrs are the attributes
-   --  of the task type. Flag In_Task_Body should be set when the processing is
-   --  initiated from a task body.
-
-   procedure Process_Activation_Guaranteed_ABE_Impl
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Obj_Id       : Entity_Id;
-      Task_Attrs   : Task_Attributes;
-      In_Task_Body : Boolean);
-   --  Perform common guaranteed ABE checks and diagnostics for call Call
-   --  which activates task Obj_Id ignoring the Ada or SPARK rules. CAll_Attrs
-   --  are the attributes of the activation call. Task_Attrs are the attributes
-   --  of the task type. Flag In_Task_Body should be set when the processing is
-   --  initiated from a task body.
-
-   procedure Process_Call
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      In_Task_Body : Boolean);
+   --  of the task type. State is the current state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Call
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Target_Id  : Entity_Id;
+      State      : Processing_Attributes);
    --  Top-level dispatcher for processing of calls. Perform ABE checks and
    --  diagnostics for call Call which invokes target Target_Id. Call_Attrs
-   --  are the attributes of the call. Flag In_Task_Body should be set when
-   --  the processing is initiated from a task body.
-
-   procedure Process_Call_Ada
+   --  are the attributes of the call. State is the current state of the
+   --  Processing phase.
+
+   procedure Process_Conditional_ABE_Call_Ada
      (Call         : Node_Id;
       Call_Attrs   : Call_Attributes;
       Target_Id    : Entity_Id;
       Target_Attrs : Target_Attributes;
-      In_Task_Body : Boolean);
+      State        : Processing_Attributes);
    --  Perform ABE checks and diagnostics for call Call which invokes target
    --  Target_Id using the Ada rules. Call_Attrs are the attributes of the
-   --  call. Target_Attrs are attributes of the target. Flag In_Task_Body
-   --  should be set when the processing is initiated from a task body.
-
-   procedure Process_Call_Conditional_ABE
+   --  call. Target_Attrs are attributes of the target. State is the current
+   --  state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Call_SPARK
      (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
       Target_Id    : Entity_Id;
-      Target_Attrs : Target_Attributes);
-   --  Perform common conditional ABE checks and diagnostics for call Call that
-   --  invokes target Target_Id ignoring the Ada or SPARK rules. Call_Attrs are
-   --  the attributes of the call. Target_Attrs are attributes of the target.
-
-   procedure Process_Call_Guaranteed_ABE
+      Target_Attrs : Target_Attributes;
+      State        : Processing_Attributes);
+   --  Perform ABE checks and diagnostics for call Call which invokes target
+   --  Target_Id using the SPARK rules. Target_Attrs denotes the attributes of
+   --  the target. State is the current state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Instantiation
+     (Exp_Inst : Node_Id;
+      State    : Processing_Attributes);
+   --  Top-level dispatcher for processing of instantiations. Perform ABE
+   --  checks and diagnostics for expanded instantiation Exp_Inst. State is
+   --  the current state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Instantiation_Ada
+     (Exp_Inst   : Node_Id;
+      Inst       : Node_Id;
+      Inst_Attrs : Instantiation_Attributes;
+      Gen_Id     : Entity_Id;
+      Gen_Attrs  : Target_Attributes;
+      State      : Processing_Attributes);
+   --  Perform ABE checks and diagnostics for expanded instantiation Exp_Inst
+   --  of generic Gen_Id using the Ada rules. Inst is the instantiation node.
+   --  Inst_Attrs are the attributes of the instance. Gen_Attrs denotes the
+   --  attributes of the generic. State is the current state of the Processing
+   --  phase.
+
+   procedure Process_Conditional_ABE_Instantiation_SPARK
+     (Inst      : Node_Id;
+      Gen_Id    : Entity_Id;
+      Gen_Attrs : Target_Attributes;
+      State     : Processing_Attributes);
+   --  Perform ABE checks and diagnostics for instantiation Inst of generic
+   --  Gen_Id using the SPARK rules. Gen_Attrs denotes the attributes of the
+   --  generic. State is the current state of the Processing phase.
+
+   procedure Process_Conditional_ABE_Variable_Assignment (Asmt : Node_Id);
+   --  Top-level dispatcher for processing of variable assignments. Perform ABE
+   --  checks and diagnostics for assignment statement Asmt.
+
+   procedure Process_Conditional_ABE_Variable_Assignment_Ada
+     (Asmt   : Node_Id;
+      Var_Id : Entity_Id);
+   --  Perform ABE checks and diagnostics for assignment statement Asmt that
+   --  updates the value of variable Var_Id using the Ada rules.
+
+   procedure Process_Conditional_ABE_Variable_Assignment_SPARK
+     (Asmt   : Node_Id;
+      Var_Id : Entity_Id);
+   --  Perform ABE checks and diagnostics for assignment statement Asmt that
+   --  updates the value of variable Var_Id using the SPARK rules.
+
+   procedure Process_Conditional_ABE_Variable_Reference (Ref : Node_Id);
+   --  Top-level dispatcher for processing of variable references. Perform ABE
+   --  checks and diagnostics for variable reference Ref.
+
+   procedure Process_Conditional_ABE_Variable_Reference_Read
+     (Ref    : Node_Id;
+      Var_Id : Entity_Id;
+      Attrs  : Variable_Attributes);
+   --  Perform ABE checks and diagnostics for reference Ref described by its
+   --  attributes Attrs, that reads variable Var_Id.
+
+   procedure Process_Guaranteed_ABE (N : Node_Id);
+   --  Top-level dispatcher for processing of scenarios which result in a
+   --  guaranteed ABE.
+
+   procedure Process_Guaranteed_ABE_Activation_Impl
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Obj_Id     : Entity_Id;
+      Task_Attrs : Task_Attributes;
+      State      : Processing_Attributes);
+   --  Perform common guaranteed ABE checks and diagnostics for call Call which
+   --  activates task Obj_Id ignoring the Ada or SPARK rules. Call_Attrs are
+   --  the attributes of the activation call. Task_Attrs are the attributes of
+   --  the task type. State is provided for compatibility and is not used.
+
+   procedure Process_Guaranteed_ABE_Call
      (Call       : Node_Id;
       Call_Attrs : Call_Attributes;
       Target_Id  : Entity_Id);
@@ -1291,110 +1807,69 @@
    --  invokes target Target_Id ignoring the Ada or SPARK rules. Call_Attrs are
    --  the attributes of the call.
 
-   procedure Process_Call_SPARK
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      Target_Attrs : Target_Attributes);
-   --  Perform ABE checks and diagnostics for call Call which invokes target
-   --  Target_Id using the SPARK rules. Call_Attrs are the attributes of the
-   --  call. Target_Attrs are attributes of the target.
-
-   procedure Process_Guaranteed_ABE (N : Node_Id);
-   --  Top level dispatcher for processing of scenarios which result in a
-   --  guaranteed ABE.
-
-   procedure Process_Instantiation
-     (Exp_Inst     : Node_Id;
-      In_Task_Body : Boolean);
-   --  Top level dispatcher for processing of instantiations. Perform ABE
-   --  checks and diagnostics for expanded instantiation Exp_Inst. Flag
-   --  In_Task_Body should be set when the processing is initiated from a
-   --  task body.
-
-   procedure Process_Instantiation_Ada
-     (Exp_Inst     : Node_Id;
-      Inst         : Node_Id;
-      Inst_Attrs   : Instantiation_Attributes;
-      Gen_Id       : Entity_Id;
-      Gen_Attrs    : Target_Attributes;
-      In_Task_Body : Boolean);
-   --  Perform ABE checks and diagnostics for expanded instantiation Exp_Inst
-   --  of generic Gen_Id using the Ada rules. Inst is the instantiation node.
-   --  Inst_Attrs are the attributes of the instance. Gen_Attrs are the
-   --  attributes of the generic. Flag In_Task_Body should be set when the
-   --  processing is initiated from a task body.
-
-   procedure Process_Instantiation_Conditional_ABE
-     (Exp_Inst   : Node_Id;
-      Inst       : Node_Id;
-      Inst_Attrs : Instantiation_Attributes;
-      Gen_Id     : Entity_Id;
-      Gen_Attrs  : Target_Attributes);
-   --  Perform common conditional ABE checks and diagnostics for expanded
-   --  instantiation Exp_Inst of generic Gen_Id ignoring the Ada or SPARK
-   --  rules. Inst is the instantiation node. Inst_Attrs are the attributes
-   --  of the instance. Gen_Attrs are the attributes of the generic.
-
-   procedure Process_Instantiation_Guaranteed_ABE (Exp_Inst : Node_Id);
+   procedure Process_Guaranteed_ABE_Instantiation (Exp_Inst : Node_Id);
    --  Perform common guaranteed ABE checks and diagnostics for expanded
    --  instantiation Exp_Inst of generic Gen_Id ignoring the Ada or SPARK
    --  rules.
 
-   procedure Process_Instantiation_SPARK
-     (Exp_Inst   : Node_Id;
-      Inst       : Node_Id;
-      Inst_Attrs : Instantiation_Attributes;
-      Gen_Id     : Entity_Id;
-      Gen_Attrs  : Target_Attributes);
-   --  Perform ABE checks and diagnostics for expanded instantiation Exp_Inst
-   --  of generic Gen_Id using the SPARK rules. Inst is the instantiation node.
-   --  Inst_Attrs are the attributes of the instance. Gen_Attrs are the
-   --  attributes of the generic.
-
-   procedure Process_Scenario (N : Node_Id; In_Task_Body : Boolean := False);
-   --  Top level dispatcher for processing of various elaboration scenarios.
-   --  Perform ABE checks and diagnostics for scenario N. Flag In_Task_Body
-   --  should be set when the processing is initiated from a task body.
-
-   procedure Process_Variable_Assignment (Asmt : Node_Id);
-   --  Top level dispatcher for processing of variable assignments. Perform ABE
-   --  checks and diagnostics for assignment statement Asmt.
-
-   procedure Process_Variable_Assignment_Ada
-     (Asmt   : Node_Id;
-      Var_Id : Entity_Id);
-   --  Perform ABE checks and diagnostics for assignment statement Asmt that
-   --  updates the value of variable Var_Id using the Ada rules.
-
-   procedure Process_Variable_Assignment_SPARK
-     (Asmt   : Node_Id;
-      Var_Id : Entity_Id);
-   --  Perform ABE checks and diagnostics for assignment statement Asmt that
-   --  updates the value of variable Var_Id using the SPARK rules.
-
-   procedure Process_Variable_Read (Ref : Node_Id);
-   --  Perform ABE checks and diagnostics for reference Ref that reads a
-   --  variable.
-
    procedure Push_Active_Scenario (N : Node_Id);
    pragma Inline (Push_Active_Scenario);
    --  Push scenario N on top of the scenario stack
 
+   procedure Record_SPARK_Elaboration_Scenario (N : Node_Id);
+   pragma Inline (Record_SPARK_Elaboration_Scenario);
+   --  Save SPARK scenario N in table SPARK_Scenarios for later processing
+
+   procedure Reset_Visited_Bodies;
+   pragma Inline (Reset_Visited_Bodies);
+   --  Clear the contents of table Visited_Bodies
+
    function Root_Scenario return Node_Id;
    pragma Inline (Root_Scenario);
-   --  Return the top level scenario which started a recursive search for other
-   --  scenarios. It is assumed that there is a valid top level scenario on the
+   --  Return the top-level scenario which started a recursive search for other
+   --  scenarios. It is assumed that there is a valid top-level scenario on the
    --  active scenario stack.
 
+   procedure Set_Early_Call_Region (Body_Id : Entity_Id; Start : Node_Id);
+   pragma Inline (Set_Early_Call_Region);
+   --  Associate an early call region with begins at construct Start with entry
+   --  or subprogram body Body_Id.
+
+   procedure Set_Elaboration_Status
+     (Unit_Id : Entity_Id;
+      Val     : Elaboration_Attributes);
+   pragma Inline (Set_Elaboration_Status);
+   --  Associate an set of elaboration attributes with unit Unit_Id
+
+   procedure Set_Is_Recorded_SPARK_Scenario
+     (N   : Node_Id;
+      Val : Boolean := True);
+   pragma Inline (Set_Is_Recorded_SPARK_Scenario);
+   --  Mark scenario N as being recorded in table SPARK_Scenarios
+
+   procedure Set_Is_Recorded_Top_Level_Scenario
+     (N   : Node_Id;
+      Val : Boolean := True);
+   pragma Inline (Set_Is_Recorded_Top_Level_Scenario);
+   --  Mark scenario N as being recorded in table Top_Level_Scenarios
+
+   procedure Set_Is_Visited_Body (Subp_Body : Node_Id);
+   pragma Inline (Set_Is_Visited_Body);
+   --  Mark subprogram body Subp_Body as being visited during a recursive
+   --  traversal started from a top-level scenario.
+
    function Static_Elaboration_Checks return Boolean;
    pragma Inline (Static_Elaboration_Checks);
    --  Determine whether the static model is in effect
 
-   procedure Traverse_Body (N : Node_Id; In_Task_Body : Boolean);
-   --  Inspect the declarations and statements of subprogram body N for
-   --  suitable elaboration scenarios and process them. Flag In_Task_Body
-   --  should be set when the traversal is initiated from a task body.
+   procedure Traverse_Body (N : Node_Id; State : Processing_Attributes);
+   --  Inspect the declarative and statement lists of subprogram body N for
+   --  suitable elaboration scenarios and process them. State is the current
+   --  state of the Processing phase.
+
+   function Unit_Entity (Unit_Id : Entity_Id) return Entity_Id;
+   pragma Inline (Unit_Entity);
+   --  Return the entity of the initial declaration for unit Unit_Id
 
    procedure Update_Elaboration_Scenario (New_N : Node_Id; Old_N : Node_Id);
    pragma Inline (Update_Elaboration_Scenario);
@@ -1407,11 +1882,11 @@
 
    procedure Build_Call_Marker (N : Node_Id) is
       function In_External_Context
-        (Call      : Node_Id;
-         Target_Id : Entity_Id) return Boolean;
+        (Call         : Node_Id;
+         Target_Attrs : Target_Attributes) return Boolean;
       pragma Inline (In_External_Context);
-      --  Determine whether target Target_Id is external to call N which must
-      --  reside within an instance.
+      --  Determine whether a target described by attributes Target_Attrs is
+      --  external to call Call which must reside within an instance.
 
       function In_Premature_Context (Call : Node_Id) return Boolean;
       --  Determine whether call Call appears within a premature context
@@ -1435,11 +1910,9 @@
       -------------------------
 
       function In_External_Context
-        (Call      : Node_Id;
-         Target_Id : Entity_Id) return Boolean
+        (Call         : Node_Id;
+         Target_Attrs : Target_Attributes) return Boolean
       is
-         Target_Decl : constant Node_Id := Unit_Declaration_Node (Target_Id);
-
          Inst      : Node_Id;
          Inst_Body : Node_Id;
          Inst_Decl : Node_Id;
@@ -1456,7 +1929,7 @@
             --  The call comes from the main unit and the target does not
 
             if In_Extended_Main_Code_Unit (Call)
-              and then not In_Extended_Main_Code_Unit (Target_Decl)
+              and then not In_Extended_Main_Code_Unit (Target_Attrs.Spec_Decl)
             then
                return True;
 
@@ -1472,7 +1945,7 @@
                --  Performance note: parent traversal
 
                return not In_Subtree
-                            (N     => Target_Decl,
+                            (N     => Target_Attrs.Spec_Decl,
                              Root1 => Inst_Decl,
                              Root2 => Inst_Body);
             end if;
@@ -1583,18 +2056,32 @@
 
       --  Local variables
 
-      Call_Attrs : Call_Attributes;
-      Call_Nam   : Node_Id;
-      Marker     : Node_Id;
-      Target_Id  : Entity_Id;
+      Call_Attrs   : Call_Attributes;
+      Call_Nam     : Node_Id;
+      Marker       : Node_Id;
+      Target_Attrs : Target_Attributes;
+      Target_Id    : Entity_Id;
 
    --  Start of processing for Build_Call_Marker
 
    begin
-      --  Nothing to do for ASIS. As a result, ABE checks and diagnostics are
-      --  not performed in this mode.
-
-      if ASIS_Mode then
+      --  Nothing to do when switch -gnatH (legacy elaboration checking mode
+      --  enabled) is in effect because the legacy ABE mechanism does not need
+      --  to carry out this action.
+
+      if Legacy_Elaboration_Checks then
+         return;
+
+      --  Nothing to do for ASIS because ABE checks and diagnostics are not
+      --  performed in this mode.
+
+      elsif ASIS_Mode then
+         return;
+
+      --  Nothing to do when the call is being preanalyzed as the marker will
+      --  be inserted in the wrong place.
+
+      elsif Preanalysis_Active then
          return;
 
       --  Nothing to do when the input does not denote a call or a requeue
@@ -1606,18 +2093,13 @@
       then
          return;
 
-      --  Nothing to do when the call is being preanalyzed as the marker will
-      --  be inserted in the wrong place.
-
-      elsif Preanalysis_Active then
-         return;
-
-      --  Nothing to do when the call is analyzed/resolved too early within an
-      --  intermediate context.
-
-      --  Performance note: parent traversal
-
-      elsif In_Premature_Context (N) then
+      --  Nothing to do when the input denotes entry call or requeue statement,
+      --  and switch -gnatd_e (ignore entry calls and requeue statements for
+      --  elaboration) is in effect.
+
+      elsif Debug_Flag_Underscore_E
+        and then Nkind_In (N, N_Entry_Call_Statement, N_Requeue_Statement)
+      then
          return;
       end if;
 
@@ -1641,6 +2123,15 @@
         and then Is_Generic_Formal_Subp (Entity (Call_Nam))
       then
          return;
+
+      --  Nothing to do when the call is analyzed/resolved too early within an
+      --  intermediate context. This check is saved for last because it incurs
+      --  a performance penalty.
+
+      --  Performance note: parent traversal
+
+      elsif In_Premature_Context (N) then
+         return;
       end if;
 
       Extract_Call_Attributes
@@ -1648,11 +2139,15 @@
          Target_Id => Target_Id,
          Attrs     => Call_Attrs);
 
+      Extract_Target_Attributes
+        (Target_Id => Target_Id,
+         Attrs     => Target_Attrs);
+
       --  Nothing to do when the call appears within the expanded spec or
       --  body of an instantiated generic, the call does not invoke a generic
       --  formal subprogram, the target is external to the instance, and switch
       --  -gnatdL (ignore external calls from instances for elaboration) is in
-      --  effect. This behaviour approximates that of the old ABE mechanism.
+      --  effect.
 
       if Debug_Flag_LL
         and then not Is_Generic_Formal_Subp (Entity (Call_Nam))
@@ -1660,21 +2155,30 @@
         --  Performance note: parent traversal
 
         and then In_External_Context
-                   (Call      => N,
-                    Target_Id => Target_Id)
+                   (Call         => N,
+                    Target_Attrs => Target_Attrs)
+      then
+         return;
+
+      --  Nothing to do when the call invokes an assertion pragma procedure
+      --  and switch -gnatd_p (ignore assertion pragmas for elaboration) is
+      --  in effect.
+
+      elsif Debug_Flag_Underscore_P
+        and then Is_Assertion_Pragma_Target (Target_Id)
       then
          return;
 
       --  Source calls to source targets are always considered because they
       --  reflect the original call graph.
 
-      elsif Comes_From_Source (Target_Id) and then Call_Attrs.From_Source then
+      elsif Target_Attrs.From_Source and then Call_Attrs.From_Source then
          null;
 
       --  A call to a source function which acts as the default expression in
       --  another call requires special detection.
 
-      elsif Comes_From_Source (Target_Id)
+      elsif Target_Attrs.From_Source
         and then Nkind (N) = N_Function_Call
         and then Is_Default_Expression (N)
       then
@@ -1711,13 +2215,16 @@
 
       --  Inherit the attributes of the original call
 
-      Set_Target                        (Marker, Target_Id);
-      Set_Is_Elaboration_Checks_OK_Node (Marker, Call_Attrs.Elab_Checks_OK);
-      Set_Is_Declaration_Level_Node     (Marker, Call_Attrs.In_Declarations);
-      Set_Is_Dispatching_Call           (Marker, Call_Attrs.Is_Dispatching);
-      Set_Is_Ignored_Ghost_Node         (Marker, Call_Attrs.Ghost_Mode_Ignore);
-      Set_Is_Source_Call                (Marker, Call_Attrs.From_Source);
-      Set_Is_SPARK_Mode_On_Node         (Marker, Call_Attrs.SPARK_Mode_On);
+      Set_Target                    (Marker, Target_Id);
+      Set_Is_Declaration_Level_Node (Marker, Call_Attrs.In_Declarations);
+      Set_Is_Dispatching_Call       (Marker, Call_Attrs.Is_Dispatching);
+      Set_Is_Elaboration_Checks_OK_Node
+                                    (Marker, Call_Attrs.Elab_Checks_OK);
+      Set_Is_Elaboration_Warnings_OK_Node
+                                    (Marker, Call_Attrs.Elab_Warnings_OK);
+      Set_Is_Ignored_Ghost_Node     (Marker, Call_Attrs.Ghost_Mode_Ignore);
+      Set_Is_Source_Call            (Marker, Call_Attrs.From_Source);
+      Set_Is_SPARK_Mode_On_Node     (Marker, Call_Attrs.SPARK_Mode_On);
 
       --  The marker is inserted prior to the original call. This placement has
       --  several desirable effects:
@@ -1758,35 +2265,96 @@
       Record_Elaboration_Scenario (Marker);
    end Build_Call_Marker;
 
+   -------------------------------------
+   -- Build_Variable_Reference_Marker --
+   -------------------------------------
+
+   procedure Build_Variable_Reference_Marker
+     (N     : Node_Id;
+      Read  : Boolean;
+      Write : Boolean)
+   is
+      Marker    : Node_Id;
+      Var_Attrs : Variable_Attributes;
+      Var_Id    : Entity_Id;
+
+   begin
+      Extract_Variable_Reference_Attributes
+        (Ref    => N,
+         Var_Id => Var_Id,
+         Attrs  => Var_Attrs);
+
+      Marker := Make_Variable_Reference_Marker (Sloc (N));
+
+      --  Inherit the attributes of the original variable reference
+
+      Set_Target   (Marker, Var_Id);
+      Set_Is_Read  (Marker, Read);
+      Set_Is_Write (Marker, Write);
+
+      --  The marker is inserted prior to the original variable reference. The
+      --  insertion must take place even when the reference does not occur in
+      --  the main unit to keep the tree symmetric. This ensures that internal
+      --  name serialization is consistent in case the variable marker causes
+      --  the tree to transform in some way.
+
+      Insert_Action (N, Marker);
+
+      --  The marker becomes the "corresponding" scenario for the reference.
+      --  Save the marker for later processing for the ABE phase.
+
+      Record_Elaboration_Scenario (Marker);
+   end Build_Variable_Reference_Marker;
+
    ---------------------------------
    -- Check_Elaboration_Scenarios --
    ---------------------------------
 
    procedure Check_Elaboration_Scenarios is
    begin
-      --  Nothing to do for ASIS. As a result, no ABE checks and diagnostics
-      --  are performed in this mode.
-
-      if ASIS_Mode then
-         return;
-      end if;
+      --  Nothing to do when switch -gnatH (legacy elaboration checking mode
+      --  enabled) is in effect because the legacy ABE mechanism does not need
+      --  to carry out this action.
+
+      if Legacy_Elaboration_Checks then
+         return;
+
+      --  Nothing to do for ASIS because ABE checks and diagnostics are not
+      --  performed in this mode.
+
+      elsif ASIS_Mode then
+         return;
+      end if;
+
+      --  Restore the original elaboration model which was in effect when the
+      --  scenarios were first recorded. The model may be specified by pragma
+      --  Elaboration_Checks which appears on the initial declaration of the
+      --  main unit.
+
+      Install_Elaboration_Model (Unit_Entity (Cunit_Entity (Main_Unit)));
 
       --  Examine the context of the main unit and record all units with prior
       --  elaboration with respect to it.
 
       Find_Elaborated_Units;
 
-      --  Examine each top level scenario saved during the Recording phase and
-      --  perform various actions depending on the elaboration model in effect.
+      --  Examine each top-level scenario saved during the Recording phase for
+      --  conditional ABEs and perform various actions depending on the model
+      --  in effect. The table of visited bodies is created for each new top-
+      --  level scenario.
 
       for Index in Top_Level_Scenarios.First .. Top_Level_Scenarios.Last loop
-
-         --  Clear the table of visited scenario bodies for each new top level
-         --  scenario.
-
-         Visited_Bodies.Reset;
-
-         Process_Scenario (Top_Level_Scenarios.Table (Index));
+         Reset_Visited_Bodies;
+
+         Process_Conditional_ABE (Top_Level_Scenarios.Table (Index));
+      end loop;
+
+      --  Examine each SPARK scenario saved during the Recording phase which
+      --  is not necessarily executable during elaboration, but still requires
+      --  elaboration-related checks.
+
+      for Index in SPARK_Scenarios.First .. SPARK_Scenarios.Last loop
+         Check_SPARK_Scenario (SPARK_Scenarios.Table (Index));
       end loop;
    end Check_Elaboration_Scenarios;
 
@@ -1852,7 +2420,7 @@
 
       Level := Find_Enclosing_Level (Call);
 
-      --  Library level calls are always considered because they are part of
+      --  Library-level calls are always considered because they are part of
       --  the associated unit's elaboration actions.
 
       if Level in Library_Level then
@@ -1883,6 +2451,627 @@
       end if;
    end Check_Preelaborated_Call;
 
+   ------------------------------
+   -- Check_SPARK_Derived_Type --
+   ------------------------------
+
+   procedure Check_SPARK_Derived_Type (Typ_Decl : Node_Id) is
+      Typ : constant Entity_Id := Defining_Entity (Typ_Decl);
+
+      --  NOTE: The routines within Check_SPARK_Derived_Type are intentionally
+      --  unnested to avoid deep indentation of code.
+
+      Stop_Check : exception;
+      --  This exception is raised when the freeze node violates the placement
+      --  rules.
+
+      procedure Check_Overriding_Primitive
+        (Prim  : Entity_Id;
+         FNode : Node_Id);
+      pragma Inline (Check_Overriding_Primitive);
+      --  Verify that freeze node FNode is within the early call region of
+      --  overriding primitive Prim's body.
+
+      function Freeze_Node_Location (FNode : Node_Id) return Source_Ptr;
+      pragma Inline (Freeze_Node_Location);
+      --  Return a more accurate source location associated with freeze node
+      --  FNode.
+
+      function Precedes_Source_Construct (N : Node_Id) return Boolean;
+      pragma Inline (Precedes_Source_Construct);
+      --  Determine whether arbitrary node N appears prior to some source
+      --  construct.
+
+      procedure Suggest_Elaborate_Body
+        (N         : Node_Id;
+         Body_Decl : Node_Id;
+         Error_Nod : Node_Id);
+      pragma Inline (Suggest_Elaborate_Body);
+      --  Suggest the use of pragma Elaborate_Body when the pragma will allow
+      --  for node N to appear within the early call region of subprogram body
+      --  Body_Decl. The suggestion is attached to Error_Nod as a continuation
+      --  error.
+
+      --------------------------------
+      -- Check_Overriding_Primitive --
+      --------------------------------
+
+      procedure Check_Overriding_Primitive
+        (Prim  : Entity_Id;
+         FNode : Node_Id)
+      is
+         Prim_Decl : constant Node_Id := Unit_Declaration_Node (Prim);
+         Body_Decl : Node_Id;
+         Body_Id   : Entity_Id;
+         Region    : Node_Id;
+
+      begin
+         --  Nothing to do for predefined primitives because they are artifacts
+         --  of tagged type expansion and cannot override source primitives.
+
+         if Is_Predefined_Dispatching_Operation (Prim) then
+            return;
+         end if;
+
+         Body_Id := Corresponding_Body (Prim_Decl);
+
+         --  Nothing to do when the primitive does not have a corresponding
+         --  body. This can happen when the unit with the bodies is not the
+         --  main unit subjected to ABE checks.
+
+         if No (Body_Id) then
+            return;
+
+         --  The primitive overrides a parent or progenitor primitive
+
+         elsif Present (Overridden_Operation (Prim)) then
+
+            --  Nothing to do when overriding an interface primitive happens by
+            --  inheriting a non-interface primitive as the check would be done
+            --  on the parent primitive.
+
+            if Present (Alias (Prim)) then
+               return;
+            end if;
+
+         --  Nothing to do when the primitive is not overriding. The body of
+         --  such a primitive cannot be targeted by a dispatching call which
+         --  is executable during elaboration, and cannot cause an ABE.
+
+         else
+            return;
+         end if;
+
+         Body_Decl := Unit_Declaration_Node (Body_Id);
+         Region    := Find_Early_Call_Region (Body_Decl);
+
+         --  The freeze node appears prior to the early call region of the
+         --  primitive body.
+
+         --  IMPORTANT: This check must always be performed even when -gnatd.v
+         --  (enforce SPARK elaboration rules in SPARK code) is not specified
+         --  because the static model cannot guarantee the absence of ABEs in
+         --  in the presence of dispatching calls.
+
+         if Earlier_In_Extended_Unit (FNode, Region) then
+            Error_Msg_Node_2 := Prim;
+            Error_Msg_NE
+              ("first freezing point of type & must appear within early call "
+               & "region of primitive body & (SPARK RM 7.7(8))",
+               Typ_Decl, Typ);
+
+            Error_Msg_Sloc := Sloc (Region);
+            Error_Msg_N ("\region starts #", Typ_Decl);
+
+            Error_Msg_Sloc := Sloc (Body_Decl);
+            Error_Msg_N ("\region ends #", Typ_Decl);
+
+            Error_Msg_Sloc := Freeze_Node_Location (FNode);
+            Error_Msg_N ("\first freezing point #", Typ_Decl);
+
+            --  If applicable, suggest the use of pragma Elaborate_Body in the
+            --  associated package spec.
+
+            Suggest_Elaborate_Body
+              (N         => FNode,
+               Body_Decl => Body_Decl,
+               Error_Nod => Typ_Decl);
+
+            raise Stop_Check;
+         end if;
+      end Check_Overriding_Primitive;
+
+      --------------------------
+      -- Freeze_Node_Location --
+      --------------------------
+
+      function Freeze_Node_Location (FNode : Node_Id) return Source_Ptr is
+         Context : constant Node_Id    := Parent (FNode);
+         Loc     : constant Source_Ptr := Sloc (FNode);
+
+         Prv_Decls : List_Id;
+         Vis_Decls : List_Id;
+
+      begin
+         --  In general, the source location of the freeze node is as close as
+         --  possible to the real freeze point, except when the freeze node is
+         --  at the "bottom" of a package spec.
+
+         if Nkind (Context) = N_Package_Specification then
+            Prv_Decls := Private_Declarations (Context);
+            Vis_Decls := Visible_Declarations (Context);
+
+            --  The freeze node appears in the private declarations of the
+            --  package.
+
+            if Present (Prv_Decls)
+              and then List_Containing (FNode) = Prv_Decls
+            then
+               null;
+
+            --  The freeze node appears in the visible declarations of the
+            --  package and there are no private declarations.
+
+            elsif Present (Vis_Decls)
+              and then List_Containing (FNode) = Vis_Decls
+              and then (No (Prv_Decls) or else Is_Empty_List (Prv_Decls))
+            then
+               null;
+
+            --  Otherwise the freeze node is not in the "last" declarative list
+            --  of the package. Use the existing source location of the freeze
+            --  node.
+
+            else
+               return Loc;
+            end if;
+
+            --  The freeze node appears at the "bottom" of the package when it
+            --  is in the "last" declarative list and is either the last in the
+            --  list or is followed by internal constructs only. In that case
+            --  the more appropriate source location is that of the package end
+            --  label.
+
+            if not Precedes_Source_Construct (FNode) then
+               return Sloc (End_Label (Context));
+            end if;
+         end if;
+
+         return Loc;
+      end Freeze_Node_Location;
+
+      -------------------------------
+      -- Precedes_Source_Construct --
+      -------------------------------
+
+      function Precedes_Source_Construct (N : Node_Id) return Boolean is
+         Decl : Node_Id;
+
+      begin
+         Decl := Next (N);
+         while Present (Decl) loop
+            if Comes_From_Source (Decl) then
+               return True;
+
+            --  A generated body for a source expression function is treated as
+            --  a source construct.
+
+            elsif Nkind (Decl) = N_Subprogram_Body
+              and then Was_Expression_Function (Decl)
+              and then Comes_From_Source (Original_Node (Decl))
+            then
+               return True;
+            end if;
+
+            Next (Decl);
+         end loop;
+
+         return False;
+      end Precedes_Source_Construct;
+
+      ----------------------------
+      -- Suggest_Elaborate_Body --
+      ----------------------------
+
+      procedure Suggest_Elaborate_Body
+        (N         : Node_Id;
+         Body_Decl : Node_Id;
+         Error_Nod : Node_Id)
+      is
+         Unt    : constant Node_Id := Unit (Cunit (Main_Unit));
+         Region : Node_Id;
+
+      begin
+         --  The suggestion applies only when the subprogram body resides in a
+         --  compilation package body, and a pragma Elaborate_Body would allow
+         --  for the node to appear in the early call region of the subprogram
+         --  body. This implies that all code from the subprogram body up to
+         --  the node is preelaborable.
+
+         if Nkind (Unt) = N_Package_Body then
+
+            --  Find the start of the early call region again assuming that the
+            --  package spec has pragma Elaborate_Body. Note that the internal
+            --  data structures are intentionally not updated because this is a
+            --  speculative search.
+
+            Region :=
+              Find_Early_Call_Region
+                (Body_Decl        => Body_Decl,
+                 Assume_Elab_Body => True,
+                 Skip_Memoization => True);
+
+            --  If the node appears within the early call region, assuming that
+            --  the package spec carries pragma Elaborate_Body, then it is safe
+            --  to suggest the pragma.
+
+            if Earlier_In_Extended_Unit (Region, N) then
+               Error_Msg_Name_1 := Name_Elaborate_Body;
+               Error_Msg_NE
+                 ("\consider adding pragma % in spec of unit &",
+                  Error_Nod, Defining_Entity (Unt));
+            end if;
+         end if;
+      end Suggest_Elaborate_Body;
+
+      --  Local variables
+
+      FNode : constant Node_Id  := Freeze_Node (Typ);
+      Prims : constant Elist_Id := Direct_Primitive_Operations (Typ);
+
+      Prim_Elmt : Elmt_Id;
+
+   --  Start of processing for Check_SPARK_Derived_Type
+
+   begin
+      --  A type should have its freeze node set by the time SPARK scenarios
+      --  are being verified.
+
+      pragma Assert (Present (FNode));
+
+      --  Verify that the freeze node of the derived type is within the early
+      --  call region of each overriding primitive body (SPARK RM 7.7(8)).
+
+      if Present (Prims) then
+         Prim_Elmt := First_Elmt (Prims);
+         while Present (Prim_Elmt) loop
+            Check_Overriding_Primitive
+              (Prim  => Node (Prim_Elmt),
+               FNode => FNode);
+
+            Next_Elmt (Prim_Elmt);
+         end loop;
+      end if;
+
+   exception
+      when Stop_Check =>
+         null;
+   end Check_SPARK_Derived_Type;
+
+   -------------------------------
+   -- Check_SPARK_Instantiation --
+   -------------------------------
+
+   procedure Check_SPARK_Instantiation (Exp_Inst : Node_Id) is
+      Gen_Attrs  : Target_Attributes;
+      Gen_Id     : Entity_Id;
+      Inst       : Node_Id;
+      Inst_Attrs : Instantiation_Attributes;
+      Inst_Id    : Entity_Id;
+
+   begin
+      Extract_Instantiation_Attributes
+        (Exp_Inst => Exp_Inst,
+         Inst     => Inst,
+         Inst_Id  => Inst_Id,
+         Gen_Id   => Gen_Id,
+         Attrs    => Inst_Attrs);
+
+      Extract_Target_Attributes (Gen_Id, Gen_Attrs);
+
+      --  The instantiation and the generic body are both in the main unit
+
+      if Present (Gen_Attrs.Body_Decl)
+        and then In_Extended_Main_Code_Unit (Gen_Attrs.Body_Decl)
+
+        --  If the instantiation appears prior to the generic body, then the
+        --  instantiation is illegal (SPARK RM 7.7(6)).
+
+        --  IMPORTANT: This check must always be performed even when -gnatd.v
+        --  (enforce SPARK elaboration rules in SPARK code) is not specified
+        --  because the rule prevents use-before-declaration of objects that
+        --  may precede the generic body.
+
+        and then Earlier_In_Extended_Unit (Inst, Gen_Attrs.Body_Decl)
+      then
+         Error_Msg_NE ("cannot instantiate & before body seen", Inst, Gen_Id);
+      end if;
+   end Check_SPARK_Instantiation;
+
+   ---------------------------------
+   -- Check_SPARK_Model_In_Effect --
+   ---------------------------------
+
+   SPARK_Model_Warning_Posted : Boolean := False;
+   --  This flag prevents the same SPARK model-related warning from being
+   --  emitted multiple times.
+
+   procedure Check_SPARK_Model_In_Effect (N : Node_Id) is
+   begin
+      --  Do not emit the warning multiple times as this creates useless noise
+
+      if SPARK_Model_Warning_Posted then
+         null;
+
+      --  SPARK rule verification requires the "strict" static model
+
+      elsif Static_Elaboration_Checks and not Relaxed_Elaboration_Checks then
+         null;
+
+      --  Any other combination of models does not guarantee the absence of ABE
+      --  problems for SPARK rule verification purposes. Note that there is no
+      --  need to check for the legacy ABE mechanism because the legacy code
+      --  has its own orthogonal processing for SPARK rules.
+
+      else
+         SPARK_Model_Warning_Posted := True;
+
+         Error_Msg_N
+           ("??SPARK elaboration checks require static elaboration model", N);
+
+         if Dynamic_Elaboration_Checks then
+            Error_Msg_N ("\dynamic elaboration model is in effect", N);
+         else
+            pragma Assert (Relaxed_Elaboration_Checks);
+            Error_Msg_N ("\relaxed elaboration model is in effect", N);
+         end if;
+      end if;
+   end Check_SPARK_Model_In_Effect;
+
+   --------------------------
+   -- Check_SPARK_Scenario --
+   --------------------------
+
+   procedure Check_SPARK_Scenario (N : Node_Id) is
+   begin
+      --  Ensure that a suitable elaboration model is in effect for SPARK rule
+      --  verification.
+
+      Check_SPARK_Model_In_Effect (N);
+
+      --  Add the current scenario to the stack of active scenarios
+
+      Push_Active_Scenario (N);
+
+      if Is_Suitable_SPARK_Derived_Type (N) then
+         Check_SPARK_Derived_Type (N);
+
+      elsif Is_Suitable_SPARK_Instantiation (N) then
+         Check_SPARK_Instantiation (N);
+
+      elsif Is_Suitable_SPARK_Refined_State_Pragma (N) then
+         Check_SPARK_Refined_State_Pragma (N);
+      end if;
+
+      --  Remove the current scenario from the stack of active scenarios once
+      --  all ABE diagnostics and checks have been performed.
+
+      Pop_Active_Scenario (N);
+   end Check_SPARK_Scenario;
+
+   --------------------------------------
+   -- Check_SPARK_Refined_State_Pragma --
+   --------------------------------------
+
+   procedure Check_SPARK_Refined_State_Pragma (N : Node_Id) is
+
+      --  NOTE: The routines within Check_SPARK_Refined_State_Pragma are
+      --  intentionally unnested to avoid deep indentation of code.
+
+      procedure Check_SPARK_Constituent (Constit_Id : Entity_Id);
+      pragma Inline (Check_SPARK_Constituent);
+      --  Ensure that a single constituent Constit_Id is elaborated prior to
+      --  the main unit.
+
+      procedure Check_SPARK_Constituents (Constits : Elist_Id);
+      pragma Inline (Check_SPARK_Constituents);
+      --  Ensure that all constituents found in list Constits are elaborated
+      --  prior to the main unit.
+
+      procedure Check_SPARK_Initialized_State (State : Node_Id);
+      pragma Inline (Check_SPARK_Initialized_State);
+      --  Ensure that the constituents of single abstract state State are
+      --  elaborated prior to the main unit.
+
+      procedure Check_SPARK_Initialized_States (Pack_Id : Entity_Id);
+      pragma Inline (Check_SPARK_Initialized_States);
+      --  Ensure that the constituents of all abstract states which appear in
+      --  the Initializes pragma of package Pack_Id are elaborated prior to the
+      --  main unit.
+
+      -----------------------------
+      -- Check_SPARK_Constituent --
+      -----------------------------
+
+      procedure Check_SPARK_Constituent (Constit_Id : Entity_Id) is
+         Prag : Node_Id;
+
+      begin
+         --  Nothing to do for "null" constituents
+
+         if Nkind (Constit_Id) = N_Null then
+            return;
+
+         --  Nothing to do for illegal constituents
+
+         elsif Error_Posted (Constit_Id) then
+            return;
+         end if;
+
+         Prag := SPARK_Pragma (Constit_Id);
+
+         --  The check applies only when the constituent is subject to pragma
+         --  SPARK_Mode On.
+
+         if Present (Prag)
+           and then Get_SPARK_Mode_From_Annotation (Prag) = On
+         then
+            --  An external constituent of an abstract state which appears in
+            --  the Initializes pragma of a package spec imposes an Elaborate
+            --  requirement on the context of the main unit. Determine whether
+            --  the context has a pragma strong enough to meet the requirement.
+
+            --  IMPORTANT: This check is performed only when -gnatd.v (enforce
+            --  SPARK elaboration rules in SPARK code) is in effect because the
+            --  static model can ensure the prior elaboration of the unit which
+            --  contains a constituent by installing implicit Elaborate pragma.
+
+            if Debug_Flag_Dot_V then
+               Meet_Elaboration_Requirement
+                 (N         => N,
+                  Target_Id => Constit_Id,
+                  Req_Nam   => Name_Elaborate);
+
+            --  Otherwise ensure that the unit with the external constituent is
+            --  elaborated prior to the main unit.
+
+            else
+               Ensure_Prior_Elaboration
+                 (N        => N,
+                  Unit_Id  => Find_Top_Unit (Constit_Id),
+                  Prag_Nam => Name_Elaborate,
+                  State    => Initial_State);
+            end if;
+         end if;
+      end Check_SPARK_Constituent;
+
+      ------------------------------
+      -- Check_SPARK_Constituents --
+      ------------------------------
+
+      procedure Check_SPARK_Constituents (Constits : Elist_Id) is
+         Constit_Elmt : Elmt_Id;
+
+      begin
+         if Present (Constits) then
+            Constit_Elmt := First_Elmt (Constits);
+            while Present (Constit_Elmt) loop
+               Check_SPARK_Constituent (Node (Constit_Elmt));
+               Next_Elmt (Constit_Elmt);
+            end loop;
+         end if;
+      end Check_SPARK_Constituents;
+
+      -----------------------------------
+      -- Check_SPARK_Initialized_State --
+      -----------------------------------
+
+      procedure Check_SPARK_Initialized_State (State : Node_Id) is
+         Prag     : Node_Id;
+         State_Id : Entity_Id;
+
+      begin
+         --  Nothing to do for "null" initialization items
+
+         if Nkind (State) = N_Null then
+            return;
+
+         --  Nothing to do for illegal states
+
+         elsif Error_Posted (State) then
+            return;
+         end if;
+
+         State_Id := Entity_Of (State);
+
+         --  Sanitize the state
+
+         if No (State_Id) then
+            return;
+
+         elsif Error_Posted (State_Id) then
+            return;
+
+         elsif Ekind (State_Id) /= E_Abstract_State then
+            return;
+         end if;
+
+         --  The check is performed only when the abstract state is subject to
+         --  SPARK_Mode On.
+
+         Prag := SPARK_Pragma (State_Id);
+
+         if Present (Prag)
+           and then Get_SPARK_Mode_From_Annotation (Prag) = On
+         then
+            Check_SPARK_Constituents (Refinement_Constituents (State_Id));
+         end if;
+      end Check_SPARK_Initialized_State;
+
+      ------------------------------------
+      -- Check_SPARK_Initialized_States --
+      ------------------------------------
+
+      procedure Check_SPARK_Initialized_States (Pack_Id : Entity_Id) is
+         Prag  : constant Node_Id := Get_Pragma (Pack_Id, Pragma_Initializes);
+         Init  : Node_Id;
+         Inits : Node_Id;
+
+      begin
+         if Present (Prag) then
+            Inits := Expression (Get_Argument (Prag, Pack_Id));
+
+            --  Avoid processing a "null" initialization list. The only other
+            --  alternative is an aggregate.
+
+            if Nkind (Inits) = N_Aggregate then
+
+               --  The initialization items appear in list form:
+               --
+               --    (state1, state2)
+
+               if Present (Expressions (Inits)) then
+                  Init := First (Expressions (Inits));
+                  while Present (Init) loop
+                     Check_SPARK_Initialized_State (Init);
+                     Next (Init);
+                  end loop;
+               end if;
+
+               --  The initialization items appear in associated form:
+               --
+               --    (state1 => item1,
+               --     state2 => (item2, item3))
+
+               if Present (Component_Associations (Inits)) then
+                  Init := First (Component_Associations (Inits));
+                  while Present (Init) loop
+                     Check_SPARK_Initialized_State (Init);
+                     Next (Init);
+                  end loop;
+               end if;
+            end if;
+         end if;
+      end Check_SPARK_Initialized_States;
+
+      --  Local variables
+
+      Pack_Body : constant Node_Id := Find_Related_Package_Or_Body (N);
+
+   --  Start of processing for Check_SPARK_Refined_State_Pragma
+
+   begin
+      --  Pragma Refined_State must be associated with a package body
+
+      pragma Assert
+        (Present (Pack_Body) and then Nkind (Pack_Body) = N_Package_Body);
+
+      --  Verify that each external contitunent of an abstract state mentioned
+      --  in pragma Initializes is properly elaborated.
+
+      Check_SPARK_Initialized_States (Unique_Defining_Entity (Pack_Body));
+   end Check_SPARK_Refined_State_Pragma;
+
    ----------------------
    -- Compilation_Unit --
    ----------------------
@@ -1931,6 +3120,36 @@
       return Comp_Unit;
    end Compilation_Unit;
 
+   -----------------------
+   -- Early_Call_Region --
+   -----------------------
+
+   function Early_Call_Region (Body_Id : Entity_Id) return Node_Id is
+   begin
+      pragma Assert (Ekind_In (Body_Id, E_Entry,
+                                        E_Entry_Family,
+                                        E_Function,
+                                        E_Procedure,
+                                        E_Subprogram_Body));
+
+      if Early_Call_Regions_In_Use then
+         return Early_Call_Regions.Get (Body_Id);
+      end if;
+
+      return Early_Call_Regions_No_Element;
+   end Early_Call_Region;
+
+   -----------------------------
+   -- Early_Call_Regions_Hash --
+   -----------------------------
+
+   function Early_Call_Regions_Hash
+     (Key : Entity_Id) return Early_Call_Regions_Index
+   is
+   begin
+      return Early_Call_Regions_Index (Key mod Early_Call_Regions_Max);
+   end Early_Call_Regions_Hash;
+
    -----------------
    -- Elab_Msg_NE --
    -----------------
@@ -1980,66 +3199,63 @@
       Error_Msg_NE (Prefix & Msg & Suffix, N, Id);
    end Elab_Msg_NE;
 
-   ------------------------------
-   -- Elaboration_Context_Hash --
-   ------------------------------
-
-   function Elaboration_Context_Hash
-     (Key : Entity_Id) return Elaboration_Context_Index
+   ------------------------
+   -- Elaboration_Status --
+   ------------------------
+
+   function Elaboration_Status
+     (Unit_Id : Entity_Id) return Elaboration_Attributes
    is
    begin
-      return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
-   end Elaboration_Context_Hash;
+      if Elaboration_Statuses_In_Use then
+         return Elaboration_Statuses.Get (Unit_Id);
+      end if;
+
+      return Elaboration_Statuses_No_Element;
+   end Elaboration_Status;
+
+   -------------------------------
+   -- Elaboration_Statuses_Hash --
+   -------------------------------
+
+   function Elaboration_Statuses_Hash
+     (Key : Entity_Id) return Elaboration_Statuses_Index
+   is
+   begin
+      return Elaboration_Statuses_Index (Key mod Elaboration_Statuses_Max);
+   end Elaboration_Statuses_Hash;
 
    ------------------------------
    -- Ensure_Prior_Elaboration --
    ------------------------------
 
    procedure Ensure_Prior_Elaboration
-     (N            : Node_Id;
-      Unit_Id      : Entity_Id;
-      In_Task_Body : Boolean)
-   is
+     (N        : Node_Id;
+      Unit_Id  : Entity_Id;
       Prag_Nam : Name_Id;
-
-   begin
-      --  Instantiating an external generic unit requires an implicit Elaborate
-      --  because Elaborate_All is too strong and could introduce non-existent
-      --  elaboration cycles.
-
-      --    package External is
-      --       function Func ...;
-      --    end External;
-
-      --    with External;
-      --    generic
-      --    package Gen is
-      --       X : ... := External.Func;
-      --    end Gen;
-
-      --   [with External;]                      --  implicit with for External
-      --   [pragma Elaborate_All (External);]    --  Elaborate_All for External
-      --    with Gen;
-      --   [pragma Elaborate (Gen);]             --  Elaborate for generic
-      --    procedure Main is
-      --       package Inst is new Gen;          --  calls External.Func
-      --       ...
-      --    end Main;
-
-      if Nkind (N) in N_Generic_Instantiation then
-         Prag_Nam := Name_Elaborate;
-
-      --  Otherwise generate an implicit Elaborate_All
-
-      else
-         Prag_Nam := Name_Elaborate_All;
-      end if;
+      State    : Processing_Attributes)
+   is
+   begin
+      pragma Assert (Nam_In (Prag_Nam, Name_Elaborate, Name_Elaborate_All));
+
+      --  Nothing to do when the caller has suppressed the generation of
+      --  implicit Elaborate[_All] pragmas.
+
+      if State.Suppress_Implicit_Pragmas then
+         return;
+
+      --  Nothing to do when the need for prior elaboration came from a partial
+      --  finalization routine which occurs in an initialization context. This
+      --  behaviour parallels that of the old ABE mechanism.
+
+      elsif State.Within_Partial_Finalization then
+         return;
 
       --  Nothing to do when the need for prior elaboration came from a task
       --  body and switch -gnatd.y (disable implicit pragma Elaborate_All on
       --  task bodies) is in effect.
 
-      if Debug_Flag_Dot_Y and then In_Task_Body then
+      elsif Debug_Flag_Dot_Y and then State.Within_Task_Body then
          return;
 
       --  Nothing to do when the unit is elaborated prior to the main unit.
@@ -2170,7 +3386,7 @@
    --  Start of processing for Ensure_Prior_Elaboration_Dynamic
 
    begin
-      Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+      Elab_Attrs := Elaboration_Status (Unit_Id);
 
       --  Nothing to do when the unit is guaranteed prior elaboration by means
       --  of a source Elaborate[_All] pragma.
@@ -2299,9 +3515,6 @@
       Loc        : constant Source_Ptr := Sloc (Main_Cunit);
       Unit_Cunit : constant Node_Id    := Compilation_Unit (Unit_Id);
 
-      Is_Instantiation : constant Boolean :=
-                           Nkind (N) in N_Generic_Instantiation;
-
       Clause     : Node_Id;
       Elab_Attrs : Elaboration_Attributes;
       Items      : List_Id;
@@ -2309,7 +3522,7 @@
    --  Start of processing for Ensure_Prior_Elaboration_Static
 
    begin
-      Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+      Elab_Attrs := Elaboration_Status (Unit_Id);
 
       --  Nothing to do when the unit is guaranteed prior elaboration by means
       --  of a source Elaborate[_All] pragma.
@@ -2374,14 +3587,10 @@
          Append_To (Items, Clause);
       end if;
 
-      --  Instantiations require an implicit Elaborate because Elaborate_All is
-      --  too conservative and may introduce non-existent elaboration cycles.
-
-      if Is_Instantiation then
+      --  Mark the with clause depending on the pragma required
+
+      if Prag_Nam = Name_Elaborate then
          Set_Elaborate_Desirable (Clause);
-
-      --  Otherwise generate an implicit Elaborate_All
-
       else
          Set_Elaborate_All_Desirable (Clause);
       end if;
@@ -2389,9 +3598,10 @@
       --  The implicit Elaborate[_All] ensures the prior elaboration of the
       --  unit. Include the unit in the elaboration context of the main unit.
 
-      Elaboration_Context.Set (Unit_Id,
-        Elaboration_Attributes'(Source_Pragma => Empty,
-                                With_Clause   => Clause));
+      Set_Elaboration_Status
+        (Unit_Id => Unit_Id,
+         Val     => Elaboration_Attributes'(Source_Pragma => Empty,
+                                            With_Clause   => Clause));
 
       --  Output extra information on an implicit Elaborate[_All] pragma when
       --  switch -gnatel (info messages on implicit Elaborate[_All] pragmas is
@@ -2482,6 +3692,7 @@
       --  Set all attributes
 
       Attrs.Elab_Checks_OK    := Is_Elaboration_Checks_OK_Node (Call);
+      Attrs.Elab_Warnings_OK  := Is_Elaboration_Warnings_OK_Node (Call);
       Attrs.From_Source       := From_Source;
       Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Node (Call);
       Attrs.In_Declarations   := In_Declarations;
@@ -2568,8 +3779,8 @@
       Attrs    : out Instantiation_Attributes)
    is
    begin
-      Inst     := Original_Node (Exp_Inst);
-      Inst_Id  := Defining_Entity (Inst);
+      Inst    := Original_Node (Exp_Inst);
+      Inst_Id := Defining_Entity (Inst);
 
       --  Traverse a possible chain of renamings to obtain the original generic
       --  being instantiatied.
@@ -2579,6 +3790,7 @@
       --  Set all attributes
 
       Attrs.Elab_Checks_OK    := Is_Elaboration_Checks_OK_Node (Inst);
+      Attrs.Elab_Warnings_OK  := Is_Elaboration_Warnings_OK_Node (Inst);
       Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Node (Inst);
       Attrs.In_Declarations   := Is_Declaration_Level_Node (Inst);
       Attrs.SPARK_Mode_On     := Is_SPARK_Mode_On_Node (Inst);
@@ -2859,6 +4071,7 @@
       Attrs.Body_Barf         := Body_Barf;
       Attrs.Body_Decl         := Body_Decl;
       Attrs.Elab_Checks_OK    := Is_Elaboration_Checks_OK_Id (Target_Id);
+      Attrs.Elab_Warnings_OK  := Is_Elaboration_Warnings_OK_Id (Target_Id);
       Attrs.From_Source       := Comes_From_Source (Target_Id);
       Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Entity (Target_Id);
       Attrs.SPARK_Mode_On     :=
@@ -2909,6 +4122,7 @@
 
       Attrs.Body_Decl         := Body_Decl;
       Attrs.Elab_Checks_OK    := Is_Elaboration_Checks_OK_Id (Task_Typ);
+      Attrs.Elab_Warnings_OK  := Is_Elaboration_Warnings_OK_Id (Task_Typ);
       Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Entity (Task_Typ);
       Attrs.SPARK_Mode_On     :=
         Present (Prag) and then Get_SPARK_Mode_From_Annotation (Prag) = On;
@@ -2932,14 +4146,45 @@
       Var_Id : out Entity_Id;
       Attrs  : out Variable_Attributes)
    is
-   begin
-      --  Traverse a possible chain of renamings to obtain the original
-      --  variable being referenced.
-
-      Var_Id := Get_Renamed_Entity (Entity (Ref));
-
-      Attrs.SPARK_Mode_On := Is_SPARK_Mode_On_Node (Ref);
-      Attrs.Unit_Id       := Find_Top_Unit (Var_Id);
+      function Get_Renamed_Variable (Id : Entity_Id) return Entity_Id;
+      --  Obtain the ultimate renamed variable of variable Id
+
+      --------------------------
+      -- Get_Renamed_Variable --
+      --------------------------
+
+      function Get_Renamed_Variable (Id : Entity_Id) return Entity_Id is
+         Ren_Id : Entity_Id;
+
+      begin
+         Ren_Id := Id;
+         while Present (Renamed_Entity (Ren_Id))
+           and then Nkind (Renamed_Entity (Ren_Id)) in N_Entity
+         loop
+            Ren_Id := Renamed_Entity (Ren_Id);
+         end loop;
+
+         return Ren_Id;
+      end Get_Renamed_Variable;
+
+   --  Start of processing for Extract_Variable_Reference_Attributes
+
+   begin
+      --  Extraction for variable reference markers
+
+      if Nkind (Ref) = N_Variable_Reference_Marker then
+         Var_Id := Target (Ref);
+
+      --  Extraction for expanded names and identifiers
+
+      else
+         Var_Id := Entity (Ref);
+      end if;
+
+      --  Obtain the original variable which the reference mentions
+
+      Var_Id        := Get_Renamed_Variable (Var_Id);
+      Attrs.Unit_Id := Find_Top_Unit (Var_Id);
 
       --  At this point certain attributes should always be available
 
@@ -2955,6 +4200,847 @@
       return Find_Unit_Entity (Unit (Cunit (Get_Code_Unit (N))));
    end Find_Code_Unit;
 
+   ----------------------------
+   -- Find_Early_Call_Region --
+   ----------------------------
+
+   function Find_Early_Call_Region
+     (Body_Decl        : Node_Id;
+      Assume_Elab_Body : Boolean := False;
+      Skip_Memoization : Boolean := False) return Node_Id
+   is
+      --  NOTE: The routines within Find_Early_Call_Region are intentionally
+      --  unnested to avoid deep indentation of code.
+
+      ECR_Found : exception;
+      --  This exception is raised when the early call region has been found
+
+      Start : Node_Id := Empty;
+      --  The start of the early call region. This variable is updated by the
+      --  various nested routines. Due to the use of exceptions, the variable
+      --  must be global to the nested routines.
+
+      --  The algorithm implemented in this routine attempts to find the early
+      --  call region of a subprogram body by inspecting constructs in reverse
+      --  declarative order, while navigating the tree. The algorithm consists
+      --  of an Inspection phase and an Advancement phase. The pseudocode is as
+      --  follows:
+      --
+      --    loop
+      --       inspection phase
+      --       advancement phase
+      --    end loop
+      --
+      --  The infinite loop is terminated by raising exception ECR_Found. The
+      --  algorithm utilizes two pointers, Curr and Start, to represent the
+      --  current construct to inspect and the start of the early call region.
+      --
+      --  IMPORTANT: The algorithm must maintain the following invariant at all
+      --  time for it to function properly - a nested construct is entered only
+      --  when it contains suitable constructs. This guarantees that leaving a
+      --  nested or encapsulating construct functions properly.
+      --
+      --  The Inspection phase determines whether the current construct is non-
+      --  preelaborable, and if it is, the algorithm terminates.
+      --
+      --  The Advancement phase walks the tree in reverse declarative order,
+      --  while entering and leaving nested and encapsulating constructs. It
+      --  may also terminate the elaborithm. There are several special cases
+      --  of advancement.
+      --
+      --  1) General case:
+      --
+      --    <construct 1>
+      --     ...
+      --    <construct N-1>                      <- Curr
+      --    <construct N>                        <- Start
+      --    <subprogram body>
+      --
+      --  In the general case, a declarative or statement list is traversed in
+      --  reverse order where Curr is the lead pointer, and Start indicates the
+      --  last preelaborable construct.
+      --
+      --  2) Entering handled bodies
+      --
+      --    package body Nested is               <- Curr (2.3)
+      --       <declarations>                    <- Curr (2.2)
+      --    begin
+      --       <statements>                      <- Curr (2.1)
+      --    end Nested;
+      --    <construct>                          <- Start
+      --
+      --  In this case, the algorithm enters a handled body by starting from
+      --  the last statement (2.1), or the last declaration (2.2), or the body
+      --  is consumed (2.3) because it is empty and thus preelaborable.
+      --
+      --  3) Entering package declarations
+      --
+      --    package Nested is                    <- Curr (2.3)
+      --       <visible declarations>            <- Curr (2.2)
+      --    private
+      --       <private declarations>            <- Curr (2.1)
+      --    end Nested;
+      --    <construct>                          <- Start
+      --
+      --  In this case, the algorithm enters a package declaration by starting
+      --  from the last private declaration (2.1), the last visible declaration
+      --  (2.2), or the package is consumed (2.3) because it is empty and thus
+      --  preelaborable.
+      --
+      --  4) Transitioning from list to list of the same construct
+      --
+      --  Certain constructs have two eligible lists. The algorithm must thus
+      --  transition from the second to the first list when the second list is
+      --  exhausted.
+      --
+      --    declare                              <- Curr (4.2)
+      --       <declarations>                    <- Curr (4.1)
+      --    begin
+      --       <statements>                      <- Start
+      --    end;
+      --
+      --  In this case, the algorithm has exhausted the second list (statements
+      --  in the example), and continues with the last declaration (4.1) or the
+      --  construct is consumed (4.2) because it contains only preelaborable
+      --  code.
+      --
+      --  5) Transitioning from list to construct
+      --
+      --    tack body Task is                    <- Curr (5.1)
+      --                                         <- Curr (Empty)
+      --       <construct 1>                     <- Start
+      --
+      --  In this case, the algorithm has exhausted a list, Curr is Empty, and
+      --  the owner of the list is consumed (5.1).
+      --
+      --  6) Transitioning from unit to unit
+      --
+      --  A package body with a spec subject to pragma Elaborate_Body extends
+      --  the possible range of the early call region to the package spec.
+      --
+      --    package Pack is                      <- Curr (6.3)
+      --       pragma Elaborate_Body;            <- Curr (6.2)
+      --       <visible declarations>            <- Curr (6.2)
+      --    private
+      --       <private declarations>            <- Curr (6.1)
+      --    end Pack;
+      --
+      --    package body Pack is                 <- Curr, Start
+      --
+      --  In this case, the algorithm has reached a package body compilation
+      --  unit whose spec is subject to pragma Elaborate_Body, or the caller
+      --  of the algorithm has specified this behavior. This transition is
+      --  equivalent to 3).
+      --
+      --  7) Transitioning from unit to termination
+      --
+      --  Reaching a compilation unit always terminates the algorithm as there
+      --  are no more lists to examine. This must take 6) into account.
+      --
+      --  8) Transitioning from subunit to stub
+      --
+      --    package body Pack is separate;       <- Curr (8.1)
+      --
+      --    separate (...)
+      --    package body Pack is                 <- Curr, Start
+      --
+      --  Reaching a subunit continues the search from the corresponding stub
+      --  (8.1).
+
+      procedure Advance (Curr : in out Node_Id);
+      pragma Inline (Advance);
+      --  Update the Curr and Start pointers depending on their location in the
+      --  tree to the next eligible construct. This routine raises ECR_Found.
+
+      procedure Enter_Handled_Body (Curr : in out Node_Id);
+      pragma Inline (Enter_Handled_Body);
+      --  Update the Curr and Start pointers to enter a nested handled body if
+      --  applicable. This routine raises ECR_Found.
+
+      procedure Enter_Package_Declaration (Curr : in out Node_Id);
+      pragma Inline (Enter_Package_Declaration);
+      --  Update the Curr and Start pointers to enter a nested package spec if
+      --  applicable. This routine raises ECR_Found.
+
+      function Find_ECR (N : Node_Id) return Node_Id;
+      pragma Inline (Find_ECR);
+      --  Find an early call region starting from arbitrary node N
+
+      function Has_Suitable_Construct (List : List_Id) return Boolean;
+      pragma Inline (Has_Suitable_Construct);
+      --  Determine whether list List contains at least one suitable construct
+      --  for inclusion into an early call region.
+
+      procedure Include (N : Node_Id; Curr : out Node_Id);
+      pragma Inline (Include);
+      --  Update the Curr and Start pointers to include arbitrary construct N
+      --  in the early call region. This routine raises ECR_Found.
+
+      function Is_OK_Preelaborable_Construct (N : Node_Id) return Boolean;
+      pragma Inline (Is_OK_Preelaborable_Construct);
+      --  Determine whether arbitrary node N denotes a preelaboration-safe
+      --  construct.
+
+      function Is_Suitable_Construct (N : Node_Id) return Boolean;
+      pragma Inline (Is_Suitable_Construct);
+      --  Determine whether arbitrary node N denotes a suitable construct for
+      --  inclusion into the early call region.
+
+      procedure Transition_Body_Declarations
+        (Bod  : Node_Id;
+         Curr : out Node_Id);
+      pragma Inline (Transition_Body_Declarations);
+      --  Update the Curr and Start pointers when construct Bod denotes a block
+      --  statement or a suitable body. This routine raises ECR_Found.
+
+      procedure Transition_Handled_Statements
+        (HSS  : Node_Id;
+         Curr : out Node_Id);
+      pragma Inline (Transition_Handled_Statements);
+      --  Update the Curr and Start pointers when node HSS denotes a handled
+      --  sequence of statements. This routine raises ECR_Found.
+
+      procedure Transition_Spec_Declarations
+        (Spec : Node_Id;
+         Curr : out Node_Id);
+      pragma Inline (Transition_Spec_Declarations);
+      --  Update the Curr and Start pointers when construct Spec denotes
+      --  a concurrent definition or a package spec. This routine raises
+      --  ECR_Found.
+
+      procedure Transition_Unit (Unit : Node_Id; Curr : out Node_Id);
+      pragma Inline (Transition_Unit);
+      --  Update the Curr and Start pointers when node Unit denotes a potential
+      --  compilation unit. This routine raises ECR_Found.
+
+      -------------
+      -- Advance --
+      -------------
+
+      procedure Advance (Curr : in out Node_Id) is
+         Context : Node_Id;
+
+      begin
+         --  Curr denotes one of the following cases upon entry into this
+         --  routine:
+         --
+         --    * Empty - There is no current construct when a declarative or a
+         --      statement list has been exhausted. This does not necessarily
+         --      indicate that the early call region has been computed as it
+         --      may still be possible to transition to another list.
+         --
+         --    * Encapsulator - The current construct encapsulates declarations
+         --      and/or statements. This indicates that the early call region
+         --      may extend within the nested construct.
+         --
+         --    * Preelaborable - The current construct is always preelaborable
+         --      because Find_ECR would not invoke Advance if this was not the
+         --      case.
+
+         --  The current construct is an encapsulator or is preelaborable
+
+         if Present (Curr) then
+
+            --  Enter encapsulators by inspecting their declarations and/or
+            --  statements.
+
+            if Nkind_In (Curr, N_Block_Statement, N_Package_Body) then
+               Enter_Handled_Body (Curr);
+
+            elsif Nkind (Curr) = N_Package_Declaration then
+               Enter_Package_Declaration (Curr);
+
+            --  Early call regions have a property which can be exploited to
+            --  optimize the algorithm.
+            --
+            --    <preceding subprogram body>
+            --    <preelaborable construct 1>
+            --     ...
+            --    <preelaborable construct N>
+            --    <initiating subprogram body>
+            --
+            --  If a traversal initiated from a subprogram body reaches a
+            --  preceding subprogram body, then both bodies share the same
+            --  early call region.
+            --
+            --  The property results in the following desirable effects:
+            --
+            --  * If the preceding body already has an early call region, then
+            --    the initiating body can reuse it. This minimizes the amount
+            --    of processing performed by the algorithm.
+            --
+            --  * If the preceding body lack an early call region, then the
+            --    algorithm can compute the early call region, and reuse it
+            --    for the initiating body. This processing performs the same
+            --    amount of work, but has the beneficial effect of computing
+            --    the early call regions of all preceding bodies.
+
+            elsif Nkind_In (Curr, N_Entry_Body, N_Subprogram_Body) then
+               Start :=
+                 Find_Early_Call_Region
+                   (Body_Decl        => Curr,
+                    Assume_Elab_Body => Assume_Elab_Body,
+                    Skip_Memoization => Skip_Memoization);
+
+               raise ECR_Found;
+
+            --  Otherwise current construct is preelaborable. Unpdate the early
+            --  call region to include it.
+
+            else
+               Include (Curr, Curr);
+            end if;
+
+         --  Otherwise the current construct is missing, indicating that the
+         --  current list has been exhausted. Depending on the context of the
+         --  list, several transitions are possible.
+
+         else
+            --  The invariant of the algorithm ensures that Curr and Start are
+            --  at the same level of nesting at the point of a transition. The
+            --  algorithm can determine which list the traversal came from by
+            --  examining Start.
+
+            Context := Parent (Start);
+
+            --  Attempt the following transitions:
+            --
+            --    private declarations -> visible declarations
+            --    private declarations -> upper level
+            --    private declarations -> terminate
+            --    visible declarations -> upper level
+            --    visible declarations -> terminate
+
+            if Nkind_In (Context, N_Package_Specification,
+                                  N_Protected_Definition,
+                                  N_Task_Definition)
+            then
+               Transition_Spec_Declarations (Context, Curr);
+
+            --  Attempt the following transitions:
+            --
+            --    statements -> declarations
+            --    statements -> upper level
+            --    statements -> corresponding package spec (Elab_Body)
+            --    statements -> terminate
+
+            elsif Nkind (Context) = N_Handled_Sequence_Of_Statements then
+               Transition_Handled_Statements (Context, Curr);
+
+            --  Attempt the following transitions:
+            --
+            --    declarations -> upper level
+            --    declarations -> corresponding package spec (Elab_Body)
+            --    declarations -> terminate
+
+            elsif Nkind_In (Context, N_Block_Statement,
+                                     N_Entry_Body,
+                                     N_Package_Body,
+                                     N_Protected_Body,
+                                     N_Subprogram_Body,
+                                     N_Task_Body)
+            then
+               Transition_Body_Declarations (Context, Curr);
+
+            --  Otherwise it is not possible to transition. Stop the search
+            --  because there are no more declarations or statements to check.
+
+            else
+               raise ECR_Found;
+            end if;
+         end if;
+      end Advance;
+
+      --------------------------
+      -- Enter_Handled_Body --
+      --------------------------
+
+      procedure Enter_Handled_Body (Curr : in out Node_Id) is
+         Decls : constant List_Id := Declarations (Curr);
+         HSS   : constant Node_Id := Handled_Statement_Sequence (Curr);
+         Stmts : List_Id := No_List;
+
+      begin
+         if Present (HSS) then
+            Stmts := Statements (HSS);
+         end if;
+
+         --  The handled body has a non-empty statement sequence. The construct
+         --  to inspect is the last statement.
+
+         if Has_Suitable_Construct (Stmts) then
+            Curr := Last (Stmts);
+
+         --  The handled body lacks statements, but has non-empty declarations.
+         --  The construct to inspect is the last declaration.
+
+         elsif Has_Suitable_Construct (Decls) then
+            Curr := Last (Decls);
+
+         --  Otherwise the handled body lacks both declarations and statements.
+         --  The construct to inspect is the node which precedes the handled
+         --  body. Update the early call region to include the handled body.
+
+         else
+            Include (Curr, Curr);
+         end if;
+      end Enter_Handled_Body;
+
+      -------------------------------
+      -- Enter_Package_Declaration --
+      -------------------------------
+
+      procedure Enter_Package_Declaration (Curr : in out Node_Id) is
+         Pack_Spec : constant Node_Id := Specification (Curr);
+         Prv_Decls : constant List_Id := Private_Declarations (Pack_Spec);
+         Vis_Decls : constant List_Id := Visible_Declarations (Pack_Spec);
+
+      begin
+         --  The package has a non-empty private declarations. The construct to
+         --  inspect is the last private declaration.
+
+         if Has_Suitable_Construct (Prv_Decls) then
+            Curr := Last (Prv_Decls);
+
+         --  The package lacks private declarations, but has non-empty visible
+         --  declarations. In this case the construct to inspect is the last
+         --  visible declaration.
+
+         elsif Has_Suitable_Construct (Vis_Decls) then
+            Curr := Last (Vis_Decls);
+
+         --  Otherwise the package lacks any declarations. The construct to
+         --  inspect is the node which precedes the package. Update the early
+         --  call region to include the package declaration.
+
+         else
+            Include (Curr, Curr);
+         end if;
+      end Enter_Package_Declaration;
+
+      --------------
+      -- Find_ECR --
+      --------------
+
+      function Find_ECR (N : Node_Id) return Node_Id is
+         Curr : Node_Id;
+
+      begin
+         --  The early call region starts at N
+
+         Curr  := Prev (N);
+         Start := N;
+
+         --  Inspect each node in reverse declarative order while going in and
+         --  out of nested and enclosing constructs. Note that the only way to
+         --  terminate this infinite loop is to raise exception ECR_Found.
+
+         loop
+            --  The current construct is not preelaboration-safe. Terminate the
+            --  traversal.
+
+            if Present (Curr)
+              and then not Is_OK_Preelaborable_Construct (Curr)
+            then
+               raise ECR_Found;
+            end if;
+
+            --  Advance to the next suitable construct. This may terminate the
+            --  traversal by raising ECR_Found.
+
+            Advance (Curr);
+         end loop;
+
+      exception
+         when ECR_Found =>
+            return Start;
+      end Find_ECR;
+
+      ----------------------------
+      -- Has_Suitable_Construct --
+      ----------------------------
+
+      function Has_Suitable_Construct (List : List_Id) return Boolean is
+         Item : Node_Id;
+
+      begin
+         --  Examine the list in reverse declarative order, looking for a
+         --  suitable construct.
+
+         if Present (List) then
+            Item := Last (List);
+            while Present (Item) loop
+               if Is_Suitable_Construct (Item) then
+                  return True;
+               end if;
+
+               Prev (Item);
+            end loop;
+         end if;
+
+         return False;
+      end Has_Suitable_Construct;
+
+      -------------
+      -- Include --
+      -------------
+
+      procedure Include (N : Node_Id; Curr : out Node_Id) is
+      begin
+         Start := N;
+
+         --  The input node is a compilation unit. This terminates the search
+         --  because there are no more lists to inspect and there are no more
+         --  enclosing constructs to climb up to. The transitions are:
+         --
+         --    private declarations -> terminate
+         --    visible declarations -> terminate
+         --    statements           -> terminate
+         --    declarations         -> terminate
+
+         if Nkind (Parent (Start)) = N_Compilation_Unit then
+            raise ECR_Found;
+
+         --  Otherwise the input node is still within some list
+
+         else
+            Curr := Prev (Start);
+         end if;
+      end Include;
+
+      -----------------------------------
+      -- Is_OK_Preelaborable_Construct --
+      -----------------------------------
+
+      function Is_OK_Preelaborable_Construct (N : Node_Id) return Boolean is
+      begin
+         --  Assignment statements are acceptable as long as they were produced
+         --  by the ABE mechanism to update elaboration flags.
+
+         if Nkind (N) = N_Assignment_Statement then
+            return Is_Elaboration_Code (N);
+
+         --  Block statements are acceptable even though they directly violate
+         --  preelaborability. The intention is not to penalize the early call
+         --  region when a block contains only preelaborable constructs.
+         --
+         --    declare
+         --       Val : constant Integer := 1;
+         --    begin
+         --       pragma Assert (Val = 1);
+         --       null;
+         --    end;
+         --
+         --  Note that the Advancement phase does enter blocks, and will detect
+         --  any non-preelaborable declarations or statements within.
+
+         elsif Nkind (N) = N_Block_Statement then
+            return True;
+         end if;
+
+         --  Otherwise the construct must be preelaborable. The check must take
+         --  the syntactic and semantic structure of the construct. DO NOT use
+         --  Is_Preelaborable_Construct here.
+
+         return not Is_Non_Preelaborable_Construct (N);
+      end Is_OK_Preelaborable_Construct;
+
+      ---------------------------
+      -- Is_Suitable_Construct --
+      ---------------------------
+
+      function Is_Suitable_Construct (N : Node_Id) return Boolean is
+         Context : constant Node_Id := Parent (N);
+
+      begin
+         --  An internally-generated statement sequence which contains only a
+         --  single null statement is not a suitable construct because it is a
+         --  byproduct of the parser. Such a null statement should be excluded
+         --  from the early call region because it carries the source location
+         --  of the "end" keyword, and may lead to confusing diagnistics.
+
+         if Nkind (N) = N_Null_Statement
+           and then not Comes_From_Source (N)
+           and then Present (Context)
+           and then Nkind (Context) = N_Handled_Sequence_Of_Statements
+         then
+            return False;
+         end if;
+
+         --  Otherwise only constructs which correspond to pure Ada constructs
+         --  are considered suitable.
+
+         case Nkind (N) is
+            when N_Call_Marker
+               | N_Freeze_Entity
+               | N_Freeze_Generic_Entity
+               | N_Implicit_Label_Declaration
+               | N_Itype_Reference
+               | N_Pop_Constraint_Error_Label
+               | N_Pop_Program_Error_Label
+               | N_Pop_Storage_Error_Label
+               | N_Push_Constraint_Error_Label
+               | N_Push_Program_Error_Label
+               | N_Push_Storage_Error_Label
+               | N_SCIL_Dispatch_Table_Tag_Init
+               | N_SCIL_Dispatching_Call
+               | N_SCIL_Membership_Test
+               | N_Variable_Reference_Marker
+            =>
+               return False;
+
+            when others =>
+               return True;
+         end case;
+      end Is_Suitable_Construct;
+
+      ----------------------------------
+      -- Transition_Body_Declarations --
+      ----------------------------------
+
+      procedure Transition_Body_Declarations
+        (Bod  : Node_Id;
+         Curr : out Node_Id)
+      is
+         Decls : constant List_Id := Declarations (Bod);
+
+      begin
+         --  The search must come from the declarations of the body
+
+         pragma Assert
+           (Is_Non_Empty_List (Decls)
+             and then List_Containing (Start) = Decls);
+
+         --  The search finished inspecting the declarations. The construct
+         --  to inspect is the node which precedes the handled body, unless
+         --  the body is a compilation unit. The transitions are:
+         --
+         --    declarations -> upper level
+         --    declarations -> corresponding package spec (Elab_Body)
+         --    declarations -> terminate
+
+         Transition_Unit (Bod, Curr);
+      end Transition_Body_Declarations;
+
+      -----------------------------------
+      -- Transition_Handled_Statements --
+      -----------------------------------
+
+      procedure Transition_Handled_Statements
+        (HSS  : Node_Id;
+         Curr : out Node_Id)
+      is
+         Bod   : constant Node_Id := Parent (HSS);
+         Decls : constant List_Id := Declarations (Bod);
+         Stmts : constant List_Id := Statements (HSS);
+
+      begin
+         --  The search must come from the statements of certain bodies or
+         --  statements.
+
+         pragma Assert (Nkind_In (Bod, N_Block_Statement,
+                                       N_Entry_Body,
+                                       N_Package_Body,
+                                       N_Protected_Body,
+                                       N_Subprogram_Body,
+                                       N_Task_Body));
+
+         --  The search must come from the statements of the handled sequence
+
+         pragma Assert
+           (Is_Non_Empty_List (Stmts)
+             and then List_Containing (Start) = Stmts);
+
+         --  The search finished inspecting the statements. The handled body
+         --  has non-empty declarations. The construct to inspect is the last
+         --  declaration. The transitions are:
+         --
+         --    statements -> declarations
+
+         if Has_Suitable_Construct (Decls) then
+            Curr := Last (Decls);
+
+         --  Otherwise the handled body lacks declarations. The construct to
+         --  inspect is the node which precedes the handled body, unless the
+         --  body is a compilation unit. The transitions are:
+         --
+         --    statements -> upper level
+         --    statements -> corresponding package spec (Elab_Body)
+         --    statements -> terminate
+
+         else
+            Transition_Unit (Bod, Curr);
+         end if;
+      end Transition_Handled_Statements;
+
+      ----------------------------------
+      -- Transition_Spec_Declarations --
+      ----------------------------------
+
+      procedure Transition_Spec_Declarations
+        (Spec : Node_Id;
+         Curr : out Node_Id)
+      is
+         Prv_Decls : constant List_Id := Private_Declarations (Spec);
+         Vis_Decls : constant List_Id := Visible_Declarations (Spec);
+
+      begin
+         pragma Assert (Present (Start) and then Is_List_Member (Start));
+
+         --  The search came from the private declarations and finished their
+         --  inspection.
+
+         if Has_Suitable_Construct (Prv_Decls)
+           and then List_Containing (Start) = Prv_Decls
+         then
+            --  The context has non-empty visible declarations. The node to
+            --  inspect is the last visible declaration. The transitions are:
+            --
+            --    private declarations -> visible declarations
+
+            if Has_Suitable_Construct (Vis_Decls) then
+               Curr := Last (Vis_Decls);
+
+            --  Otherwise the context lacks visible declarations. The construct
+            --  to inspect is the node which precedes the context unless the
+            --  context is a compilation unit. The transitions are:
+            --
+            --    private declarations -> upper level
+            --    private declarations -> terminate
+
+            else
+               Transition_Unit (Parent (Spec), Curr);
+            end if;
+
+         --  The search came from the visible declarations and finished their
+         --  inspections. The construct to inspect is the node which precedes
+         --  the context, unless the context is a compilaton unit. The
+         --  transitions are:
+         --
+         --    visible declarations -> upper level
+         --    visible declarations -> terminate
+
+         elsif Has_Suitable_Construct (Vis_Decls)
+           and then List_Containing (Start) = Vis_Decls
+         then
+            Transition_Unit (Parent (Spec), Curr);
+
+         --  At this point both declarative lists are empty, but the traversal
+         --  still came from within the spec. This indicates that the invariant
+         --  of the algorithm has been violated.
+
+         else
+            pragma Assert (False);
+            raise ECR_Found;
+         end if;
+      end Transition_Spec_Declarations;
+
+      ---------------------
+      -- Transition_Unit --
+      ---------------------
+
+      procedure Transition_Unit
+        (Unit : Node_Id;
+         Curr : out Node_Id)
+      is
+         Context : constant Node_Id := Parent (Unit);
+
+      begin
+         --  The unit is a compilation unit. This terminates the search because
+         --  there are no more lists to inspect and there are no more enclosing
+         --  constructs to climb up to.
+
+         if Nkind (Context) = N_Compilation_Unit then
+
+            --  A package body with a corresponding spec subject to pragma
+            --  Elaborate_Body is an exception to the above. The annotation
+            --  allows the search to continue into the package declaration.
+            --  The transitions are:
+            --
+            --    statements   -> corresponding package spec (Elab_Body)
+            --    declarations -> corresponding package spec (Elab_Body)
+
+            if Nkind (Unit) = N_Package_Body
+              and then (Assume_Elab_Body
+                         or else Has_Pragma_Elaborate_Body
+                                   (Corresponding_Spec (Unit)))
+            then
+               Curr := Unit_Declaration_Node (Corresponding_Spec (Unit));
+               Enter_Package_Declaration (Curr);
+
+            --  Otherwise terminate the search. The transitions are:
+            --
+            --    private declarations -> terminate
+            --    visible declarations -> terminate
+            --    statements           -> terminate
+            --    declarations         -> terminate
+
+            else
+               raise ECR_Found;
+            end if;
+
+         --  The unit is a subunit. The construct to inspect is the node which
+         --  precedes the corresponding stub. Update the early call region to
+         --  include the unit.
+
+         elsif Nkind (Context) = N_Subunit then
+            Start := Unit;
+            Curr  := Corresponding_Stub (Context);
+
+         --  Otherwise the unit is nested. The construct to inspect is the node
+         --  which precedes the unit. Update the early call region to include
+         --  the unit.
+
+         else
+            Include (Unit, Curr);
+         end if;
+      end Transition_Unit;
+
+      --  Local variables
+
+      Body_Id : constant Entity_Id := Defining_Entity (Body_Decl);
+      Region  : Node_Id;
+
+   --  Start of processing for Find_Early_Call_Region
+
+   begin
+      --  The caller demands the start of the early call region without saving
+      --  or retrieving it to/from internal data structures.
+
+      if Skip_Memoization then
+         Region := Find_ECR (Body_Decl);
+
+      --  Default behavior
+
+      else
+         --  Check whether the early call region of the subprogram body is
+         --  available.
+
+         Region := Early_Call_Region (Body_Id);
+
+         if No (Region) then
+
+            --  Traverse the declarations in reverse order, starting from the
+            --  subprogram body, searching for the nearest non-preelaborable
+            --  construct. The early call region starts after this construct
+            --  and ends at the subprogram body.
+
+            Region := Find_ECR (Body_Decl);
+
+            --  Associate the early call region with the subprogram body in
+            --  case other scenarios need it.
+
+            Set_Early_Call_Region (Body_Id, Region);
+         end if;
+      end if;
+
+      --  A subprogram body must always have an early call region
+
+      pragma Assert (Present (Region));
+
+      return Region;
+   end Find_Early_Call_Region;
+
    ---------------------------
    -- Find_Elaborated_Units --
    ---------------------------
@@ -3034,35 +5120,41 @@
             return;
          end if;
 
-         Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+         Elab_Attrs := Elaboration_Status (Unit_Id);
+
+         --  The unit is already included in the context by means of pragma
+         --  Elaborate[_All].
+
+         if Present (Elab_Attrs.Source_Pragma) then
+
+            --  Upgrade an existing pragma Elaborate when the unit is subject
+            --  to Elaborate_All because the new pragma covers a larger set of
+            --  units.
+
+            if Pragma_Name (Elab_Attrs.Source_Pragma) = Name_Elaborate
+              and then Pragma_Name (Prag) = Name_Elaborate_All
+            then
+               Elab_Attrs.Source_Pragma := Prag;
+
+            --  Otherwise the unit retains its existing pragma and does not
+            --  need to be included in the context again.
+
+            else
+               return;
+            end if;
 
          --  The current unit is not part of the context. Prepare a new set of
          --  attributes.
 
-         if Elab_Attrs = No_Elaboration_Attributes then
+         else
             Elab_Attrs :=
               Elaboration_Attributes'(Source_Pragma => Prag,
                                       With_Clause   => Empty);
-
-         --  The unit is already included in the context by means of pragma
-         --  Elaborate. "Upgrage" the existing attributes when the unit is
-         --  subject to Elaborate_All because the new pragma covers a larger
-         --  set of units. All other properties remain the same.
-
-         elsif Pragma_Name (Elab_Attrs.Source_Pragma) = Name_Elaborate
-           and then Pragma_Name (Prag) = Name_Elaborate_All
-         then
-            Elab_Attrs.Source_Pragma := Prag;
-
-         --  Otherwise the unit is already included in the context
-
-         else
-            return;
          end if;
 
          --  Add or update the attributes of the unit
 
-         Elaboration_Context.Set (Unit_Id, Elab_Attrs);
+         Set_Elaboration_Status (Unit_Id, Elab_Attrs);
 
          --  Includes all units withed by the current one when computing the
          --  full context.
@@ -3356,7 +5448,7 @@
                return Declaration_Level;
             end if;
 
-         --  The current construct is a declaration level encapsulator
+         --  The current construct is a declaration-level encapsulator
 
          elsif Nkind_In (Curr, N_Entry_Body,
                                N_Subprogram_Body,
@@ -3379,9 +5471,9 @@
                return Declaration_Level;
             end if;
 
-         --  The current construct is a non-library level encapsulator which
+         --  The current construct is a non-library-level encapsulator which
          --  indicates that the node cannot possibly appear at any level.
-         --  Note that this check must come after the declaration level check
+         --  Note that this check must come after the declaration-level check
          --  because both predicates share certain nodes.
 
          elsif Is_Non_Library_Level_Encapsulator (Curr) then
@@ -3761,7 +5853,7 @@
       --  main unit. Consider this case only when requested by the caller.
 
       elsif Context_OK
-        and then Elaboration_Context.Get (Unit_Id) /= No_Elaboration_Attributes
+        and then Elaboration_Status (Unit_Id) /= No_Elaboration_Attributes
       then
          return True;
 
@@ -3870,7 +5962,7 @@
       Nested_OK : Boolean := False) return Boolean
    is
       function Find_Enclosing_Context (N : Node_Id) return Node_Id;
-      --  Return the nearest enclosing non-library level or compilation unit
+      --  Return the nearest enclosing non-library-level or compilation unit
       --  node which which encapsulates arbitrary node N. Return Empty is no
       --  such context is available.
 
@@ -3897,7 +5989,7 @@
             if Nkind (Par) = N_Subunit then
                Par := Corresponding_Stub (Par);
 
-            --  Stop the traversal when the nearest enclosing non-library level
+            --  Stop the traversal when the nearest enclosing non-library-level
             --  encapsulator has been reached.
 
             elsif Is_Non_Library_Level_Encapsulator (Par) then
@@ -3916,7 +6008,7 @@
                   return Par;
                end if;
 
-            --  Reaching a compilation unit node without hitting a non-library
+            --  Reaching a compilation unit node without hitting a non-library-
             --  level encapsulator indicates that N is at the library level in
             --  which case the compilation unit is the context.
 
@@ -3992,13 +6084,46 @@
       return False;
    end In_Same_Context;
 
+   ------------------
+   -- In_Task_Body --
+   ------------------
+
+   function In_Task_Body (N : Node_Id) return Boolean is
+      Par : Node_Id;
+
+   begin
+      --  Climb the parent chain looking for a task body [procedure]
+
+      Par := N;
+      while Present (Par) loop
+         if Nkind (Par) = N_Task_Body then
+            return True;
+
+         elsif Nkind (Par) = N_Subprogram_Body
+           and then Is_Task_Body_Procedure (Par)
+         then
+            return True;
+
+         --  Prevent the search from going too far. Note that this predicate
+         --  shares nodes with the two cases above, and must come last.
+
+         elsif Is_Body_Or_Package_Declaration (Par) then
+            return False;
+         end if;
+
+         Par := Parent (Par);
+      end loop;
+
+      return False;
+   end In_Task_Body;
+
    ----------------
    -- Initialize --
    ----------------
 
    procedure Initialize is
    begin
-      --  Set the soft link which enables Atree.Rewrite to update a top level
+      --  Set the soft link which enables Atree.Rewrite to update a top-level
       --  scenario each time it is transformed into another node.
 
       Set_Rewriting_Proc (Update_Elaboration_Scenario'Access);
@@ -4226,24 +6351,26 @@
          In_SPARK => In_SPARK);
    end Info_Instantiation;
 
-   ------------------------
-   -- Info_Variable_Read --
-   ------------------------
-
-   procedure Info_Variable_Read
+   -----------------------------
+   -- Info_Variable_Reference --
+   -----------------------------
+
+   procedure Info_Variable_Reference
      (Ref      : Node_Id;
       Var_Id   : Entity_Id;
       Info_Msg : Boolean;
       In_SPARK : Boolean)
    is
    begin
-      Elab_Msg_NE
-        (Msg      => "read of variable & during elaboration",
-         N        => Ref,
-         Id       => Var_Id,
-         Info_Msg => Info_Msg,
-         In_SPARK => In_SPARK);
-   end Info_Variable_Read;
+      if Is_Read (Ref) then
+         Elab_Msg_NE
+           (Msg      => "read of variable & during elaboration",
+            N        => Ref,
+            Id       => Var_Id,
+            Info_Msg => Info_Msg,
+            In_SPARK => In_SPARK);
+      end if;
+   end Info_Variable_Reference;
 
    --------------------
    -- Insertion_Node --
@@ -4571,6 +6698,20 @@
           or else Is_Task_Entry (Id);
    end Is_Ada_Semantic_Target;
 
+   --------------------------------
+   -- Is_Assertion_Pragma_Target --
+   --------------------------------
+
+   function Is_Assertion_Pragma_Target (Id : Entity_Id) return Boolean is
+   begin
+      return
+        Is_Default_Initial_Condition_Proc (Id)
+          or else Is_Initial_Condition_Proc (Id)
+          or else Is_Invariant_Proc (Id)
+          or else Is_Partial_Invariant_Proc (Id)
+          or else Is_Postconditions_Proc (Id);
+   end Is_Assertion_Pragma_Target;
+
    ----------------------------
    -- Is_Bodiless_Subprogram --
    ----------------------------
@@ -4602,19 +6743,6 @@
       return False;
    end Is_Bodiless_Subprogram;
 
-   --------------------------------
-   -- Is_Check_Emitting_Scenario --
-   --------------------------------
-
-   function Is_Check_Emitting_Scenario (N : Node_Id) return Boolean is
-   begin
-      return
-        Nkind_In (N, N_Call_Marker,
-                     N_Function_Instantiation,
-                     N_Package_Instantiation,
-                     N_Procedure_Instantiation);
-   end Is_Check_Emitting_Scenario;
-
    ------------------------
    -- Is_Controlled_Proc --
    ------------------------
@@ -4870,6 +6998,32 @@
           and then Present (Protected_Subprogram (Id));
    end Is_Protected_Body_Subp;
 
+   --------------------------------
+   -- Is_Recorded_SPARK_Scenario --
+   --------------------------------
+
+   function Is_Recorded_SPARK_Scenario (N : Node_Id) return Boolean is
+   begin
+      if Recorded_SPARK_Scenarios_In_Use then
+         return Recorded_SPARK_Scenarios.Get (N);
+      end if;
+
+      return Recorded_SPARK_Scenarios_No_Element;
+   end Is_Recorded_SPARK_Scenario;
+
+   ------------------------------------
+   -- Is_Recorded_Top_Level_Scenario --
+   ------------------------------------
+
+   function Is_Recorded_Top_Level_Scenario (N : Node_Id) return Boolean is
+   begin
+      if Recorded_Top_Level_Scenarios_In_Use then
+         return Recorded_Top_Level_Scenarios.Get (N);
+      end if;
+
+      return Recorded_Top_Level_Scenarios_No_Element;
+   end Is_Recorded_Top_Level_Scenario;
+
    ------------------------
    -- Is_Safe_Activation --
    ------------------------
@@ -4999,50 +7153,8 @@
      (Unit_1 : Entity_Id;
       Unit_2 : Entity_Id) return Boolean
    is
-      function Is_Subunit (Unit_Id : Entity_Id) return Boolean;
-      pragma Inline (Is_Subunit);
-      --  Determine whether unit Unit_Id is a subunit
-
-      function Normalize_Unit (Unit_Id : Entity_Id) return Entity_Id;
-      --  Strip a potential subunit chain ending with unit Unit_Id and return
-      --  the corresponding spec.
-
-      ----------------
-      -- Is_Subunit --
-      ----------------
-
-      function Is_Subunit (Unit_Id : Entity_Id) return Boolean is
-      begin
-         return Nkind (Parent (Unit_Declaration_Node (Unit_Id))) = N_Subunit;
-      end Is_Subunit;
-
-      --------------------
-      -- Normalize_Unit --
-      --------------------
-
-      function Normalize_Unit (Unit_Id : Entity_Id) return Entity_Id is
-         Result : Entity_Id;
-
-      begin
-         --  Eliminate a potential chain of subunits to reach to proper body
-
-         Result := Unit_Id;
-         while Present (Result)
-           and then Result /= Standard_Standard
-           and then Is_Subunit (Result)
-         loop
-            Result := Scope (Result);
-         end loop;
-
-         --  Obtain the entity of the corresponding spec (if any)
-
-         return Unique_Entity (Result);
-      end Normalize_Unit;
-
-   --  Start of processing for Is_Same_Unit
-
-   begin
-      return Normalize_Unit (Unit_1) = Normalize_Unit (Unit_2);
+   begin
+      return Unit_Entity (Unit_1) = Unit_Entity (Unit_2);
    end Is_Same_Unit;
 
    -----------------
@@ -5195,14 +7307,91 @@
 
    function Is_Suitable_Scenario (N : Node_Id) return Boolean is
    begin
+      --  NOTE: Derived types and pragma Refined_State are intentionally left
+      --  out because they are not executable during elaboration.
+
       return
         Is_Suitable_Access (N)
           or else Is_Suitable_Call (N)
           or else Is_Suitable_Instantiation (N)
           or else Is_Suitable_Variable_Assignment (N)
-          or else Is_Suitable_Variable_Read (N);
+          or else Is_Suitable_Variable_Reference (N);
    end Is_Suitable_Scenario;
 
+   ------------------------------------
+   -- Is_Suitable_SPARK_Derived_Type --
+   ------------------------------------
+
+   function Is_Suitable_SPARK_Derived_Type (N : Node_Id) return Boolean is
+      Prag : Node_Id;
+      Typ  : Entity_Id;
+
+   begin
+      --  To qualify, the type declaration must denote a derived tagged type
+      --  with primitive operations, subject to pragma SPARK_Mode On.
+
+      if Nkind (N) = N_Full_Type_Declaration
+        and then Nkind (Type_Definition (N)) = N_Derived_Type_Definition
+      then
+         Typ  := Defining_Entity (N);
+         Prag := SPARK_Pragma (Typ);
+
+         return
+           Is_Tagged_Type (Typ)
+             and then Has_Primitive_Operations (Typ)
+             and then Present (Prag)
+             and then Get_SPARK_Mode_From_Annotation (Prag) = On;
+      end if;
+
+      return False;
+   end Is_Suitable_SPARK_Derived_Type;
+
+   -------------------------------------
+   -- Is_Suitable_SPARK_Instantiation --
+   -------------------------------------
+
+   function Is_Suitable_SPARK_Instantiation (N : Node_Id) return Boolean is
+      Gen_Attrs  : Target_Attributes;
+      Gen_Id     : Entity_Id;
+      Inst       : Node_Id;
+      Inst_Attrs : Instantiation_Attributes;
+      Inst_Id    : Entity_Id;
+
+   begin
+      --  To qualify, both the instantiation and the generic must be subject to
+      --  SPARK_Mode On.
+
+      if Is_Suitable_Instantiation (N) then
+         Extract_Instantiation_Attributes
+           (Exp_Inst => N,
+            Inst     => Inst,
+            Inst_Id  => Inst_Id,
+            Gen_Id   => Gen_Id,
+            Attrs    => Inst_Attrs);
+
+         Extract_Target_Attributes (Gen_Id, Gen_Attrs);
+
+         return Inst_Attrs.SPARK_Mode_On and Gen_Attrs.SPARK_Mode_On;
+      end if;
+
+      return False;
+   end Is_Suitable_SPARK_Instantiation;
+
+   --------------------------------------------
+   -- Is_Suitable_SPARK_Refined_State_Pragma --
+   --------------------------------------------
+
+   function Is_Suitable_SPARK_Refined_State_Pragma
+     (N : Node_Id) return Boolean
+   is
+   begin
+      --  To qualfy, the pragma must denote Refined_State
+
+      return
+        Nkind (N) = N_Pragma
+          and then Pragma_Name (N) = Name_Refined_State;
+   end Is_Suitable_SPARK_Refined_State_Pragma;
+
    -------------------------------------
    -- Is_Suitable_Variable_Assignment --
    -------------------------------------
@@ -5297,187 +7486,46 @@
           and then Corresponding_Body (Var_Unit) = N_Unit_Id;
    end Is_Suitable_Variable_Assignment;
 
-   -------------------------------
-   -- Is_Suitable_Variable_Read --
-   -------------------------------
-
-   function Is_Suitable_Variable_Read (N : Node_Id) return Boolean is
-      function In_Pragma (Nod : Node_Id) return Boolean;
-      --  Determine whether arbitrary node Nod appears within a pragma
-
-      function Is_Variable_Read (Ref : Node_Id) return Boolean;
-      --  Determine whether variable reference Ref constitutes a read
-
-      ---------------
-      -- In_Pragma --
-      ---------------
-
-      function In_Pragma (Nod : Node_Id) return Boolean is
-         Par : Node_Id;
-
-      begin
-         Par := Nod;
-         while Present (Par) loop
-            if Nkind (Par) = N_Pragma then
-               return True;
-
-            --  Prevent the search from going too far
-
-            elsif Is_Body_Or_Package_Declaration (Par) then
-               exit;
-            end if;
-
-            Par := Parent (Par);
-         end loop;
-
-         return False;
-      end In_Pragma;
-
-      ----------------------
-      -- Is_Variable_Read --
-      ----------------------
-
-      function Is_Variable_Read (Ref : Node_Id) return Boolean is
-         function Is_Out_Actual (Call : Node_Id) return Boolean;
-         --  Determine whether the corresponding formal of actual Ref which
-         --  appears in call Call has mode OUT.
-
-         -------------------
-         -- Is_Out_Actual --
-         -------------------
-
-         function Is_Out_Actual (Call : Node_Id) return Boolean is
-            Actual     : Node_Id;
-            Call_Attrs : Call_Attributes;
-            Formal     : Entity_Id;
-            Target_Id  : Entity_Id;
-
-         begin
-            Extract_Call_Attributes
-              (Call      => Call,
-               Target_Id => Target_Id,
-               Attrs     => Call_Attrs);
-
-            --  Inspect the actual and formal parameters, trying to find the
-            --  corresponding formal for Ref.
-
-            Actual := First_Actual (Call);
-            Formal := First_Formal (Target_Id);
-            while Present (Actual) and then Present (Formal) loop
-               if Actual = Ref then
-                  return Ekind (Formal) = E_Out_Parameter;
-               end if;
-
-               Next_Actual (Actual);
-               Next_Formal (Formal);
-            end loop;
-
-            return False;
-         end Is_Out_Actual;
-
-         --  Local variables
-
-         Context : constant Node_Id := Parent (Ref);
-
-      --  Start of processing for Is_Variable_Read
-
-      begin
-         --  The majority of variable references are reads, and they can appear
-         --  in a great number of contexts. To determine whether a reference is
-         --  a read, it is more practical to find out whether it is a write.
-
-         --  A reference is a write when it appears immediately on the left-
-         --  hand side of an assignment.
-
-         if Nkind (Context) = N_Assignment_Statement
-           and then Name (Context) = Ref
-         then
-            return False;
-
-         --  A reference is a write when it acts as an actual in a subprogram
-         --  call and the corresponding formal has mode OUT.
-
-         elsif Nkind_In (Context, N_Function_Call,
-                                  N_Procedure_Call_Statement)
-           and then Is_Out_Actual (Context)
-         then
-            return False;
-         end if;
-
-         --  Any other reference is a read
-
-         return True;
-      end Is_Variable_Read;
-
-      --  Local variables
-
-      Prag   : Node_Id;
-      Var_Id : Entity_Id;
-
-   --  Start of processing for Is_Suitable_Variable_Read
-
-   begin
-      --  This scenario is relevant only when the static model is in effect
-      --  because it is graph-dependent and does not involve any run-time
-      --  checks. Allowing it in the dynamic model would create confusing
-      --  noise.
-
-      if not Static_Elaboration_Checks then
-         return False;
-
-      --  Attributes and operator sumbols are not considered to be suitable
-      --  references even though they are part of predicate Is_Entity_Name.
-
-      elsif not Nkind_In (N, N_Expanded_Name, N_Identifier) then
-         return False;
-
-      --  Nothing to do for internally-generated references because they are
-      --  assumed to be ABE safe.
-
-      elsif not Comes_From_Source (N) then
-         return False;
-      end if;
-
-      --  Sanitize the reference
-
-      Var_Id := Entity (N);
-
-      if No (Var_Id) then
-         return False;
-
-      elsif Var_Id = Any_Id then
-         return False;
-
-      elsif Ekind (Var_Id) /= E_Variable then
-         return False;
-      end if;
-
-      Prag := SPARK_Pragma (Var_Id);
-
-      --  To qualify, the reference must meet the following prerequisites:
-
-      return
-        Comes_From_Source (Var_Id)
-
-          --  Both the variable and the reference must appear in SPARK_Mode On
-          --  regions because this scenario falls under the SPARK rules.
-
-          and then Present (Prag)
-          and then Get_SPARK_Mode_From_Annotation (Prag) = On
-          and then Is_SPARK_Mode_On_Node (N)
-
-          --  The reference must denote a variable read
-
-          and then Is_Variable_Read (N)
-
-          --  The reference must not be considered when it appears in a pragma.
-          --  If the pragma has run-time semantics, then the reference will be
-          --  reconsidered once the pragma is expanded.
-
-          --  Performance note: parent traversal
-
-          and then not In_Pragma (N);
-   end Is_Suitable_Variable_Read;
+   ------------------------------------
+   -- Is_Suitable_Variable_Reference --
+   ------------------------------------
+
+   function Is_Suitable_Variable_Reference (N : Node_Id) return Boolean is
+   begin
+      --  Expanded names and identifiers are intentionally ignored because they
+      --  be folded, optimized away, etc. Variable references markers play the
+      --  role of variable references and provide a uniform foundation for ABE
+      --  processing.
+
+      return Nkind (N) = N_Variable_Reference_Marker;
+   end Is_Suitable_Variable_Reference;
+
+   ------------------------------------
+   -- Is_Synchronous_Suspension_Call --
+   ------------------------------------
+
+   function Is_Synchronous_Suspension_Call (N : Node_Id) return Boolean is
+      Call_Attrs : Call_Attributes;
+      Target_Id  : Entity_Id;
+
+   begin
+      --  To qualify, the call must invoke one of the runtime routines which
+      --  perform synchronous suspension.
+
+      if Is_Suitable_Call (N) then
+         Extract_Call_Attributes
+           (Call      => N,
+            Target_Id => Target_Id,
+            Attrs     => Call_Attrs);
+
+         return
+           Is_RTE (Target_Id, RE_Suspend_Until_True)
+             or else
+           Is_RTE (Target_Id, RE_Wait_For_Release);
+      end if;
+
+      return False;
+   end Is_Synchronous_Suspension_Call;
 
    -------------------
    -- Is_Task_Entry --
@@ -5501,7 +7549,7 @@
    begin
       --  The root appears within the declaratons of a block statement, entry
       --  body, subprogram body, or task body ignoring enclosing packages. The
-      --  root is always within the main unit. An up level target is a notion
+      --  root is always within the main unit. An up-level target is a notion
       --  applicable only to the static model because scenarios are reached by
       --  means of graph traversal started from a fixed declarative or library
       --  level.
@@ -5511,7 +7559,7 @@
       if Static_Elaboration_Checks
         and then Find_Enclosing_Level (Root) = Declaration_Level
       then
-         --  The target is within the main unit. It acts as an up level target
+         --  The target is within the main unit. It acts as an up-level target
          --  when it appears within a context which encloses the root.
 
          --    package body Main_Unit is
@@ -5527,7 +7575,7 @@
             return not In_Same_Context (Root, Target_Decl, Nested_OK => True);
 
          --  Otherwise the target is external to the main unit which makes it
-         --  an up level target.
+         --  an up-level target.
 
          else
             return True;
@@ -5537,19 +7585,111 @@
       return False;
    end Is_Up_Level_Target;
 
+   ---------------------
+   -- Is_Visited_Body --
+   ---------------------
+
+   function Is_Visited_Body (Body_Decl : Node_Id) return Boolean is
+   begin
+      if Visited_Bodies_In_Use then
+         return Visited_Bodies.Get (Body_Decl);
+      end if;
+
+      return Visited_Bodies_No_Element;
+   end Is_Visited_Body;
+
    -------------------------------
    -- Kill_Elaboration_Scenario --
    -------------------------------
 
    procedure Kill_Elaboration_Scenario (N : Node_Id) is
-   begin
-      --  Eliminate the scenario by suppressing the generation of conditional
-      --  ABE checks or guaranteed ABE failures. Note that other diagnostics
-      --  must be carried out ignoring the fact that the scenario is within
-      --  dead code.
+      procedure Kill_SPARK_Scenario;
+      pragma Inline (Kill_SPARK_Scenario);
+      --  Eliminate scenario N from table SPARK_Scenarios if it is recorded
+      --  there.
+
+      procedure Kill_Top_Level_Scenario;
+      pragma Inline (Kill_Top_Level_Scenario);
+      --  Eliminate scenario N from table Top_Level_Scenarios if it is recorded
+      --  there.
+
+      -------------------------
+      -- Kill_SPARK_Scenario --
+      -------------------------
+
+      procedure Kill_SPARK_Scenario is
+         package Scenarios renames SPARK_Scenarios;
+
+      begin
+         if Is_Recorded_SPARK_Scenario (N) then
+
+            --  Performance note: list traversal
+
+            for Index in Scenarios.First .. Scenarios.Last loop
+               if Scenarios.Table (Index) = N then
+                  Scenarios.Table (Index) := Empty;
+
+                  --  The SPARK scenario is no longer recorded
+
+                  Set_Is_Recorded_SPARK_Scenario (N, False);
+                  return;
+               end if;
+            end loop;
+
+            --  A recorded SPARK scenario must be in the table of recorded
+            --  SPARK scenarios.
+
+            pragma Assert (False);
+         end if;
+      end Kill_SPARK_Scenario;
+
+      -----------------------------
+      -- Kill_Top_Level_Scenario --
+      -----------------------------
+
+      procedure Kill_Top_Level_Scenario is
+         package Scenarios renames Top_Level_Scenarios;
+
+      begin
+         if Is_Recorded_Top_Level_Scenario (N) then
+
+            --  Performance node: list traversal
+
+            for Index in Scenarios.First .. Scenarios.Last loop
+               if Scenarios.Table (Index) = N then
+                  Scenarios.Table (Index) := Empty;
+
+                  --  The top-level scenario is no longer recorded
+
+                  Set_Is_Recorded_Top_Level_Scenario (N, False);
+                  return;
+               end if;
+            end loop;
+
+            --  A recorded top-level scenario must be in the table of recorded
+            --  top-level scenarios.
+
+            pragma Assert (False);
+         end if;
+      end Kill_Top_Level_Scenario;
+
+   --  Start of processing for Kill_Elaboration_Scenario
+
+   begin
+      --  Nothing to do when switch -gnatH (legacy elaboration checking mode
+      --  enabled) is in effect because the legacy ABE lechanism does not need
+      --  to carry out this action.
+
+      if Legacy_Elaboration_Checks then
+         return;
+      end if;
+
+      --  Eliminate a recorded scenario when it appears within dead code
+      --  because it will not be executed at elaboration time.
 
       if Is_Scenario (N) then
-         Set_Is_Elaboration_Checks_OK_Node (N, False);
+         Kill_SPARK_Scenario;
+         Kill_Top_Level_Scenario;
       end if;
    end Kill_Elaboration_Scenario;
 
@@ -5604,7 +7744,7 @@
                      return Decl;
 
                   --  Otherwise the construct terminates the region where the
-                  --  preelabortion-related pragma may appear.
+                  --  preelaboration-related pragma may appear.
 
                   else
                      exit;
@@ -5652,8 +7792,13 @@
                Info_Msg => False,
                In_SPARK => True);
 
-         elsif Is_Suitable_Variable_Read (N) then
-            Info_Variable_Read
+         elsif Is_Suitable_SPARK_Refined_State_Pragma (N) then
+            Error_Msg_N
+              ("read of refinement constituents during elaboration in SPARK",
+               N);
+
+         elsif Is_Suitable_Variable_Reference (N) then
+            Info_Variable_Reference
               (Ref      => N,
                Var_Id   => Target_Id,
                Info_Msg => False,
@@ -5741,7 +7886,7 @@
       --  enough to meet the requirement.
 
       else
-         Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+         Elab_Attrs := Elaboration_Status (Unit_Id);
 
          --  The pragma must be either Elaborate_All or be as strong as the
          --  requirement.
@@ -5781,16 +7926,12 @@
    ----------------------
 
    function Non_Private_View (Typ : Entity_Id) return Entity_Id is
-      Result : Entity_Id;
-
-   begin
-      Result := Typ;
-
-      if Is_Private_Type (Result) and then Present (Full_View (Result)) then
-         Result := Full_View (Result);
-      end if;
-
-      return Result;
+   begin
+      if Is_Private_Type (Typ) and then Present (Full_View (Typ)) then
+         return Full_View (Typ);
+      else
+         return Typ;
+      end if;
    end Non_Private_View;
 
    -----------------------------
@@ -5814,11 +7955,14 @@
       procedure Output_Instantiation (N : Node_Id);
       --  Emit a specific diagnostic message for instantiation N
 
+      procedure Output_SPARK_Refined_State_Pragma (N : Node_Id);
+      --  Emit a specific diagnostic message for Refined_State pragma N
+
       procedure Output_Variable_Assignment (N : Node_Id);
       --  Emit a specific diagnostic message for assignment statement N
 
-      procedure Output_Variable_Read (N : Node_Id);
-      --  Emit a specific diagnostic message for reference N which reads a
+      procedure Output_Variable_Reference (N : Node_Id);
+      --  Emit a specific diagnostic message for reference N which mentions a
       --  variable.
 
       -------------------
@@ -6136,6 +8280,16 @@
          end if;
       end Output_Instantiation;
 
+      ---------------------------------------
+      -- Output_SPARK_Refined_State_Pragma --
+      ---------------------------------------
+
+      procedure Output_SPARK_Refined_State_Pragma (N : Node_Id) is
+      begin
+         Error_Msg_Sloc := Sloc (N);
+         Error_Msg_N ("\\  refinement constituents read #", Error_Nod);
+      end Output_SPARK_Refined_State_Pragma;
+
       --------------------------------
       -- Output_Variable_Assignment --
       --------------------------------
@@ -6148,11 +8302,11 @@
          Error_Msg_NE ("\\  variable & assigned #", Error_Nod, Var_Id);
       end Output_Variable_Assignment;
 
-      --------------------------
-      -- Output_Variable_Read --
-      --------------------------
-
-      procedure Output_Variable_Read (N : Node_Id) is
+      -------------------------------
+      -- Output_Variable_Reference --
+      -------------------------------
+
+      procedure Output_Variable_Reference (N : Node_Id) is
          Dummy  : Variable_Attributes;
          Var_Id : Entity_Id;
 
@@ -6163,8 +8317,15 @@
             Attrs  => Dummy);
 
          Error_Msg_Sloc := Sloc (N);
-         Error_Msg_NE ("\\  variable & read #", Error_Nod, Var_Id);
-      end Output_Variable_Read;
+
+         if Is_Read (N) then
+            Error_Msg_NE ("\\  variable & read #", Error_Nod, Var_Id);
+
+         else
+            pragma Assert (False);
+            null;
+         end if;
+      end Output_Variable_Reference;
 
       --  Local variables
 
@@ -6220,15 +8381,20 @@
          elsif Is_Suitable_Instantiation (N) then
             Output_Instantiation (N);
 
+         --  Pragma Refined_State
+
+         elsif Is_Suitable_SPARK_Refined_State_Pragma (N) then
+            Output_SPARK_Refined_State_Pragma (N);
+
          --  Variable assignments
 
          elsif Nkind (N) = N_Assignment_Statement then
             Output_Variable_Assignment (N);
 
-         --  Variable read
-
-         elsif Is_Suitable_Variable_Read (N) then
-            Output_Variable_Read (N);
+         --  Variable references
+
+         elsif Is_Suitable_Variable_Reference (N) then
+            Output_Variable_Reference (N);
 
          else
             pragma Assert (False);
@@ -6249,119 +8415,14 @@
       Scenario_Stack.Decrement_Last;
    end Pop_Active_Scenario;
 
-   --------------------
-   -- Process_Access --
-   --------------------
-
-   procedure Process_Access (Attr : Node_Id; In_Task_Body : Boolean) is
-      function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id;
-      pragma Inline (Build_Access_Marker);
-      --  Create a suitable call marker which invokes target Target_Id
-
-      -------------------------
-      -- Build_Access_Marker --
-      -------------------------
-
-      function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id is
-         Marker : Node_Id;
-
-      begin
-         Marker := Make_Call_Marker (Sloc (Attr));
-
-         --  Inherit relevant attributes from the attribute
-
-         --  Performance note: parent traversal
-
-         Set_Target (Marker, Target_Id);
-         Set_Is_Declaration_Level_Node
-                    (Marker, Find_Enclosing_Level (Attr) = Declaration_Level);
-         Set_Is_Dispatching_Call
-                    (Marker, False);
-         Set_Is_Elaboration_Checks_OK_Node
-                    (Marker, Is_Elaboration_Checks_OK_Node (Attr));
-         Set_Is_Source_Call
-                    (Marker, Comes_From_Source (Attr));
-         Set_Is_SPARK_Mode_On_Node
-                    (Marker, Is_SPARK_Mode_On_Node (Attr));
-
-         --  Partially insert the call marker into the tree by setting its
-         --  parent pointer.
-
-         Set_Parent (Marker, Attr);
-
-         return Marker;
-      end Build_Access_Marker;
-
-      --  Local variables
-
-      Root      : constant Node_Id   := Root_Scenario;
-      Target_Id : constant Entity_Id := Entity (Prefix (Attr));
-
-      Target_Attrs : Target_Attributes;
-
-   --  Start of processing for Process_Access
-
-   begin
-      --  Output relevant information when switch -gnatel (info messages on
-      --  implicit Elaborate[_All] pragmas) is in effect.
-
-      if Elab_Info_Messages then
-         Error_Msg_NE
-           ("info: access to & during elaboration", Attr, Target_Id);
-      end if;
-
-      Extract_Target_Attributes
-        (Target_Id => Target_Id,
-         Attrs     => Target_Attrs);
-
-      --  Both the attribute and the corresponding body are in the same unit.
-      --  The corresponding body must appear prior to the root scenario which
-      --  started the recursive search. If this is not the case, then there is
-      --  a potential ABE if the access value is used to call the subprogram.
-      --  Emit a warning only when switch -gnatw.f (warnings on suspucious
-      --  'Access) is in effect.
-
-      if Warn_On_Elab_Access
-        and then Present (Target_Attrs.Body_Decl)
-        and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
-        and then Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl)
-      then
-         Error_Msg_Name_1 := Attribute_Name (Attr);
-         Error_Msg_NE ("??% attribute of & before body seen", Attr, Target_Id);
-         Error_Msg_N ("\possible Program_Error on later references", Attr);
-
-         Output_Active_Scenarios (Attr);
-      end if;
-
-      --  Treat the attribute as an immediate invocation of the target when
-      --  switch -gnatd.o (conservative elaboration order for indirect calls)
-      --  is in effect. Note that the prior elaboration of the unit containing
-      --  the target is ensured processing the corresponding call marker.
-
-      if Debug_Flag_Dot_O then
-         Process_Scenario
-           (N            => Build_Access_Marker (Target_Id),
-            In_Task_Body => In_Task_Body);
-
-      --  Otherwise ensure that the unit with the corresponding body is
-      --  elaborated prior to the main unit.
-
-      else
-         Ensure_Prior_Elaboration
-           (N            => Attr,
-            Unit_Id      => Target_Attrs.Unit_Id,
-            In_Task_Body => In_Task_Body);
-      end if;
-   end Process_Access;
-
-   -----------------------------
-   -- Process_Activation_Call --
-   -----------------------------
-
-   procedure Process_Activation_Call
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      In_Task_Body : Boolean)
+   --------------------------------
+   -- Process_Activation_Generic --
+   --------------------------------
+
+   procedure Process_Activation_Generic
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      State      : Processing_Attributes)
    is
       procedure Process_Task_Object (Obj_Id : Entity_Id; Typ : Entity_Id);
       --  Perform ABE checks and diagnostics for object Obj_Id with type Typ.
@@ -6369,8 +8430,8 @@
       --  component.
 
       procedure Process_Task_Objects (List : List_Id);
-      --  Perform ABE checks and diagnostics for all task objects found in
-      --  the list List.
+      --  Perform ABE checks and diagnostics for all task objects found in the
+      --  list List.
 
       -------------------------
       -- Process_Task_Object --
@@ -6382,30 +8443,54 @@
          Comp_Id    : Entity_Id;
          Task_Attrs : Task_Attributes;
 
+         New_State : Processing_Attributes := State;
+         --  Each step of the Processing phase constitutes a new state
+
       begin
          if Is_Task_Type (Typ) then
             Extract_Task_Attributes
               (Typ   => Base_Typ,
                Attrs => Task_Attrs);
 
+            --  Warnings are suppressed when a prior scenario is already in
+            --  that mode, or when the object, activation call, or task type
+            --  have warnings suppressed. Update the state of the Processing
+            --  phase to reflect this.
+
+            New_State.Suppress_Warnings :=
+              New_State.Suppress_Warnings
+                or else not Is_Elaboration_Warnings_OK_Id (Obj_Id)
+                or else not Call_Attrs.Elab_Warnings_OK
+                or else not Task_Attrs.Elab_Warnings_OK;
+
+            --  Update the state of the Processing phase to indicate that any
+            --  further traversal is now within a task body.
+
+            New_State.Within_Task_Body := True;
+
             Process_Single_Activation
-              (Call         => Call,
-               Call_Attrs   => Call_Attrs,
-               Obj_Id       => Obj_Id,
-               Task_Attrs   => Task_Attrs,
-               In_Task_Body => In_Task_Body);
+              (Call       => Call,
+               Call_Attrs => Call_Attrs,
+               Obj_Id     => Obj_Id,
+               Task_Attrs => Task_Attrs,
+               State      => New_State);
 
          --  Examine the component type when the object is an array
 
          elsif Is_Array_Type (Typ) and then Has_Task (Base_Typ) then
-            Process_Task_Object (Obj_Id, Component_Type (Typ));
+            Process_Task_Object
+              (Obj_Id => Obj_Id,
+               Typ    => Component_Type (Typ));
 
          --  Examine individual component types when the object is a record
 
          elsif Is_Record_Type (Typ) and then Has_Task (Base_Typ) then
             Comp_Id := First_Component (Typ);
             while Present (Comp_Id) loop
-               Process_Task_Object (Obj_Id, Etype (Comp_Id));
+               Process_Task_Object
+                 (Obj_Id => Obj_Id,
+                  Typ    => Etype (Comp_Id));
+
                Next_Component (Comp_Id);
             end loop;
          end if;
@@ -6431,7 +8516,9 @@
                Item_Typ := Etype (Item_Id);
 
                if Has_Task (Item_Typ) then
-                  Process_Task_Object (Item_Id, Item_Typ);
+                  Process_Task_Object
+                    (Obj_Id => Item_Id,
+                     Typ    => Item_Typ);
                end if;
             end if;
 
@@ -6444,7 +8531,7 @@
       Context : Node_Id;
       Spec    : Node_Id;
 
-   --  Start of processing for Process_Activation_Call
+   --  Start of processing for Process_Activation_Generic
 
    begin
       --  Nothing to do when the activation is a guaranteed ABE
@@ -6500,18 +8587,147 @@
 
          Process_Task_Objects (Statements (Context));
       end if;
-   end Process_Activation_Call;
+   end Process_Activation_Generic;
+
+   ------------------------------------
+   -- Process_Conditional_ABE_Access --
+   ------------------------------------
+
+   procedure Process_Conditional_ABE_Access
+     (Attr  : Node_Id;
+      State : Processing_Attributes)
+   is
+      function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id;
+      pragma Inline (Build_Access_Marker);
+      --  Create a suitable call marker which invokes target Target_Id
+
+      -------------------------
+      -- Build_Access_Marker --
+      -------------------------
+
+      function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id is
+         Marker : Node_Id;
+
+      begin
+         Marker := Make_Call_Marker (Sloc (Attr));
+
+         --  Inherit relevant attributes from the attribute
+
+         --  Performance note: parent traversal
+
+         Set_Target (Marker, Target_Id);
+         Set_Is_Declaration_Level_Node
+                    (Marker, Find_Enclosing_Level (Attr) = Declaration_Level);
+         Set_Is_Dispatching_Call
+                    (Marker, False);
+         Set_Is_Elaboration_Checks_OK_Node
+                    (Marker, Is_Elaboration_Checks_OK_Node (Attr));
+         Set_Is_Elaboration_Warnings_OK_Node
+                    (Marker, Is_Elaboration_Warnings_OK_Node (Attr));
+         Set_Is_Source_Call
+                    (Marker, Comes_From_Source (Attr));
+         Set_Is_SPARK_Mode_On_Node
+                    (Marker, Is_SPARK_Mode_On_Node (Attr));
+
+         --  Partially insert the call marker into the tree by setting its
+         --  parent pointer.
+
+         Set_Parent (Marker, Attr);
+
+         return Marker;
+      end Build_Access_Marker;
+
+      --  Local variables
+
+      Root      : constant Node_Id   := Root_Scenario;
+      Target_Id : constant Entity_Id := Entity (Prefix (Attr));
+
+      Target_Attrs : Target_Attributes;
+
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
+
+   --  Start of processing for Process_Conditional_ABE_Access
+
+   begin
+      --  Output relevant information when switch -gnatel (info messages on
+      --  implicit Elaborate[_All] pragmas) is in effect.
+
+      if Elab_Info_Messages then
+         Error_Msg_NE
+           ("info: access to & during elaboration", Attr, Target_Id);
+      end if;
+
+      Extract_Target_Attributes
+        (Target_Id => Target_Id,
+         Attrs     => Target_Attrs);
+
+      --  Warnings are suppressed when a prior scenario is already in that
+      --  mode, or when the attribute or the target have warnings suppressed.
+      --  Update the state of the Processing phase to reflect this.
+
+      New_State.Suppress_Warnings :=
+        New_State.Suppress_Warnings
+          or else not Is_Elaboration_Warnings_OK_Node (Attr)
+          or else not Target_Attrs.Elab_Warnings_OK;
+
+      --  Do not emit any ABE diagnostics when the current or previous scenario
+      --  in this traversal has suppressed elaboration warnings.
+
+      if New_State.Suppress_Warnings then
+         null;
+
+      --  Both the attribute and the corresponding body are in the same unit.
+      --  The corresponding body must appear prior to the root scenario which
+      --  started the recursive search. If this is not the case, then there is
+      --  a potential ABE if the access value is used to call the subprogram.
+      --  Emit a warning only when switch -gnatw.f (warnings on suspucious
+      --  'Access) is in effect.
+
+      elsif Warn_On_Elab_Access
+        and then Present (Target_Attrs.Body_Decl)
+        and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
+        and then Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl)
+      then
+         Error_Msg_Name_1 := Attribute_Name (Attr);
+         Error_Msg_NE ("??% attribute of & before body seen", Attr, Target_Id);
+         Error_Msg_N ("\possible Program_Error on later references", Attr);
+
+         Output_Active_Scenarios (Attr);
+      end if;
+
+      --  Treat the attribute as an immediate invocation of the target when
+      --  switch -gnatd.o (conservative elaboration order for indirect calls)
+      --  is in effect. Note that the prior elaboration of the unit containing
+      --  the target is ensured processing the corresponding call marker.
+
+      if Debug_Flag_Dot_O then
+         Process_Conditional_ABE
+           (N     => Build_Access_Marker (Target_Id),
+            State => New_State);
+
+      --  Otherwise ensure that the unit with the corresponding body is
+      --  elaborated prior to the main unit.
+
+      else
+         Ensure_Prior_Elaboration
+           (N        => Attr,
+            Unit_Id  => Target_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate_All,
+            State    => New_State);
+      end if;
+   end Process_Conditional_ABE_Access;
 
    ---------------------------------------------
-   -- Process_Activation_Conditional_ABE_Impl --
+   -- Process_Conditional_ABE_Activation_Impl --
    ---------------------------------------------
 
-   procedure Process_Activation_Conditional_ABE_Impl
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Obj_Id       : Entity_Id;
-      Task_Attrs   : Task_Attributes;
-      In_Task_Body : Boolean)
+   procedure Process_Conditional_ABE_Activation_Impl
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Obj_Id     : Entity_Id;
+      Task_Attrs : Task_Attributes;
+      State      : Processing_Attributes)
    is
       Check_OK : constant Boolean :=
                    not Is_Ignored_Ghost_Entity (Obj_Id)
@@ -6524,6 +8740,9 @@
 
       Root : constant Node_Id := Root_Scenario;
 
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
+
    begin
       --  Output relevant information when switch -gnatel (info messages on
       --  implicit Elaborate[_All] pragmas) is in effect.
@@ -6533,16 +8752,27 @@
            ("info: activation of & during elaboration", Call, Obj_Id);
       end if;
 
+      --  Nothing to do when the call activates a task whose type is defined
+      --  within an instance and switch -gnatd_i (ignore activations and calls
+      --  to instances for elaboration) is in effect.
+
+      if Debug_Flag_Underscore_I
+        and then In_External_Instance
+                   (N           => Call,
+                    Target_Decl => Task_Attrs.Task_Decl)
+      then
+         return;
+
       --  Nothing to do when the activation is a guaranteed ABE
 
-      if Is_Known_Guaranteed_ABE (Call) then
+      elsif Is_Known_Guaranteed_ABE (Call) then
          return;
 
       --  Nothing to do when the root scenario appears at the declaration
       --  level and the task is in the same unit, but outside this context.
-
+      --
       --    task type Task_Typ;                  --  task declaration
-
+      --
       --    procedure Proc is
       --       function A ... is
       --       begin
@@ -6554,14 +8784,14 @@
       --             end;
       --          ...
       --       end A;
-
+      --
       --       X : ... := A;                     --  root scenario
       --    ...
-
+      --
       --    task body Task_Typ is
       --       ...
       --    end Task_Typ;
-
+      --
       --  In the example above, the context of X is the declarative list of
       --  Proc. The "elaboration" of X may reach the activation of T whose body
       --  is defined outside of X's context. The task body is relevant only
@@ -6575,29 +8805,24 @@
          return;
 
       --  Nothing to do when the activation is ABE-safe
-
+      --
       --    generic
       --    package Gen is
       --       task type Task_Typ;
       --    end Gen;
-
+      --
       --    package body Gen is
       --       task body Task_Typ is
       --       begin
       --          ...
       --       end Task_Typ;
       --    end Gen;
-
+      --
       --    with Gen;
       --    procedure Main is
       --       package Nested is
-      --          ...
-      --       end Nested;
-
-      --       package body Nested is
       --          package Inst is new Gen;
       --          T : Inst.Task_Typ;
-      --      [begin]
       --          <activation call>              --  safe activation
       --       end Nested;
       --    ...
@@ -6616,33 +8841,27 @@
       then
          --  If the root scenario appears prior to the task body, then this is
          --  a possible ABE with respect to the root scenario.
-
+         --
          --    task type Task_Typ;
-
+         --
          --    function A ... is
          --    begin
          --       if Some_Condition then
          --          declare
          --             package Pack is
-         --                ...
-         --             end Pack;
-
-         --             package body Pack is
          --                T : Task_Typ;
-         --            [begin]
-         --                <activation call>     --  activation of T
-         --             end Pack;
+         --             end Pack;                --  activation of T
          --       ...
          --    end A;
-
+         --
          --    X : ... := A;                     --  root scenario
-
+         --
          --    task body Task_Typ is             --  task body
          --       ...
          --    end Task_Typ;
-
+         --
          --    Y : ... := A;                     --  root scenario
-
+         --
          --  IMPORTANT: The activation of T is a possible ABE for X, but
          --  not for Y. Intalling an unconditional ABE raise prior to the
          --  activation call would be wrong as it will fail for Y as well
@@ -6650,12 +8869,25 @@
 
          if Earlier_In_Extended_Unit (Root, Task_Attrs.Body_Decl) then
 
+            --  Do not emit any ABE diagnostics when a previous scenario in
+            --  this traversal has suppressed elaboration warnings.
+
+            if State.Suppress_Warnings then
+               null;
+
+            --  Do not emit any ABE diagnostics when the activation occurs in
+            --  a partial finalization context because this leads to confusing
+            --  noise.
+
+            elsif State.Within_Partial_Finalization then
+               null;
+
             --  ABE diagnostics are emitted only in the static model because
             --  there is a well-defined order to visiting scenarios. Without
             --  this order diagnostics appear jumbled and result in unwanted
             --  noise.
 
-            if Static_Elaboration_Checks then
+            elsif Static_Elaboration_Checks then
                Error_Msg_Sloc := Sloc (Call);
                Error_Msg_N
                  ("??task & will be activated # before elaboration of its "
@@ -6676,6 +8908,40 @@
                   Target_Id   => Task_Attrs.Spec_Id,
                   Target_Decl => Task_Attrs.Task_Decl,
                   Target_Body => Task_Attrs.Body_Decl);
+
+               --  Update the state of the Processing phase to indicate that
+               --  no implicit Elaborate[_All] pragmas must be generated from
+               --  this point on.
+               --
+               --    task type Task_Typ;
+               --
+               --    function A ... is
+               --    begin
+               --       if Some_Condition then
+               --          declare
+               --             package Pack is
+               --                <ABE check>
+               --                T : Task_Typ;
+               --             end Pack;          --  activation of T
+               --       ...
+               --    end A;
+               --
+               --    X : ... := A;
+               --
+               --    task body Task_Typ is
+               --    begin
+               --       External.Subp;           --  imparts Elaborate_All
+               --    end Task_Typ;
+               --
+               --  If Some_Condition is True, then the ABE check will fail at
+               --  runtime and the call to External.Subp will never take place,
+               --  rendering the implicit Elaborate_All useless.
+               --
+               --  If Some_Condition is False, then the call to External.Subp
+               --  will never take place, rendering the implicit Elaborate_All
+               --  useless.
+
+               New_State.Suppress_Implicit_Pragmas := True;
             end if;
          end if;
 
@@ -6707,291 +8973,39 @@
 
       else
          Ensure_Prior_Elaboration
-           (N            => Call,
-            Unit_Id      => Task_Attrs.Unit_Id,
-            In_Task_Body => In_Task_Body);
-      end if;
-
-      Traverse_Body (Task_Attrs.Body_Decl, In_Task_Body => True);
-   end Process_Activation_Conditional_ABE_Impl;
-
-   procedure Process_Activation_Conditional_ABE is
-     new Process_Activation_Call (Process_Activation_Conditional_ABE_Impl);
-
-   --------------------------------------------
-   -- Process_Activation_Guaranteed_ABE_Impl --
-   --------------------------------------------
-
-   procedure Process_Activation_Guaranteed_ABE_Impl
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Obj_Id       : Entity_Id;
-      Task_Attrs   : Task_Attributes;
-      In_Task_Body : Boolean)
-   is
-      pragma Unreferenced (Call_Attrs);
-      pragma Unreferenced (In_Task_Body);
-
-      Check_OK : constant Boolean :=
-                   not Is_Ignored_Ghost_Entity (Obj_Id)
-                     and then not Task_Attrs.Ghost_Mode_Ignore
-                     and then Is_Elaboration_Checks_OK_Id (Obj_Id)
-                     and then Task_Attrs.Elab_Checks_OK;
-      --  A run-time ABE check may be installed only when the object and the
-      --  task type have active elaboration checks, and both are not ignored
-      --  Ghost constructs.
-
-   begin
-      --  Nothing to do when the root scenario appears at the declaration
-      --  level and the task is in the same unit, but outside this context.
-
-      --    task type Task_Typ;                  --  task declaration
-
-      --    procedure Proc is
-      --       function A ... is
-      --       begin
-      --          if Some_Condition then
-      --             declare
-      --                T : Task_Typ;
-      --             begin
-      --                <activation call>        --  activation site
-      --             end;
-      --          ...
-      --       end A;
-
-      --       X : ... := A;                     --  root scenario
-      --    ...
-
-      --    task body Task_Typ is
-      --       ...
-      --    end Task_Typ;
-
-      --  In the example above, the context of X is the declarative list of
-      --  Proc. The "elaboration" of X may reach the activation of T whose body
-      --  is defined outside of X's context. The task body is relevant only
-      --  when Proc is invoked, but this happens only in "normal" elaboration,
-      --  therefore the task body must not be considered if this is not the
-      --  case.
-
-      --  Performance note: parent traversal
-
-      if Is_Up_Level_Target (Task_Attrs.Task_Decl) then
-         return;
-
-      --  Nothing to do when the activation is ABE-safe
-
-      --    generic
-      --    package Gen is
-      --       task type Task_Typ;
-      --    end Gen;
-
-      --    package body Gen is
-      --       task body Task_Typ is
-      --       begin
-      --          ...
-      --       end Task_Typ;
-      --    end Gen;
-
-      --    with Gen;
-      --    procedure Main is
-      --       package Nested is
-      --          ...
-      --       end Nested;
-
-      --       package body Nested is
-      --          package Inst is new Gen;
-      --          T : Inst.Task_Typ;
-      --      [begin]
-      --          <activation call>              --  safe activation
-      --       end Nested;
-      --    ...
-
-      elsif Is_Safe_Activation (Call, Task_Attrs.Task_Decl) then
-         return;
-
-      --  An activation call leads to a guaranteed ABE when the activation
-      --  call and the task appear within the same context ignoring library
-      --  levels, and the body of the task has not been seen yet or appears
-      --  after the activation call.
-
-      --    procedure Guaranteed_ABE is
-      --       task type Task_Typ;
-
-      --       package Nested is
-      --          ...
-      --       end Nested;
-
-      --       package body Nested is
-      --          T : Task_Typ;
-      --      [begin]
-      --          <activation call>              --  guaranteed ABE
-      --       end Nested;
-
-      --       task body Task_Typ is
-      --          ...
-      --       end Task_Typ;
-      --    ...
-
-      --  Performance note: parent traversal
-
-      elsif Is_Guaranteed_ABE
-              (N           => Call,
-               Target_Decl => Task_Attrs.Task_Decl,
-               Target_Body => Task_Attrs.Body_Decl)
-      then
-         Error_Msg_Sloc := Sloc (Call);
-         Error_Msg_N
-           ("??task & will be activated # before elaboration of its body",
-            Obj_Id);
-         Error_Msg_N ("\Program_Error will be raised at run time", Obj_Id);
-
-         --  Mark the activation call as a guaranteed ABE
-
-         Set_Is_Known_Guaranteed_ABE (Call);
-
-         --  Install a run-time ABE failue because this activation call will
-         --  always result in an ABE.
-
-         if Check_OK then
-            Install_ABE_Failure
-              (N       => Call,
-               Ins_Nod => Call);
-         end if;
-      end if;
-   end Process_Activation_Guaranteed_ABE_Impl;
-
-   procedure Process_Activation_Guaranteed_ABE is
-     new Process_Activation_Call (Process_Activation_Guaranteed_ABE_Impl);
-
-   ------------------
-   -- Process_Call --
-   ------------------
-
-   procedure Process_Call
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      In_Task_Body : Boolean)
-   is
-      SPARK_Rules_On : Boolean;
-      Target_Attrs   : Target_Attributes;
-
-   begin
-      Extract_Target_Attributes
-        (Target_Id => Target_Id,
-         Attrs     => Target_Attrs);
-
-      --  The SPARK rules are in effect when both the call and target are
-      --  subject to SPARK_Mode On.
-
-      SPARK_Rules_On :=
-        Call_Attrs.SPARK_Mode_On and Target_Attrs.SPARK_Mode_On;
-
-      --  Output relevant information when switch -gnatel (info messages on
-      --  implicit Elaborate[_All] pragmas) is in effect.
-
-      if Elab_Info_Messages then
-         Info_Call
-           (Call      => Call,
-            Target_Id => Target_Id,
-            Info_Msg  => True,
-            In_SPARK  => SPARK_Rules_On);
-      end if;
-
-      --  Check whether the invocation of an entry clashes with an existing
-      --  restriction.
-
-      if Is_Protected_Entry (Target_Id) then
-         Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
-
-      elsif Is_Task_Entry (Target_Id) then
-         Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
-
-         --  Task entry calls are never processed because the entry being
-         --  invoked does not have a corresponding "body", it has a select.
-
-         return;
-      end if;
-
-      --  Nothing to do when the call is a guaranteed ABE
-
-      if Is_Known_Guaranteed_ABE (Call) then
-         return;
-
-      --  Nothing to do when the root scenario appears at the declaration level
-      --  and the target is in the same unit, but outside this context.
-
-      --    function B ...;                      --  target declaration
-
-      --    procedure Proc is
-      --       function A ... is
-      --       begin
-      --          if Some_Condition then
-      --             return B;                   --  call site
-      --          ...
-      --       end A;
-
-      --       X : ... := A;                     --  root scenario
-      --    ...
-
-      --    function B ... is
-      --       ...
-      --    end B;
-
-      --  In the example above, the context of X is the declarative region of
-      --  Proc. The "elaboration" of X may eventually reach B which is defined
-      --  outside of X's context. B is relevant only when Proc is invoked, but
-      --  this happens only by means of "normal" elaboration, therefore B must
-      --  not be considered if this is not the case.
-
-      --  Performance note: parent traversal
-
-      elsif Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
-         return;
-
-      --  The SPARK rules are verified only when -gnatd.v (enforce SPARK
-      --  elaboration rules in SPARK code) is in effect.
-
-      elsif SPARK_Rules_On and Debug_Flag_Dot_V then
-         Process_Call_SPARK
-           (Call         => Call,
-            Call_Attrs   => Call_Attrs,
-            Target_Id    => Target_Id,
-            Target_Attrs => Target_Attrs);
-
-      --  Otherwise the Ada rules are in effect, or SPARK code is allowed to
-      --  violate the SPARK rules.
-
-      else
-         Process_Call_Ada
-           (Call         => Call,
-            Call_Attrs   => Call_Attrs,
-            Target_Id    => Target_Id,
-            Target_Attrs => Target_Attrs,
-            In_Task_Body => In_Task_Body);
-      end if;
-
-      --  Inspect the target body (and barried function) for other suitable
-      --  elaboration scenarios.
-
-      Traverse_Body (Target_Attrs.Body_Barf, In_Task_Body);
-      Traverse_Body (Target_Attrs.Body_Decl, In_Task_Body);
-   end Process_Call;
-
-   ----------------------
-   -- Process_Call_Ada --
-   ----------------------
-
-   procedure Process_Call_Ada
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      Target_Attrs : Target_Attributes;
-      In_Task_Body : Boolean)
+           (N        => Call,
+            Unit_Id  => Task_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate_All,
+            State    => New_State);
+      end if;
+
+      Traverse_Body
+        (N     => Task_Attrs.Body_Decl,
+         State => New_State);
+   end Process_Conditional_ABE_Activation_Impl;
+
+   procedure Process_Conditional_ABE_Activation is
+     new Process_Activation_Generic (Process_Conditional_ABE_Activation_Impl);
+
+   ----------------------------------
+   -- Process_Conditional_ABE_Call --
+   ----------------------------------
+
+   procedure Process_Conditional_ABE_Call
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Target_Id  : Entity_Id;
+      State      : Processing_Attributes)
    is
       function In_Initialization_Context (N : Node_Id) return Boolean;
-      --  Determine whether arbitrary node N appears within a type init proc or
-      --  primitive [Deep_]Initialize.
+      --  Determine whether arbitrary node N appears within a type init proc,
+      --  primitive [Deep_]Initialize, or a block created for initialization
+      --  purposes.
+
+      function Is_Partial_Finalization_Proc return Boolean;
+      pragma Inline (Is_Partial_Finalization_Proc);
+      --  Determine whether call Call with target Target_Id invokes a partial
+      --  finalization procedure.
 
       -------------------------------
       -- In_Initialization_Context --
@@ -7042,8 +9056,190 @@
          return False;
       end In_Initialization_Context;
 
+      ----------------------------------
+      -- Is_Partial_Finalization_Proc --
+      ----------------------------------
+
+      function Is_Partial_Finalization_Proc return Boolean is
+      begin
+         --  To qualify, the target must denote primitive [Deep_]Finalize or a
+         --  finalizer procedure, and the call must appear in an initialization
+         --  context.
+
+         return
+           (Is_Controlled_Proc (Target_Id, Name_Finalize)
+              or else Is_Finalizer_Proc (Target_Id)
+              or else Is_TSS (Target_Id, TSS_Deep_Finalize))
+            and then In_Initialization_Context (Call);
+      end Is_Partial_Finalization_Proc;
+
       --  Local variables
 
+      SPARK_Rules_On : Boolean;
+      Target_Attrs   : Target_Attributes;
+
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
+
+   --  Start of processing for Process_Conditional_ABE_Call
+
+   begin
+      Extract_Target_Attributes
+        (Target_Id => Target_Id,
+         Attrs     => Target_Attrs);
+
+      --  The SPARK rules are in effect when both the call and target are
+      --  subject to SPARK_Mode On.
+
+      SPARK_Rules_On :=
+        Call_Attrs.SPARK_Mode_On and Target_Attrs.SPARK_Mode_On;
+
+      --  Output relevant information when switch -gnatel (info messages on
+      --  implicit Elaborate[_All] pragmas) is in effect.
+
+      if Elab_Info_Messages then
+         Info_Call
+           (Call      => Call,
+            Target_Id => Target_Id,
+            Info_Msg  => True,
+            In_SPARK  => SPARK_Rules_On);
+      end if;
+
+      --  Check whether the invocation of an entry clashes with an existing
+      --  restriction.
+
+      if Is_Protected_Entry (Target_Id) then
+         Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
+
+      elsif Is_Task_Entry (Target_Id) then
+         Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
+
+         --  Task entry calls are never processed because the entry being
+         --  invoked does not have a corresponding "body", it has a select.
+
+         return;
+      end if;
+
+      --  Nothing to do when the call invokes a target defined within an
+      --  instance and switch -gnatd_i (ignore activations and calls to
+      --  instances for elaboration) is in effect.
+
+      if Debug_Flag_Underscore_I
+        and then In_External_Instance
+                   (N           => Call,
+                    Target_Decl => Target_Attrs.Spec_Decl)
+      then
+         return;
+
+      --  Nothing to do when the call is a guaranteed ABE
+
+      elsif Is_Known_Guaranteed_ABE (Call) then
+         return;
+
+      --  Nothing to do when the root scenario appears at the declaration level
+      --  and the target is in the same unit, but outside this context.
+      --
+      --    function B ...;                      --  target declaration
+      --
+      --    procedure Proc is
+      --       function A ... is
+      --       begin
+      --          if Some_Condition then
+      --             return B;                   --  call site
+      --          ...
+      --       end A;
+      --
+      --       X : ... := A;                     --  root scenario
+      --    ...
+      --
+      --    function B ... is
+      --       ...
+      --    end B;
+      --
+      --  In the example above, the context of X is the declarative region of
+      --  Proc. The "elaboration" of X may eventually reach B which is defined
+      --  outside of X's context. B is relevant only when Proc is invoked, but
+      --  this happens only by means of "normal" elaboration, therefore B must
+      --  not be considered if this is not the case.
+
+      --  Performance note: parent traversal
+
+      elsif Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
+         return;
+      end if;
+
+      --  Warnings are suppressed when a prior scenario is already in that
+      --  mode, or the call or target have warnings suppressed. Update the
+      --  state of the Processing phase to reflect this.
+
+      New_State.Suppress_Warnings :=
+        New_State.Suppress_Warnings
+          or else not Call_Attrs.Elab_Warnings_OK
+          or else not Target_Attrs.Elab_Warnings_OK;
+
+      --  The call occurs in an initial condition context when a prior scenario
+      --  is already in that mode, or when the target is an Initial_Condition
+      --  procedure. Update the state of the Processing phase to reflect this.
+
+      New_State.Within_Initial_Condition :=
+        New_State.Within_Initial_Condition
+          or else Is_Initial_Condition_Proc (Target_Id);
+
+      --  The call occurs in a partial finalization context when a prior
+      --  scenario is already in that mode, or when the target denotes a
+      --  [Deep_]Finalize primitive or a finalizer within an initialization
+      --  context. Update the state of the Processing phase to reflect this.
+
+      New_State.Within_Partial_Finalization :=
+        New_State.Within_Partial_Finalization
+          or else Is_Partial_Finalization_Proc;
+
+      --  The SPARK rules are in effect. Note that -gnatd.v (enforce SPARK
+      --  elaboration rules in SPARK code) is intentionally not taken into
+      --  account here because Process_Conditional_ABE_Call_SPARK has two
+      --  separate modes of operation.
+
+      if SPARK_Rules_On then
+         Process_Conditional_ABE_Call_SPARK
+           (Call         => Call,
+            Target_Id    => Target_Id,
+            Target_Attrs => Target_Attrs,
+            State        => New_State);
+
+      --  Otherwise the Ada rules are in effect
+
+      else
+         Process_Conditional_ABE_Call_Ada
+           (Call         => Call,
+            Call_Attrs   => Call_Attrs,
+            Target_Id    => Target_Id,
+            Target_Attrs => Target_Attrs,
+            State        => New_State);
+      end if;
+
+      --  Inspect the target body (and barried function) for other suitable
+      --  elaboration scenarios.
+
+      Traverse_Body
+        (N     => Target_Attrs.Body_Barf,
+         State => New_State);
+
+      Traverse_Body
+        (N     => Target_Attrs.Body_Decl,
+         State => New_State);
+   end Process_Conditional_ABE_Call;
+
+   --------------------------------------
+   -- Process_Conditional_ABE_Call_Ada --
+   --------------------------------------
+
+   procedure Process_Conditional_ABE_Call_Ada
+     (Call         : Node_Id;
+      Call_Attrs   : Call_Attributes;
+      Target_Id    : Entity_Id;
+      Target_Attrs : Target_Attributes;
+      State        : Processing_Attributes)
+   is
       Check_OK : constant Boolean :=
                    not Call_Attrs.Ghost_Mode_Ignore
                      and then not Target_Attrs.Ghost_Mode_Ignore
@@ -7053,7 +9249,10 @@
       --  target have active elaboration checks, and both are not ignored Ghost
       --  constructs.
 
-   --  Start of processing for Process_Call_Ada
+      Root : constant Node_Id := Root_Scenario;
+
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
 
    begin
       --  Nothing to do for an Ada dispatching call because there are no ABE
@@ -7064,15 +9263,15 @@
          return;
 
       --  Nothing to do when the call is ABE-safe
-
+      --
       --    generic
       --    function Gen ...;
-
+      --
       --    function Gen ... is
       --    begin
       --       ...
       --    end Gen;
-
+      --
       --    with Gen;
       --    procedure Main is
       --       function Inst is new Gen;
@@ -7087,11 +9286,101 @@
       elsif Present (Target_Attrs.Body_Decl)
         and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
       then
-         Process_Call_Conditional_ABE
-           (Call         => Call,
-            Call_Attrs   => Call_Attrs,
-            Target_Id    => Target_Id,
-            Target_Attrs => Target_Attrs);
+         --  If the root scenario appears prior to the target body, then this
+         --  is a possible ABE with respect to the root scenario.
+         --
+         --    function B ...;
+         --
+         --    function A ... is
+         --    begin
+         --       if Some_Condition then
+         --          return B;                      --  call site
+         --       ...
+         --    end A;
+         --
+         --    X : ... := A;                        --  root scenario
+         --
+         --    function B ... is                    --  target body
+         --       ...
+         --    end B;
+         --
+         --    Y : ... := A;                        --  root scenario
+         --
+         --  IMPORTANT: The call to B from A is a possible ABE for X, but not
+         --  for Y. Installing an unconditional ABE raise prior to the call to
+         --  B would be wrong as it will fail for Y as well, but in Y's case
+         --  the call to B is never an ABE.
+
+         if Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl) then
+
+            --  Do not emit any ABE diagnostics when a previous scenario in
+            --  this traversal has suppressed elaboration warnings.
+
+            if State.Suppress_Warnings then
+               null;
+
+            --  Do not emit any ABE diagnostics when the call occurs in a
+            --  partial finalization context because this leads to confusing
+            --  noise.
+
+            elsif State.Within_Partial_Finalization then
+               null;
+
+            --  ABE diagnostics are emitted only in the static model because
+            --  there is a well-defined order to visiting scenarios. Without
+            --  this order diagnostics appear jumbled and result in unwanted
+            --  noise.
+
+            elsif Static_Elaboration_Checks then
+               Error_Msg_NE
+                 ("??cannot call & before body seen", Call, Target_Id);
+               Error_Msg_N ("\Program_Error may be raised at run time", Call);
+
+               Output_Active_Scenarios (Call);
+            end if;
+
+            --  Install a conditional run-time ABE check to verify that the
+            --  target body has been elaborated prior to the call.
+
+            if Check_OK then
+               Install_ABE_Check
+                 (N           => Call,
+                  Ins_Nod     => Call,
+                  Target_Id   => Target_Attrs.Spec_Id,
+                  Target_Decl => Target_Attrs.Spec_Decl,
+                  Target_Body => Target_Attrs.Body_Decl);
+
+               --  Update the state of the Processing phase to indicate that
+               --  no implicit Elaborate[_All] pragmas must be generated from
+               --  this point on.
+               --
+               --    function B ...;
+               --
+               --    function A ... is
+               --    begin
+               --       if Some_Condition then
+               --          <ABE check>
+               --          return B;
+               --       ...
+               --    end A;
+               --
+               --    X : ... := A;
+               --
+               --    function B ... is
+               --       External.Subp;           --  imparts Elaborate_All
+               --    end B;
+               --
+               --  If Some_Condition is True, then the ABE check will fail at
+               --  runtime and the call to External.Subp will never take place,
+               --  rendering the implicit Elaborate_All useless.
+               --
+               --  If Some_Condition is False, then the call to External.Subp
+               --  will never take place, rendering the implicit Elaborate_All
+               --  useless.
+
+               New_State.Suppress_Implicit_Pragmas := True;
+            end if;
+         end if;
 
       --  Otherwise the target body is not available in this compilation or it
       --  resides in an external unit. Install a run-time ABE check to verify
@@ -7105,345 +9394,219 @@
             Id      => Target_Attrs.Unit_Id);
       end if;
 
-      --  No implicit pragma Elaborate[_All] is generated when the call has
-      --  elaboration checks suppressed. This behaviour parallels that of the
-      --  old ABE mechanism.
-
-      if not Call_Attrs.Elab_Checks_OK then
-         null;
-
-      --  No implicit pragma Elaborate[_All] is generated for finalization
-      --  actions when primitive [Deep_]Finalize is not defined in the main
-      --  unit and the call appears within some initialization actions. This
-      --  behaviour parallels that of the old ABE mechanism.
-
-      --  Performance note: parent traversal
-
-      elsif (Is_Controlled_Proc (Target_Id, Name_Finalize)
-              or else Is_TSS (Target_Id, TSS_Deep_Finalize))
-        and then not In_Extended_Main_Code_Unit (Target_Attrs.Spec_Decl)
-        and then In_Initialization_Context (Call)
-      then
-         null;
+      --  Ensure that the unit with the target body is elaborated prior to the
+      --  main unit. The implicit Elaborate[_All] is generated only when the
+      --  call has elaboration checks enabled. This behaviour parallels that of
+      --  the old ABE mechanism.
+
+      if Call_Attrs.Elab_Checks_OK then
+         Ensure_Prior_Elaboration
+           (N        => Call,
+            Unit_Id  => Target_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate_All,
+            State    => New_State);
+      end if;
+   end Process_Conditional_ABE_Call_Ada;
+
+   ----------------------------------------
+   -- Process_Conditional_ABE_Call_SPARK --
+   ----------------------------------------
+
+   procedure Process_Conditional_ABE_Call_SPARK
+     (Call         : Node_Id;
+      Target_Id    : Entity_Id;
+      Target_Attrs : Target_Attributes;
+      State        : Processing_Attributes)
+   is
+      Region : Node_Id;
+
+   begin
+      --  Ensure that a suitable elaboration model is in effect for SPARK rule
+      --  verification.
+
+      Check_SPARK_Model_In_Effect (Call);
+
+      --  The call and the target body are both in the main unit
+
+      if Present (Target_Attrs.Body_Decl)
+        and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
+      then
+         --  If the call appears prior to the target body, then the call must
+         --  appear within the early call region of the target body.
+         --
+         --    function B ...;
+         --
+         --    X : ... := B;                     --  call site
+         --
+         --    <preelaborable construct 1>       --+
+         --               ...                      | early call region
+         --    <preelaborable construct N>       --+
+         --
+         --    function B ... is                 --  target body
+         --       ...
+         --    end B;
+         --
+         --  When the call to B is not nested within some other scenario, the
+         --  call is automatically illegal because it can never appear in the
+         --  early call region of B's body. This is equivalent to a guaranteed
+         --  ABE.
+         --
+         --    <preelaborable construct 1>       --+
+         --                                        |
+         --    function B ...;                     |
+         --                                        |
+         --    function A ... is                   |
+         --    begin                               | early call region
+         --       if Some_Condition then
+         --          return B;                   --  call site
+         --       ...
+         --    end A;                              |
+         --                                        |
+         --    <preelaborable construct N>       --+
+         --
+         --    function B ... is                 --  target body
+         --       ...
+         --    end B;
+         --
+         --  When the call to B is nested within some other scenario, the call
+         --  is always ABE-safe. It is not immediately obvious why this is the
+         --  case. The elaboration safety follows from the early call region
+         --  rule being applied to ALL calls preceding their associated bodies.
+         --
+         --  In the example above, the call to B is safe as long as the call to
+         --  A is safe. There are several cases to consider:
+         --
+         --    <call 1 to A>
+         --    function B ...;
+         --
+         --    <call 2 to A>
+         --    function A ... is
+         --    begin
+         --       if Some_Condition then
+         --          return B;
+         --       ...
+         --    end A;
+         --
+         --    <call 3 to A>
+         --    function B ... is
+         --       ...
+         --    end B;
+         --
+         --  * Call 1 - This call is either nested within some scenario or not,
+         --    which falls under the two general cases outlined above.
+         --
+         --  * Call 2 - This is the same case as Call 1.
+         --
+         --  * Call 3 - The placement of this call limits the range of B's
+         --    early call region unto call 3, therefore the call to B is no
+         --    longer within the early call region of B's body, making it ABE-
+         --    unsafe and therefore illegal.
+
+         if Earlier_In_Extended_Unit (Call, Target_Attrs.Body_Decl) then
+
+            --  Do not emit any ABE diagnostics when a previous scenario in
+            --  this traversal has suppressed elaboration warnings.
+
+            if State.Suppress_Warnings then
+               null;
+
+            --  Do not emit any ABE diagnostics when the call occurs in an
+            --  initial condition context because this leads to incorrect
+            --  diagnostics.
+
+            elsif State.Within_Initial_Condition then
+               null;
+
+            --  Do not emit any ABE diagnostics when the call occurs in a
+            --  partial finalization context because this leads to confusing
+            --  noise.
+
+            elsif State.Within_Partial_Finalization then
+               null;
+
+            --  ABE diagnostics are emitted only in the static model because
+            --  there is a well-defined order to visiting scenarios. Without
+            --  this order diagnostics appear jumbled and result in unwanted
+            --  noise.
+
+            elsif Static_Elaboration_Checks then
+
+               --  Ensure that a call which textually precedes the subprogram
+               --  body it invokes appears within the early call region of the
+               --  subprogram body.
+
+               --  IMPORTANT: This check must always be performed even when
+               --  -gnatd.v (enforce SPARK elaboration rules in SPARK code) is
+               --  not specified because the static model cannot guarantee the
+               --  absence of elaboration issues in the presence of dispatching
+               --  calls.
+
+               Region := Find_Early_Call_Region (Target_Attrs.Body_Decl);
+
+               if Earlier_In_Extended_Unit (Call, Region) then
+                  Error_Msg_NE
+                    ("call must appear within early call region of subprogram "
+                     & "body & (SPARK RM 7.7(3))", Call, Target_Id);
+
+                  Error_Msg_Sloc := Sloc (Region);
+                  Error_Msg_N ("\region starts #", Call);
+
+                  Error_Msg_Sloc := Sloc (Target_Attrs.Body_Decl);
+                  Error_Msg_N ("\region ends #", Call);
+
+                  Output_Active_Scenarios (Call);
+               end if;
+            end if;
+
+         --  Otherwise the call appears after the target body. The call is
+         --  ABE-safe as a consequence of applying the early call region rule
+         --  to ALL calls preceding their associated bodies.
+
+         else
+            null;
+         end if;
+      end if;
+
+      --  A call to a source target or to a target which emulates Ada or SPARK
+      --  semantics imposes an Elaborate_All requirement on the context of the
+      --  main unit. Determine whether the context has a pragma strong enough
+      --  to meet the requirement.
+
+      --  IMPORTANT: This check must be performed only when -gnatd.v (enforce
+      --  SPARK elaboration rules in SPARK code) is active because the static
+      --  model can ensure the prior elaboration of the unit which contains a
+      --  body by installing an implicit Elaborate[_All] pragma.
+
+      if Debug_Flag_Dot_V then
+         if Target_Attrs.From_Source
+           or else Is_Ada_Semantic_Target (Target_Id)
+           or else Is_SPARK_Semantic_Target (Target_Id)
+         then
+            Meet_Elaboration_Requirement
+              (N         => Call,
+               Target_Id => Target_Id,
+               Req_Nam   => Name_Elaborate_All);
+         end if;
 
       --  Otherwise ensure that the unit with the target body is elaborated
       --  prior to the main unit.
 
       else
          Ensure_Prior_Elaboration
-           (N            => Call,
-            Unit_Id      => Target_Attrs.Unit_Id,
-            In_Task_Body => In_Task_Body);
-      end if;
-   end Process_Call_Ada;
-
-   ----------------------------------
-   -- Process_Call_Conditional_ABE --
-   ----------------------------------
-
-   procedure Process_Call_Conditional_ABE
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      Target_Attrs : Target_Attributes)
-   is
-      Check_OK : constant Boolean :=
-                   not Call_Attrs.Ghost_Mode_Ignore
-                     and then not Target_Attrs.Ghost_Mode_Ignore
-                     and then Call_Attrs.Elab_Checks_OK
-                     and then Target_Attrs.Elab_Checks_OK;
-      --  A run-time ABE check may be installed only when both the call and the
-      --  target have active elaboration checks, and both are not ignored Ghost
-      --  constructs.
-
-      Root : constant Node_Id := Root_Scenario;
-
-   begin
-      --  If the root scenario appears prior to the target body, then this is a
-      --  possible ABE with respect to the root scenario.
-
-      --    function B ...;
-
-      --    function A ... is
-      --    begin
-      --       if Some_Condition then
-      --          return B;                      --  call site
-      --       ...
-      --    end A;
-
-      --    X : ... := A;                        --  root scenario
-
-      --    function B ... is                    --  target body
-      --       ...
-      --    end B;
-
-      --    Y : ... := A;                        --  root scenario
-
-      --  IMPORTANT: The call to B from A is a possible ABE for X, but not for
-      --  Y. Installing an unconditional ABE raise prior to the call to B would
-      --  be wrong as it will fail for Y as well, but in Y's case the call to B
-      --  is never an ABE.
-
-      if Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl) then
-
-         --  ABE diagnostics are emitted only in the static model because there
-         --  is a well-defined order to visiting scenarios. Without this order
-         --  diagnostics appear jumbled and result in unwanted noise.
-
-         if Static_Elaboration_Checks then
-            Error_Msg_NE ("??cannot call & before body seen", Call, Target_Id);
-            Error_Msg_N ("\Program_Error may be raised at run time", Call);
-
-            Output_Active_Scenarios (Call);
-         end if;
-
-         --  Install a conditional run-time ABE check to verify that the target
-         --  body has been elaborated prior to the call.
-
-         if Check_OK then
-            Install_ABE_Check
-              (N           => Call,
-               Ins_Nod     => Call,
-               Target_Id   => Target_Attrs.Spec_Id,
-               Target_Decl => Target_Attrs.Spec_Decl,
-               Target_Body => Target_Attrs.Body_Decl);
-         end if;
-      end if;
-   end Process_Call_Conditional_ABE;
-
-   ---------------------------------
-   -- Process_Call_Guaranteed_ABE --
-   ---------------------------------
-
-   procedure Process_Call_Guaranteed_ABE
-     (Call       : Node_Id;
-      Call_Attrs : Call_Attributes;
-      Target_Id  : Entity_Id)
-   is
-      Target_Attrs : Target_Attributes;
-
-   begin
-      Extract_Target_Attributes
-        (Target_Id => Target_Id,
-         Attrs     => Target_Attrs);
-
-      --  Nothing to do when the root scenario appears at the declaration level
-      --  and the target is in the same unit, but outside this context.
-
-      --    function B ...;                      --  target declaration
-
-      --    procedure Proc is
-      --       function A ... is
-      --       begin
-      --          if Some_Condition then
-      --             return B;                   --  call site
-      --          ...
-      --       end A;
-
-      --       X : ... := A;                     --  root scenario
-      --    ...
-
-      --    function B ... is
-      --       ...
-      --    end B;
-
-      --  In the example above, the context of X is the declarative region of
-      --  Proc. The "elaboration" of X may eventually reach B which is defined
-      --  outside of X's context. B is relevant only when Proc is invoked, but
-      --  this happens only by means of "normal" elaboration, therefore B must
-      --  not be considered if this is not the case.
-
-      --  Performance note: parent traversal
-
-      if Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
-         return;
-
-      --  Nothing to do when the call is ABE-safe
-
-      --    generic
-      --    function Gen ...;
-
-      --    function Gen ... is
-      --    begin
-      --       ...
-      --    end Gen;
-
-      --    with Gen;
-      --    procedure Main is
-      --       function Inst is new Gen;
-      --       X : ... := Inst;                  --  safe call
-      --    ...
-
-      elsif Is_Safe_Call (Call, Target_Attrs) then
-         return;
-
-      --  A call leads to a guaranteed ABE when the call and the target appear
-      --  within the same context ignoring library levels, and the body of the
-      --  target has not been seen yet or appears after the call.
-
-      --    procedure Guaranteed_ABE is
-      --       function Func ...;
-
-      --       package Nested is
-      --          Obj : ... := Func;             --  guaranteed ABE
-      --       end Nested;
-
-      --       function Func ... is
-      --          ...
-      --       end Func;
-      --    ...
-
-      --  Performance note: parent traversal
-
-      elsif Is_Guaranteed_ABE
-              (N           => Call,
-               Target_Decl => Target_Attrs.Spec_Decl,
-               Target_Body => Target_Attrs.Body_Decl)
-      then
-         Error_Msg_NE ("??cannot call & before body seen", Call, Target_Id);
-         Error_Msg_N ("\Program_Error will be raised at run time", Call);
-
-         --  Mark the call as a guarnateed ABE
-
-         Set_Is_Known_Guaranteed_ABE (Call);
-
-         --  Install a run-time ABE failure because the call will always result
-         --  in an ABE. The failure is installed when both the call and target
-         --  have enabled elaboration checks, and both are not ignored Ghost
-         --  constructs.
-
-         if Call_Attrs.Elab_Checks_OK
-           and then Target_Attrs.Elab_Checks_OK
-           and then not Call_Attrs.Ghost_Mode_Ignore
-           and then not Target_Attrs.Ghost_Mode_Ignore
-         then
-            Install_ABE_Failure
-              (N       => Call,
-               Ins_Nod => Call);
-         end if;
-      end if;
-   end Process_Call_Guaranteed_ABE;
-
-   ------------------------
-   -- Process_Call_SPARK --
-   ------------------------
-
-   procedure Process_Call_SPARK
-     (Call         : Node_Id;
-      Call_Attrs   : Call_Attributes;
-      Target_Id    : Entity_Id;
-      Target_Attrs : Target_Attributes)
-   is
-   begin
-      --  A call to a source target or to a target which emulates Ada or SPARK
-      --  semantics imposes an Elaborate_All requirement on the context of the
-      --  main unit. Determine whether the context has a pragma strong enough
-      --  to meet the requirement. The check is orthogonal to the ABE effects
-      --  of the call.
-
-      if Target_Attrs.From_Source
-        or else Is_Ada_Semantic_Target (Target_Id)
-        or else Is_SPARK_Semantic_Target (Target_Id)
-      then
-         Meet_Elaboration_Requirement
-           (N         => Call,
-            Target_Id => Target_Id,
-            Req_Nam   => Name_Elaborate_All);
-      end if;
-
-      --  Nothing to do when the call is ABE-safe
-
-      --    generic
-      --    function Gen ...;
-
-      --    function Gen ... is
-      --    begin
-      --       ...
-      --    end Gen;
-
-      --    with Gen;
-      --    procedure Main is
-      --       function Inst is new Gen;
-      --       X : ... := Inst;                  --  safe call
-      --    ...
-
-      if Is_Safe_Call (Call, Target_Attrs) then
-         return;
-
-      --  The call and the target body are both in the main unit
-
-      elsif Present (Target_Attrs.Body_Decl)
-        and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
-      then
-         Process_Call_Conditional_ABE
-           (Call         => Call,
-            Call_Attrs   => Call_Attrs,
-            Target_Id    => Target_Id,
-            Target_Attrs => Target_Attrs);
-
-      --  Otherwise the target body is not available in this compilation or it
-      --  resides in an external unit. There is no need to guarantee the prior
-      --  elaboration of the unit with the target body because either the main
-      --  unit meets the Elaborate_All requirement imposed by the call, or the
-      --  program is illegal.
-
-      else
-         null;
-      end if;
-   end Process_Call_SPARK;
-
-   ----------------------------
-   -- Process_Guaranteed_ABE --
-   ----------------------------
-
-   procedure Process_Guaranteed_ABE (N : Node_Id) is
-      Call_Attrs : Call_Attributes;
-      Target_Id  : Entity_Id;
-
-   begin
-      --  Add the current scenario to the stack of active scenarios
-
-      Push_Active_Scenario (N);
-
-      --  Only calls, instantiations, and task activations may result in a
-      --  guaranteed ABE.
-
-      if Is_Suitable_Call (N) then
-         Extract_Call_Attributes
-           (Call      => N,
-            Target_Id => Target_Id,
-            Attrs     => Call_Attrs);
-
-         if Is_Activation_Proc (Target_Id) then
-            Process_Activation_Guaranteed_ABE
-              (Call         => N,
-               Call_Attrs   => Call_Attrs,
-               In_Task_Body => False);
-
-         else
-            Process_Call_Guaranteed_ABE
-              (Call       => N,
-               Call_Attrs => Call_Attrs,
-               Target_Id  => Target_Id);
-         end if;
-
-      elsif Is_Suitable_Instantiation (N) then
-         Process_Instantiation_Guaranteed_ABE (N);
-      end if;
-
-      --  Remove the current scenario from the stack of active scenarios once
-      --  all ABE diagnostics and checks have been performed.
-
-      Pop_Active_Scenario (N);
-   end Process_Guaranteed_ABE;
-
-   ---------------------------
-   -- Process_Instantiation --
-   ---------------------------
-
-   procedure Process_Instantiation
-     (Exp_Inst     : Node_Id;
-      In_Task_Body : Boolean)
+           (N        => Call,
+            Unit_Id  => Target_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate_All,
+            State    => State);
+      end if;
+   end Process_Conditional_ABE_Call_SPARK;
+
+   -------------------------------------------
+   -- Process_Conditional_ABE_Instantiation --
+   -------------------------------------------
+
+   procedure Process_Conditional_ABE_Instantiation
+     (Exp_Inst : Node_Id;
+      State    : Processing_Attributes)
    is
       Gen_Attrs  : Target_Attributes;
       Gen_Id     : Entity_Id;
@@ -7454,6 +9617,9 @@
       SPARK_Rules_On : Boolean;
       --  This flag is set when the SPARK rules are in effect
 
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
+
    begin
       Extract_Instantiation_Attributes
         (Exp_Inst => Exp_Inst,
@@ -7487,10 +9653,10 @@
 
       --  Nothing to do when the root scenario appears at the declaration level
       --  and the generic is in the same unit, but outside this context.
-
+      --
       --    generic
       --    procedure Gen is ...;                --  generic declaration
-
+      --
       --    procedure Proc is
       --       function A ... is
       --       begin
@@ -7500,14 +9666,14 @@
       --             ...
       --          ...
       --       end A;
-
+      --
       --       X : ... := A;                     --  root scenario
       --    ...
-
+      --
       --    procedure Gen is
       --       ...
       --    end Gen;
-
+      --
       --  In the example above, the context of X is the declarative region of
       --  Proc. The "elaboration" of X may eventually reach Gen which appears
       --  outside of X's context. Gen is relevant only when Proc is invoked,
@@ -7518,43 +9684,49 @@
 
       elsif Is_Up_Level_Target (Gen_Attrs.Spec_Decl) then
          return;
-
-      --  The SPARK rules are verified only when -gnatd.v (enforce SPARK
-      --  elaboration rules in SPARK code) is in effect.
-
-      elsif SPARK_Rules_On and Debug_Flag_Dot_V then
-         Process_Instantiation_SPARK
-           (Exp_Inst   => Exp_Inst,
-            Inst       => Inst,
-            Inst_Attrs => Inst_Attrs,
-            Gen_Id     => Gen_Id,
-            Gen_Attrs  => Gen_Attrs);
+      end if;
+
+      --  Warnings are suppressed when a prior scenario is already in that
+      --  mode, or when the instantiation has warnings suppressed. Update
+      --  the state of the processing phase to reflect this.
+
+      New_State.Suppress_Warnings :=
+        New_State.Suppress_Warnings or else not Inst_Attrs.Elab_Warnings_OK;
+
+      --  The SPARK rules are in effect
+
+      if SPARK_Rules_On then
+         Process_Conditional_ABE_Instantiation_SPARK
+           (Inst      => Inst,
+            Gen_Id    => Gen_Id,
+            Gen_Attrs => Gen_Attrs,
+            State     => New_State);
 
       --  Otherwise the Ada rules are in effect, or SPARK code is allowed to
       --  violate the SPARK rules.
 
       else
-         Process_Instantiation_Ada
-           (Exp_Inst     => Exp_Inst,
-            Inst         => Inst,
-            Inst_Attrs   => Inst_Attrs,
-            Gen_Id       => Gen_Id,
-            Gen_Attrs    => Gen_Attrs,
-            In_Task_Body => In_Task_Body);
-      end if;
-   end Process_Instantiation;
-
-   -------------------------------
-   -- Process_Instantiation_Ada --
-   -------------------------------
-
-   procedure Process_Instantiation_Ada
-     (Exp_Inst     : Node_Id;
-      Inst         : Node_Id;
-      Inst_Attrs   : Instantiation_Attributes;
-      Gen_Id       : Entity_Id;
-      Gen_Attrs    : Target_Attributes;
-      In_Task_Body : Boolean)
+         Process_Conditional_ABE_Instantiation_Ada
+           (Exp_Inst   => Exp_Inst,
+            Inst       => Inst,
+            Inst_Attrs => Inst_Attrs,
+            Gen_Id     => Gen_Id,
+            Gen_Attrs  => Gen_Attrs,
+            State      => New_State);
+      end if;
+   end Process_Conditional_ABE_Instantiation;
+
+   -----------------------------------------------
+   -- Process_Conditional_ABE_Instantiation_Ada --
+   -----------------------------------------------
+
+   procedure Process_Conditional_ABE_Instantiation_Ada
+     (Exp_Inst   : Node_Id;
+      Inst       : Node_Id;
+      Inst_Attrs : Instantiation_Attributes;
+      Gen_Id     : Entity_Id;
+      Gen_Attrs  : Target_Attributes;
+      State      : Processing_Attributes)
    is
       Check_OK : constant Boolean :=
                    not Inst_Attrs.Ghost_Mode_Ignore
@@ -7565,18 +9737,23 @@
       --  the generic have active elaboration checks and both are not ignored
       --  Ghost constructs.
 
+      Root : constant Node_Id := Root_Scenario;
+
+      New_State : Processing_Attributes := State;
+      --  Each step of the Processing phase constitutes a new state
+
    begin
       --  Nothing to do when the instantiation is ABE-safe
-
+      --
       --    generic
       --    package Gen is
       --       ...
       --    end Gen;
-
+      --
       --    package body Gen is
       --       ...
       --    end Gen;
-
+      --
       --    with Gen;
       --    procedure Main is
       --       package Inst is new Gen (ABE);    --  safe instantiation
@@ -7590,12 +9767,109 @@
       elsif Present (Gen_Attrs.Body_Decl)
         and then In_Extended_Main_Code_Unit (Gen_Attrs.Body_Decl)
       then
-         Process_Instantiation_Conditional_ABE
-           (Exp_Inst   => Exp_Inst,
-            Inst       => Inst,
-            Inst_Attrs => Inst_Attrs,
-            Gen_Id     => Gen_Id,
-            Gen_Attrs  => Gen_Attrs);
+         --  If the root scenario appears prior to the generic body, then this
+         --  is a possible ABE with respect to the root scenario.
+         --
+         --    generic
+         --    package Gen is
+         --       ...
+         --    end Gen;
+         --
+         --    function A ... is
+         --    begin
+         --       if Some_Condition then
+         --          declare
+         --             package Inst is new Gen;    --  instantiation site
+         --       ...
+         --    end A;
+         --
+         --    X : ... := A;                        --  root scenario
+         --
+         --    package body Gen is                  --  generic body
+         --       ...
+         --    end Gen;
+         --
+         --    Y : ... := A;                        --  root scenario
+         --
+         --  IMPORTANT: The instantiation of Gen is a possible ABE for X, but
+         --  not for Y. Installing an unconditional ABE raise prior to the
+         --  instance site would be wrong as it will fail for Y as well, but in
+         --  Y's case the instantiation of Gen is never an ABE.
+
+         if Earlier_In_Extended_Unit (Root, Gen_Attrs.Body_Decl) then
+
+            --  Do not emit any ABE diagnostics when a previous scenario in
+            --  this traversal has suppressed elaboration warnings.
+
+            if State.Suppress_Warnings then
+               null;
+
+            --  Do not emit any ABE diagnostics when the instantiation occurs
+            --  in partial finalization context because this leads to unwanted
+            --  noise.
+
+            elsif State.Within_Partial_Finalization then
+               null;
+
+            --  ABE diagnostics are emitted only in the static model because
+            --  there is a well-defined order to visiting scenarios. Without
+            --  this order diagnostics appear jumbled and result in unwanted
+            --  noise.
+
+            elsif Static_Elaboration_Checks then
+               Error_Msg_NE
+                 ("??cannot instantiate & before body seen", Inst, Gen_Id);
+               Error_Msg_N ("\Program_Error may be raised at run time", Inst);
+
+               Output_Active_Scenarios (Inst);
+            end if;
+
+            --  Install a conditional run-time ABE check to verify that the
+            --  generic body has been elaborated prior to the instantiation.
+
+            if Check_OK then
+               Install_ABE_Check
+                 (N           => Inst,
+                  Ins_Nod     => Exp_Inst,
+                  Target_Id   => Gen_Attrs.Spec_Id,
+                  Target_Decl => Gen_Attrs.Spec_Decl,
+                  Target_Body => Gen_Attrs.Body_Decl);
+
+               --  Update the state of the Processing phase to indicate that
+               --  no implicit Elaborate[_All] pragmas must be generated from
+               --  this point on.
+               --
+               --    generic
+               --    package Gen is
+               --       ...
+               --    end Gen;
+               --
+               --    function A ... is
+               --    begin
+               --       if Some_Condition then
+               --          <ABE check>
+               --          declare Inst is new Gen;
+               --       ...
+               --    end A;
+               --
+               --    X : ... := A;
+               --
+               --    package body Gen is
+               --    begin
+               --       External.Subp;           --  imparts Elaborate_All
+               --    end Gen;
+               --
+               --  If Some_Condition is True, then the ABE check will fail at
+               --  runtime and the call to External.Subp will never take place,
+               --  rendering the implicit Elaborate_All useless.
+               --
+               --  If Some_Condition is False, then the call to External.Subp
+               --  will never take place, rendering the implicit Elaborate_All
+               --  useless.
+
+               New_State.Suppress_Implicit_Pragmas := True;
+            end if;
+         end if;
 
       --  Otherwise the generic body is not available in this compilation or it
       --  resides in an external unit. Install a run-time ABE check to verify
@@ -7610,300 +9884,76 @@
       end if;
 
       --  Ensure that the unit with the generic body is elaborated prior to
-      --  the main unit. No implicit pragma Elaborate[_All] is generated if
-      --  the instantiation has elaboration checks suppressed. This behaviour
-      --  parallels that of the old ABE mechanism.
+      --  the main unit. No implicit pragma is generated if the instantiation
+      --  has elaboration checks suppressed. This behaviour parallels that of
+      --  the old ABE mechanism.
 
       if Inst_Attrs.Elab_Checks_OK then
          Ensure_Prior_Elaboration
-           (N            => Inst,
-            Unit_Id      => Gen_Attrs.Unit_Id,
-            In_Task_Body => In_Task_Body);
-      end if;
-   end Process_Instantiation_Ada;
-
-   -------------------------------------------
-   -- Process_Instantiation_Conditional_ABE --
-   -------------------------------------------
-
-   procedure Process_Instantiation_Conditional_ABE
-     (Exp_Inst   : Node_Id;
-      Inst       : Node_Id;
-      Inst_Attrs : Instantiation_Attributes;
-      Gen_Id     : Entity_Id;
-      Gen_Attrs  : Target_Attributes)
-   is
-      Check_OK : constant Boolean :=
-                   not Inst_Attrs.Ghost_Mode_Ignore
-                     and then not Gen_Attrs.Ghost_Mode_Ignore
-                     and then Inst_Attrs.Elab_Checks_OK
-                     and then Gen_Attrs.Elab_Checks_OK;
-      --  A run-time ABE check may be installed only when both the instance and
-      --  the generic have active elaboration checks and both are not ignored
-      --  Ghost constructs.
-
-      Root : constant Node_Id := Root_Scenario;
-
-   begin
-      --  If the root scenario appears prior to the generic body, then this is
-      --  a possible ABE with respect to the root scenario.
-
-      --    generic
-      --    package Gen is
-      --       ...
-      --    end Gen;
-
-      --    function A ... is
-      --    begin
-      --       if Some_Condition then
-      --          declare
-      --             package Inst is new Gen;    --  instantiation site
-      --       ...
-      --    end A;
-
-      --    X : ... := A;                        --  root scenario
-
-      --    package body Gen is                  --  generic body
-      --       ...
-      --    end Gen;
-
-      --    Y : ... := A;                        --  root scenario
-
-      --  IMPORTANT: The instantiation of Gen is a possible ABE for X, but not
-      --  for Y. Installing an unconditional ABE raise prior to the instance
-      --  site would be wrong as it will fail for Y as well, but in Y's case
-      --  the instantiation of Gen is never an ABE.
-
-      if Earlier_In_Extended_Unit (Root, Gen_Attrs.Body_Decl) then
-
-         --  ABE diagnostics are emitted only in the static model because there
-         --  is a well-defined order to visiting scenarios. Without this order
-         --  diagnostics appear jumbled and result in unwanted noise.
-
-         if Static_Elaboration_Checks then
-            Error_Msg_NE
-              ("??cannot instantiate & before body seen", Inst, Gen_Id);
-            Error_Msg_N ("\Program_Error may be raised at run time", Inst);
-
-            Output_Active_Scenarios (Inst);
-         end if;
-
-         --  Install a conditional run-time ABE check to verify that the
-         --  generic body has been elaborated prior to the instantiation.
-
-         if Check_OK then
-            Install_ABE_Check
-              (N           => Inst,
-               Ins_Nod     => Exp_Inst,
-               Target_Id   => Gen_Attrs.Spec_Id,
-               Target_Decl => Gen_Attrs.Spec_Decl,
-               Target_Body => Gen_Attrs.Body_Decl);
-         end if;
-      end if;
-   end Process_Instantiation_Conditional_ABE;
-
-   ------------------------------------------
-   -- Process_Instantiation_Guaranteed_ABE --
-   ------------------------------------------
-
-   procedure Process_Instantiation_Guaranteed_ABE (Exp_Inst : Node_Id) is
-      Gen_Attrs  : Target_Attributes;
-      Gen_Id     : Entity_Id;
-      Inst       : Node_Id;
-      Inst_Attrs : Instantiation_Attributes;
-      Inst_Id    : Entity_Id;
-
-   begin
-      Extract_Instantiation_Attributes
-        (Exp_Inst => Exp_Inst,
-         Inst     => Inst,
-         Inst_Id  => Inst_Id,
-         Gen_Id   => Gen_Id,
-         Attrs    => Inst_Attrs);
-
-      Extract_Target_Attributes (Gen_Id, Gen_Attrs);
-
-      --  Nothing to do when the root scenario appears at the declaration level
-      --  and the generic is in the same unit, but outside this context.
-
-      --    generic
-      --    procedure Gen is ...;                --  generic declaration
-
-      --    procedure Proc is
-      --       function A ... is
-      --       begin
-      --          if Some_Condition then
-      --             declare
-      --                procedure I is new Gen;  --  instantiation site
-      --             ...
-      --          ...
-      --       end A;
-
-      --       X : ... := A;                     --  root scenario
-      --    ...
-
-      --    procedure Gen is
-      --       ...
-      --    end Gen;
-
-      --  In the example above, the context of X is the declarative region of
-      --  Proc. The "elaboration" of X may eventually reach Gen which appears
-      --  outside of X's context. Gen is relevant only when Proc is invoked,
-      --  but this happens only by means of "normal" elaboration, therefore
-      --  Gen must not be considered if this is not the case.
-
-      --  Performance note: parent traversal
-
-      if Is_Up_Level_Target (Gen_Attrs.Spec_Decl) then
-         return;
-
-      --  Nothing to do when the instantiation is ABE-safe
-
-      --    generic
-      --    package Gen is
-      --       ...
-      --    end Gen;
-
-      --    package body Gen is
-      --       ...
-      --    end Gen;
-
-      --    with Gen;
-      --    procedure Main is
-      --       package Inst is new Gen (ABE);    --  safe instantiation
-      --    ...
-
-      elsif Is_Safe_Instantiation (Inst, Gen_Attrs) then
-         return;
-
-      --  An instantiation leads to a guaranteed ABE when the instantiation and
-      --  the generic appear within the same context ignoring library levels,
-      --  and the body of the generic has not been seen yet or appears after
-      --  the instantiation.
-
-      --    procedure Guaranteed_ABE is
-      --       generic
-      --       procedure Gen;
-
-      --       package Nested is
-      --          procedure Inst is new Gen;     --  guaranteed ABE
-      --       end Nested;
-
-      --       procedure Gen is
-      --          ...
-      --       end Gen;
-      --    ...
-
-      --  Performance note: parent traversal
-
-      elsif Is_Guaranteed_ABE
-              (N           => Inst,
-               Target_Decl => Gen_Attrs.Spec_Decl,
-               Target_Body => Gen_Attrs.Body_Decl)
-      then
-         Error_Msg_NE
-           ("??cannot instantiate & before body seen", Inst, Gen_Id);
-         Error_Msg_N ("\Program_Error will be raised at run time", Inst);
-
-         --  Mark the instantiation as a guarantee ABE. This automatically
-         --  suppresses the instantiation of the generic body.
-
-         Set_Is_Known_Guaranteed_ABE (Inst);
-
-         --  Install a run-time ABE failure because the instantiation will
-         --  always result in an ABE. The failure is installed when both the
-         --  instance and the generic have enabled elaboration checks, and both
-         --  are not ignored Ghost constructs.
-
-         if Inst_Attrs.Elab_Checks_OK
-           and then Gen_Attrs.Elab_Checks_OK
-           and then not Inst_Attrs.Ghost_Mode_Ignore
-           and then not Gen_Attrs.Ghost_Mode_Ignore
-         then
-            Install_ABE_Failure
-              (N       => Inst,
-               Ins_Nod => Exp_Inst);
-         end if;
-      end if;
-   end Process_Instantiation_Guaranteed_ABE;
-
-   ---------------------------------
-   -- Process_Instantiation_SPARK --
-   ---------------------------------
-
-   procedure Process_Instantiation_SPARK
-     (Exp_Inst   : Node_Id;
-      Inst       : Node_Id;
-      Inst_Attrs : Instantiation_Attributes;
-      Gen_Id     : Entity_Id;
-      Gen_Attrs  : Target_Attributes)
+           (N        => Inst,
+            Unit_Id  => Gen_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate,
+            State    => New_State);
+      end if;
+   end Process_Conditional_ABE_Instantiation_Ada;
+
+   -------------------------------------------------
+   -- Process_Conditional_ABE_Instantiation_SPARK --
+   -------------------------------------------------
+
+   procedure Process_Conditional_ABE_Instantiation_SPARK
+     (Inst      : Node_Id;
+      Gen_Id    : Entity_Id;
+      Gen_Attrs : Target_Attributes;
+      State     : Processing_Attributes)
    is
       Req_Nam : Name_Id;
 
    begin
+      --  Ensure that a suitable elaboration model is in effect for SPARK rule
+      --  verification.
+
+      Check_SPARK_Model_In_Effect (Inst);
+
       --  A source instantiation imposes an Elaborate[_All] requirement on the
       --  context of the main unit. Determine whether the context has a pragma
       --  strong enough to meet the requirement. The check is orthogonal to the
       --  ABE ramifications of the instantiation.
 
-      if Nkind (Inst) = N_Package_Instantiation then
-         Req_Nam := Name_Elaborate_All;
-      else
-         Req_Nam := Name_Elaborate;
-      end if;
-
-      Meet_Elaboration_Requirement
-        (N         => Inst,
-         Target_Id => Gen_Id,
-         Req_Nam   => Req_Nam);
-
-      --  Nothing to do when the instantiation is ABE-safe
-
-      --    generic
-      --    package Gen is
-      --       ...
-      --    end Gen;
-
-      --    package body Gen is
-      --       ...
-      --    end Gen;
-
-      --    with Gen;
-      --    procedure Main is
-      --       package Inst is new Gen (ABE);    --  safe instantiation
-      --    ...
-
-      if Is_Safe_Instantiation (Inst, Gen_Attrs) then
-         return;
-
-      --  The instantiation and the generic body are both in the main unit
-
-      elsif Present (Gen_Attrs.Body_Decl)
-        and then In_Extended_Main_Code_Unit (Gen_Attrs.Body_Decl)
-      then
-         Process_Instantiation_Conditional_ABE
-           (Exp_Inst   => Exp_Inst,
-            Inst       => Inst,
-            Inst_Attrs => Inst_Attrs,
-            Gen_Id     => Gen_Id,
-            Gen_Attrs  => Gen_Attrs);
-
-      --  Otherwise the generic body is not available in this compilation or
-      --  it resides in an external unit. There is no need to guarantee the
-      --  prior elaboration of the unit with the generic body because either
-      --  the main unit meets the Elaborate[_All] requirement imposed by the
-      --  instantiation, or the program is illegal.
+      --  IMPORTANT: This check must be performed only when -gnatd.v (enforce
+      --  SPARK elaboration rules in SPARK code) is active because the static
+      --  model can ensure the prior elaboration of the unit which contains a
+      --  body by installing an implicit Elaborate[_All] pragma.
+
+      if Debug_Flag_Dot_V then
+         if Nkind (Inst) = N_Package_Instantiation then
+            Req_Nam := Name_Elaborate_All;
+         else
+            Req_Nam := Name_Elaborate;
+         end if;
+
+         Meet_Elaboration_Requirement
+           (N         => Inst,
+            Target_Id => Gen_Id,
+            Req_Nam   => Req_Nam);
+
+      --  Otherwise ensure that the unit with the target body is elaborated
+      --  prior to the main unit.
 
       else
-         null;
-      end if;
-   end Process_Instantiation_SPARK;
-
-   ---------------------------------
-   -- Process_Variable_Assignment --
-   ---------------------------------
-
-   procedure Process_Variable_Assignment (Asmt : Node_Id) is
+         Ensure_Prior_Elaboration
+           (N        => Inst,
+            Unit_Id  => Gen_Attrs.Unit_Id,
+            Prag_Nam => Name_Elaborate,
+            State    => State);
+      end if;
+   end Process_Conditional_ABE_Instantiation_SPARK;
+
+   -------------------------------------------------
+   -- Process_Conditional_ABE_Variable_Assignment --
+   -------------------------------------------------
+
+   procedure Process_Conditional_ABE_Variable_Assignment (Asmt : Node_Id) is
       Var_Id : constant Entity_Id := Entity (Extract_Assignment_Name (Asmt));
       Prag   : constant Node_Id   := SPARK_Pragma (Var_Id);
 
@@ -7937,24 +9987,24 @@
       --  variables.
 
       if SPARK_Rules_On then
-         Process_Variable_Assignment_SPARK
+         Process_Conditional_ABE_Variable_Assignment_SPARK
            (Asmt   => Asmt,
             Var_Id => Var_Id);
 
       --  Otherwise the Ada rules are in effect
 
       else
-         Process_Variable_Assignment_Ada
+         Process_Conditional_ABE_Variable_Assignment_Ada
            (Asmt   => Asmt,
             Var_Id => Var_Id);
       end if;
-   end Process_Variable_Assignment;
-
-   -------------------------------------
-   -- Process_Variable_Assignment_Ada --
-   -------------------------------------
-
-   procedure Process_Variable_Assignment_Ada
+   end Process_Conditional_ABE_Variable_Assignment;
+
+   -----------------------------------------------------
+   -- Process_Conditional_ABE_Variable_Assignment_Ada --
+   -----------------------------------------------------
+
+   procedure Process_Conditional_ABE_Variable_Assignment_Ada
      (Asmt   : Node_Id;
       Var_Id : Entity_Id)
    is
@@ -7966,14 +10016,10 @@
       --  spec without a pragma Elaborate_Body is initialized by elaboration
       --  code within the corresponding body.
 
-      if not Warnings_Off (Var_Id)
+      if Is_Elaboration_Warnings_OK_Id (Var_Id)
         and then not Is_Initialized (Var_Decl)
         and then not Has_Pragma_Elaborate_Body (Spec_Id)
       then
-         --  Generate an implicit Elaborate_Body in the spec
-
-         Set_Elaborate_Body_Desirable (Spec_Id);
-
          Error_Msg_NE
            ("??variable & can be accessed by clients before this "
             & "initialization", Asmt, Var_Id);
@@ -7983,14 +10029,18 @@
             & "initialization", Asmt, Spec_Id);
 
          Output_Active_Scenarios (Asmt);
-      end if;
-   end Process_Variable_Assignment_Ada;
-
-   ---------------------------------------
-   -- Process_Variable_Assignment_SPARK --
-   ---------------------------------------
-
-   procedure Process_Variable_Assignment_SPARK
+
+         --  Generate an implicit Elaborate_Body in the spec
+
+         Set_Elaborate_Body_Desirable (Spec_Id);
+      end if;
+   end Process_Conditional_ABE_Variable_Assignment_Ada;
+
+   -------------------------------------------------------
+   -- Process_Conditional_ABE_Variable_Assignment_SPARK --
+   -------------------------------------------------------
+
+   procedure Process_Conditional_ABE_Variable_Assignment_SPARK
      (Asmt   : Node_Id;
       Var_Id : Entity_Id)
    is
@@ -7998,11 +10048,17 @@
       Spec_Id  : constant Entity_Id := Find_Top_Unit (Var_Decl);
 
    begin
+      --  Ensure that a suitable elaboration model is in effect for SPARK rule
+      --  verification.
+
+      Check_SPARK_Model_In_Effect (Asmt);
+
       --  Emit an error when an initialized variable declared in a package spec
       --  without pragma Elaborate_Body is further modified by elaboration code
       --  within the corresponding body.
 
-      if Is_Initialized (Var_Decl)
+      if Is_Elaboration_Warnings_OK_Id (Var_Id)
+        and then Is_Initialized (Var_Decl)
         and then not Has_Pragma_Elaborate_Body (Spec_Id)
       then
          Error_Msg_NE
@@ -8015,13 +10071,13 @@
 
          Output_Active_Scenarios (Asmt);
       end if;
-   end Process_Variable_Assignment_SPARK;
-
-   ---------------------------
-   -- Process_Variable_Read --
-   ---------------------------
-
-   procedure Process_Variable_Read (Ref : Node_Id) is
+   end Process_Conditional_ABE_Variable_Assignment_SPARK;
+
+   ------------------------------------------------
+   -- Process_Conditional_ABE_Variable_Reference --
+   ------------------------------------------------
+
+   procedure Process_Conditional_ABE_Variable_Reference (Ref : Node_Id) is
       Var_Attrs : Variable_Attributes;
       Var_Id    : Entity_Id;
 
@@ -8031,6 +10087,24 @@
          Var_Id => Var_Id,
          Attrs  => Var_Attrs);
 
+      if Is_Read (Ref) then
+         Process_Conditional_ABE_Variable_Reference_Read
+           (Ref    => Ref,
+            Var_Id => Var_Id,
+            Attrs  => Var_Attrs);
+      end if;
+   end Process_Conditional_ABE_Variable_Reference;
+
+   -----------------------------------------------------
+   -- Process_Conditional_ABE_Variable_Reference_Read --
+   -----------------------------------------------------
+
+   procedure Process_Conditional_ABE_Variable_Reference_Read
+     (Ref    : Node_Id;
+      Var_Id : Entity_Id;
+      Attrs  : Variable_Attributes)
+   is
+   begin
       --  Output relevant information when switch -gnatel (info messages on
       --  implicit Elaborate[_All] pragmas) is in effect.
 
@@ -8046,7 +10120,7 @@
       --  Nothing to do when the variable appears within the main unit because
       --  diagnostics on reads are relevant only for external variables.
 
-      if Is_Same_Unit (Var_Attrs.Unit_Id, Cunit_Entity (Main_Unit)) then
+      if Is_Same_Unit (Attrs.Unit_Id, Cunit_Entity (Main_Unit)) then
          null;
 
       --  Nothing to do when the variable is already initialized. Note that the
@@ -8058,7 +10132,7 @@
       --  Nothing to do when the external unit guarantees the initialization of
       --  the variable by means of pragma Elaborate_Body.
 
-      elsif Has_Pragma_Elaborate_Body (Var_Attrs.Unit_Id) then
+      elsif Has_Pragma_Elaborate_Body (Attrs.Unit_Id) then
          null;
 
       --  A variable read imposes an Elaborate requirement on the context of
@@ -8071,22 +10145,20 @@
             Target_Id => Var_Id,
             Req_Nam   => Name_Elaborate);
       end if;
-   end Process_Variable_Read;
-
-   --------------------------
-   -- Push_Active_Scenario --
-   --------------------------
-
-   procedure Push_Active_Scenario (N : Node_Id) is
-   begin
-      Scenario_Stack.Append (N);
-   end Push_Active_Scenario;
-
-   ----------------------
-   -- Process_Scenario --
-   ----------------------
-
-   procedure Process_Scenario (N : Node_Id; In_Task_Body : Boolean := False) is
+   end Process_Conditional_ABE_Variable_Reference_Read;
+
+   -----------------------------
+   -- Process_Conditional_ABE --
+   -----------------------------
+
+   --  NOTE: The body of this routine is intentionally out of order because it
+   --  invokes an instantiated subprogram (Process_Conditional_ABE_Activation).
+   --  Placing the body in alphabetical order will result in a guaranteed ABE.
+
+   procedure Process_Conditional_ABE
+     (N     : Node_Id;
+      State : Processing_Attributes := Initial_State)
+   is
       Call_Attrs : Call_Attributes;
       Target_Id  : Entity_Id;
 
@@ -8098,9 +10170,11 @@
       --  'Access
 
       if Is_Suitable_Access (N) then
-         Process_Access (N, In_Task_Body);
-
-      --  Calls
+         Process_Conditional_ABE_Access
+           (Attr  => N,
+            State => State);
+
+      --  Activations and calls
 
       elsif Is_Suitable_Call (N) then
 
@@ -8118,41 +10192,489 @@
                Attrs     => Call_Attrs);
 
             if Is_Activation_Proc (Target_Id) then
-               Process_Activation_Conditional_ABE
-                 (Call         => N,
-                  Call_Attrs   => Call_Attrs,
-                  In_Task_Body => In_Task_Body);
+               Process_Conditional_ABE_Activation
+                 (Call       => N,
+                  Call_Attrs => Call_Attrs,
+                  State      => State);
 
             else
-               Process_Call
-                 (Call         => N,
-                  Call_Attrs   => Call_Attrs,
-                  Target_Id    => Target_Id,
-                  In_Task_Body => In_Task_Body);
+               Process_Conditional_ABE_Call
+                 (Call       => N,
+                  Call_Attrs => Call_Attrs,
+                  Target_Id  => Target_Id,
+                  State      => State);
             end if;
          end if;
 
       --  Instantiations
 
       elsif Is_Suitable_Instantiation (N) then
-         Process_Instantiation (N, In_Task_Body);
+         Process_Conditional_ABE_Instantiation
+           (Exp_Inst => N,
+            State    => State);
 
       --  Variable assignments
 
       elsif Is_Suitable_Variable_Assignment (N) then
-         Process_Variable_Assignment (N);
-
-      --  Variable read
-
-      elsif Is_Suitable_Variable_Read (N) then
-         Process_Variable_Read (N);
+         Process_Conditional_ABE_Variable_Assignment (N);
+
+      --  Variable references
+
+      elsif Is_Suitable_Variable_Reference (N) then
+
+         --  In general, only variable references found within the main unit
+         --  are processed because the ALI information supplied to binde is for
+         --  the main unit only. However, to preserve the consistency of the
+         --  tree and ensure proper serialization of internal names, external
+         --  variable references also receive corresponding variable reference
+         --  markers (see Build_Varaible_Reference_Marker). Regardless of the
+         --  reason, external variable references must not be processed.
+
+         if In_Main_Context (N) then
+            Process_Conditional_ABE_Variable_Reference (N);
+         end if;
       end if;
 
       --  Remove the current scenario from the stack of active scenarios once
       --  all ABE diagnostics and checks have been performed.
 
       Pop_Active_Scenario (N);
-   end Process_Scenario;
+   end Process_Conditional_ABE;
+
+   --------------------------------------------
+   -- Process_Guaranteed_ABE_Activation_Impl --
+   --------------------------------------------
+
+   procedure Process_Guaranteed_ABE_Activation_Impl
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Obj_Id     : Entity_Id;
+      Task_Attrs : Task_Attributes;
+      State      : Processing_Attributes)
+   is
+      pragma Unreferenced (State);
+
+      Check_OK : constant Boolean :=
+                   not Is_Ignored_Ghost_Entity (Obj_Id)
+                     and then not Task_Attrs.Ghost_Mode_Ignore
+                     and then Is_Elaboration_Checks_OK_Id (Obj_Id)
+                     and then Task_Attrs.Elab_Checks_OK;
+      --  A run-time ABE check may be installed only when the object and the
+      --  task type have active elaboration checks, and both are not ignored
+      --  Ghost constructs.
+
+   begin
+      --  Nothing to do when the root scenario appears at the declaration
+      --  level and the task is in the same unit, but outside this context.
+      --
+      --    task type Task_Typ;                  --  task declaration
+      --
+      --    procedure Proc is
+      --       function A ... is
+      --       begin
+      --          if Some_Condition then
+      --             declare
+      --                T : Task_Typ;
+      --             begin
+      --                <activation call>        --  activation site
+      --             end;
+      --          ...
+      --       end A;
+      --
+      --       X : ... := A;                     --  root scenario
+      --    ...
+      --
+      --    task body Task_Typ is
+      --       ...
+      --    end Task_Typ;
+      --
+      --  In the example above, the context of X is the declarative list of
+      --  Proc. The "elaboration" of X may reach the activation of T whose body
+      --  is defined outside of X's context. The task body is relevant only
+      --  when Proc is invoked, but this happens only in "normal" elaboration,
+      --  therefore the task body must not be considered if this is not the
+      --  case.
+
+      --  Performance note: parent traversal
+
+      if Is_Up_Level_Target (Task_Attrs.Task_Decl) then
+         return;
+
+      --  Nothing to do when the activation is ABE-safe
+      --
+      --    generic
+      --    package Gen is
+      --       task type Task_Typ;
+      --    end Gen;
+      --
+      --    package body Gen is
+      --       task body Task_Typ is
+      --       begin
+      --          ...
+      --       end Task_Typ;
+      --    end Gen;
+      --
+      --    with Gen;
+      --    procedure Main is
+      --       package Nested is
+      --          package Inst is new Gen;
+      --          T : Inst.Task_Typ;
+      --       end Nested;                       --  safe activation
+      --    ...
+
+      elsif Is_Safe_Activation (Call, Task_Attrs.Task_Decl) then
+         return;
+
+      --  An activation call leads to a guaranteed ABE when the activation
+      --  call and the task appear within the same context ignoring library
+      --  levels, and the body of the task has not been seen yet or appears
+      --  after the activation call.
+      --
+      --    procedure Guaranteed_ABE is
+      --       task type Task_Typ;
+      --
+      --       package Nested is
+      --          T : Task_Typ;
+      --          <activation call>              --  guaranteed ABE
+      --       end Nested;
+      --
+      --       task body Task_Typ is
+      --          ...
+      --       end Task_Typ;
+      --    ...
+
+      --  Performance note: parent traversal
+
+      elsif Is_Guaranteed_ABE
+              (N           => Call,
+               Target_Decl => Task_Attrs.Task_Decl,
+               Target_Body => Task_Attrs.Body_Decl)
+      then
+         if Call_Attrs.Elab_Warnings_OK then
+            Error_Msg_Sloc := Sloc (Call);
+            Error_Msg_N
+              ("??task & will be activated # before elaboration of its body",
+               Obj_Id);
+            Error_Msg_N ("\Program_Error will be raised at run time", Obj_Id);
+         end if;
+
+         --  Mark the activation call as a guaranteed ABE
+
+         Set_Is_Known_Guaranteed_ABE (Call);
+
+         --  Install a run-time ABE failue because this activation call will
+         --  always result in an ABE.
+
+         if Check_OK then
+            Install_ABE_Failure
+              (N       => Call,
+               Ins_Nod => Call);
+         end if;
+      end if;
+   end Process_Guaranteed_ABE_Activation_Impl;
+
+   procedure Process_Guaranteed_ABE_Activation is
+     new Process_Activation_Generic (Process_Guaranteed_ABE_Activation_Impl);
+
+   ---------------------------------
+   -- Process_Guaranteed_ABE_Call --
+   ---------------------------------
+
+   procedure Process_Guaranteed_ABE_Call
+     (Call       : Node_Id;
+      Call_Attrs : Call_Attributes;
+      Target_Id  : Entity_Id)
+   is
+      Target_Attrs : Target_Attributes;
+
+   begin
+      Extract_Target_Attributes
+        (Target_Id => Target_Id,
+         Attrs     => Target_Attrs);
+
+      --  Nothing to do when the root scenario appears at the declaration level
+      --  and the target is in the same unit, but outside this context.
+      --
+      --    function B ...;                      --  target declaration
+      --
+      --    procedure Proc is
+      --       function A ... is
+      --       begin
+      --          if Some_Condition then
+      --             return B;                   --  call site
+      --          ...
+      --       end A;
+      --
+      --       X : ... := A;                     --  root scenario
+      --    ...
+      --
+      --    function B ... is
+      --       ...
+      --    end B;
+      --
+      --  In the example above, the context of X is the declarative region of
+      --  Proc. The "elaboration" of X may eventually reach B which is defined
+      --  outside of X's context. B is relevant only when Proc is invoked, but
+      --  this happens only by means of "normal" elaboration, therefore B must
+      --  not be considered if this is not the case.
+
+      --  Performance note: parent traversal
+
+      if Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
+         return;
+
+      --  Nothing to do when the call is ABE-safe
+      --
+      --    generic
+      --    function Gen ...;
+      --
+      --    function Gen ... is
+      --    begin
+      --       ...
+      --    end Gen;
+      --
+      --    with Gen;
+      --    procedure Main is
+      --       function Inst is new Gen;
+      --       X : ... := Inst;                  --  safe call
+      --    ...
+
+      elsif Is_Safe_Call (Call, Target_Attrs) then
+         return;
+
+      --  A call leads to a guaranteed ABE when the call and the target appear
+      --  within the same context ignoring library levels, and the body of the
+      --  target has not been seen yet or appears after the call.
+      --
+      --    procedure Guaranteed_ABE is
+      --       function Func ...;
+      --
+      --       package Nested is
+      --          Obj : ... := Func;             --  guaranteed ABE
+      --       end Nested;
+      --
+      --       function Func ... is
+      --          ...
+      --       end Func;
+      --    ...
+
+      --  Performance note: parent traversal
+
+      elsif Is_Guaranteed_ABE
+              (N           => Call,
+               Target_Decl => Target_Attrs.Spec_Decl,
+               Target_Body => Target_Attrs.Body_Decl)
+      then
+         if Call_Attrs.Elab_Warnings_OK then
+            Error_Msg_NE ("??cannot call & before body seen", Call, Target_Id);
+            Error_Msg_N ("\Program_Error will be raised at run time", Call);
+         end if;
+
+         --  Mark the call as a guarnateed ABE
+
+         Set_Is_Known_Guaranteed_ABE (Call);
+
+         --  Install a run-time ABE failure because the call will always result
+         --  in an ABE. The failure is installed when both the call and target
+         --  have enabled elaboration checks, and both are not ignored Ghost
+         --  constructs.
+
+         if Call_Attrs.Elab_Checks_OK
+           and then Target_Attrs.Elab_Checks_OK
+           and then not Call_Attrs.Ghost_Mode_Ignore
+           and then not Target_Attrs.Ghost_Mode_Ignore
+         then
+            Install_ABE_Failure
+              (N       => Call,
+               Ins_Nod => Call);
+         end if;
+      end if;
+   end Process_Guaranteed_ABE_Call;
+
+   ------------------------------------------
+   -- Process_Guaranteed_ABE_Instantiation --
+   ------------------------------------------
+
+   procedure Process_Guaranteed_ABE_Instantiation (Exp_Inst : Node_Id) is
+      Gen_Attrs  : Target_Attributes;
+      Gen_Id     : Entity_Id;
+      Inst       : Node_Id;
+      Inst_Attrs : Instantiation_Attributes;
+      Inst_Id    : Entity_Id;
+
+   begin
+      Extract_Instantiation_Attributes
+        (Exp_Inst => Exp_Inst,
+         Inst     => Inst,
+         Inst_Id  => Inst_Id,
+         Gen_Id   => Gen_Id,
+         Attrs    => Inst_Attrs);
+
+      Extract_Target_Attributes (Gen_Id, Gen_Attrs);
+
+      --  Nothing to do when the root scenario appears at the declaration level
+      --  and the generic is in the same unit, but outside this context.
+      --
+      --    generic
+      --    procedure Gen is ...;                --  generic declaration
+      --
+      --    procedure Proc is
+      --       function A ... is
+      --       begin
+      --          if Some_Condition then
+      --             declare
+      --                procedure I is new Gen;  --  instantiation site
+      --             ...
+      --          ...
+      --       end A;
+      --
+      --       X : ... := A;                     --  root scenario
+      --    ...
+      --
+      --    procedure Gen is
+      --       ...
+      --    end Gen;
+      --
+      --  In the example above, the context of X is the declarative region of
+      --  Proc. The "elaboration" of X may eventually reach Gen which appears
+      --  outside of X's context. Gen is relevant only when Proc is invoked,
+      --  but this happens only by means of "normal" elaboration, therefore
+      --  Gen must not be considered if this is not the case.
+
+      --  Performance note: parent traversal
+
+      if Is_Up_Level_Target (Gen_Attrs.Spec_Decl) then
+         return;
+
+      --  Nothing to do when the instantiation is ABE-safe
+      --
+      --    generic
+      --    package Gen is
+      --       ...
+      --    end Gen;
+      --
+      --    package body Gen is
+      --       ...
+      --    end Gen;
+      --
+      --    with Gen;
+      --    procedure Main is
+      --       package Inst is new Gen (ABE);    --  safe instantiation
+      --    ...
+
+      elsif Is_Safe_Instantiation (Inst, Gen_Attrs) then
+         return;
+
+      --  An instantiation leads to a guaranteed ABE when the instantiation and
+      --  the generic appear within the same context ignoring library levels,
+      --  and the body of the generic has not been seen yet or appears after
+      --  the instantiation.
+      --
+      --    procedure Guaranteed_ABE is
+      --       generic
+      --       procedure Gen;
+      --
+      --       package Nested is
+      --          procedure Inst is new Gen;     --  guaranteed ABE
+      --       end Nested;
+      --
+      --       procedure Gen is
+      --          ...
+      --       end Gen;
+      --    ...
+
+      --  Performance note: parent traversal
+
+      elsif Is_Guaranteed_ABE
+              (N           => Inst,
+               Target_Decl => Gen_Attrs.Spec_Decl,
+               Target_Body => Gen_Attrs.Body_Decl)
+      then
+         if Inst_Attrs.Elab_Warnings_OK then
+            Error_Msg_NE
+              ("??cannot instantiate & before body seen", Inst, Gen_Id);
+            Error_Msg_N ("\Program_Error will be raised at run time", Inst);
+         end if;
+
+         --  Mark the instantiation as a guarantee ABE. This automatically
+         --  suppresses the instantiation of the generic body.
+
+         Set_Is_Known_Guaranteed_ABE (Inst);
+
+         --  Install a run-time ABE failure because the instantiation will
+         --  always result in an ABE. The failure is installed when both the
+         --  instance and the generic have enabled elaboration checks, and both
+         --  are not ignored Ghost constructs.
+
+         if Inst_Attrs.Elab_Checks_OK
+           and then Gen_Attrs.Elab_Checks_OK
+           and then not Inst_Attrs.Ghost_Mode_Ignore
+           and then not Gen_Attrs.Ghost_Mode_Ignore
+         then
+            Install_ABE_Failure
+              (N       => Inst,
+               Ins_Nod => Exp_Inst);
+         end if;
+      end if;
+   end Process_Guaranteed_ABE_Instantiation;
+
+   ----------------------------
+   -- Process_Guaranteed_ABE --
+   ----------------------------
+
+   --  NOTE: The body of this routine is intentionally out of order because it
+   --  invokes an instantiated subprogram (Process_Guaranteed_ABE_Activation).
+   --  Placing the body in alphabetical order will result in a guaranteed ABE.
+
+   procedure Process_Guaranteed_ABE (N : Node_Id) is
+      Call_Attrs : Call_Attributes;
+      Target_Id  : Entity_Id;
+
+   begin
+      --  Add the current scenario to the stack of active scenarios
+
+      Push_Active_Scenario (N);
+
+      --  Only calls, instantiations, and task activations may result in a
+      --  guaranteed ABE.
+
+      if Is_Suitable_Call (N) then
+         Extract_Call_Attributes
+           (Call      => N,
+            Target_Id => Target_Id,
+            Attrs     => Call_Attrs);
+
+         if Is_Activation_Proc (Target_Id) then
+            Process_Guaranteed_ABE_Activation
+              (Call       => N,
+               Call_Attrs => Call_Attrs,
+               State      => Initial_State);
+
+         else
+            Process_Guaranteed_ABE_Call
+              (Call       => N,
+               Call_Attrs => Call_Attrs,
+               Target_Id  => Target_Id);
+         end if;
+
+      elsif Is_Suitable_Instantiation (N) then
+         Process_Guaranteed_ABE_Instantiation (N);
+      end if;
+
+      --  Remove the current scenario from the stack of active scenarios once
+      --  all ABE diagnostics and checks have been performed.
+
+      Pop_Active_Scenario (N);
+   end Process_Guaranteed_ABE;
+
+   --------------------------
+   -- Push_Active_Scenario --
+   --------------------------
+
+   procedure Push_Active_Scenario (N : Node_Id) is
+   begin
+      Scenario_Stack.Append (N);
+   end Push_Active_Scenario;
 
    ---------------------------------
    -- Record_Elaboration_Scenario --
@@ -8161,19 +10683,36 @@
    procedure Record_Elaboration_Scenario (N : Node_Id) is
       Level : Enclosing_Level_Kind;
 
+      Any_Level_OK : Boolean;
+      --  This flag is set when a particular scenario is allowed to appear at
+      --  any level.
+
       Declaration_Level_OK : Boolean;
       --  This flag is set when a particular scenario is allowed to appear at
       --  the declaration level.
 
-   begin
-      --  Assume that the scenario must not appear at the declaration level
-
+      Library_Level_OK : Boolean;
+      --  This flag is set when a particular scenario is allowed to appear at
+      --  the library level.
+
+   begin
+      --  Assume that the scenario cannot appear on any level
+
+      Any_Level_OK         := False;
       Declaration_Level_OK := False;
-
-      --  Nothing to do for ASIS. As a result, no ABE checks and diagnostics
-      --  are performed in this mode.
-
-      if ASIS_Mode then
+      Library_Level_OK     := False;
+
+      --  Nothing to do when switch -gnatH (legacy elaboration checking mode
+      --  enabled) is in effect because the legacy ABE mechanism does not need
+      --  to carry out this action.
+
+      if Legacy_Elaboration_Checks then
+         return;
+
+      --  Nothing to do for ASIS because ABE checks and diagnostics are not
+      --  performed in this mode.
+
+      elsif ASIS_Mode then
          return;
 
       --  Nothing to do when the scenario is being preanalyzed
@@ -8182,7 +10721,7 @@
          return;
       end if;
 
-      --  Ensure that a library level call does not appear in a preelaborated
+      --  Ensure that a library-level call does not appear in a preelaborated
       --  unit. The check must come before ignoring scenarios within external
       --  units or inside generics because calls in those context must also be
       --  verified.
@@ -8208,10 +10747,13 @@
       --   'Access for entries, operators, and subprograms
       --    Assignments to variables
       --    Calls (includes task activation)
+      --    Derived types
       --    Instantiations
+      --    Pragma Refined_State
       --    Reads of variables
 
       elsif Is_Suitable_Access (N) then
+         Library_Level_OK := True;
 
          --  Signal any enclosing local exception handlers that the 'Access may
          --  raise Program_Error due to a failed ABE check when switch -gnatd.o
@@ -8226,6 +10768,7 @@
 
       elsif Is_Suitable_Call (N) or else Is_Suitable_Instantiation (N) then
          Declaration_Level_OK := True;
+         Library_Level_OK     := True;
 
          --  Signal any enclosing local exception handlers that the call or
          --  instantiation may raise Program_Error due to a failed ABE check.
@@ -8235,10 +10778,16 @@
 
          Possible_Local_Raise (N, Standard_Program_Error);
 
+      elsif Is_Suitable_SPARK_Derived_Type (N) then
+         Any_Level_OK := True;
+
+      elsif Is_Suitable_SPARK_Refined_State_Pragma (N) then
+         Library_Level_OK := True;
+
       elsif Is_Suitable_Variable_Assignment (N)
-        or else Is_Suitable_Variable_Read (N)
-      then
-         null;
+        or else Is_Suitable_Variable_Reference (N)
+      then
+         Library_Level_OK := True;
 
       --  Otherwise the input does not denote a suitable scenario
 
@@ -8252,31 +10801,76 @@
 
       if Static_Elaboration_Checks then
 
-         --  Performance note: parent traversal
-
-         Level := Find_Enclosing_Level (N);
-
-         --  Declaration level scenario
-
-         if Declaration_Level_OK and then Level = Declaration_Level then
+         --  Certain scenarios are allowed to appear at any level. This check
+         --  is performed here in order to save on a parent traversal.
+
+         if Any_Level_OK then
             null;
 
-         --  Library level scenario
-
-         elsif Level in Library_Level then
-            null;
-
-         --  Instantiation library level scenario
-
-         elsif Level = Instantiation then
-            null;
-
-         --  Otherwise the scenario does not appear at the proper level and
-         --  cannot possibly act as a top level scenario.
+         --  Otherwise the scenario must appear at a specific level
 
          else
-            return;
-         end if;
+            --  Performance note: parent traversal
+
+            Level := Find_Enclosing_Level (N);
+
+            --  Declaration-level scenario
+
+            if Declaration_Level_OK and then Level = Declaration_Level then
+               null;
+
+            --  Library-level or instantiation scenario
+
+            elsif Library_Level_OK
+              and then Level in Library_Or_Instantiation_Level
+            then
+               null;
+
+            --  Otherwise the scenario does not appear at the proper level and
+            --  cannot possibly act as a top-level scenario.
+
+            else
+               return;
+            end if;
+         end if;
+      end if;
+
+      --  Derived types subject to SPARK_Mode On require elaboration-related
+      --  checks even though the type may not be declared within elaboration
+      --  code. The types are recorded in a separate table which is examined
+      --  during the Processing phase. Note that the checks must be delayed
+      --  because the bodies of overriding primitives are not available yet.
+
+      if Is_Suitable_SPARK_Derived_Type (N) then
+         Record_SPARK_Elaboration_Scenario (N);
+
+         --  Nothing left to do for derived types
+
+         return;
+
+      --  Instantiations of generics both subject to SPARK_Mode On require
+      --  elaboration-related checks even though the instantiations may not
+      --  appear within elaboration code. The instantiations are recored in
+      --  a separate table which is examined during the Procesing phase. Note
+      --  that the checks must be delayed because it is not known yet whether
+      --  the generic unit has a body or not.
+
+      --  IMPORTANT: A SPARK instantiation is also a normal instantiation which
+      --  is subject to common conditional and guaranteed ABE checks.
+
+      elsif Is_Suitable_SPARK_Instantiation (N) then
+         Record_SPARK_Elaboration_Scenario (N);
+
+      --  External constituents that refine abstract states which appear in
+      --  pragma Initializes require elaboration-related checks even though
+      --  a Refined_State pragma lacks any elaboration semantic.
+
+      elsif Is_Suitable_SPARK_Refined_State_Pragma (N) then
+         Record_SPARK_Elaboration_Scenario (N);
+
+         --  Nothing left to do for pragma Refined_State
+
+         return;
       end if;
 
       --  Perform early detection of guaranteed ABEs in order to suppress the
@@ -8289,17 +10883,56 @@
       --  later processing by the ABE phase.
 
       Top_Level_Scenarios.Append (N);
-
-      --  Mark a scenario which may produce run-time conditional ABE checks or
-      --  guaranteed ABE failures as recorded. The flag ensures that scenario
-      --  rewriting performed by Atree.Rewrite will be properly reflected in
-      --  all relevant internal data structures.
-
-      if Is_Check_Emitting_Scenario (N) then
-         Set_Is_Recorded_Scenario (N);
-      end if;
+      Set_Is_Recorded_Top_Level_Scenario (N);
    end Record_Elaboration_Scenario;
 
+   ---------------------------------------
+   -- Record_SPARK_Elaboration_Scenario --
+   ---------------------------------------
+
+   procedure Record_SPARK_Elaboration_Scenario (N : Node_Id) is
+   begin
+      SPARK_Scenarios.Append (N);
+      Set_Is_Recorded_SPARK_Scenario (N);
+   end Record_SPARK_Elaboration_Scenario;
+
+   -----------------------------------
+   -- Recorded_SPARK_Scenarios_Hash --
+   -----------------------------------
+
+   function Recorded_SPARK_Scenarios_Hash
+     (Key : Node_Id) return Recorded_SPARK_Scenarios_Index
+   is
+   begin
+      return
+        Recorded_SPARK_Scenarios_Index (Key mod Recorded_SPARK_Scenarios_Max);
+   end Recorded_SPARK_Scenarios_Hash;
+
+   ---------------------------------------
+   -- Recorded_Top_Level_Scenarios_Hash --
+   ---------------------------------------
+
+   function Recorded_Top_Level_Scenarios_Hash
+     (Key : Node_Id) return Recorded_Top_Level_Scenarios_Index
+   is
+   begin
+      return
+        Recorded_Top_Level_Scenarios_Index
+          (Key mod Recorded_Top_Level_Scenarios_Max);
+   end Recorded_Top_Level_Scenarios_Hash;
+
+   --------------------------
+   -- Reset_Visited_Bodies --
+   --------------------------
+
+   procedure Reset_Visited_Bodies is
+   begin
+      if Visited_Bodies_In_Use then
+         Visited_Bodies_In_Use := False;
+         Visited_Bodies.Reset;
+      end if;
+   end Reset_Visited_Bodies;
+
    -------------------
    -- Root_Scenario --
    -------------------
@@ -8315,6 +10948,71 @@
       return Stack.Table (Stack.First);
    end Root_Scenario;
 
+   ---------------------------
+   -- Set_Early_Call_Region --
+   ---------------------------
+
+   procedure Set_Early_Call_Region (Body_Id : Entity_Id; Start : Node_Id) is
+   begin
+      pragma Assert (Ekind_In (Body_Id, E_Entry,
+                                        E_Entry_Family,
+                                        E_Function,
+                                        E_Procedure,
+                                        E_Subprogram_Body));
+
+      Early_Call_Regions_In_Use := True;
+      Early_Call_Regions.Set (Body_Id, Start);
+   end Set_Early_Call_Region;
+
+   ----------------------------
+   -- Set_Elaboration_Status --
+   ----------------------------
+
+   procedure Set_Elaboration_Status
+     (Unit_Id : Entity_Id;
+      Val     : Elaboration_Attributes)
+   is
+   begin
+      Elaboration_Statuses_In_Use := True;
+      Elaboration_Statuses.Set (Unit_Id, Val);
+   end Set_Elaboration_Status;
+
+   ------------------------------------
+   -- Set_Is_Recorded_SPARK_Scenario --
+   ------------------------------------
+
+   procedure Set_Is_Recorded_SPARK_Scenario
+     (N   : Node_Id;
+      Val : Boolean := True)
+   is
+   begin
+      Recorded_SPARK_Scenarios_In_Use := True;
+      Recorded_SPARK_Scenarios.Set (N, Val);
+   end Set_Is_Recorded_SPARK_Scenario;
+
+   ----------------------------------------
+   -- Set_Is_Recorded_Top_Level_Scenario --
+   ----------------------------------------
+
+   procedure Set_Is_Recorded_Top_Level_Scenario
+     (N   : Node_Id;
+      Val : Boolean := True)
+   is
+   begin
+      Recorded_Top_Level_Scenarios_In_Use := True;
+      Recorded_Top_Level_Scenarios.Set (N, Val);
+   end Set_Is_Recorded_Top_Level_Scenario;
+
+   -------------------------
+   -- Set_Is_Visited_Body --
+   -------------------------
+
+   procedure Set_Is_Visited_Body (Subp_Body : Node_Id) is
+   begin
+      Visited_Bodies_In_Use := True;
+      Visited_Bodies.Set (Subp_Body, True);
+   end Set_Is_Visited_Body;
+
    -------------------------------
    -- Static_Elaboration_Checks --
    -------------------------------
@@ -8328,85 +11026,151 @@
    -- Traverse_Body --
    -------------------
 
-   procedure Traverse_Body (N : Node_Id; In_Task_Body : Boolean) is
-      function Is_Potential_Scenario (Nod : Node_Id) return Traverse_Result;
-      --  Determine whether arbitrary node Nod denotes a suitable scenario and
-      --  if so, process it.
-
-      procedure Traverse_Potential_Scenarios is
-        new Traverse_Proc (Is_Potential_Scenario);
-
-      procedure Traverse_List (List : List_Id);
-      --  Inspect list List for suitable elaboration scenarios and process them
-
-      ---------------------------
-      -- Is_Potential_Scenario --
-      ---------------------------
-
-      function Is_Potential_Scenario (Nod : Node_Id) return Traverse_Result is
-      begin
-         --  Special cases
-
-         --  Skip constructs which do not have elaboration of their own and
-         --  need to be elaborated by other means such as invocation, task
-         --  activation, etc.
-
-         if Is_Non_Library_Level_Encapsulator (Nod) then
-            return Skip;
-
-         --  Terminate the traversal of a task body with an accept statement
-         --  when no entry calls in elaboration are allowed because the task
-         --  will block at run-time and none of the remaining statements will
-         --  be executed.
-
-         elsif Nkind_In (Original_Node (Nod), N_Accept_Statement,
-                                              N_Selective_Accept)
-           and then Restriction_Active (No_Entry_Calls_In_Elaboration_Code)
-         then
-            return Abandon;
-
-         --  Certain nodes carry semantic lists which act as repositories until
-         --  expansion transforms the node and relocates the contents. Examine
-         --  these lists in case expansion is disabled.
-
-         elsif Nkind_In (Nod, N_And_Then, N_Or_Else) then
-            Traverse_List (Actions (Nod));
-
-         elsif Nkind_In (Nod, N_Elsif_Part, N_Iteration_Scheme) then
-            Traverse_List (Condition_Actions (Nod));
-
-         elsif Nkind (Nod) = N_If_Expression then
-            Traverse_List (Then_Actions (Nod));
-            Traverse_List (Else_Actions (Nod));
-
-         elsif Nkind_In (Nod, N_Component_Association,
-                              N_Iterated_Component_Association)
-         then
-            Traverse_List (Loop_Actions (Nod));
-
-         --  General case
-
-         elsif Is_Suitable_Scenario (Nod) then
-            Process_Scenario (Nod, In_Task_Body);
-         end if;
-
-         return OK;
-      end Is_Potential_Scenario;
-
-      -------------------
-      -- Traverse_List --
-      -------------------
-
-      procedure Traverse_List (List : List_Id) is
-         Item : Node_Id;
-
-      begin
-         Item := First (List);
-         while Present (Item) loop
-            Traverse_Potential_Scenarios (Item);
-            Next (Item);
-         end loop;
-      end Traverse_List;
+   procedure Traverse_Body (N : Node_Id; State : Processing_Attributes) is
+      procedure Find_And_Process_Nested_Scenarios;
+      pragma Inline (Find_And_Process_Nested_Scenarios);
+      --  Examine the declarations and statements of subprogram body N for
+      --  suitable scenarios.
+
+      ---------------------------------------
+      -- Find_And_Process_Nested_Scenarios --
+      ---------------------------------------
+
+      procedure Find_And_Process_Nested_Scenarios is
+         function Is_Potential_Scenario
+           (Nod : Node_Id) return Traverse_Result;
+         --  Determine whether arbitrary node Nod denotes a suitable scenario.
+         --  If it does, save it in the Nested_Scenarios list of the subprogram
+         --  body, and process it.
+
+         procedure Traverse_List (List : List_Id);
+         pragma Inline (Traverse_List);
+         --  Invoke Traverse_Potential_Scenarios on each node in list List
+
+         procedure Traverse_Potential_Scenarios is
+           new Traverse_Proc (Is_Potential_Scenario);
+
+         ---------------------------
+         -- Is_Potential_Scenario --
+         ---------------------------
+
+         function Is_Potential_Scenario
+           (Nod : Node_Id) return Traverse_Result
+         is
+         begin
+            --  Special cases
+
+            --  Skip constructs which do not have elaboration of their own and
+            --  need to be elaborated by other means such as invocation, task
+            --  activation, etc.
+
+            if Is_Non_Library_Level_Encapsulator (Nod) then
+               return Skip;
+
+            --  Terminate the traversal of a task body when encountering an
+            --  accept or select statement, and
+            --
+            --    * Entry calls during elaboration are not allowed. In this
+            --      case the accept or select statement will cause the task
+            --      to block at elaboration time because there are no entry
+            --      calls to unblock it.
+            --
+            --  or
+            --
+            --    * Switch -gnatd_a (stop elaboration checks on accept or
+            --      select statement) is in effect.
+
+            elsif (Debug_Flag_Underscore_A
+                    or else Restriction_Active
+                              (No_Entry_Calls_In_Elaboration_Code))
+              and then Nkind_In (Original_Node (Nod), N_Accept_Statement,
+                                                      N_Selective_Accept)
+            then
+               return Abandon;
+
+            --  Terminate the traversal of a task body when encountering a
+            --  suspension call, and
+            --
+            --    * Entry calls during elaboration are not allowed. In this
+            --      case the suspension call emulates an entry call and will
+            --      cause the task to block at elaboration time.
+            --
+            --  or
+            --
+            --    * Switch -gnatd_s (stop elaboration checks on synchronous
+            --      suspension) is in effect.
+            --
+            --  Note that the guard should not be checking the state of flag
+            --  Within_Task_Body because only suspension calls which appear
+            --  immediately within the statements of the task are supported.
+            --  Flag Within_Task_Body carries over to deeper levels of the
+            --  traversal.
+
+            elsif (Debug_Flag_Underscore_S
+                    or else Restriction_Active
+                              (No_Entry_Calls_In_Elaboration_Code))
+              and then Is_Synchronous_Suspension_Call (Nod)
+              and then In_Task_Body (Nod)
+            then
+               return Abandon;
+
+            --  Certain nodes carry semantic lists which act as repositories
+            --  until expansion transforms the node and relocates the contents.
+            --  Examine these lists in case expansion is disabled.
+
+            elsif Nkind_In (Nod, N_And_Then, N_Or_Else) then
+               Traverse_List (Actions (Nod));
+
+            elsif Nkind_In (Nod, N_Elsif_Part, N_Iteration_Scheme) then
+               Traverse_List (Condition_Actions (Nod));
+
+            elsif Nkind (Nod) = N_If_Expression then
+               Traverse_List (Then_Actions (Nod));
+               Traverse_List (Else_Actions (Nod));
+
+            elsif Nkind_In (Nod, N_Component_Association,
+                                 N_Iterated_Component_Association)
+            then
+               Traverse_List (Loop_Actions (Nod));
+
+            --  General case
+
+            elsif Is_Suitable_Scenario (Nod) then
+               Process_Conditional_ABE
+                 (N     => Nod,
+                  State => State);
+            end if;
+
+            return OK;
+         end Is_Potential_Scenario;
+
+         -------------------
+         -- Traverse_List --
+         -------------------
+
+         procedure Traverse_List (List : List_Id) is
+            Item : Node_Id;
+
+         begin
+            Item := First (List);
+            while Present (Item) loop
+               Traverse_Potential_Scenarios (Item);
+               Next (Item);
+            end loop;
+         end Traverse_List;
+
+      --  Start of processing for Find_And_Process_Nested_Scenarios
+
+      begin
+         --  Examine the declarations for suitable scenarios
+
+         Traverse_List (Declarations (N));
+
+         --  Examine the handled sequence of statements. This also includes any
+         --  exceptions handlers.
+
+         Traverse_Potential_Scenarios (Handled_Statement_Sequence (N));
+      end Find_And_Process_Nested_Scenarios;
 
    --  Start of processing for Traverse_Body
 
@@ -8421,59 +11185,167 @@
       end if;
 
       --  Nothing to do if the body was already traversed during the processing
-      --  of the same top level scenario.
-
-      if Visited_Bodies.Get (N) then
+      --  of the same top-level scenario.
+
+      if Is_Visited_Body (N) then
          return;
 
       --  Otherwise mark the body as traversed
 
       else
-         Visited_Bodies.Set (N, True);
-      end if;
-
-      --  Examine the declarations for suitable scenarios
-
-      Traverse_List (Declarations (N));
-
-      --  Examine the handled sequence of statements. This also includes any
-      --  exceptions handlers.
-
-      Traverse_Potential_Scenarios (Handled_Statement_Sequence (N));
+         Set_Is_Visited_Body (N);
+      end if;
+
+      --  Examine the declarations and statements of the subprogram body for
+      --  suitable scenarios, save and process them accordingly.
+
+      Find_And_Process_Nested_Scenarios;
    end Traverse_Body;
 
+   -----------------
+   -- Unit_Entity --
+   -----------------
+
+   function Unit_Entity (Unit_Id : Entity_Id) return Entity_Id is
+      function Is_Subunit (Id : Entity_Id) return Boolean;
+      pragma Inline (Is_Subunit);
+      --  Determine whether the entity of an initial declaration denotes a
+      --  subunit.
+
+      ----------------
+      -- Is_Subunit --
+      ----------------
+
+      function Is_Subunit (Id : Entity_Id) return Boolean is
+         Decl : constant Node_Id := Unit_Declaration_Node (Id);
+
+      begin
+         return
+           Nkind_In (Decl, N_Generic_Package_Declaration,
+                           N_Generic_Subprogram_Declaration,
+                           N_Package_Declaration,
+                           N_Protected_Type_Declaration,
+                           N_Subprogram_Declaration,
+                           N_Task_Type_Declaration)
+             and then Present (Corresponding_Body (Decl))
+             and then Nkind (Parent (Unit_Declaration_Node
+                        (Corresponding_Body (Decl)))) = N_Subunit;
+      end Is_Subunit;
+
+      --  Local variables
+
+      Id : Entity_Id;
+
+   --  Start of processing for Unit_Entity
+
+   begin
+      Id := Unique_Entity (Unit_Id);
+
+      --  Skip all subunits found in the scope chain which ends at the input
+      --  unit.
+
+      while Is_Subunit (Id) loop
+         Id := Scope (Id);
+      end loop;
+
+      return Id;
+   end Unit_Entity;
+
    ---------------------------------
    -- Update_Elaboration_Scenario --
    ---------------------------------
 
    procedure Update_Elaboration_Scenario (New_N : Node_Id; Old_N : Node_Id) is
-      package Scenarios renames Top_Level_Scenarios;
-
-   begin
+      procedure Update_SPARK_Scenario;
+      pragma Inline (Update_SPARK_Scenario);
+      --  Update the contents of table SPARK_Scenarios if Old_N is recorded
+      --  there.
+
+      procedure Update_Top_Level_Scenario;
+      pragma Inline (Update_Top_Level_Scenario);
+      --  Update the contexts of table Top_Level_Scenarios if Old_N is recorded
+      --  there.
+
+      ---------------------------
+      -- Update_SPARK_Scenario --
+      ---------------------------
+
+      procedure Update_SPARK_Scenario is
+         package Scenarios renames SPARK_Scenarios;
+
+      begin
+         if Is_Recorded_SPARK_Scenario (Old_N) then
+
+            --  Performance note: list traversal
+
+            for Index in Scenarios.First .. Scenarios.Last loop
+               if Scenarios.Table (Index) = Old_N then
+                  Scenarios.Table (Index) := New_N;
+
+                  --  The old SPARK scenario is no longer recorded, but the new
+                  --  one is.
+
+                  Set_Is_Recorded_Top_Level_Scenario (Old_N, False);
+                  Set_Is_Recorded_Top_Level_Scenario (New_N);
+                  return;
+               end if;
+            end loop;
+
+            --  A recorded SPARK scenario must be in the table of recorded
+            --  SPARK scenarios.
+
+            pragma Assert (False);
+         end if;
+      end Update_SPARK_Scenario;
+
+      -------------------------------
+      -- Update_Top_Level_Scenario --
+      -------------------------------
+
+      procedure Update_Top_Level_Scenario is
+         package Scenarios renames Top_Level_Scenarios;
+
+      begin
+         if Is_Recorded_Top_Level_Scenario (Old_N) then
+
+            --  Performance note: list traversal
+
+            for Index in Scenarios.First .. Scenarios.Last loop
+               if Scenarios.Table (Index) = Old_N then
+                  Scenarios.Table (Index) := New_N;
+
+                  --  The old top-level scenario is no longer recorded, but the
+                  --  new one is.
+
+                  Set_Is_Recorded_Top_Level_Scenario (Old_N, False);
+                  Set_Is_Recorded_Top_Level_Scenario (New_N);
+                  return;
+               end if;
+            end loop;
+
+            --  A recorded top-level scenario must be in the table of recorded
+            --  top-level scenarios.
+
+            pragma Assert (False);
+         end if;
+      end Update_Top_Level_Scenario;
+
+   --  Start of processing for Update_Elaboration_Requirement
+
+   begin
+      --  Nothing to do when the old and new scenarios are one and the same
+
+      if Old_N = New_N then
+         return;
+
       --  A scenario is being transformed by Atree.Rewrite. Update all relevant
       --  internal data structures to reflect this change. This ensures that a
       --  potential run-time conditional ABE check or a guaranteed ABE failure
       --  is inserted at the proper place in the tree.
 
-      if Is_Check_Emitting_Scenario (Old_N)
-        and then Is_Recorded_Scenario (Old_N)
-        and then Old_N /= New_N
-      then
-         --  Performance note: list traversal
-
-         for Index in Scenarios.First .. Scenarios.Last loop
-            if Scenarios.Table (Index) = Old_N then
-               Scenarios.Table (Index) := New_N;
-
-               Set_Is_Recorded_Scenario (Old_N, False);
-               Set_Is_Recorded_Scenario (New_N);
-               return;
-            end if;
-         end loop;
-
-         --  A recorded scenario must be in the table of recorded scenarios
-
-         pragma Assert (False);
+      elsif Is_Scenario (Old_N) then
+         Update_SPARK_Scenario;
+         Update_Top_Level_Scenario;
       end if;
    end Update_Elaboration_Scenario;
 
@@ -8486,4 +11358,3811 @@
       return Visited_Bodies_Index (Key mod Visited_Bodies_Max);
    end Visited_Bodies_Hash;
 
+   ---------------------------------------------------------------------------
+   --                                                                       --
+   --  L E G A C Y    A C C E S S    B E F O R E    E L A B O R A T I O N   --
+   --                                                                       --
+   --                          M E C H A N I S M                            --
+   --                                                                       --
+   ---------------------------------------------------------------------------
+
+   --  This section contains the implementation of the pre-18.x legacy ABE
+   --  mechanism. The mechanism can be activated using switch -gnatH (legacy
+   --  elaboration checking mode enabled).
+
+   -----------------------------
+   -- Description of Approach --
+   -----------------------------
+
+   --  Every non-static call that is encountered by Sem_Res results in a call
+   --  to Check_Elab_Call, with N being the call node, and Outer set to its
+   --  default value of True. In addition X'Access is treated like a call
+   --  for the access-to-procedure case, and in SPARK mode only we also
+   --  check variable references.
+
+   --  The goal of Check_Elab_Call is to determine whether or not the reference
+   --  in question can generate an access before elaboration error (raising
+   --  Program_Error) either by directly calling a subprogram whose body
+   --  has not yet been elaborated, or indirectly, by calling a subprogram
+   --  whose body has been elaborated, but which contains a call to such a
+   --  subprogram.
+
+   --  In addition, in SPARK mode, we are checking for a variable reference in
+   --  another package, which requires an explicit Elaborate_All pragma.
+
+   --  The only references that we need to look at the outer level are
+   --  references that occur in elaboration code. There are two cases. The
+   --  reference can be at the outer level of elaboration code, or it can
+   --  be within another unit, e.g. the elaboration code of a subprogram.
+
+   --  In the case of an elaboration call at the outer level, we must trace
+   --  all calls to outer level routines either within the current unit or to
+   --  other units that are with'ed. For calls within the current unit, we can
+   --  determine if the body has been elaborated or not, and if it has not,
+   --  then a warning is generated.
+
+   --  Note that there are two subcases. If the original call directly calls a
+   --  subprogram whose body has not been elaborated, then we know that an ABE
+   --  will take place, and we replace the call by a raise of Program_Error.
+   --  If the call is indirect, then we don't know that the PE will be raised,
+   --  since the call might be guarded by a conditional. In this case we set
+   --  Do_Elab_Check on the call so that a dynamic check is generated, and
+   --  output a warning.
+
+   --  For calls to a subprogram in a with'ed unit or a 'Access or variable
+   --  reference (SPARK mode case), we require that a pragma Elaborate_All
+   --  or pragma Elaborate be present, or that the referenced unit have a
+   --  pragma Preelaborate, pragma Pure, or pragma Elaborate_Body. If none
+   --  of these conditions is met, then a warning is generated that a pragma
+   --  Elaborate_All may be needed (error in the SPARK case), or an implicit
+   --  pragma is generated.
+
+   --  For the case of an elaboration call at some inner level, we are
+   --  interested in tracing only calls to subprograms at the same level, i.e.
+   --  those that can be called during elaboration. Any calls to outer level
+   --  routines cannot cause ABE's as a result of the original call (there
+   --  might be an outer level call to the subprogram from outside that causes
+   --  the ABE, but that gets analyzed separately).
+
+   --  Note that we never trace calls to inner level subprograms, since these
+   --  cannot result in ABE's unless there is an elaboration problem at a lower
+   --  level, which will be separately detected.
+
+   --  Note on pragma Elaborate. The checking here assumes that a pragma
+   --  Elaborate on a with'ed unit guarantees that subprograms within the unit
+   --  can be called without causing an ABE. This is not in fact the case since
+   --  pragma Elaborate does not guarantee the transitive coverage guaranteed
+   --  by Elaborate_All. However, we decide to trust the user in this case.
+
+   --------------------------------------
+   -- Instantiation Elaboration Errors --
+   --------------------------------------
+
+   --  A special case arises when an instantiation appears in a context that is
+   --  known to be before the body is elaborated, e.g.
+
+   --       generic package x is ...
+   --       ...
+   --       package xx is new x;
+   --       ...
+   --       package body x is ...
+
+   --  In this situation it is certain that an elaboration error will occur,
+   --  and an unconditional raise Program_Error statement is inserted before
+   --  the instantiation, and a warning generated.
+
+   --  The problem is that in this case we have no place to put the body of
+   --  the instantiation. We can't put it in the normal place, because it is
+   --  too early, and will cause errors to occur as a result of referencing
+   --  entities before they are declared.
+
+   --  Our approach in this case is simply to avoid creating the body of the
+   --  instantiation in such a case. The instantiation spec is modified to
+   --  include dummy bodies for all subprograms, so that the resulting code
+   --  does not contain subprogram specs with no corresponding bodies.
+
+   --  The following table records the recursive call chain for output in the
+   --  Output routine. Each entry records the call node and the entity of the
+   --  called routine. The number of entries in the table (i.e. the value of
+   --  Elab_Call.Last) indicates the current depth of recursion and is used to
+   --  identify the outer level.
+
+   type Elab_Call_Element is record
+      Cloc : Source_Ptr;
+      Ent  : Entity_Id;
+   end record;
+
+   package Elab_Call is new Table.Table
+     (Table_Component_Type => Elab_Call_Element,
+      Table_Index_Type     => Int,
+      Table_Low_Bound      => 1,
+      Table_Initial        => 50,
+      Table_Increment      => 100,
+      Table_Name           => "Elab_Call");
+
+   --  The following table records all calls that have been processed starting
+   --  from an outer level call. The table prevents both infinite recursion and
+   --  useless reanalysis of calls within the same context. The use of context
+   --  is important because it allows for proper checks in more complex code:
+
+   --    if ... then
+   --       Call;  --  requires a check
+   --       Call;  --  does not need a check thanks to the table
+   --    elsif ... then
+   --       Call;  --  requires a check, different context
+   --    end if;
+
+   --    Call;     --  requires a check, different context
+
+   type Visited_Element is record
+      Subp_Id : Entity_Id;
+      --  The entity of the subprogram being called
+
+      Context : Node_Id;
+      --  The context where the call to the subprogram occurs
+   end record;
+
+   package Elab_Visited is new Table.Table
+     (Table_Component_Type => Visited_Element,
+      Table_Index_Type     => Int,
+      Table_Low_Bound      => 1,
+      Table_Initial        => 200,
+      Table_Increment      => 100,
+      Table_Name           => "Elab_Visited");
+
+   --  The following table records delayed calls which must be examined after
+   --  all generic bodies have been instantiated.
+
+   type Delay_Element is record
+      N : Node_Id;
+      --  The parameter N from the call to Check_Internal_Call. Note that this
+      --  node may get rewritten over the delay period by expansion in the call
+      --  case (but not in the instantiation case).
+
+      E : Entity_Id;
+      --  The parameter E from the call to Check_Internal_Call
+
+      Orig_Ent : Entity_Id;
+      --  The parameter Orig_Ent from the call to Check_Internal_Call
+
+      Curscop : Entity_Id;
+      --  The current scope of the call. This is restored when we complete the
+      --  delayed call, so that we do this in the right scope.
+
+      Outer_Scope : Entity_Id;
+      --  Save scope of outer level call
+
+      From_Elab_Code : Boolean;
+      --  Save indication of whether this call is from elaboration code
+
+      In_Task_Activation : Boolean;
+      --  Save indication of whether this call is from a task body. Tasks are
+      --  activated at the "begin", which is after all local procedure bodies,
+      --  so calls to those procedures can't fail, even if they occur after the
+      --  task body.
+
+      From_SPARK_Code : Boolean;
+      --  Save indication of whether this call is under SPARK_Mode => On
+   end record;
+
+   package Delay_Check is new Table.Table
+     (Table_Component_Type => Delay_Element,
+      Table_Index_Type     => Int,
+      Table_Low_Bound      => 1,
+      Table_Initial        => 1000,
+      Table_Increment      => 100,
+      Table_Name           => "Delay_Check");
+
+   C_Scope : Entity_Id;
+   --  Top-level scope of current scope. Compute this only once at the outer
+   --  level, i.e. for a call to Check_Elab_Call from outside this unit.
+
+   Outer_Level_Sloc : Source_Ptr;
+   --  Save Sloc value for outer level call node for comparisons of source
+   --  locations. A body is too late if it appears after the *outer* level
+   --  call, not the particular call that is being analyzed.
+
+   From_Elab_Code : Boolean;
+   --  This flag shows whether the outer level call currently being examined
+   --  is or is not in elaboration code. We are only interested in calls to
+   --  routines in other units if this flag is True.
+
+   In_Task_Activation : Boolean := False;
+   --  This flag indicates whether we are performing elaboration checks on task
+   --  bodies, at the point of activation. If true, we do not raise
+   --  Program_Error for calls to local procedures, because all local bodies
+   --  are known to be elaborated. However, we still need to trace such calls,
+   --  because a local procedure could call a procedure in another package,
+   --  so we might need an implicit Elaborate_All.
+
+   Delaying_Elab_Checks : Boolean := True;
+   --  This is set True till the compilation is complete, including the
+   --  insertion of all instance bodies. Then when Check_Elab_Calls is called,
+   --  the delay table is used to make the delayed calls and this flag is reset
+   --  to False, so that the calls are processed.
+
+   -----------------------
+   -- Local Subprograms --
+   -----------------------
+
+   --  Note: Outer_Scope in all following specs represents the scope of
+   --  interest of the outer level call. If it is set to Standard_Standard,
+   --  then it means the outer level call was at elaboration level, and that
+   --  thus all calls are of interest. If it was set to some other scope,
+   --  then the original call was an inner call, and we are not interested
+   --  in calls that go outside this scope.
+
+   procedure Activate_Elaborate_All_Desirable (N : Node_Id; U : Entity_Id);
+   --  Analysis of construct N shows that we should set Elaborate_All_Desirable
+   --  for the WITH clause for unit U (which will always be present). A special
+   --  case is when N is a function or procedure instantiation, in which case
+   --  it is sufficient to set Elaborate_Desirable, since in this case there is
+   --  no possibility of transitive elaboration issues.
+
+   procedure Check_A_Call
+     (N                 : Node_Id;
+      E                 : Entity_Id;
+      Outer_Scope       : Entity_Id;
+      Inter_Unit_Only   : Boolean;
+      Generate_Warnings : Boolean := True;
+      In_Init_Proc      : Boolean := False);
+   --  This is the internal recursive routine that is called to check for
+   --  possible elaboration error. The argument N is a subprogram call or
+   --  generic instantiation, or 'Access attribute reference to be checked, and
+   --  E is the entity of the called subprogram, or instantiated generic unit,
+   --  or subprogram referenced by 'Access.
+   --
+   --  In SPARK mode, N can also be a variable reference, since in SPARK this
+   --  also triggers a requirement for Elaborate_All, and in this case E is the
+   --  entity being referenced.
+   --
+   --  Outer_Scope is the outer level scope for the original reference.
+   --  Inter_Unit_Only is set if the call is only to be checked in the
+   --  case where it is to another unit (and skipped if within a unit).
+   --  Generate_Warnings is set to False to suppress warning messages about
+   --  missing pragma Elaborate_All's. These messages are not wanted for
+   --  inner calls in the dynamic model. Note that an instance of the Access
+   --  attribute applied to a subprogram also generates a call to this
+   --  procedure (since the referenced subprogram may be called later
+   --  indirectly). Flag In_Init_Proc should be set whenever the current
+   --  context is a type init proc.
+   --
+   --  Note: this might better be called Check_A_Reference to recognize the
+   --  variable case for SPARK, but we prefer to retain the historical name
+   --  since in practice this is mostly about checking calls for the possible
+   --  occurrence of an access-before-elaboration exception.
+
+   procedure Check_Bad_Instantiation (N : Node_Id);
+   --  N is a node for an instantiation (if called with any other node kind,
+   --  Check_Bad_Instantiation ignores the call). This subprogram checks for
+   --  the special case of a generic instantiation of a generic spec in the
+   --  same declarative part as the instantiation where a body is present and
+   --  has not yet been seen. This is an obvious error, but needs to be checked
+   --  specially at the time of the instantiation, since it is a case where we
+   --  cannot insert the body anywhere. If this case is detected, warnings are
+   --  generated, and a raise of Program_Error is inserted. In addition any
+   --  subprograms in the generic spec are stubbed, and the Bad_Instantiation
+   --  flag is set on the instantiation node. The caller in Sem_Ch12 uses this
+   --  flag as an indication that no attempt should be made to insert an
+   --  instance body.
+
+   procedure Check_Internal_Call
+     (N           : Node_Id;
+      E           : Entity_Id;
+      Outer_Scope : Entity_Id;
+      Orig_Ent    : Entity_Id);
+   --  N is a function call or procedure statement call node and E is the
+   --  entity of the called function, which is within the current compilation
+   --  unit (where subunits count as part of the parent). This call checks if
+   --  this call, or any call within any accessed body could cause an ABE, and
+   --  if so, outputs a warning. Orig_Ent differs from E only in the case of
+   --  renamings, and points to the original name of the entity. This is used
+   --  for error messages. Outer_Scope is the outer level scope for the
+   --  original call.
+
+   procedure Check_Internal_Call_Continue
+     (N           : Node_Id;
+      E           : Entity_Id;
+      Outer_Scope : Entity_Id;
+      Orig_Ent    : Entity_Id);
+   --  The processing for Check_Internal_Call is divided up into two phases,
+   --  and this represents the second phase. The second phase is delayed if
+   --  Delaying_Elab_Checks is set to True. In this delayed case, the first
+   --  phase makes an entry in the Delay_Check table, which is processed when
+   --  Check_Elab_Calls is called. N, E and Orig_Ent are as for the call to
+   --  Check_Internal_Call. Outer_Scope is the outer level scope for the
+   --  original call.
+
+   function Get_Referenced_Ent (N : Node_Id) return Entity_Id;
+   --  N is either a function or procedure call or an access attribute that
+   --  references a subprogram. This call retrieves the relevant entity. If
+   --  this is a call to a protected subprogram, the entity is a selected
+   --  component. The callable entity may be absent, in which case Empty is
+   --  returned. This happens with non-analyzed calls in nested generics.
+   --
+   --  If SPARK_Mode is On, then N can also be a reference to an E_Variable
+   --  entity, in which case, the value returned is simply this entity.
+
+   function Has_Generic_Body (N : Node_Id) return Boolean;
+   --  N is a generic package instantiation node, and this routine determines
+   --  if this package spec does in fact have a generic body. If so, then
+   --  True is returned, otherwise False. Note that this is not at all the
+   --  same as checking if the unit requires a body, since it deals with
+   --  the case of optional bodies accurately (i.e. if a body is optional,
+   --  then it looks to see if a body is actually present). Note: this
+   --  function can only do a fully correct job if in generating code mode
+   --  where all bodies have to be present. If we are operating in semantics
+   --  check only mode, then in some cases of optional bodies, a result of
+   --  False may incorrectly be given. In practice this simply means that
+   --  some cases of warnings for incorrect order of elaboration will only
+   --  be given when generating code, which is not a big problem (and is
+   --  inevitable, given the optional body semantics of Ada).
+
+   procedure Insert_Elab_Check (N : Node_Id; C : Node_Id := Empty);
+   --  Given code for an elaboration check (or unconditional raise if the check
+   --  is not needed), inserts the code in the appropriate place. N is the call
+   --  or instantiation node for which the check code is required. C is the
+   --  test whose failure triggers the raise.
+
+   function Is_Call_Of_Generic_Formal (N : Node_Id) return Boolean;
+   --  Returns True if node N is a call to a generic formal subprogram
+
+   function Is_Finalization_Procedure (Id : Entity_Id) return Boolean;
+   --  Determine whether entity Id denotes a [Deep_]Finalize procedure
+
+   procedure Output_Calls
+     (N               : Node_Id;
+      Check_Elab_Flag : Boolean);
+   --  Outputs chain of calls stored in the Elab_Call table. The caller has
+   --  already generated the main warning message, so the warnings generated
+   --  are all continuation messages. The argument is the call node at which
+   --  the messages are to be placed. When Check_Elab_Flag is set, calls are
+   --  enumerated only when flag Elab_Warning is set for the dynamic case or
+   --  when flag Elab_Info_Messages is set for the static case.
+
+   function Same_Elaboration_Scope (Scop1, Scop2 : Entity_Id) return Boolean;
+   --  Given two scopes, determine whether they are the same scope from an
+   --  elaboration point of view, i.e. packages and blocks are ignored.
+
+   procedure Set_C_Scope;
+   --  On entry C_Scope is set to some scope. On return, C_Scope is reset
+   --  to be the enclosing compilation unit of this scope.
+
+   procedure Set_Elaboration_Constraint
+    (Call : Node_Id;
+     Subp : Entity_Id;
+     Scop : Entity_Id);
+   --  The current unit U may depend semantically on some unit P that is not
+   --  in the current context. If there is an elaboration call that reaches P,
+   --  we need to indicate that P requires an Elaborate_All, but this is not
+   --  effective in U's ali file, if there is no with_clause for P. In this
+   --  case we add the Elaborate_All on the unit Q that directly or indirectly
+   --  makes P available. This can happen in two cases:
+   --
+   --    a) Q declares a subtype of a type declared in P, and the call is an
+   --    initialization call for an object of that subtype.
+   --
+   --    b) Q declares an object of some tagged type whose root type is
+   --    declared in P, and the initialization call uses object notation on
+   --    that object to reach a primitive operation or a classwide operation
+   --    declared in P.
+   --
+   --  If P appears in the context of U, the current processing is correct.
+   --  Otherwise we must identify these two cases to retrieve Q and place the
+   --  Elaborate_All_Desirable on it.
+
+   function Spec_Entity (E : Entity_Id) return Entity_Id;
+   --  Given a compilation unit entity, if it is a spec entity, it is returned
+   --  unchanged. If it is a body entity, then the spec for the corresponding
+   --  spec is returned
+
+   function Within (E1, E2 : Entity_Id) return Boolean;
+   --  Given two scopes E1 and E2, returns True if E1 is equal to E2, or is one
+   --  of its contained scopes, False otherwise.
+
+   function Within_Elaborate_All
+     (Unit : Unit_Number_Type;
+      E    : Entity_Id) return Boolean;
+   --  Return True if we are within the scope of an Elaborate_All for E, or if
+   --  we are within the scope of an Elaborate_All for some other unit U, and U
+   --  with's E. This prevents spurious warnings when the called entity is
+   --  renamed within U, or in case of generic instances.
+
+   --------------------------------------
+   -- Activate_Elaborate_All_Desirable --
+   --------------------------------------
+
+   procedure Activate_Elaborate_All_Desirable (N : Node_Id; U : Entity_Id) is
+      UN  : constant Unit_Number_Type := Get_Code_Unit (N);
+      CU  : constant Node_Id          := Cunit (UN);
+      UE  : constant Entity_Id        := Cunit_Entity (UN);
+      Unm : constant Unit_Name_Type   := Unit_Name (UN);
+      CI  : constant List_Id          := Context_Items (CU);
+      Itm : Node_Id;
+      Ent : Entity_Id;
+
+      procedure Add_To_Context_And_Mark (Itm : Node_Id);
+      --  This procedure is called when the elaborate indication must be
+      --  applied to a unit not in the context of the referencing unit. The
+      --  unit gets added to the context as an implicit with.
+
+      function In_Withs_Of (UEs : Entity_Id) return Boolean;
+      --  UEs is the spec entity of a unit. If the unit to be marked is
+      --  in the context item list of this unit spec, then the call returns
+      --  True and Itm is left set to point to the relevant N_With_Clause node.
+
+      procedure Set_Elab_Flag (Itm : Node_Id);
+      --  Sets Elaborate_[All_]Desirable as appropriate on Itm
+
+      -----------------------------
+      -- Add_To_Context_And_Mark --
+      -----------------------------
+
+      procedure Add_To_Context_And_Mark (Itm : Node_Id) is
+         CW : constant Node_Id :=
+                Make_With_Clause (Sloc (Itm),
+                  Name => Name (Itm));
+
+      begin
+         Set_Library_Unit  (CW, Library_Unit (Itm));
+         Set_Implicit_With (CW);
+
+         --  Set elaborate all desirable on copy and then append the copy to
+         --  the list of body with's and we are done.
+
+         Set_Elab_Flag (CW);
+         Append_To (CI, CW);
+      end Add_To_Context_And_Mark;
+
+      -----------------
+      -- In_Withs_Of --
+      -----------------
+
+      function In_Withs_Of (UEs : Entity_Id) return Boolean is
+         UNs : constant Unit_Number_Type := Get_Source_Unit (UEs);
+         CUs : constant Node_Id          := Cunit (UNs);
+         CIs : constant List_Id          := Context_Items (CUs);
+
+      begin
+         Itm := First (CIs);
+         while Present (Itm) loop
+            if Nkind (Itm) = N_With_Clause then
+               Ent :=
+                 Cunit_Entity (Get_Cunit_Unit_Number (Library_Unit (Itm)));
+
+               if U = Ent then
+                  return True;
+               end if;
+            end if;
+
+            Next (Itm);
+         end loop;
+
+         return False;
+      end In_Withs_Of;
+
+      -------------------
+      -- Set_Elab_Flag --
+      -------------------
+
+      procedure Set_Elab_Flag (Itm : Node_Id) is
+      begin
+         if Nkind (N) in N_Subprogram_Instantiation then
+            Set_Elaborate_Desirable (Itm);
+         else
+            Set_Elaborate_All_Desirable (Itm);
+         end if;
+      end Set_Elab_Flag;
+
+   --  Start of processing for Activate_Elaborate_All_Desirable
+
+   begin
+      --  Do not set binder indication if expansion is disabled, as when
+      --  compiling a generic unit.
+
+      if not Expander_Active then
+         return;
+      end if;
+
+      --  If an instance of a generic package contains a controlled object (so
+      --  we're calling Initialize at elaboration time), and the instance is in
+      --  a package body P that says "with P;", then we need to return without
+      --  adding "pragma Elaborate_All (P);" to P.
+
+      if U = Main_Unit_Entity then
+         return;
+      end if;
+
+      Itm := First (CI);
+      while Present (Itm) loop
+         if Nkind (Itm) = N_With_Clause then
+            Ent := Cunit_Entity (Get_Cunit_Unit_Number (Library_Unit (Itm)));
+
+            --  If we find it, then mark elaborate all desirable and return
+
+            if U = Ent then
+               Set_Elab_Flag (Itm);
+               return;
+            end if;
+         end if;
+
+         Next (Itm);
+      end loop;
+
+      --  If we fall through then the with clause is not present in the
+      --  current unit. One legitimate possibility is that the with clause
+      --  is present in the spec when we are a body.
+
+      if Is_Body_Name (Unm)
+        and then In_Withs_Of (Spec_Entity (UE))
+      then
+         Add_To_Context_And_Mark (Itm);
+         return;
+      end if;
+
+      --  Similarly, we may be in the spec or body of a child unit, where
+      --  the unit in question is with'ed by some ancestor of the child unit.
+
+      if Is_Child_Name (Unm) then
+         declare
+            Pkg : Entity_Id;
+
+         begin
+            Pkg := UE;
+            loop
+               Pkg := Scope (Pkg);
+               exit when Pkg = Standard_Standard;
+
+               if In_Withs_Of (Pkg) then
+                  Add_To_Context_And_Mark (Itm);
+                  return;
+               end if;
+            end loop;
+         end;
+      end if;
+
+      --  Here if we do not find with clause on spec or body. We just ignore
+      --  this case; it means that the elaboration involves some other unit
+      --  than the unit being compiled, and will be caught elsewhere.
+   end Activate_Elaborate_All_Desirable;
+
+   ------------------
+   -- Check_A_Call --
+   ------------------
+
+   procedure Check_A_Call
+     (N                 : Node_Id;
+      E                 : Entity_Id;
+      Outer_Scope       : Entity_Id;
+      Inter_Unit_Only   : Boolean;
+      Generate_Warnings : Boolean := True;
+      In_Init_Proc      : Boolean := False)
+   is
+      Access_Case : constant Boolean := Nkind (N) = N_Attribute_Reference;
+      --  Indicates if we have Access attribute case
+
+      function Call_To_Instance_From_Outside (Id : Entity_Id) return Boolean;
+      --  True if we're calling an instance of a generic subprogram, or a
+      --  subprogram in an instance of a generic package, and the call is
+      --  outside that instance.
+
+      procedure Elab_Warning
+        (Msg_D : String;
+         Msg_S : String;
+         Ent   : Node_Or_Entity_Id);
+       --  Generate a call to Error_Msg_NE with parameters Msg_D or Msg_S (for
+       --  dynamic or static elaboration model), N and Ent. Msg_D is a real
+       --  warning (output if Msg_D is non-null and Elab_Warnings is set),
+       --  Msg_S is an info message (output if Elab_Info_Messages is set).
+
+      function Find_W_Scope return Entity_Id;
+      --  Find top-level scope for called entity (not following renamings
+      --  or derivations). This is where the Elaborate_All will go if it is
+      --  needed. We start with the called entity, except in the case of an
+      --  initialization procedure outside the current package, where the init
+      --  proc is in the root package, and we start from the entity of the name
+      --  in the call.
+
+      -----------------------------------
+      -- Call_To_Instance_From_Outside --
+      -----------------------------------
+
+      function Call_To_Instance_From_Outside (Id : Entity_Id) return Boolean is
+         Scop : Entity_Id := Id;
+
+      begin
+         loop
+            if Scop = Standard_Standard then
+               return False;
+            end if;
+
+            if Is_Generic_Instance (Scop) then
+               return not In_Open_Scopes (Scop);
+            end if;
+
+            Scop := Scope (Scop);
+         end loop;
+      end Call_To_Instance_From_Outside;
+
+      ------------------
+      -- Elab_Warning --
+      ------------------
+
+      procedure Elab_Warning
+        (Msg_D : String;
+         Msg_S : String;
+         Ent   : Node_Or_Entity_Id)
+      is
+      begin
+         --  Dynamic elaboration checks, real warning
+
+         if Dynamic_Elaboration_Checks then
+            if not Access_Case then
+               if Msg_D /= "" and then Elab_Warnings then
+                  Error_Msg_NE (Msg_D, N, Ent);
+               end if;
+
+            --  In the access case emit first warning message as well,
+            --  otherwise list of calls will appear as errors.
+
+            elsif Elab_Warnings then
+               Error_Msg_NE (Msg_S, N, Ent);
+            end if;
+
+         --  Static elaboration checks, info message
+
+         else
+            if Elab_Info_Messages then
+               Error_Msg_NE (Msg_S, N, Ent);
+            end if;
+         end if;
+      end Elab_Warning;
+
+      ------------------
+      -- Find_W_Scope --
+      ------------------
+
+      function Find_W_Scope return Entity_Id is
+         Refed_Ent : constant Entity_Id := Get_Referenced_Ent (N);
+         W_Scope   : Entity_Id;
+
+      begin
+         if Is_Init_Proc (Refed_Ent)
+           and then not In_Same_Extended_Unit (N, Refed_Ent)
+         then
+            W_Scope := Scope (Refed_Ent);
+         else
+            W_Scope := E;
+         end if;
+
+         --  Now loop through scopes to get to the enclosing compilation unit
+
+         while not Is_Compilation_Unit (W_Scope) loop
+            W_Scope := Scope (W_Scope);
+         end loop;
+
+         return W_Scope;
+      end Find_W_Scope;
+
+      --  Local variables
+
+      Inst_Case : constant Boolean := Nkind (N) in N_Generic_Instantiation;
+      --  Indicates if we have instantiation case
+
+      Loc : constant Source_Ptr := Sloc (N);
+
+      Variable_Case : constant Boolean :=
+                        Nkind (N) in N_Has_Entity
+                          and then Present (Entity (N))
+                          and then Ekind (Entity (N)) = E_Variable;
+      --  Indicates if we have variable reference case
+
+      W_Scope : constant Entity_Id := Find_W_Scope;
+      --  Top-level scope of directly called entity for subprogram. This
+      --  differs from E_Scope in the case where renamings or derivations
+      --  are involved, since it does not follow these links. W_Scope is
+      --  generally in a visible unit, and it is this scope that may require
+      --  an Elaborate_All. However, there are some cases (initialization
+      --  calls and calls involving object notation) where W_Scope might not
+      --  be in the context of the current unit, and there is an intermediate
+      --  package that is, in which case the Elaborate_All has to be placed
+      --  on this intermediate package. These special cases are handled in
+      --  Set_Elaboration_Constraint.
+
+      Ent                  : Entity_Id;
+      Callee_Unit_Internal : Boolean;
+      Caller_Unit_Internal : Boolean;
+      Decl                 : Node_Id;
+      Inst_Callee          : Source_Ptr;
+      Inst_Caller          : Source_Ptr;
+      Unit_Callee          : Unit_Number_Type;
+      Unit_Caller          : Unit_Number_Type;
+
+      Body_Acts_As_Spec : Boolean;
+      --  Set to true if call is to body acting as spec (no separate spec)
+
+      Cunit_SC : Boolean := False;
+      --  Set to suppress dynamic elaboration checks where one of the
+      --  enclosing scopes has Elaboration_Checks_Suppressed set, or else
+      --  if a pragma Elaborate[_All] applies to that scope, in which case
+      --  warnings on the scope are also suppressed. For the internal case,
+      --  we ignore this flag.
+
+      E_Scope : Entity_Id;
+      --  Top-level scope of entity for called subprogram. This value includes
+      --  following renamings and derivations, so this scope can be in a
+      --  non-visible unit. This is the scope that is to be investigated to
+      --  see whether an elaboration check is required.
+
+      Is_DIC : Boolean;
+      --  Flag set when the subprogram being invoked is the procedure generated
+      --  for pragma Default_Initial_Condition.
+
+      SPARK_Elab_Errors : Boolean;
+      --  Flag set when an entity is called or a variable is read during SPARK
+      --  dynamic elaboration.
+
+   --  Start of processing for Check_A_Call
+
+   begin
+      --  If the call is known to be within a local Suppress Elaboration
+      --  pragma, nothing to check. This can happen in task bodies. But
+      --  we ignore this for a call to a generic formal.
+
+      if Nkind (N) in N_Subprogram_Call
+        and then No_Elaboration_Check (N)
+        and then not Is_Call_Of_Generic_Formal (N)
+      then
+         return;
+
+      --  If this is a rewrite of a Valid_Scalars attribute, then nothing to
+      --  check, we don't mind in this case if the call occurs before the body
+      --  since this is all generated code.
+
+      elsif Nkind (Original_Node (N)) = N_Attribute_Reference
+        and then Attribute_Name (Original_Node (N)) = Name_Valid_Scalars
+      then
+         return;
+
+      --  Intrinsics such as instances of Unchecked_Deallocation do not have
+      --  any body, so elaboration checking is not needed, and would be wrong.
+
+      elsif Is_Intrinsic_Subprogram (E) then
+         return;
+
+      --  Do not consider references to internal variables for SPARK semantics
+
+      elsif Variable_Case and then not Comes_From_Source (E) then
+         return;
+      end if;
+
+      --  Proceed with check
+
+      Ent := E;
+
+      --  For a variable reference, just set Body_Acts_As_Spec to False
+
+      if Variable_Case then
+         Body_Acts_As_Spec := False;
+
+      --  Additional checks for all other cases
+
+      else
+         --  Go to parent for derived subprogram, or to original subprogram in
+         --  the case of a renaming (Alias covers both these cases).
+
+         loop
+            if (Suppress_Elaboration_Warnings (Ent)
+                 or else Elaboration_Checks_Suppressed (Ent))
+              and then (Inst_Case or else No (Alias (Ent)))
+            then
+               return;
+            end if;
+
+            --  Nothing to do for imported entities
+
+            if Is_Imported (Ent) then
+               return;
+            end if;
+
+            exit when Inst_Case or else No (Alias (Ent));
+            Ent := Alias (Ent);
+         end loop;
+
+         Decl := Unit_Declaration_Node (Ent);
+
+         if Nkind (Decl) = N_Subprogram_Body then
+            Body_Acts_As_Spec := True;
+
+         elsif Nkind_In (Decl, N_Subprogram_Declaration,
+                               N_Subprogram_Body_Stub)
+           or else Inst_Case
+         then
+            Body_Acts_As_Spec := False;
+
+         --  If we have none of an instantiation, subprogram body or subprogram
+         --  declaration, or in the SPARK case, a variable reference, then
+         --  it is not a case that we want to check. (One case is a call to a
+         --  generic formal subprogram, where we do not want the check in the
+         --  template).
+
+         else
+            return;
+         end if;
+      end if;
+
+      E_Scope := Ent;
+      loop
+         if Elaboration_Checks_Suppressed (E_Scope)
+           or else Suppress_Elaboration_Warnings (E_Scope)
+         then
+            Cunit_SC := True;
+         end if;
+
+         --  Exit when we get to compilation unit, not counting subunits
+
+         exit when Is_Compilation_Unit (E_Scope)
+           and then (Is_Child_Unit (E_Scope)
+                      or else Scope (E_Scope) = Standard_Standard);
+
+         pragma Assert (E_Scope /= Standard_Standard);
+
+         --  Move up a scope looking for compilation unit
+
+         E_Scope := Scope (E_Scope);
+      end loop;
+
+      --  No checks needed for pure or preelaborated compilation units
+
+      if Is_Pure (E_Scope) or else Is_Preelaborated (E_Scope) then
+         return;
+      end if;
+
+      --  If the generic entity is within a deeper instance than we are, then
+      --  either the instantiation to which we refer itself caused an ABE, in
+      --  which case that will be handled separately, or else we know that the
+      --  body we need appears as needed at the point of the instantiation.
+      --  However, this assumption is only valid if we are in static mode.
+
+      if not Dynamic_Elaboration_Checks
+        and then
+          Instantiation_Depth (Sloc (Ent)) > Instantiation_Depth (Sloc (N))
+      then
+         return;
+      end if;
+
+      --  Do not give a warning for a package with no body
+
+      if Ekind (Ent) = E_Generic_Package and then not Has_Generic_Body (N) then
+         return;
+      end if;
+
+      --  Case of entity is in same unit as call or instantiation. In the
+      --  instantiation case, W_Scope may be different from E_Scope; we want
+      --  the unit in which the instantiation occurs, since we're analyzing
+      --  based on the expansion.
+
+      if W_Scope = C_Scope then
+         if not Inter_Unit_Only then
+            Check_Internal_Call (N, Ent, Outer_Scope, E);
+         end if;
+
+         return;
+      end if;
+
+      --  Case of entity is not in current unit (i.e. with'ed unit case)
+
+      --  We are only interested in such calls if the outer call was from
+      --  elaboration code, or if we are in Dynamic_Elaboration_Checks mode.
+
+      if not From_Elab_Code and then not Dynamic_Elaboration_Checks then
+         return;
+      end if;
+
+      --  Nothing to do if some scope said that no checks were required
+
+      if Cunit_SC then
+         return;
+      end if;
+
+      --  Nothing to do for a generic instance, because a call to an instance
+      --  cannot fail the elaboration check, because the body of the instance
+      --  is always elaborated immediately after the spec.
+
+      if Call_To_Instance_From_Outside (Ent) then
+         return;
+      end if;
+
+      --  Nothing to do if subprogram with no separate spec. However, a call
+      --  to Deep_Initialize may result in a call to a user-defined Initialize
+      --  procedure, which imposes a body dependency. This happens only if the
+      --  type is controlled and the Initialize procedure is not inherited.
+
+      if Body_Acts_As_Spec then
+         if Is_TSS (Ent, TSS_Deep_Initialize) then
+            declare
+               Typ  : constant Entity_Id := Etype (First_Formal (Ent));
+               Init : Entity_Id;
+
+            begin
+               if not Is_Controlled (Typ) then
+                  return;
+               else
+                  Init := Find_Prim_Op (Typ, Name_Initialize);
+
+                  if Comes_From_Source (Init) then
+                     Ent := Init;
+                  else
+                     return;
+                  end if;
+               end if;
+            end;
+
+         else
+            return;
+         end if;
+      end if;
+
+      --  Check cases of internal units
+
+      Callee_Unit_Internal := In_Internal_Unit (E_Scope);
+
+      --  Do not give a warning if the with'ed unit is internal and this is
+      --  the generic instantiation case (this saves a lot of hassle dealing
+      --  with the Text_IO special child units)
+
+      if Callee_Unit_Internal and Inst_Case then
+         return;
+      end if;
+
+      if C_Scope = Standard_Standard then
+         Caller_Unit_Internal := False;
+      else
+         Caller_Unit_Internal := In_Internal_Unit (C_Scope);
+      end if;
+
+      --  Do not give a warning if the with'ed unit is internal and the caller
+      --  is not internal (since the binder always elaborates internal units
+      --  first).
+
+      if Callee_Unit_Internal and not Caller_Unit_Internal then
+         return;
+      end if;
+
+      --  For now, if debug flag -gnatdE is not set, do no checking for one
+      --  internal unit withing another. This fixes the problem with the sgi
+      --  build and storage errors. To be resolved later ???
+
+      if (Callee_Unit_Internal and Caller_Unit_Internal)
+        and not Debug_Flag_EE
+      then
+         return;
+      end if;
+
+      if Is_TSS (E, TSS_Deep_Initialize) then
+         Ent := E;
+      end if;
+
+      --  If the call is in an instance, and the called entity is not
+      --  defined in the same instance, then the elaboration issue focuses
+      --  around the unit containing the template, it is this unit that
+      --  requires an Elaborate_All.
+
+      --  However, if we are doing dynamic elaboration, we need to chase the
+      --  call in the usual manner.
+
+      --  We also need to chase the call in the usual manner if it is a call
+      --  to a generic formal parameter, since that case was not handled as
+      --  part of the processing of the template.
+
+      Inst_Caller := Instantiation (Get_Source_File_Index (Sloc (N)));
+      Inst_Callee := Instantiation (Get_Source_File_Index (Sloc (Ent)));
+
+      if Inst_Caller = No_Location then
+         Unit_Caller := No_Unit;
+      else
+         Unit_Caller := Get_Source_Unit (N);
+      end if;
+
+      if Inst_Callee = No_Location then
+         Unit_Callee := No_Unit;
+      else
+         Unit_Callee := Get_Source_Unit (Ent);
+      end if;
+
+      if Unit_Caller /= No_Unit
+        and then Unit_Callee /= Unit_Caller
+        and then not Dynamic_Elaboration_Checks
+        and then not Is_Call_Of_Generic_Formal (N)
+      then
+         E_Scope := Spec_Entity (Cunit_Entity (Unit_Caller));
+
+         --  If we don't get a spec entity, just ignore call. Not quite
+         --  clear why this check is necessary. ???
+
+         if No (E_Scope) then
+            return;
+         end if;
+
+         --  Otherwise step to enclosing compilation unit
+
+         while not Is_Compilation_Unit (E_Scope) loop
+            E_Scope := Scope (E_Scope);
+         end loop;
+
+      --  For the case where N is not an instance, and is not a call within
+      --  instance to other than a generic formal, we recompute E_Scope
+      --  for the error message, since we do NOT want to go to the unit
+      --  that has the ultimate declaration in the case of renaming and
+      --  derivation and we also want to go to the generic unit in the
+      --  case of an instance, and no further.
+
+      else
+         --  Loop to carefully follow renamings and derivations one step
+         --  outside the current unit, but not further.
+
+         if not (Inst_Case or Variable_Case)
+           and then Present (Alias (Ent))
+         then
+            E_Scope := Alias (Ent);
+         else
+            E_Scope := Ent;
+         end if;
+
+         loop
+            while not Is_Compilation_Unit (E_Scope) loop
+               E_Scope := Scope (E_Scope);
+            end loop;
+
+            --  If E_Scope is the same as C_Scope, it means that there
+            --  definitely was a local renaming or derivation, and we
+            --  are not yet out of the current unit.
+
+            exit when E_Scope /= C_Scope;
+            Ent := Alias (Ent);
+            E_Scope := Ent;
+
+            --  If no alias, there could be a previous error, but not if we've
+            --  already reached the outermost level (Standard).
+
+            if No (Ent) then
+               return;
+            end if;
+         end loop;
+      end if;
+
+      if Within_Elaborate_All (Current_Sem_Unit, E_Scope) then
+         return;
+      end if;
+
+      --  Determine whether the Default_Initial_Condition procedure of some
+      --  type is being invoked.
+
+      Is_DIC := Ekind (Ent) = E_Procedure and then Is_DIC_Procedure (Ent);
+
+      --  Checks related to Default_Initial_Condition fall under the SPARK
+      --  umbrella because this is a SPARK-specific annotation.
+
+      SPARK_Elab_Errors :=
+        SPARK_Mode = On and (Is_DIC or Dynamic_Elaboration_Checks);
+
+      --  Now check if an Elaborate_All (or dynamic check) is needed
+
+      if (Elab_Info_Messages or Elab_Warnings or SPARK_Elab_Errors)
+        and then Generate_Warnings
+        and then not Suppress_Elaboration_Warnings (Ent)
+        and then not Elaboration_Checks_Suppressed (Ent)
+        and then not Suppress_Elaboration_Warnings (E_Scope)
+        and then not Elaboration_Checks_Suppressed (E_Scope)
+      then
+         --  Instantiation case
+
+         if Inst_Case then
+            if Comes_From_Source (Ent) and then SPARK_Elab_Errors then
+               Error_Msg_NE
+                 ("instantiation of & during elaboration in SPARK", N, Ent);
+            else
+               Elab_Warning
+                 ("instantiation of & may raise Program_Error?l?",
+                  "info: instantiation of & during elaboration?$?", Ent);
+            end if;
+
+         --  Indirect call case, info message only in static elaboration
+         --  case, because the attribute reference itself cannot raise an
+         --  exception. Note that SPARK does not permit indirect calls.
+
+         elsif Access_Case then
+            Elab_Warning ("", "info: access to & during elaboration?$?", Ent);
+
+         --  Variable reference in SPARK mode
+
+         elsif Variable_Case then
+            if Comes_From_Source (Ent) and then SPARK_Elab_Errors then
+               Error_Msg_NE
+                 ("reference to & during elaboration in SPARK", N, Ent);
+            end if;
+
+         --  Subprogram call case
+
+         else
+            if Nkind (Name (N)) in N_Has_Entity
+              and then Is_Init_Proc (Entity (Name (N)))
+              and then Comes_From_Source (Ent)
+            then
+               Elab_Warning
+                 ("implicit call to & may raise Program_Error?l?",
+                  "info: implicit call to & during elaboration?$?",
+                  Ent);
+
+            elsif SPARK_Elab_Errors then
+
+               --  Emit a specialized error message when the elaboration of an
+               --  object of a private type evaluates the expression of pragma
+               --  Default_Initial_Condition. This prevents the internal name
+               --  of the procedure from appearing in the error message.
+
+               if Is_DIC then
+                  Error_Msg_N
+                    ("call to Default_Initial_Condition during elaboration in "
+                     & "SPARK", N);
+               else
+                  Error_Msg_NE
+                    ("call to & during elaboration in SPARK", N, Ent);
+               end if;
+
+            else
+               Elab_Warning
+                 ("call to & may raise Program_Error?l?",
+                  "info: call to & during elaboration?$?",
+                  Ent);
+            end if;
+         end if;
+
+         Error_Msg_Qual_Level := Nat'Last;
+
+         --  Case of Elaborate_All not present and required, for SPARK this
+         --  is an error, so give an error message.
+
+         if SPARK_Elab_Errors then
+            Error_Msg_NE -- CODEFIX
+              ("\Elaborate_All pragma required for&", N, W_Scope);
+
+         --  Otherwise we generate an implicit pragma. For a subprogram
+         --  instantiation, Elaborate is good enough, since no transitive
+         --  call is possible at elaboration time in this case.
+
+         elsif Nkind (N) in N_Subprogram_Instantiation then
+            Elab_Warning
+              ("\missing pragma Elaborate for&?l?",
+               "\implicit pragma Elaborate for& generated?$?",
+               W_Scope);
+
+         --  For all other cases, we need an implicit Elaborate_All
+
+         else
+            Elab_Warning
+              ("\missing pragma Elaborate_All for&?l?",
+               "\implicit pragma Elaborate_All for & generated?$?",
+               W_Scope);
+         end if;
+
+         Error_Msg_Qual_Level := 0;
+
+         --  Take into account the flags related to elaboration warning
+         --  messages when enumerating the various calls involved. This
+         --  ensures the proper pairing of the main warning and the
+         --  clarification messages generated by Output_Calls.
+
+         Output_Calls (N, Check_Elab_Flag => True);
+
+         --  Set flag to prevent further warnings for same unit unless in
+         --  All_Errors_Mode.
+
+         if not All_Errors_Mode and not Dynamic_Elaboration_Checks then
+            Set_Suppress_Elaboration_Warnings (W_Scope);
+         end if;
+      end if;
+
+      --  Check for runtime elaboration check required
+
+      if Dynamic_Elaboration_Checks then
+         if not Elaboration_Checks_Suppressed (Ent)
+           and then not Elaboration_Checks_Suppressed (W_Scope)
+           and then not Elaboration_Checks_Suppressed (E_Scope)
+           and then not Cunit_SC
+         then
+            --  Runtime elaboration check required. Generate check of the
+            --  elaboration Boolean for the unit containing the entity.
+
+            --  Note that for this case, we do check the real unit (the one
+            --  from following renamings, since that is the issue).
+
+            --  Could this possibly miss a useless but required PE???
+
+            Insert_Elab_Check (N,
+              Make_Attribute_Reference (Loc,
+                Attribute_Name => Name_Elaborated,
+                Prefix         =>
+                  New_Occurrence_Of (Spec_Entity (E_Scope), Loc)));
+
+            --  Prevent duplicate elaboration checks on the same call, which
+            --  can happen if the body enclosing the call appears itself in a
+            --  call whose elaboration check is delayed.
+
+            if Nkind (N) in N_Subprogram_Call then
+               Set_No_Elaboration_Check (N);
+            end if;
+         end if;
+
+      --  Case of static elaboration model
+
+      else
+         --  Do not do anything if elaboration checks suppressed. Note that
+         --  we check Ent here, not E, since we want the real entity for the
+         --  body to see if checks are suppressed for it, not the dummy
+         --  entry for renamings or derivations.
+
+         if Elaboration_Checks_Suppressed (Ent)
+           or else Elaboration_Checks_Suppressed (E_Scope)
+           or else Elaboration_Checks_Suppressed (W_Scope)
+         then
+            null;
+
+         --  Do not generate an Elaborate_All for finalization routines
+         --  that perform partial clean up as part of initialization.
+
+         elsif In_Init_Proc and then Is_Finalization_Procedure (Ent) then
+            null;
+
+         --  Here we need to generate an implicit elaborate all
+
+         else
+            --  Generate Elaborate_All warning unless suppressed
+
+            if (Elab_Info_Messages and Generate_Warnings and not Inst_Case)
+              and then not Suppress_Elaboration_Warnings (Ent)
+              and then not Suppress_Elaboration_Warnings (E_Scope)
+              and then not Suppress_Elaboration_Warnings (W_Scope)
+            then
+               Error_Msg_Node_2 := W_Scope;
+               Error_Msg_NE
+                 ("info: call to& in elaboration code requires pragma "
+                  & "Elaborate_All on&?$?", N, E);
+            end if;
+
+            --  Set indication for binder to generate Elaborate_All
+
+            Set_Elaboration_Constraint (N, E, W_Scope);
+         end if;
+      end if;
+   end Check_A_Call;
+
+   -----------------------------
+   -- Check_Bad_Instantiation --
+   -----------------------------
+
+   procedure Check_Bad_Instantiation (N : Node_Id) is
+      Ent : Entity_Id;
+
+   begin
+      --  Nothing to do if we do not have an instantiation (happens in some
+      --  error cases, and also in the formal package declaration case)
+
+      if Nkind (N) not in N_Generic_Instantiation then
+         return;
+
+      --  Nothing to do if serious errors detected (avoid cascaded errors)
+
+      elsif Serious_Errors_Detected /= 0 then
+         return;
+
+      --  Nothing to do if not in full analysis mode
+
+      elsif not Full_Analysis then
+         return;
+
+      --  Nothing to do if inside a generic template
+
+      elsif Inside_A_Generic then
+         return;
+
+      --  Nothing to do if a library level instantiation
+
+      elsif Nkind (Parent (N)) = N_Compilation_Unit then
+         return;
+
+      --  Nothing to do if we are compiling a proper body for semantic
+      --  purposes only. The generic body may be in another proper body.
+
+      elsif
+        Nkind (Parent (Unit_Declaration_Node (Main_Unit_Entity))) = N_Subunit
+      then
+         return;
+      end if;
+
+      Ent := Get_Generic_Entity (N);
+
+      --  The case we are interested in is when the generic spec is in the
+      --  current declarative part
+
+      if not Same_Elaboration_Scope (Current_Scope, Scope (Ent))
+        or else not In_Same_Extended_Unit (N, Ent)
+      then
+         return;
+      end if;
+
+      --  If the generic entity is within a deeper instance than we are, then
+      --  either the instantiation to which we refer itself caused an ABE, in
+      --  which case that will be handled separately. Otherwise, we know that
+      --  the body we need appears as needed at the point of the instantiation.
+      --  If they are both at the same level but not within the same instance
+      --  then the body of the generic will be in the earlier instance.
+
+      declare
+         D1 : constant Nat := Instantiation_Depth (Sloc (Ent));
+         D2 : constant Nat := Instantiation_Depth (Sloc (N));
+
+      begin
+         if D1 > D2 then
+            return;
+
+         elsif D1 = D2
+           and then Is_Generic_Instance (Scope (Ent))
+           and then not In_Open_Scopes (Scope (Ent))
+         then
+            return;
+         end if;
+      end;
+
+      --  Now we can proceed, if the entity being called has a completion,
+      --  then we are definitely OK, since we have already seen the body.
+
+      if Has_Completion (Ent) then
+         return;
+      end if;
+
+      --  If there is no body, then nothing to do
+
+      if not Has_Generic_Body (N) then
+         return;
+      end if;
+
+      --  Here we definitely have a bad instantiation
+
+      Error_Msg_Warn := SPARK_Mode /= On;
+      Error_Msg_NE ("cannot instantiate& before body seen<<", N, Ent);
+      Error_Msg_N ("\Program_Error [<<", N);
+
+      Insert_Elab_Check (N);
+      Set_Is_Known_Guaranteed_ABE (N);
+   end Check_Bad_Instantiation;
+
+   ---------------------
+   -- Check_Elab_Call --
+   ---------------------
+
+   procedure Check_Elab_Call
+     (N            : Node_Id;
+      Outer_Scope  : Entity_Id := Empty;
+      In_Init_Proc : Boolean   := False)
+   is
+      Ent : Entity_Id;
+      P   : Node_Id;
+
+   begin
+      pragma Assert (Legacy_Elaboration_Checks);
+
+      --  If the reference is not in the main unit, there is nothing to check.
+      --  Elaboration call from units in the context of the main unit will lead
+      --  to semantic dependencies when those units are compiled.
+
+      if not In_Extended_Main_Code_Unit (N) then
+         return;
+      end if;
+
+      --  For an entry call, check relevant restriction
+
+      if Nkind (N) = N_Entry_Call_Statement
+        and then not In_Subprogram_Or_Concurrent_Unit
+      then
+         Check_Restriction (No_Entry_Calls_In_Elaboration_Code, N);
+
+      --  Nothing to do if this is not an expected type of reference (happens
+      --  in some error conditions, and in some cases where rewriting occurs).
+
+      elsif Nkind (N) not in N_Subprogram_Call
+        and then Nkind (N) /= N_Attribute_Reference
+        and then (SPARK_Mode /= On
+                   or else Nkind (N) not in N_Has_Entity
+                   or else No (Entity (N))
+                   or else Ekind (Entity (N)) /= E_Variable)
+      then
+         return;
+
+      --  Nothing to do if this is a call already rewritten for elab checking.
+      --  Such calls appear as the targets of If_Expressions.
+
+      --  This check MUST be wrong, it catches far too much
+
+      elsif Nkind (Parent (N)) = N_If_Expression then
+         return;
+
+      --  Nothing to do if inside a generic template
+
+      elsif Inside_A_Generic
+        and then No (Enclosing_Generic_Body (N))
+      then
+         return;
+
+      --  Nothing to do if call is being preanalyzed, as when within a
+      --  pre/postcondition, a predicate, or an invariant.
+
+      elsif In_Spec_Expression then
+         return;
+      end if;
+
+      --  Nothing to do if this is a call to a postcondition, which is always
+      --  within a subprogram body, even though the current scope may be the
+      --  enclosing scope of the subprogram.
+
+      if Nkind (N) = N_Procedure_Call_Statement
+        and then Is_Entity_Name (Name (N))
+        and then Chars (Entity (Name (N))) = Name_uPostconditions
+      then
+         return;
+      end if;
+
+      --  Here we have a reference at elaboration time that must be checked
+
+      if Debug_Flag_Underscore_LL then
+         Write_Str ("  Check_Elab_Ref: ");
+
+         if Nkind (N) = N_Attribute_Reference then
+            if not Is_Entity_Name (Prefix (N)) then
+               Write_Str ("<<not entity name>>");
+            else
+               Write_Name (Chars (Entity (Prefix (N))));
+            end if;
+
+            Write_Str ("'Access");
+
+         elsif No (Name (N)) or else not Is_Entity_Name (Name (N)) then
+            Write_Str ("<<not entity name>> ");
+
+         else
+            Write_Name (Chars (Entity (Name (N))));
+         end if;
+
+         Write_Str ("  reference at ");
+         Write_Location (Sloc (N));
+         Write_Eol;
+      end if;
+
+      --  Climb up the tree to make sure we are not inside default expression
+      --  of a parameter specification or a record component, since in both
+      --  these cases, we will be doing the actual reference later, not now,
+      --  and it is at the time of the actual reference (statically speaking)
+      --  that we must do our static check, not at the time of its initial
+      --  analysis).
+
+      --  However, we have to check references within component definitions
+      --  (e.g. a function call that determines an array component bound),
+      --  so we terminate the loop in that case.
+
+      P := Parent (N);
+      while Present (P) loop
+         if Nkind_In (P, N_Parameter_Specification,
+                         N_Component_Declaration)
+         then
+            return;
+
+         --  The reference occurs within the constraint of a component,
+         --  so it must be checked.
+
+         elsif Nkind (P) = N_Component_Definition then
+            exit;
+
+         else
+            P := Parent (P);
+         end if;
+      end loop;
+
+      --  Stuff that happens only at the outer level
+
+      if No (Outer_Scope) then
+         Elab_Visited.Set_Last (0);
+
+         --  Nothing to do if current scope is Standard (this is a bit odd, but
+         --  it happens in the case of generic instantiations).
+
+         C_Scope := Current_Scope;
+
+         if C_Scope = Standard_Standard then
+            return;
+         end if;
+
+         --  First case, we are in elaboration code
+
+         From_Elab_Code := not In_Subprogram_Or_Concurrent_Unit;
+
+         if From_Elab_Code then
+
+            --  Complain if ref that comes from source in preelaborated unit
+            --  and we are not inside a subprogram (i.e. we are in elab code).
+
+            if Comes_From_Source (N)
+              and then In_Preelaborated_Unit
+              and then not In_Inlined_Body
+              and then Nkind (N) /= N_Attribute_Reference
+            then
+               --  This is a warning in GNAT mode allowing such calls to be
+               --  used in the predefined library with appropriate care.
+
+               Error_Msg_Warn := GNAT_Mode;
+               Error_Msg_N
+                 ("<<non-static call not allowed in preelaborated unit", N);
+               return;
+            end if;
+
+         --  Second case, we are inside a subprogram or concurrent unit, which
+         --  means we are not in elaboration code.
+
+         else
+            --  In this case, the issue is whether we are inside the
+            --  declarative part of the unit in which we live, or inside its
+            --  statements. In the latter case, there is no issue of ABE calls
+            --  at this level (a call from outside to the unit in which we live
+            --  might cause an ABE, but that will be detected when we analyze
+            --  that outer level call, as it recurses into the called unit).
+
+            --  Climb up the tree, doing this test, and also testing for being
+            --  inside a default expression, which, as discussed above, is not
+            --  checked at this stage.
+
+            declare
+               P : Node_Id;
+               L : List_Id;
+
+            begin
+               P := N;
+               loop
+                  --  If we find a parentless subtree, it seems safe to assume
+                  --  that we are not in a declarative part and that no
+                  --  checking is required.
+
+                  if No (P) then
+                     return;
+                  end if;
+
+                  if Is_List_Member (P) then
+                     L := List_Containing (P);
+                     P := Parent (L);
+                  else
+                     L := No_List;
+                     P := Parent (P);
+                  end if;
+
+                  exit when Nkind (P) = N_Subunit;
+
+                  --  Filter out case of default expressions, where we do not
+                  --  do the check at this stage.
+
+                  if Nkind_In (P, N_Parameter_Specification,
+                                  N_Component_Declaration)
+                  then
+                     return;
+                  end if;
+
+                  --  A protected body has no elaboration code and contains
+                  --  only other bodies.
+
+                  if Nkind (P) = N_Protected_Body then
+                     return;
+
+                  elsif Nkind_In (P, N_Subprogram_Body,
+                                     N_Task_Body,
+                                     N_Block_Statement,
+                                     N_Entry_Body)
+                  then
+                     if L = Declarations (P) then
+                        exit;
+
+                     --  We are not in elaboration code, but we are doing
+                     --  dynamic elaboration checks, in this case, we still
+                     --  need to do the reference, since the subprogram we are
+                     --  in could be called from another unit, also in dynamic
+                     --  elaboration check mode, at elaboration time.
+
+                     elsif Dynamic_Elaboration_Checks then
+
+                        --  We provide a debug flag to disable this check. That
+                        --  way we have an easy work around for regressions
+                        --  that are caused by this new check. This debug flag
+                        --  can be removed later.
+
+                        if Debug_Flag_DD then
+                           return;
+                        end if;
+
+                        --  Do the check in this case
+
+                        exit;
+
+                     elsif Nkind (P) = N_Task_Body then
+
+                        --  The check is deferred until Check_Task_Activation
+                        --  but we need to capture local suppress pragmas
+                        --  that may inhibit checks on this call.
+
+                        Ent := Get_Referenced_Ent (N);
+
+                        if No (Ent) then
+                           return;
+
+                        elsif Elaboration_Checks_Suppressed (Current_Scope)
+                          or else Elaboration_Checks_Suppressed (Ent)
+                          or else Elaboration_Checks_Suppressed (Scope (Ent))
+                        then
+                           if Nkind (N) in N_Subprogram_Call then
+                              Set_No_Elaboration_Check (N);
+                           end if;
+                        end if;
+
+                        return;
+
+                     --  Static model, call is not in elaboration code, we
+                     --  never need to worry, because in the static model the
+                     --  top-level caller always takes care of things.
+
+                     else
+                        return;
+                     end if;
+                  end if;
+               end loop;
+            end;
+         end if;
+      end if;
+
+      Ent := Get_Referenced_Ent (N);
+
+      if No (Ent) then
+         return;
+      end if;
+
+      --  Determine whether a prior call to the same subprogram was already
+      --  examined within the same context. If this is the case, then there is
+      --  no need to proceed with the various warnings and checks because the
+      --  work was already done for the previous call.
+
+      declare
+         Self : constant Visited_Element :=
+                  (Subp_Id => Ent, Context => Parent (N));
+
+      begin
+         for Index in 1 .. Elab_Visited.Last loop
+            if Self = Elab_Visited.Table (Index) then
+               return;
+            end if;
+         end loop;
+      end;
+
+      --  See if we need to analyze this reference. We analyze it if either of
+      --  the following conditions is met:
+
+      --    It is an inner level call (since in this case it was triggered
+      --    by an outer level call from elaboration code), but only if the
+      --    call is within the scope of the original outer level call.
+
+      --    It is an outer level reference from elaboration code, or a call to
+      --    an entity is in the same elaboration scope.
+
+      --  And in these cases, we will check both inter-unit calls and
+      --  intra-unit (within a single unit) calls.
+
+      C_Scope := Current_Scope;
+
+      --  If not outer level reference, then we follow it if it is within the
+      --  original scope of the outer reference.
+
+      if Present (Outer_Scope)
+        and then Within (Scope (Ent), Outer_Scope)
+      then
+         Set_C_Scope;
+         Check_A_Call
+           (N               => N,
+            E               => Ent,
+            Outer_Scope     => Outer_Scope,
+            Inter_Unit_Only => False,
+            In_Init_Proc    => In_Init_Proc);
+
+      --  Nothing to do if elaboration checks suppressed for this scope.
+      --  However, an interesting exception, the fact that elaboration checks
+      --  are suppressed within an instance (because we can trace the body when
+      --  we process the template) does not extend to calls to generic formal
+      --  subprograms.
+
+      elsif Elaboration_Checks_Suppressed (Current_Scope)
+        and then not Is_Call_Of_Generic_Formal (N)
+      then
+         null;
+
+      elsif From_Elab_Code then
+         Set_C_Scope;
+         Check_A_Call (N, Ent, Standard_Standard, Inter_Unit_Only => False);
+
+      elsif Same_Elaboration_Scope (C_Scope, Scope (Ent)) then
+         Set_C_Scope;
+         Check_A_Call (N, Ent, Scope (Ent), Inter_Unit_Only => False);
+
+      --  If none of those cases holds, but Dynamic_Elaboration_Checks mode
+      --  is set, then we will do the check, but only in the inter-unit case
+      --  (this is to accommodate unguarded elaboration calls from other units
+      --  in which this same mode is set). We don't want warnings in this case,
+      --  it would generate warnings having nothing to do with elaboration.
+
+      elsif Dynamic_Elaboration_Checks then
+         Set_C_Scope;
+         Check_A_Call
+           (N,
+            Ent,
+            Standard_Standard,
+            Inter_Unit_Only   => True,
+            Generate_Warnings => False);
+
+      --  Otherwise nothing to do
+
+      else
+         return;
+      end if;
+
+      --  A call to an Init_Proc in elaboration code may bring additional
+      --  dependencies, if some of the record components thereof have
+      --  initializations that are function calls that come from source. We
+      --  treat the current node as a call to each of these functions, to check
+      --  their elaboration impact.
+
+      if Is_Init_Proc (Ent) and then From_Elab_Code then
+         Process_Init_Proc : declare
+            Unit_Decl : constant Node_Id := Unit_Declaration_Node (Ent);
+
+            function Check_Init_Call (Nod : Node_Id) return Traverse_Result;
+            --  Find subprogram calls within body of Init_Proc for Traverse
+            --  instantiation below.
+
+            procedure Traverse_Body is new Traverse_Proc (Check_Init_Call);
+            --  Traversal procedure to find all calls with body of Init_Proc
+
+            ---------------------
+            -- Check_Init_Call --
+            ---------------------
+
+            function Check_Init_Call (Nod : Node_Id) return Traverse_Result is
+               Func : Entity_Id;
+
+            begin
+               if Nkind (Nod) in N_Subprogram_Call
+                 and then Is_Entity_Name (Name (Nod))
+               then
+                  Func := Entity (Name (Nod));
+
+                  if Comes_From_Source (Func) then
+                     Check_A_Call
+                       (N, Func, Standard_Standard, Inter_Unit_Only => True);
+                  end if;
+
+                  return OK;
+
+               else
+                  return OK;
+               end if;
+            end Check_Init_Call;
+
+         --  Start of processing for Process_Init_Proc
+
+         begin
+            if Nkind (Unit_Decl) = N_Subprogram_Body then
+               Traverse_Body (Handled_Statement_Sequence (Unit_Decl));
+            end if;
+         end Process_Init_Proc;
+      end if;
+   end Check_Elab_Call;
+
+   -----------------------
+   -- Check_Elab_Assign --
+   -----------------------
+
+   procedure Check_Elab_Assign (N : Node_Id) is
+      Ent  : Entity_Id;
+      Scop : Entity_Id;
+
+      Pkg_Spec : Entity_Id;
+      Pkg_Body : Entity_Id;
+
+   begin
+      pragma Assert (Legacy_Elaboration_Checks);
+
+      --  For record or array component, check prefix. If it is an access type,
+      --  then there is nothing to do (we do not know what is being assigned),
+      --  but otherwise this is an assignment to the prefix.
+
+      if Nkind_In (N, N_Indexed_Component,
+                      N_Selected_Component,
+                      N_Slice)
+      then
+         if not Is_Access_Type (Etype (Prefix (N))) then
+            Check_Elab_Assign (Prefix (N));
+         end if;
+
+         return;
+      end if;
+
+      --  For type conversion, check expression
+
+      if Nkind (N) = N_Type_Conversion then
+         Check_Elab_Assign (Expression (N));
+         return;
+      end if;
+
+      --  Nothing to do if this is not an entity reference otherwise get entity
+
+      if Is_Entity_Name (N) then
+         Ent := Entity (N);
+      else
+         return;
+      end if;
+
+      --  What we are looking for is a reference in the body of a package that
+      --  modifies a variable declared in the visible part of the package spec.
+
+      if Present (Ent)
+        and then Comes_From_Source (N)
+        and then not Suppress_Elaboration_Warnings (Ent)
+        and then Ekind (Ent) = E_Variable
+        and then not In_Private_Part (Ent)
+        and then Is_Library_Level_Entity (Ent)
+      then
+         Scop := Current_Scope;
+         loop
+            if No (Scop) or else Scop = Standard_Standard then
+               return;
+            elsif Ekind (Scop) = E_Package
+              and then Is_Compilation_Unit (Scop)
+            then
+               exit;
+            else
+               Scop := Scope (Scop);
+            end if;
+         end loop;
+
+         --  Here Scop points to the containing library package
+
+         Pkg_Spec := Scop;
+         Pkg_Body := Body_Entity (Pkg_Spec);
+
+         --  All OK if the package has an Elaborate_Body pragma
+
+         if Has_Pragma_Elaborate_Body (Scop) then
+            return;
+         end if;
+
+         --  OK if entity being modified is not in containing package spec
+
+         if not In_Same_Source_Unit (Scop, Ent) then
+            return;
+         end if;
+
+         --  All OK if entity appears in generic package or generic instance.
+         --  We just get too messed up trying to give proper warnings in the
+         --  presence of generics. Better no message than a junk one.
+
+         Scop := Scope (Ent);
+         while Present (Scop) and then Scop /= Pkg_Spec loop
+            if Ekind (Scop) = E_Generic_Package then
+               return;
+            elsif Ekind (Scop) = E_Package
+              and then Is_Generic_Instance (Scop)
+            then
+               return;
+            end if;
+
+            Scop := Scope (Scop);
+         end loop;
+
+         --  All OK if in task, don't issue warnings there
+
+         if In_Task_Activation then
+            return;
+         end if;
+
+         --  OK if no package body
+
+         if No (Pkg_Body) then
+            return;
+         end if;
+
+         --  OK if reference is not in package body
+
+         if not In_Same_Source_Unit (Pkg_Body, N) then
+            return;
+         end if;
+
+         --  OK if package body has no handled statement sequence
+
+         declare
+            HSS : constant Node_Id :=
+                    Handled_Statement_Sequence (Declaration_Node (Pkg_Body));
+         begin
+            if No (HSS) or else not Comes_From_Source (HSS) then
+               return;
+            end if;
+         end;
+
+         --  We definitely have a case of a modification of an entity in
+         --  the package spec from the elaboration code of the package body.
+         --  We may not give the warning (because there are some additional
+         --  checks to avoid too many false positives), but it would be a good
+         --  idea for the binder to try to keep the body elaboration close to
+         --  the spec elaboration.
+
+         Set_Elaborate_Body_Desirable (Pkg_Spec);
+
+         --  All OK in gnat mode (we know what we are doing)
+
+         if GNAT_Mode then
+            return;
+         end if;
+
+         --  All OK if all warnings suppressed
+
+         if Warning_Mode = Suppress then
+            return;
+         end if;
+
+         --  All OK if elaboration checks suppressed for entity
+
+         if Checks_May_Be_Suppressed (Ent)
+           and then Is_Check_Suppressed (Ent, Elaboration_Check)
+         then
+            return;
+         end if;
+
+         --  OK if the entity is initialized. Note that the No_Initialization
+         --  flag usually means that the initialization has been rewritten into
+         --  assignments, but that still counts for us.
+
+         declare
+            Decl : constant Node_Id := Declaration_Node (Ent);
+         begin
+            if Nkind (Decl) = N_Object_Declaration
+              and then (Present (Expression (Decl))
+                         or else No_Initialization (Decl))
+            then
+               return;
+            end if;
+         end;
+
+         --  Here is where we give the warning
+
+         --  All OK if warnings suppressed on the entity
+
+         if not Has_Warnings_Off (Ent) then
+            Error_Msg_Sloc := Sloc (Ent);
+
+            Error_Msg_NE
+              ("??& can be accessed by clients before this initialization",
+               N, Ent);
+            Error_Msg_NE
+              ("\??add Elaborate_Body to spec to ensure & is initialized",
+               N, Ent);
+         end if;
+
+         if not All_Errors_Mode then
+            Set_Suppress_Elaboration_Warnings (Ent);
+         end if;
+      end if;
+   end Check_Elab_Assign;
+
+   ----------------------
+   -- Check_Elab_Calls --
+   ----------------------
+
+   --  WARNING: This routine manages SPARK regions
+
+   procedure Check_Elab_Calls is
+      Saved_SM  : SPARK_Mode_Type;
+      Saved_SMP : Node_Id;
+
+   begin
+      pragma Assert (Legacy_Elaboration_Checks);
+
+      --  If expansion is disabled, do not generate any checks, unless we
+      --  are in GNATprove mode, so that errors are issued in GNATprove for
+      --  violations of static elaboration rules in SPARK code. Also skip
+      --  checks if any subunits are missing because in either case we lack the
+      --  full information that we need, and no object file will be created in
+      --  any case.
+
+      if (not Expander_Active and not GNATprove_Mode)
+        or else Is_Generic_Unit (Cunit_Entity (Main_Unit))
+        or else Subunits_Missing
+      then
+         return;
+      end if;
+
+      --  Skip delayed calls if we had any errors
+
+      if Serious_Errors_Detected = 0 then
+         Delaying_Elab_Checks := False;
+         Expander_Mode_Save_And_Set (True);
+
+         for J in Delay_Check.First .. Delay_Check.Last loop
+            Push_Scope (Delay_Check.Table (J).Curscop);
+            From_Elab_Code := Delay_Check.Table (J).From_Elab_Code;
+            In_Task_Activation := Delay_Check.Table (J).In_Task_Activation;
+
+            Saved_SM  := SPARK_Mode;
+            Saved_SMP := SPARK_Mode_Pragma;
+
+            --  Set appropriate value of SPARK_Mode
+
+            if Delay_Check.Table (J).From_SPARK_Code then
+               SPARK_Mode := On;
+            end if;
+
+            Check_Internal_Call_Continue
+              (N           => Delay_Check.Table (J).N,
+               E           => Delay_Check.Table (J).E,
+               Outer_Scope => Delay_Check.Table (J).Outer_Scope,
+               Orig_Ent    => Delay_Check.Table (J).Orig_Ent);
+
+            Restore_SPARK_Mode (Saved_SM, Saved_SMP);
+            Pop_Scope;
+         end loop;
+
+         --  Set Delaying_Elab_Checks back on for next main compilation
+
+         Expander_Mode_Restore;
+         Delaying_Elab_Checks := True;
+      end if;
+   end Check_Elab_Calls;
+
+   ------------------------------
+   -- Check_Elab_Instantiation --
+   ------------------------------
+
+   procedure Check_Elab_Instantiation
+     (N           : Node_Id;
+      Outer_Scope : Entity_Id := Empty)
+   is
+      Ent : Entity_Id;
+
+   begin
+      pragma Assert (Legacy_Elaboration_Checks);
+
+      --  Check for and deal with bad instantiation case. There is some
+      --  duplicated code here, but we will worry about this later ???
+
+      Check_Bad_Instantiation (N);
+
+      if Is_Known_Guaranteed_ABE (N) then
+         return;
+      end if;
+
+      --  Nothing to do if we do not have an instantiation (happens in some
+      --  error cases, and also in the formal package declaration case)
+
+      if Nkind (N) not in N_Generic_Instantiation then
+         return;
+      end if;
+
+      --  Nothing to do if inside a generic template
+
+      if Inside_A_Generic then
+         return;
+      end if;
+
+      --  Nothing to do if the instantiation is not in the main unit
+
+      if not In_Extended_Main_Code_Unit (N) then
+         return;
+      end if;
+
+      Ent := Get_Generic_Entity (N);
+      From_Elab_Code := not In_Subprogram_Or_Concurrent_Unit;
+
+      --  See if we need to analyze this instantiation. We analyze it if
+      --  either of the following conditions is met:
+
+      --    It is an inner level instantiation (since in this case it was
+      --    triggered by an outer level call from elaboration code), but
+      --    only if the instantiation is within the scope of the original
+      --    outer level call.
+
+      --    It is an outer level instantiation from elaboration code, or the
+      --    instantiated entity is in the same elaboration scope.
+
+      --  And in these cases, we will check both the inter-unit case and
+      --  the intra-unit (within a single unit) case.
+
+      C_Scope := Current_Scope;
+
+      if Present (Outer_Scope) and then Within (Scope (Ent), Outer_Scope) then
+         Set_C_Scope;
+         Check_A_Call (N, Ent, Outer_Scope, Inter_Unit_Only => False);
+
+      elsif From_Elab_Code then
+         Set_C_Scope;
+         Check_A_Call (N, Ent, Standard_Standard, Inter_Unit_Only => False);
+
+      elsif Same_Elaboration_Scope (C_Scope, Scope (Ent)) then
+         Set_C_Scope;
+         Check_A_Call (N, Ent, Scope (Ent), Inter_Unit_Only => False);
+
+      --  If none of those cases holds, but Dynamic_Elaboration_Checks mode is
+      --  set, then we will do the check, but only in the inter-unit case (this
+      --  is to accommodate unguarded elaboration calls from other units in
+      --  which this same mode is set). We inhibit warnings in this case, since
+      --  this instantiation is not occurring in elaboration code.
+
+      elsif Dynamic_Elaboration_Checks then
+         Set_C_Scope;
+         Check_A_Call
+           (N,
+            Ent,
+            Standard_Standard,
+            Inter_Unit_Only => True,
+            Generate_Warnings => False);
+
+      else
+         return;
+      end if;
+   end Check_Elab_Instantiation;
+
+   -------------------------
+   -- Check_Internal_Call --
+   -------------------------
+
+   procedure Check_Internal_Call
+     (N           : Node_Id;
+      E           : Entity_Id;
+      Outer_Scope : Entity_Id;
+      Orig_Ent    : Entity_Id)
+   is
+      function Within_Initial_Condition (Call : Node_Id) return Boolean;
+      --  Determine whether call Call occurs within pragma Initial_Condition or
+      --  pragma Check with check_kind set to Initial_Condition.
+
+      ------------------------------
+      -- Within_Initial_Condition --
+      ------------------------------
+
+      function Within_Initial_Condition (Call : Node_Id) return Boolean is
+         Args : List_Id;
+         Nam  : Name_Id;
+         Par  : Node_Id;
+
+      begin
+         --  Traverse the parent chain looking for an enclosing pragma
+
+         Par := Call;
+         while Present (Par) loop
+            if Nkind (Par) = N_Pragma then
+               Nam := Pragma_Name (Par);
+
+               --  Pragma Initial_Condition appears in its alternative from as
+               --  Check (Initial_Condition, ...).
+
+               if Nam = Name_Check then
+                  Args := Pragma_Argument_Associations (Par);
+
+                  --  Pragma Check should have at least two arguments
+
+                  pragma Assert (Present (Args));
+
+                  return
+                    Chars (Expression (First (Args))) = Name_Initial_Condition;
+
+               --  Direct match
+
+               elsif Nam = Name_Initial_Condition then
+                  return True;
+
+               --  Since pragmas are never nested within other pragmas, stop
+               --  the traversal.
+
+               else
+                  return False;
+               end if;
+
+            --  Prevent the search from going too far
+
+            elsif Is_Body_Or_Package_Declaration (Par) then
+               exit;
+            end if;
+
+            Par := Parent (Par);
+
+            --  If assertions are not enabled, the check pragma is rewritten
+            --  as an if_statement in sem_prag, to generate various warnings
+            --  on boolean expressions. Retrieve the original pragma.
+
+            if Nkind (Original_Node (Par)) = N_Pragma then
+               Par := Original_Node (Par);
+            end if;
+         end loop;
+
+         return False;
+      end Within_Initial_Condition;
+
+      --  Local variables
+
+      Inst_Case : constant Boolean := Nkind (N) in N_Generic_Instantiation;
+
+   --  Start of processing for Check_Internal_Call
+
+   begin
+      --  For P'Access, we want to warn if the -gnatw.f switch is set, and the
+      --  node comes from source.
+
+      if Nkind (N) = N_Attribute_Reference
+        and then ((not Warn_On_Elab_Access and then not Debug_Flag_Dot_O)
+                    or else not Comes_From_Source (N))
+      then
+         return;
+
+      --  If not function or procedure call, instantiation, or 'Access, then
+      --  ignore call (this happens in some error cases and rewriting cases).
+
+      elsif not Nkind_In (N, N_Attribute_Reference,
+                             N_Function_Call,
+                             N_Procedure_Call_Statement)
+        and then not Inst_Case
+      then
+         return;
+
+      --  Nothing to do if this is a call or instantiation that has already
+      --  been found to be a sure ABE.
+
+      elsif Nkind (N) /= N_Attribute_Reference
+        and then Is_Known_Guaranteed_ABE (N)
+      then
+         return;
+
+      --  Nothing to do if errors already detected (avoid cascaded errors)
+
+      elsif Serious_Errors_Detected /= 0 then
+         return;
+
+      --  Nothing to do if not in full analysis mode
+
+      elsif not Full_Analysis then
+         return;
+
+      --  Nothing to do if analyzing in special spec-expression mode, since the
+      --  call is not actually being made at this time.
+
+      elsif In_Spec_Expression then
+         return;
+
+      --  Nothing to do for call to intrinsic subprogram
+
+      elsif Is_Intrinsic_Subprogram (E) then
+         return;
+
+      --  Nothing to do if call is within a generic unit
+
+      elsif Inside_A_Generic then
+         return;
+
+      --  Nothing to do when the call appears within pragma Initial_Condition.
+      --  The pragma is part of the elaboration statements of a package body
+      --  and may only call external subprograms or subprograms whose body is
+      --  already available.
+
+      elsif Within_Initial_Condition (N) then
+         return;
+      end if;
+
+      --  Delay this call if we are still delaying calls
+
+      if Delaying_Elab_Checks then
+         Delay_Check.Append
+           ((N                  => N,
+             E                  => E,
+             Orig_Ent           => Orig_Ent,
+             Curscop            => Current_Scope,
+             Outer_Scope        => Outer_Scope,
+             From_Elab_Code     => From_Elab_Code,
+             In_Task_Activation => In_Task_Activation,
+             From_SPARK_Code    => SPARK_Mode = On));
+         return;
+
+      --  Otherwise, call phase 2 continuation right now
+
+      else
+         Check_Internal_Call_Continue (N, E, Outer_Scope, Orig_Ent);
+      end if;
+   end Check_Internal_Call;
+
+   ----------------------------------
+   -- Check_Internal_Call_Continue --
+   ----------------------------------
+
+   procedure Check_Internal_Call_Continue
+     (N           : Node_Id;
+      E           : Entity_Id;
+      Outer_Scope : Entity_Id;
+      Orig_Ent    : Entity_Id)
+   is
+      function Find_Elab_Reference (N : Node_Id) return Traverse_Result;
+      --  Function applied to each node as we traverse the body. Checks for
+      --  call or entity reference that needs checking, and if so checks it.
+      --  Always returns OK, so entire tree is traversed, except that as
+      --  described below subprogram bodies are skipped for now.
+
+      procedure Traverse is new Atree.Traverse_Proc (Find_Elab_Reference);
+      --  Traverse procedure using above Find_Elab_Reference function
+
+      -------------------------
+      -- Find_Elab_Reference --
+      -------------------------
+
+      function Find_Elab_Reference (N : Node_Id) return Traverse_Result is
+         Actual : Node_Id;
+
+      begin
+         --  If user has specified that there are no entry calls in elaboration
+         --  code, do not trace past an accept statement, because the rendez-
+         --  vous will happen after elaboration.
+
+         if Nkind_In (Original_Node (N), N_Accept_Statement,
+                                         N_Selective_Accept)
+           and then Restriction_Active (No_Entry_Calls_In_Elaboration_Code)
+         then
+            return Abandon;
+
+         --  If we have a function call, check it
+
+         elsif Nkind (N) = N_Function_Call then
+            Check_Elab_Call (N, Outer_Scope);
+            return OK;
+
+         --  If we have a procedure call, check the call, and also check
+         --  arguments that are assignments (OUT or IN OUT mode formals).
+
+         elsif Nkind (N) = N_Procedure_Call_Statement then
+            Check_Elab_Call (N, Outer_Scope, In_Init_Proc => Is_Init_Proc (E));
+
+            Actual := First_Actual (N);
+            while Present (Actual) loop
+               if Known_To_Be_Assigned (Actual) then
+                  Check_Elab_Assign (Actual);
+               end if;
+
+               Next_Actual (Actual);
+            end loop;
+
+            return OK;
+
+         --  If we have an access attribute for a subprogram, check it.
+         --  Suppress this behavior under debug flag.
+
+         elsif not Debug_Flag_Dot_UU
+           and then Nkind (N) = N_Attribute_Reference
+           and then Nam_In (Attribute_Name (N), Name_Access,
+                                                Name_Unrestricted_Access)
+           and then Is_Entity_Name (Prefix (N))
+           and then Is_Subprogram (Entity (Prefix (N)))
+         then
+            Check_Elab_Call (N, Outer_Scope);
+            return OK;
+
+         --  In SPARK mode, if we have an entity reference to a variable, then
+         --  check it. For now we consider any reference.
+
+         elsif SPARK_Mode = On
+           and then Nkind (N) in N_Has_Entity
+           and then Present (Entity (N))
+           and then Ekind (Entity (N)) = E_Variable
+         then
+            Check_Elab_Call (N, Outer_Scope);
+            return OK;
+
+         --  If we have a generic instantiation, check it
+
+         elsif Nkind (N) in N_Generic_Instantiation then
+            Check_Elab_Instantiation (N, Outer_Scope);
+            return OK;
+
+         --  Skip subprogram bodies that come from source (wait for call to
+         --  analyze these). The reason for the come from source test is to
+         --  avoid catching task bodies.
+
+         --  For task bodies, we should really avoid these too, waiting for the
+         --  task activation, but that's too much trouble to catch for now, so
+         --  we go in unconditionally. This is not so terrible, it means the
+         --  error backtrace is not quite complete, and we are too eager to
+         --  scan bodies of tasks that are unused, but this is hardly very
+         --  significant.
+
+         elsif Nkind (N) = N_Subprogram_Body
+           and then Comes_From_Source (N)
+         then
+            return Skip;
+
+         elsif Nkind (N) = N_Assignment_Statement
+           and then Comes_From_Source (N)
+         then
+            Check_Elab_Assign (Name (N));
+            return OK;
+
+         else
+            return OK;
+         end if;
+      end Find_Elab_Reference;
+
+      Inst_Case : constant Boolean    := Is_Generic_Unit (E);
+      Loc       : constant Source_Ptr := Sloc (N);
+
+      Ebody : Entity_Id;
+      Sbody : Node_Id;
+
+   --  Start of processing for Check_Internal_Call_Continue
+
+   begin
+      --  Save outer level call if at outer level
+
+      if Elab_Call.Last = 0 then
+         Outer_Level_Sloc := Loc;
+      end if;
+
+      --  If the call is to a function that renames a literal, no check needed
+
+      if Ekind (E) = E_Enumeration_Literal then
+         return;
+      end if;
+
+      --  Register the subprogram as examined within this particular context.
+      --  This ensures that calls to the same subprogram but in different
+      --  contexts receive warnings and checks of their own since the calls
+      --  may be reached through different flow paths.
+
+      Elab_Visited.Append ((Subp_Id => E, Context => Parent (N)));
+
+      Sbody := Unit_Declaration_Node (E);
+
+      if not Nkind_In (Sbody, N_Subprogram_Body, N_Package_Body) then
+         Ebody := Corresponding_Body (Sbody);
+
+         if No (Ebody) then
+            return;
+         else
+            Sbody := Unit_Declaration_Node (Ebody);
+         end if;
+      end if;
+
+      --  If the body appears after the outer level call or instantiation then
+      --  we have an error case handled below.
+
+      if Earlier_In_Extended_Unit (Outer_Level_Sloc, Sloc (Sbody))
+        and then not In_Task_Activation
+      then
+         null;
+
+      --  If we have the instantiation case we are done, since we now know that
+      --  the body of the generic appeared earlier.
+
+      elsif Inst_Case then
+         return;
+
+      --  Otherwise we have a call, so we trace through the called body to see
+      --  if it has any problems.
+
+      else
+         pragma Assert (Nkind (Sbody) = N_Subprogram_Body);
+
+         Elab_Call.Append ((Cloc => Loc, Ent => E));
+
+         if Debug_Flag_Underscore_LL then
+            Write_Str ("Elab_Call.Last = ");
+            Write_Int (Int (Elab_Call.Last));
+            Write_Str ("   Ent = ");
+            Write_Name (Chars (E));
+            Write_Str ("   at ");
+            Write_Location (Sloc (N));
+            Write_Eol;
+         end if;
+
+         --  Now traverse declarations and statements of subprogram body. Note
+         --  that we cannot simply Traverse (Sbody), since traverse does not
+         --  normally visit subprogram bodies.
+
+         declare
+            Decl : Node_Id;
+         begin
+            Decl := First (Declarations (Sbody));
+            while Present (Decl) loop
+               Traverse (Decl);
+               Next (Decl);
+            end loop;
+         end;
+
+         Traverse (Handled_Statement_Sequence (Sbody));
+
+         Elab_Call.Decrement_Last;
+         return;
+      end if;
+
+      --  Here is the case of calling a subprogram where the body has not yet
+      --  been encountered. A warning message is needed, except if this is the
+      --  case of appearing within an aspect specification that results in
+      --  a check call, we do not really have such a situation, so no warning
+      --  is needed (e.g. the case of a precondition, where the call appears
+      --  textually before the body, but in actual fact is moved to the
+      --  appropriate subprogram body and so does not need a check).
+
+      declare
+         P : Node_Id;
+         O : Node_Id;
+
+      begin
+         P := Parent (N);
+         loop
+            --  Keep looking at parents if we are still in the subexpression
+
+            if Nkind (P) in N_Subexpr then
+               P := Parent (P);
+
+            --  Here P is the parent of the expression, check for special case
+
+            else
+               O := Original_Node (P);
+
+               --  Definitely not the special case if orig node is not a pragma
+
+               exit when Nkind (O) /= N_Pragma;
+
+               --  Check we have an If statement or a null statement (happens
+               --  when the If has been expanded to be True).
+
+               exit when not Nkind_In (P, N_If_Statement, N_Null_Statement);
+
+               --  Our special case will be indicated either by the pragma
+               --  coming from an aspect ...
+
+               if Present (Corresponding_Aspect (O)) then
+                  return;
+
+               --  Or, in the case of an initial condition, specifically by a
+               --  Check pragma specifying an Initial_Condition check.
+
+               elsif Pragma_Name (O) = Name_Check
+                 and then
+                   Chars
+                     (Expression (First (Pragma_Argument_Associations (O)))) =
+                                                       Name_Initial_Condition
+               then
+                  return;
+
+               --  For anything else, we have an error
+
+               else
+                  exit;
+               end if;
+            end if;
+         end loop;
+      end;
+
+      --  Not that special case, warning and dynamic check is required
+
+      --  If we have nothing in the call stack, then this is at the outer
+      --  level, and the ABE is bound to occur, unless it's a 'Access, or
+      --  it's a renaming.
+
+      if Elab_Call.Last = 0 then
+         Error_Msg_Warn := SPARK_Mode /= On;
+
+         declare
+            Insert_Check : Boolean := True;
+            --  This flag is set to True if an elaboration check should be
+            --  inserted.
+
+         begin
+            if In_Task_Activation then
+               Insert_Check := False;
+
+            elsif Inst_Case then
+               Error_Msg_NE
+                 ("cannot instantiate& before body seen<<", N, Orig_Ent);
+
+            elsif Nkind (N) = N_Attribute_Reference then
+               Error_Msg_NE
+                 ("Access attribute of & before body seen<<", N, Orig_Ent);
+               Error_Msg_N ("\possible Program_Error on later references<", N);
+               Insert_Check := False;
+
+            elsif Nkind (Unit_Declaration_Node (Orig_Ent)) /=
+                    N_Subprogram_Renaming_Declaration
+            then
+               Error_Msg_NE
+                 ("cannot call& before body seen<<", N, Orig_Ent);
+
+            elsif not Is_Generic_Actual_Subprogram (Orig_Ent) then
+               Insert_Check := False;
+            end if;
+
+            if Insert_Check then
+               Error_Msg_N ("\Program_Error [<<", N);
+               Insert_Elab_Check (N);
+            end if;
+         end;
+
+      --  Call is not at outer level
+
+      else
+         --  Do not generate elaboration checks in GNATprove mode because the
+         --  elaboration counter and the check are both forms of expansion.
+
+         if GNATprove_Mode then
+            null;
+
+         --  Generate an elaboration check
+
+         elsif not Elaboration_Checks_Suppressed (E) then
+            Set_Elaboration_Entity_Required (E);
+
+            --  Create a declaration of the elaboration entity, and insert it
+            --  prior to the subprogram or the generic unit, within the same
+            --  scope. Since the subprogram may be overloaded, create a unique
+            --  entity.
+
+            if No (Elaboration_Entity (E)) then
+               declare
+                  Loce : constant Source_Ptr := Sloc (E);
+                  Ent  : constant Entity_Id  :=
+                           Make_Defining_Identifier (Loc,
+                             New_External_Name (Chars (E), 'E', -1));
+
+               begin
+                  Set_Elaboration_Entity (E, Ent);
+                  Push_Scope (Scope (E));
+
+                  Insert_Action (Declaration_Node (E),
+                    Make_Object_Declaration (Loce,
+                      Defining_Identifier => Ent,
+                      Object_Definition   =>
+                        New_Occurrence_Of (Standard_Short_Integer, Loce),
+                      Expression          =>
+                        Make_Integer_Literal (Loc, Uint_0)));
+
+                  --  Set elaboration flag at the point of the body
+
+                  Set_Elaboration_Flag (Sbody, E);
+
+                  --  Kill current value indication. This is necessary because
+                  --  the tests of this flag are inserted out of sequence and
+                  --  must not pick up bogus indications of the wrong constant
+                  --  value. Also, this is never a true constant, since one way
+                  --  or another, it gets reset.
+
+                  Set_Current_Value    (Ent, Empty);
+                  Set_Last_Assignment  (Ent, Empty);
+                  Set_Is_True_Constant (Ent, False);
+                  Pop_Scope;
+               end;
+            end if;
+
+            --  Generate:
+            --    if Enn = 0 then
+            --       raise Program_Error with "access before elaboration";
+            --    end if;
+
+            Insert_Elab_Check (N,
+              Make_Attribute_Reference (Loc,
+                Attribute_Name => Name_Elaborated,
+                Prefix         => New_Occurrence_Of (E, Loc)));
+         end if;
+
+         --  Generate the warning
+
+         if not Suppress_Elaboration_Warnings (E)
+           and then not Elaboration_Checks_Suppressed (E)
+
+           --  Suppress this warning if we have a function call that occurred
+           --  within an assertion expression, since we can get false warnings
+           --  in this case, due to the out of order handling in this case.
+
+           and then
+             (Nkind (Original_Node (N)) /= N_Function_Call
+               or else not In_Assertion_Expression_Pragma (Original_Node (N)))
+         then
+            Error_Msg_Warn := SPARK_Mode /= On;
+
+            if Inst_Case then
+               Error_Msg_NE
+                 ("instantiation of& may occur before body is seen<l<",
+                  N, Orig_Ent);
+            else
+               --  A rather specific check. For Finalize/Adjust/Initialize, if
+               --  the type has Warnings_Off set, suppress the warning.
+
+               if Nam_In (Chars (E), Name_Adjust,
+                                     Name_Finalize,
+                                     Name_Initialize)
+                 and then Present (First_Formal (E))
+               then
+                  declare
+                     T : constant Entity_Id := Etype (First_Formal (E));
+                  begin
+                     if Is_Controlled (T) then
+                        if Warnings_Off (T)
+                          or else (Ekind (T) = E_Private_Type
+                                    and then Warnings_Off (Full_View (T)))
+                        then
+                           goto Output;
+                        end if;
+                     end if;
+                  end;
+               end if;
+
+               --  Go ahead and give warning if not this special case
+
+               Error_Msg_NE
+                 ("call to& may occur before body is seen<l<", N, Orig_Ent);
+            end if;
+
+            Error_Msg_N ("\Program_Error ]<l<", N);
+
+            --  There is no need to query the elaboration warning message flags
+            --  because the main message is an error, not a warning, therefore
+            --  all the clarification messages produces by Output_Calls must be
+            --  emitted unconditionally.
+
+            <<Output>>
+
+            Output_Calls (N, Check_Elab_Flag => False);
+         end if;
+      end if;
+   end Check_Internal_Call_Continue;
+
+   ---------------------------
+   -- Check_Task_Activation --
+   ---------------------------
+
+   procedure Check_Task_Activation (N : Node_Id) is
+      Loc         : constant Source_Ptr := Sloc (N);
+      Inter_Procs : constant Elist_Id   := New_Elmt_List;
+      Intra_Procs : constant Elist_Id   := New_Elmt_List;
+      Ent         : Entity_Id;
+      P           : Entity_Id;
+      Task_Scope  : Entity_Id;
+      Cunit_SC    : Boolean := False;
+      Decl        : Node_Id;
+      Elmt        : Elmt_Id;
+      Enclosing   : Entity_Id;
+
+      procedure Add_Task_Proc (Typ : Entity_Id);
+      --  Add to Task_Procs the task body procedure(s) of task types in Typ.
+      --  For record types, this procedure recurses over component types.
+
+      procedure Collect_Tasks (Decls : List_Id);
+      --  Collect the types of the tasks that are to be activated in the given
+      --  list of declarations, in order to perform elaboration checks on the
+      --  corresponding task procedures that are called implicitly here.
+
+      function Outer_Unit (E : Entity_Id) return Entity_Id;
+      --  find enclosing compilation unit of Entity, ignoring subunits, or
+      --  else enclosing subprogram. If E is not a package, there is no need
+      --  for inter-unit elaboration checks.
+
+      -------------------
+      -- Add_Task_Proc --
+      -------------------
+
+      procedure Add_Task_Proc (Typ : Entity_Id) is
+         Comp : Entity_Id;
+         Proc : Entity_Id := Empty;
+
+      begin
+         if Is_Task_Type (Typ) then
+            Proc := Get_Task_Body_Procedure (Typ);
+
+         elsif Is_Array_Type (Typ)
+           and then Has_Task (Base_Type (Typ))
+         then
+            Add_Task_Proc (Component_Type (Typ));
+
+         elsif Is_Record_Type (Typ)
+           and then Has_Task (Base_Type (Typ))
+         then
+            Comp := First_Component (Typ);
+            while Present (Comp) loop
+               Add_Task_Proc (Etype (Comp));
+               Comp := Next_Component (Comp);
+            end loop;
+         end if;
+
+         --  If the task type is another unit, we will perform the usual
+         --  elaboration check on its enclosing unit. If the type is in the
+         --  same unit, we can trace the task body as for an internal call,
+         --  but we only need to examine other external calls, because at
+         --  the point the task is activated, internal subprogram bodies
+         --  will have been elaborated already. We keep separate lists for
+         --  each kind of task.
+
+         --  Skip this test if errors have occurred, since in this case
+         --  we can get false indications.
+
+         if Serious_Errors_Detected /= 0 then
+            return;
+         end if;
+
+         if Present (Proc) then
+            if Outer_Unit (Scope (Proc)) = Enclosing then
+
+               if No (Corresponding_Body (Unit_Declaration_Node (Proc)))
+                 and then
+                   (not Is_Generic_Instance (Scope (Proc))
+                     or else Scope (Proc) = Scope (Defining_Identifier (Decl)))
+               then
+                  Error_Msg_Warn := SPARK_Mode /= On;
+                  Error_Msg_N
+                    ("task will be activated before elaboration of its body<<",
+                      Decl);
+                  Error_Msg_N ("\Program_Error [<<", Decl);
+
+               elsif Present
+                       (Corresponding_Body (Unit_Declaration_Node (Proc)))
+               then
+                  Append_Elmt (Proc, Intra_Procs);
+               end if;
+
+            else
+               --  No need for multiple entries of the same type
+
+               Elmt := First_Elmt (Inter_Procs);
+               while Present (Elmt) loop
+                  if Node (Elmt) = Proc then
+                     return;
+                  end if;
+
+                  Next_Elmt (Elmt);
+               end loop;
+
+               Append_Elmt (Proc, Inter_Procs);
+            end if;
+         end if;
+      end Add_Task_Proc;
+
+      -------------------
+      -- Collect_Tasks --
+      -------------------
+
+      procedure Collect_Tasks (Decls : List_Id) is
+      begin
+         if Present (Decls) then
+            Decl := First (Decls);
+            while Present (Decl) loop
+               if Nkind (Decl) = N_Object_Declaration
+                 and then Has_Task (Etype (Defining_Identifier (Decl)))
+               then
+                  Add_Task_Proc (Etype (Defining_Identifier (Decl)));
+               end if;
+
+               Next (Decl);
+            end loop;
+         end if;
+      end Collect_Tasks;
+
+      ----------------
+      -- Outer_Unit --
+      ----------------
+
+      function Outer_Unit (E : Entity_Id) return Entity_Id is
+         Outer : Entity_Id;
+
+      begin
+         Outer := E;
+         while Present (Outer) loop
+            if Elaboration_Checks_Suppressed (Outer) then
+               Cunit_SC := True;
+            end if;
+
+            exit when Is_Child_Unit (Outer)
+              or else Scope (Outer) = Standard_Standard
+              or else Ekind (Outer) /= E_Package;
+            Outer := Scope (Outer);
+         end loop;
+
+         return Outer;
+      end Outer_Unit;
+
+   --  Start of processing for Check_Task_Activation
+
+   begin
+      pragma Assert (Legacy_Elaboration_Checks);
+
+      Enclosing := Outer_Unit (Current_Scope);
+
+      --  Find all tasks declared in the current unit
+
+      if Nkind (N) = N_Package_Body then
+         P := Unit_Declaration_Node (Corresponding_Spec (N));
+
+         Collect_Tasks (Declarations (N));
+         Collect_Tasks (Visible_Declarations (Specification (P)));
+         Collect_Tasks (Private_Declarations (Specification (P)));
+
+      elsif Nkind (N) = N_Package_Declaration then
+         Collect_Tasks (Visible_Declarations (Specification (N)));
+         Collect_Tasks (Private_Declarations (Specification (N)));
+
+      else
+         Collect_Tasks (Declarations (N));
+      end if;
+
+      --  We only perform detailed checks in all tasks that are library level
+      --  entities. If the master is a subprogram or task, activation will
+      --  depend on the activation of the master itself.
+
+      --  Should dynamic checks be added in the more general case???
+
+      if Ekind (Enclosing) /= E_Package then
+         return;
+      end if;
+
+      --  For task types defined in other units, we want the unit containing
+      --  the task body to be elaborated before the current one.
+
+      Elmt := First_Elmt (Inter_Procs);
+      while Present (Elmt) loop
+         Ent := Node (Elmt);
+         Task_Scope := Outer_Unit (Scope (Ent));
+
+         if not Is_Compilation_Unit (Task_Scope) then
+            null;
+
+         elsif Suppress_Elaboration_Warnings (Task_Scope)
+           or else Elaboration_Checks_Suppressed (Task_Scope)
+         then
+            null;
+
+         elsif Dynamic_Elaboration_Checks then
+            if not Elaboration_Checks_Suppressed (Ent)
+              and then not Cunit_SC
+              and then not Restriction_Active
+                             (No_Entry_Calls_In_Elaboration_Code)
+            then
+               --  Runtime elaboration check required. Generate check of the
+               --  elaboration counter for the unit containing the entity.
+
+               Insert_Elab_Check (N,
+                 Make_Attribute_Reference (Loc,
+                   Prefix         =>
+                     New_Occurrence_Of (Spec_Entity (Task_Scope), Loc),
+                   Attribute_Name => Name_Elaborated));
+            end if;
+
+         else
+            --  Force the binder to elaborate other unit first
+
+            if Elab_Info_Messages
+              and then not Suppress_Elaboration_Warnings (Ent)
+              and then not Elaboration_Checks_Suppressed (Ent)
+              and then not Suppress_Elaboration_Warnings (Task_Scope)
+              and then not Elaboration_Checks_Suppressed (Task_Scope)
+            then
+               Error_Msg_Node_2 := Task_Scope;
+               Error_Msg_NE
+                 ("info: activation of an instance of task type & requires "
+                  & "pragma Elaborate_All on &?$?", N, Ent);
+            end if;
+
+            Activate_Elaborate_All_Desirable (N, Task_Scope);
+            Set_Suppress_Elaboration_Warnings (Task_Scope);
+         end if;
+
+         Next_Elmt (Elmt);
+      end loop;
+
+      --  For tasks declared in the current unit, trace other calls within the
+      --  task procedure bodies, which are available.
+
+      if not Debug_Flag_Dot_Y then
+         In_Task_Activation := True;
+
+         Elmt := First_Elmt (Intra_Procs);
+         while Present (Elmt) loop
+            Ent := Node (Elmt);
+            Check_Internal_Call_Continue (N, Ent, Enclosing, Ent);
+            Next_Elmt (Elmt);
+         end loop;
+
+         In_Task_Activation := False;
+      end if;
+   end Check_Task_Activation;
+
+   ------------------------
+   -- Get_Referenced_Ent --
+   ------------------------
+
+   function Get_Referenced_Ent (N : Node_Id) return Entity_Id is
+      Nam : Node_Id;
+
+   begin
+      if Nkind (N) in N_Has_Entity
+        and then Present (Entity (N))
+        and then Ekind (Entity (N)) = E_Variable
+      then
+         return Entity (N);
+      end if;
+
+      if Nkind (N) = N_Attribute_Reference then
+         Nam := Prefix (N);
+      else
+         Nam := Name (N);
+      end if;
+
+      if No (Nam) then
+         return Empty;
+      elsif Nkind (Nam) = N_Selected_Component then
+         return Entity (Selector_Name (Nam));
+      elsif not Is_Entity_Name (Nam) then
+         return Empty;
+      else
+         return Entity (Nam);
+      end if;
+   end Get_Referenced_Ent;
+
+   ----------------------
+   -- Has_Generic_Body --
+   ----------------------
+
+   function Has_Generic_Body (N : Node_Id) return Boolean is
+      Ent  : constant Entity_Id := Get_Generic_Entity (N);
+      Decl : constant Node_Id   := Unit_Declaration_Node (Ent);
+      Scop : Entity_Id;
+
+      function Find_Body_In (E : Entity_Id; N : Node_Id) return Node_Id;
+      --  Determine if the list of nodes headed by N and linked by Next
+      --  contains a package body for the package spec entity E, and if so
+      --  return the package body. If not, then returns Empty.
+
+      function Load_Package_Body (Nam : Unit_Name_Type) return Node_Id;
+      --  This procedure is called load the unit whose name is given by Nam.
+      --  This unit is being loaded to see whether it contains an optional
+      --  generic body. The returned value is the loaded unit, which is always
+      --  a package body (only package bodies can contain other entities in the
+      --  sense in which Has_Generic_Body is interested). We only attempt to
+      --  load bodies if we are generating code. If we are in semantics check
+      --  only mode, then it would be wrong to load bodies that are not
+      --  required from a semantic point of view, so in this case we return
+      --  Empty. The result is that the caller may incorrectly decide that a
+      --  generic spec does not have a body when in fact it does, but the only
+      --  harm in this is that some warnings on elaboration problems may be
+      --  lost in semantic checks only mode, which is not big loss. We also
+      --  return Empty if we go for a body and it is not there.
+
+      function Locate_Corresponding_Body (PE : Entity_Id) return Node_Id;
+      --  PE is the entity for a package spec. This function locates the
+      --  corresponding package body, returning Empty if none is found. The
+      --  package body returned is fully parsed but may not yet be analyzed,
+      --  so only syntactic fields should be referenced.
+
+      ------------------
+      -- Find_Body_In --
+      ------------------
+
+      function Find_Body_In (E : Entity_Id; N : Node_Id) return Node_Id is
+         Nod : Node_Id;
+
+      begin
+         Nod := N;
+         while Present (Nod) loop
+
+            --  If we found the package body we are looking for, return it
+
+            if Nkind (Nod) = N_Package_Body
+              and then Chars (Defining_Unit_Name (Nod)) = Chars (E)
+            then
+               return Nod;
+
+            --  If we found the stub for the body, go after the subunit,
+            --  loading it if necessary.
+
+            elsif Nkind (Nod) = N_Package_Body_Stub
+              and then Chars (Defining_Identifier (Nod)) = Chars (E)
+            then
+               if Present (Library_Unit (Nod)) then
+                  return Unit (Library_Unit (Nod));
+
+               else
+                  return Load_Package_Body (Get_Unit_Name (Nod));
+               end if;
+
+            --  If neither package body nor stub, keep looking on chain
+
+            else
+               Next (Nod);
+            end if;
+         end loop;
+
+         return Empty;
+      end Find_Body_In;
+
+      -----------------------
+      -- Load_Package_Body --
+      -----------------------
+
+      function Load_Package_Body (Nam : Unit_Name_Type) return Node_Id is
+         U : Unit_Number_Type;
+
+      begin
+         if Operating_Mode /= Generate_Code then
+            return Empty;
+         else
+            U :=
+              Load_Unit
+                (Load_Name  => Nam,
+                 Required   => False,
+                 Subunit    => False,
+                 Error_Node => N);
+
+            if U = No_Unit then
+               return Empty;
+            else
+               return Unit (Cunit (U));
+            end if;
+         end if;
+      end Load_Package_Body;
+
+      -------------------------------
+      -- Locate_Corresponding_Body --
+      -------------------------------
+
+      function Locate_Corresponding_Body (PE : Entity_Id) return Node_Id is
+         Spec  : constant Node_Id   := Declaration_Node (PE);
+         Decl  : constant Node_Id   := Parent (Spec);
+         Scop  : constant Entity_Id := Scope (PE);
+         PBody : Node_Id;
+
+      begin
+         if Is_Library_Level_Entity (PE) then
+
+            --  If package is a library unit that requires a body, we have no
+            --  choice but to go after that body because it might contain an
+            --  optional body for the original generic package.
+
+            if Unit_Requires_Body (PE) then
+
+               --  Load the body. Note that we are a little careful here to use
+               --  Spec to get the unit number, rather than PE or Decl, since
+               --  in the case where the package is itself a library level
+               --  instantiation, Spec will properly reference the generic
+               --  template, which is what we really want.
+
+               return
+                 Load_Package_Body
+                   (Get_Body_Name (Unit_Name (Get_Source_Unit (Spec))));
+
+            --  But if the package is a library unit that does NOT require
+            --  a body, then no body is permitted, so we are sure that there
+            --  is no body for the original generic package.
+
+            else
+               return Empty;
+            end if;
+
+         --  Otherwise look and see if we are embedded in a further package
+
+         elsif Is_Package_Or_Generic_Package (Scop) then
+
+            --  If so, get the body of the enclosing package, and look in
+            --  its package body for the package body we are looking for.
+
+            PBody := Locate_Corresponding_Body (Scop);
+
+            if No (PBody) then
+               return Empty;
+            else
+               return Find_Body_In (PE, First (Declarations (PBody)));
+            end if;
+
+         --  If we are not embedded in a further package, then the body
+         --  must be in the same declarative part as we are.
+
+         else
+            return Find_Body_In (PE, Next (Decl));
+         end if;
+      end Locate_Corresponding_Body;
+
+   --  Start of processing for Has_Generic_Body
+
+   begin
+      if Present (Corresponding_Body (Decl)) then
+         return True;
+
+      elsif Unit_Requires_Body (Ent) then
+         return True;
+
+      --  Compilation units cannot have optional bodies
+
+      elsif Is_Compilation_Unit (Ent) then
+         return False;
+
+      --  Otherwise look at what scope we are in
+
+      else
+         Scop := Scope (Ent);
+
+         --  Case of entity is in other than a package spec, in this case
+         --  the body, if present, must be in the same declarative part.
+
+         if not Is_Package_Or_Generic_Package (Scop) then
+            declare
+               P : Node_Id;
+
+            begin
+               --  Declaration node may get us a spec, so if so, go to
+               --  the parent declaration.
+
+               P := Declaration_Node (Ent);
+               while not Is_List_Member (P) loop
+                  P := Parent (P);
+               end loop;
+
+               return Present (Find_Body_In (Ent, Next (P)));
+            end;
+
+         --  If the entity is in a package spec, then we have to locate
+         --  the corresponding package body, and look there.
+
+         else
+            declare
+               PBody : constant Node_Id := Locate_Corresponding_Body (Scop);
+
+            begin
+               if No (PBody) then
+                  return False;
+               else
+                  return
+                    Present
+                      (Find_Body_In (Ent, (First (Declarations (PBody)))));
+               end if;
+            end;
+         end if;
+      end if;
+   end Has_Generic_Body;
+
+   -----------------------
+   -- Insert_Elab_Check --
+   -----------------------
+
+   procedure Insert_Elab_Check (N : Node_Id; C : Node_Id := Empty) is
+      Nod : Node_Id;
+      Loc : constant Source_Ptr := Sloc (N);
+
+      Chk : Node_Id;
+      --  The check (N_Raise_Program_Error) node to be inserted
+
+   begin
+      --  If expansion is disabled, do not generate any checks. Also
+      --  skip checks if any subunits are missing because in either
+      --  case we lack the full information that we need, and no object
+      --  file will be created in any case.
+
+      if not Expander_Active or else Subunits_Missing then
+         return;
+      end if;
+
+      --  If we have a generic instantiation, where Instance_Spec is set,
+      --  then this field points to a generic instance spec that has
+      --  been inserted before the instantiation node itself, so that
+      --  is where we want to insert a check.
+
+      if Nkind (N) in N_Generic_Instantiation
+        and then Present (Instance_Spec (N))
+      then
+         Nod := Instance_Spec (N);
+      else
+         Nod := N;
+      end if;
+
+      --  Build check node, possibly with condition
+
+      Chk :=
+        Make_Raise_Program_Error (Loc, Reason => PE_Access_Before_Elaboration);
+
+      if Present (C) then
+         Set_Condition (Chk, Make_Op_Not (Loc, Right_Opnd => C));
+      end if;
+
+      --  If we are inserting at the top level, insert in Aux_Decls
+
+      if Nkind (Parent (Nod)) = N_Compilation_Unit then
+         declare
+            ADN : constant Node_Id := Aux_Decls_Node (Parent (Nod));
+
+         begin
+            if No (Declarations (ADN)) then
+               Set_Declarations (ADN, New_List (Chk));
+            else
+               Append_To (Declarations (ADN), Chk);
+            end if;
+
+            Analyze (Chk);
+         end;
+
+      --  Otherwise just insert as an action on the node in question
+
+      else
+         Insert_Action (Nod, Chk);
+      end if;
+   end Insert_Elab_Check;
+
+   -------------------------------
+   -- Is_Call_Of_Generic_Formal --
+   -------------------------------
+
+   function Is_Call_Of_Generic_Formal (N : Node_Id) return Boolean is
+   begin
+      return Nkind_In (N, N_Function_Call, N_Procedure_Call_Statement)
+
+        --  Always return False if debug flag -gnatd.G is set
+
+        and then not Debug_Flag_Dot_GG
+
+      --  For now, we detect this by looking for the strange identifier
+      --  node, whose Chars reflect the name of the generic formal, but
+      --  the Chars of the Entity references the generic actual.
+
+        and then Nkind (Name (N)) = N_Identifier
+        and then Chars (Name (N)) /= Chars (Entity (Name (N)));
+   end Is_Call_Of_Generic_Formal;
+
+   -------------------------------
+   -- Is_Finalization_Procedure --
+   -------------------------------
+
+   function Is_Finalization_Procedure (Id : Entity_Id) return Boolean is
+   begin
+      --  Check whether Id is a procedure with at least one parameter
+
+      if Ekind (Id) = E_Procedure and then Present (First_Formal (Id)) then
+         declare
+            Typ      : constant Entity_Id := Etype (First_Formal (Id));
+            Deep_Fin : Entity_Id := Empty;
+            Fin      : Entity_Id := Empty;
+
+         begin
+            --  If the type of the first formal does not require finalization
+            --  actions, then this is definitely not [Deep_]Finalize.
+
+            if not Needs_Finalization (Typ) then
+               return False;
+            end if;
+
+            --  At this point we have the following scenario:
+
+            --    procedure Name (Param1 : [in] [out] Ctrl[; Param2 : ...]);
+
+            --  Recover the two possible versions of [Deep_]Finalize using the
+            --  type of the first parameter and compare with the input.
+
+            Deep_Fin := TSS (Typ, TSS_Deep_Finalize);
+
+            if Is_Controlled (Typ) then
+               Fin := Find_Prim_Op (Typ, Name_Finalize);
+            end if;
+
+            return    (Present (Deep_Fin) and then Id = Deep_Fin)
+              or else (Present (Fin)      and then Id = Fin);
+         end;
+      end if;
+
+      return False;
+   end Is_Finalization_Procedure;
+
+   ------------------
+   -- Output_Calls --
+   ------------------
+
+   procedure Output_Calls
+     (N               : Node_Id;
+      Check_Elab_Flag : Boolean)
+   is
+      function Emit (Flag : Boolean) return Boolean;
+      --  Determine whether to emit an error message based on the combination
+      --  of flags Check_Elab_Flag and Flag.
+
+      function Is_Printable_Error_Name return Boolean;
+      --  An internal function, used to determine if a name, stored in the
+      --  Name_Buffer, is either a non-internal name, or is an internal name
+      --  that is printable by the error message circuits (i.e. it has a single
+      --  upper case letter at the end).
+
+      ----------
+      -- Emit --
+      ----------
+
+      function Emit (Flag : Boolean) return Boolean is
+      begin
+         if Check_Elab_Flag then
+            return Flag;
+         else
+            return True;
+         end if;
+      end Emit;
+
+      -----------------------------
+      -- Is_Printable_Error_Name --
+      -----------------------------
+
+      function Is_Printable_Error_Name return Boolean is
+      begin
+         if not Is_Internal_Name then
+            return True;
+
+         elsif Name_Len = 1 then
+            return False;
+
+         else
+            Name_Len := Name_Len - 1;
+            return not Is_Internal_Name;
+         end if;
+      end Is_Printable_Error_Name;
+
+      --  Local variables
+
+      Ent : Entity_Id;
+
+   --  Start of processing for Output_Calls
+
+   begin
+      for J in reverse 1 .. Elab_Call.Last loop
+         Error_Msg_Sloc := Elab_Call.Table (J).Cloc;
+
+         Ent := Elab_Call.Table (J).Ent;
+         Get_Name_String (Chars (Ent));
+
+         --  Dynamic elaboration model, warnings controlled by -gnatwl
+
+         if Dynamic_Elaboration_Checks then
+            if Emit (Elab_Warnings) then
+               if Is_Generic_Unit (Ent) then
+                  Error_Msg_NE ("\\?l?& instantiated #", N, Ent);
+               elsif Is_Init_Proc (Ent) then
+                  Error_Msg_N ("\\?l?initialization procedure called #", N);
+               elsif Is_Printable_Error_Name then
+                  Error_Msg_NE ("\\?l?& called #", N, Ent);
+               else
+                  Error_Msg_N ("\\?l?called #", N);
+               end if;
+            end if;
+
+         --  Static elaboration model, info messages controlled by -gnatel
+
+         else
+            if Emit (Elab_Info_Messages) then
+               if Is_Generic_Unit (Ent) then
+                  Error_Msg_NE ("\\?$?& instantiated #", N, Ent);
+               elsif Is_Init_Proc (Ent) then
+                  Error_Msg_N ("\\?$?initialization procedure called #", N);
+               elsif Is_Printable_Error_Name then
+                  Error_Msg_NE ("\\?$?& called #", N, Ent);
+               else
+                  Error_Msg_N ("\\?$?called #", N);
+               end if;
+            end if;
+         end if;
+      end loop;
+   end Output_Calls;
+
+   ----------------------------
+   -- Same_Elaboration_Scope --
+   ----------------------------
+
+   function Same_Elaboration_Scope (Scop1, Scop2 : Entity_Id) return Boolean is
+      S1 : Entity_Id;
+      S2 : Entity_Id;
+
+   begin
+      --  Find elaboration scope for Scop1
+      --  This is either a subprogram or a compilation unit.
+
+      S1 := Scop1;
+      while S1 /= Standard_Standard
+        and then not Is_Compilation_Unit (S1)
+        and then Ekind_In (S1, E_Package, E_Protected_Type, E_Block)
+      loop
+         S1 := Scope (S1);
+      end loop;
+
+      --  Find elaboration scope for Scop2
+
+      S2 := Scop2;
+      while S2 /= Standard_Standard
+        and then not Is_Compilation_Unit (S2)
+        and then Ekind_In (S2, E_Package, E_Protected_Type, E_Block)
+      loop
+         S2 := Scope (S2);
+      end loop;
+
+      return S1 = S2;
+   end Same_Elaboration_Scope;
+
+   -----------------
+   -- Set_C_Scope --
+   -----------------
+
+   procedure Set_C_Scope is
+   begin
+      while not Is_Compilation_Unit (C_Scope) loop
+         C_Scope := Scope (C_Scope);
+      end loop;
+   end Set_C_Scope;
+
+   --------------------------------
+   -- Set_Elaboration_Constraint --
+   --------------------------------
+
+   procedure Set_Elaboration_Constraint
+    (Call : Node_Id;
+     Subp : Entity_Id;
+     Scop : Entity_Id)
+   is
+      Elab_Unit : Entity_Id;
+
+      --  Check whether this is a call to an Initialize subprogram for a
+      --  controlled type. Note that Call can also be a 'Access attribute
+      --  reference, which now generates an elaboration check.
+
+      Init_Call : constant Boolean :=
+                    Nkind (Call) = N_Procedure_Call_Statement
+                      and then Chars (Subp) = Name_Initialize
+                      and then Comes_From_Source (Subp)
+                      and then Present (Parameter_Associations (Call))
+                      and then Is_Controlled (Etype (First_Actual (Call)));
+
+   begin
+      --  If the unit is mentioned in a with_clause of the current unit, it is
+      --  visible, and we can set the elaboration flag.
+
+      if Is_Immediately_Visible (Scop)
+        or else (Is_Child_Unit (Scop) and then Is_Visible_Lib_Unit (Scop))
+      then
+         Activate_Elaborate_All_Desirable (Call, Scop);
+         Set_Suppress_Elaboration_Warnings (Scop);
+         return;
+      end if;
+
+      --  If this is not an initialization call or a call using object notation
+      --  we know that the unit of the called entity is in the context, and we
+      --  can set the flag as well. The unit need not be visible if the call
+      --  occurs within an instantiation.
+
+      if Is_Init_Proc (Subp)
+        or else Init_Call
+        or else Nkind (Original_Node (Call)) = N_Selected_Component
+      then
+         null;  --  detailed processing follows.
+
+      else
+         Activate_Elaborate_All_Desirable (Call, Scop);
+         Set_Suppress_Elaboration_Warnings (Scop);
+         return;
+      end if;
+
+      --  If the unit is not in the context, there must be an intermediate unit
+      --  that is, on which we need to place to elaboration flag. This happens
+      --  with init proc calls.
+
+      if Is_Init_Proc (Subp) or else Init_Call then
+
+         --  The initialization call is on an object whose type is not declared
+         --  in the same scope as the subprogram. The type of the object must
+         --  be a subtype of the type of operation. This object is the first
+         --  actual in the call.
+
+         declare
+            Typ : constant Entity_Id :=
+                    Etype (First (Parameter_Associations (Call)));
+         begin
+            Elab_Unit := Scope (Typ);
+            while (Present (Elab_Unit))
+              and then not Is_Compilation_Unit (Elab_Unit)
+            loop
+               Elab_Unit := Scope (Elab_Unit);
+            end loop;
+         end;
+
+      --  If original node uses selected component notation, the prefix is
+      --  visible and determines the scope that must be elaborated. After
+      --  rewriting, the prefix is the first actual in the call.
+
+      elsif Nkind (Original_Node (Call)) = N_Selected_Component then
+         Elab_Unit := Scope (Etype (First (Parameter_Associations (Call))));
+
+      --  Not one of special cases above
+
+      else
+         --  Using previously computed scope. If the elaboration check is
+         --  done after analysis, the scope is not visible any longer, but
+         --  must still be in the context.
+
+         Elab_Unit := Scop;
+      end if;
+
+      Activate_Elaborate_All_Desirable (Call, Elab_Unit);
+      Set_Suppress_Elaboration_Warnings (Elab_Unit);
+   end Set_Elaboration_Constraint;
+
+   -----------------
+   -- Spec_Entity --
+   -----------------
+
+   function Spec_Entity (E : Entity_Id) return Entity_Id is
+      Decl : Node_Id;
+
+   begin
+      --  Check for case of body entity
+      --  Why is the check for E_Void needed???
+
+      if Ekind_In (E, E_Void, E_Subprogram_Body, E_Package_Body) then
+         Decl := E;
+
+         loop
+            Decl := Parent (Decl);
+            exit when Nkind (Decl) in N_Proper_Body;
+         end loop;
+
+         return Corresponding_Spec (Decl);
+
+      else
+         return E;
+      end if;
+   end Spec_Entity;
+
+   ------------
+   -- Within --
+   ------------
+
+   function Within (E1, E2 : Entity_Id) return Boolean is
+      Scop : Entity_Id;
+   begin
+      Scop := E1;
+      loop
+         if Scop = E2 then
+            return True;
+         elsif Scop = Standard_Standard then
+            return False;
+         else
+            Scop := Scope (Scop);
+         end if;
+      end loop;
+   end Within;
+
+   --------------------------
+   -- Within_Elaborate_All --
+   --------------------------
+
+   function Within_Elaborate_All
+     (Unit : Unit_Number_Type;
+      E    : Entity_Id) return Boolean
+   is
+      type Unit_Number_Set is array (Main_Unit .. Last_Unit) of Boolean;
+      pragma Pack (Unit_Number_Set);
+
+      Seen : Unit_Number_Set := (others => False);
+      --  Seen (X) is True after we have seen unit X in the walk. This is used
+      --  to prevent processing the same unit more than once.
+
+      Result : Boolean := False;
+
+      procedure Helper (Unit : Unit_Number_Type);
+      --  This helper procedure does all the work for Within_Elaborate_All. It
+      --  walks the dependency graph, and sets Result to True if it finds an
+      --  appropriate Elaborate_All.
+
+      ------------
+      -- Helper --
+      ------------
+
+      procedure Helper (Unit : Unit_Number_Type) is
+         CU : constant Node_Id := Cunit (Unit);
+
+         Item    : Node_Id;
+         Item2   : Node_Id;
+         Elab_Id : Entity_Id;
+         Par     : Node_Id;
+
+      begin
+         if Seen (Unit) then
+            return;
+         else
+            Seen (Unit) := True;
+         end if;
+
+         --  First, check for Elaborate_Alls on this unit
+
+         Item := First (Context_Items (CU));
+         while Present (Item) loop
+            if Nkind (Item) = N_Pragma
+              and then Pragma_Name (Item) = Name_Elaborate_All
+            then
+               --  Return if some previous error on the pragma itself. The
+               --  pragma may be unanalyzed, because of a previous error, or
+               --  if it is the context of a subunit, inherited by its parent.
+
+               if Error_Posted (Item) or else not Analyzed (Item) then
+                  return;
+               end if;
+
+               Elab_Id :=
+                 Entity
+                   (Expression (First (Pragma_Argument_Associations (Item))));
+
+               if E = Elab_Id then
+                  Result := True;
+                  return;
+               end if;
+
+               Par := Parent (Unit_Declaration_Node (Elab_Id));
+
+               Item2 := First (Context_Items (Par));
+               while Present (Item2) loop
+                  if Nkind (Item2) = N_With_Clause
+                    and then Entity (Name (Item2)) = E
+                    and then not Limited_Present (Item2)
+                  then
+                     Result := True;
+                     return;
+                  end if;
+
+                  Next (Item2);
+               end loop;
+            end if;
+
+            Next (Item);
+         end loop;
+
+         --  Second, recurse on with's. We could do this as part of the above
+         --  loop, but it's probably more efficient to have two loops, because
+         --  the relevant Elaborate_All is likely to be on the initial unit. In
+         --  other words, we're walking the with's breadth-first. This part is
+         --  only necessary in the dynamic elaboration model.
+
+         if Dynamic_Elaboration_Checks then
+            Item := First (Context_Items (CU));
+            while Present (Item) loop
+               if Nkind (Item) = N_With_Clause
+                 and then not Limited_Present (Item)
+               then
+                  --  Note: the following call to Get_Cunit_Unit_Number does a
+                  --  linear search, which could be slow, but it's OK because
+                  --  we're about to give a warning anyway. Also, there might
+                  --  be hundreds of units, but not millions. If it turns out
+                  --  to be a problem, we could store the Get_Cunit_Unit_Number
+                  --  in each N_Compilation_Unit node, but that would involve
+                  --  rearranging N_Compilation_Unit_Aux to make room.
+
+                  Helper (Get_Cunit_Unit_Number (Library_Unit (Item)));
+
+                  if Result then
+                     return;
+                  end if;
+               end if;
+
+               Next (Item);
+            end loop;
+         end if;
+      end Helper;
+
+   --  Start of processing for Within_Elaborate_All
+
+   begin
+      Helper (Unit);
+      return Result;
+   end Within_Elaborate_All;
+
 end Sem_Elab;