Mercurial > hg > CbC > CbC_gcc
diff gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,1822 @@ +.. role:: switch(samp) + +.. |with| replace:: *with* +.. |withs| replace:: *with*\ s +.. |withed| replace:: *with*\ ed +.. |withing| replace:: *with*\ ing + +.. -- Example: A |withing| unit has a |with| clause, it |withs| a |withed| unit + + +.. _Elaboration_Order_Handling_in_GNAT: + +********************************** +Elaboration Order Handling in GNAT +********************************** + +.. index:: Order of elaboration +.. index:: Elaboration control + +This appendix describes the handling of elaboration code in Ada and GNAT, and +discusses how the order of elaboration of program units can be controlled in +GNAT, either automatically or with explicit programming features. + +.. _Elaboration_Code: + +Elaboration Code +================ + +Ada defines the term *execution* as the process by which a construct achieves +its run-time effect. This process is also referred to as **elaboration** for +declarations and *evaluation* for expressions. + +The execution model in Ada allows for certain sections of an Ada program to be +executed prior to execution of the program itself, primarily with the intent of +initializing data. These sections are referred to as **elaboration code**. +Elaboration code is executed as follows: + +* All partitions of an Ada program are executed in parallel with one another, + possibly in a separate address space, and possibly on a separate computer. + +* The execution of a partition involves running the environment task for that + partition. + +* The environment task executes all elaboration code (if available) for all + units within that partition. This code is said to be executed at + **elaboration time**. + +* The environment task executes the Ada program (if available) for that + partition. + +In addition to the Ada terminology, this appendix defines the following terms: + +* *Scenario* + + A construct that is elaborated or executed by elaboration code is referred to + as an *elaboration scenario* or simply a **scenario**. GNAT recognizes the + following scenarios: + + - ``'Access`` of entries, operators, and subprograms + + - Activation of tasks + + - Calls to entries, operators, and subprograms + + - Instantiations of generic templates + +* *Target* + + A construct elaborated by a scenario is referred to as *elaboration target* + or simply **target**. GNAT recognizes the following targets: + + - For ``'Access`` of entries, operators, and subprograms, the target is the + entry, operator, or subprogram being aliased. + + - For activation of tasks, the target is the task body + + - For calls to entries, operators, and subprograms, the target is the entry, + operator, or subprogram being invoked. + + - For instantiations of generic templates, the target is the generic template + being instantiated. + +Elaboration code may appear in two distinct contexts: + +* *Library level* + + A scenario appears at the library level when it is encapsulated by a package + [body] compilation unit, ignoring any other package [body] declarations in + between. + + :: + + with Server; + package Client is + procedure Proc; + + package Nested is + Val : ... := Server.Func; + end Nested; + end Client; + + In the example above, the call to ``Server.Func`` is an elaboration scenario + because it appears at the library level of package ``Client``. Note that the + declaration of package ``Nested`` is ignored according to the definition + given above. As a result, the call to ``Server.Func`` will be executed when + the spec of unit ``Client`` is elaborated. + +* *Package body statements* + + A scenario appears within the statement sequence of a package body when it is + bounded by the region starting from the ``begin`` keyword of the package body + and ending at the ``end`` keyword of the package body. + + :: + + package body Client is + procedure Proc is + begin + ... + end Proc; + begin + Proc; + end Client; + + In the example above, the call to ``Proc`` is an elaboration scenario because + it appears within the statement sequence of package body ``Client``. As a + result, the call to ``Proc`` will be executed when the body of ``Client`` is + elaborated. + +.. _Elaboration_Order: + +Elaboration Order +================= + +The sequence by which the elaboration code of all units within a partition is +executed is referred to as **elaboration order**. + +Within a single unit, elaboration code is executed in sequential order. + +:: + + package body Client is + Result : ... := Server.Func; + + procedure Proc is + package Inst is new Server.Gen; + begin + Inst.Eval (Result); + end Proc; + begin + Proc; + end Client; + +In the example above, the elaboration order within package body ``Client`` is +as follows: + +1. The object declaration of ``Result`` is elaborated. + + * Function ``Server.Func`` is invoked. + +2. The subprogram body of ``Proc`` is elaborated. + +3. Procedure ``Proc`` is invoked. + + * Generic unit ``Server.Gen`` is instantiated as ``Inst``. + + * Instance ``Inst`` is elaborated. + + * Procedure ``Inst.Eval`` is invoked. + +The elaboration order of all units within a partition depends on the following +factors: + +* |withed| units + +* purity of units + +* preelaborability of units + +* presence of elaboration control pragmas + +A program may have several elaboration orders depending on its structure. + +:: + + package Server is + function Func (Index : Integer) return Integer; + end Server; + +:: + + package body Server is + Results : array (1 .. 5) of Integer := (1, 2, 3, 4, 5); + + function Func (Index : Integer) return Integer is + begin + return Results (Index); + end Func; + end Server; + +:: + + with Server; + package Client is + Val : constant Integer := Server.Func (3); + end Client; + +:: + + with Client; + procedure Main is begin null; end Main; + +The following elaboration order exhibits a fundamental problem referred to as +*access-before-elaboration* or simply **ABE**. + +:: + + spec of Server + spec of Client + body of Server + body of Main + +The elaboration of ``Server``'s spec materializes function ``Func``, making it +callable. The elaboration of ``Client``'s spec elaborates the declaration of +``Val``. This invokes function ``Server.Func``, however the body of +``Server.Func`` has not been elaborated yet because ``Server``'s body comes +after ``Client``'s spec in the elaboration order. As a result, the value of +constant ``Val`` is now undefined. + +Without any guarantees from the language, an undetected ABE problem may hinder +proper initialization of data, which in turn may lead to undefined behavior at +run time. To prevent such ABE problems, Ada employs dynamic checks in the same +vein as index or null exclusion checks. A failed ABE check raises exception +``Program_Error``. + +The following elaboration order avoids the ABE problem and the program can be +successfully elaborated. + +:: + + spec of Server + body of Server + spec of Client + body of Main + +Ada states that a total elaboration order must exist, but it does not define +what this order is. A compiler is thus tasked with choosing a suitable +elaboration order which satisfies the dependencies imposed by |with| clauses, +unit categorization, and elaboration control pragmas. Ideally an order which +avoids ABE problems should be chosen, however a compiler may not always find +such an order due to complications with respect to control and data flow. + +.. _Checking_the_Elaboration_Order: + +Checking the Elaboration Order +============================== + +To avoid placing the entire elaboration order burden on the programmer, Ada +provides three lines of defense: + +* *Static semantics* + + Static semantic rules restrict the possible choice of elaboration order. For + instance, if unit Client |withs| unit Server, then the spec of Server is + always elaborated prior to Client. The same principle applies to child units + - the spec of a parent unit is always elaborated prior to the child unit. + +* *Dynamic semantics* + + Dynamic checks are performed at run time, to ensure that a target is + elaborated prior to a scenario that executes it, thus avoiding ABE problems. + A failed run-time check raises exception ``Program_Error``. The following + restrictions apply: + + - *Restrictions on calls* + + An entry, operator, or subprogram can be called from elaboration code only + when the corresponding body has been elaborated. + + - *Restrictions on instantiations* + + A generic unit can be instantiated by elaboration code only when the + corresponding body has been elaborated. + + - *Restrictions on task activation* + + A task can be activated by elaboration code only when the body of the + associated task type has been elaborated. + + The restrictions above can be summarized by the following rule: + + *If a target has a body, then this body must be elaborated prior to the + execution of the scenario that invokes, instantiates, or activates the + target.* + +* *Elaboration control* + + Pragmas are provided for the programmer to specify the desired elaboration + order. + +.. _Controlling_the_Elaboration_Order_in_Ada: + +Controlling the Elaboration Order in Ada +======================================== + +Ada provides several idioms and pragmas to aid the programmer with specifying +the desired elaboration order and avoiding ABE problems altogether. + +* *Packages without a body* + + A library package which does not require a completing body does not suffer + from ABE problems. + + :: + + package Pack is + generic + type Element is private; + package Containers is + type Element_Array is array (1 .. 10) of Element; + end Containers; + end Pack; + + In the example above, package ``Pack`` does not require a body because it + does not contain any constructs which require completion in a body. As a + result, generic ``Pack.Containers`` can be instantiated without encountering + any ABE problems. + +.. index:: pragma Pure + +* *pragma Pure* + + Pragma ``Pure`` places sufficient restrictions on a unit to guarantee that no + scenario within the unit can result in an ABE problem. + +.. index:: pragma Preelaborate + +* *pragma Preelaborate* + + Pragma ``Preelaborate`` is slightly less restrictive than pragma ``Pure``, + but still strong enough to prevent ABE problems within a unit. + +.. index:: pragma Elaborate_Body + +* *pragma Elaborate_Body* + + Pragma ``Elaborate_Body`` requires that the body of a unit is elaborated + immediately after its spec. This restriction guarantees that no client + scenario can execute a server target before the target body has been + elaborated because the spec and body are effectively "glued" together. + + :: + + package Server is + pragma Elaborate_Body; + + function Func return Integer; + end Server; + + :: + + package body Server is + function Func return Integer is + begin + ... + end Func; + end Server; + + :: + + with Server; + package Client is + Val : constant Integer := Server.Func; + end Client; + + In the example above, pragma ``Elaborate_Body`` guarantees the following + elaboration order: + + :: + + spec of Server + body of Server + spec of Client + + because the spec of ``Server`` must be elaborated prior to ``Client`` by + virtue of the |with| clause, and in addition the body of ``Server`` must be + elaborated immediately after the spec of ``Server``. + + Removing pragma ``Elaborate_Body`` could result in the following incorrect + elaboration order: + + :: + + spec of Server + spec of Client + body of Server + + where ``Client`` invokes ``Server.Func``, but the body of ``Server.Func`` has + not been elaborated yet. + +The pragmas outlined above allow a server unit to guarantee safe elaboration +use by client units. Thus it is a good rule to mark units as ``Pure`` or +``Preelaborate``, and if this is not possible, mark them as ``Elaborate_Body``. + +There are however situations where ``Pure``, ``Preelaborate``, and +``Elaborate_Body`` are not applicable. Ada provides another set of pragmas for +use by client units to help ensure the elaboration safety of server units they +depend on. + +.. index:: pragma Elaborate (Unit) + +* *pragma Elaborate (Unit)* + + Pragma ``Elaborate`` can be placed in the context clauses of a unit, after a + |with| clause. It guarantees that both the spec and body of its argument will + be elaborated prior to the unit with the pragma. Note that other unrelated + units may be elaborated in between the spec and the body. + + :: + + package Server is + function Func return Integer; + end Server; + + :: + + package body Server is + function Func return Integer is + begin + ... + end Func; + end Server; + + :: + + with Server; + pragma Elaborate (Server); + package Client is + Val : constant Integer := Server.Func; + end Client; + + In the example above, pragma ``Elaborate`` guarantees the following + elaboration order: + + :: + + spec of Server + body of Server + spec of Client + + Removing pragma ``Elaborate`` could result in the following incorrect + elaboration order: + + :: + + spec of Server + spec of Client + body of Server + + where ``Client`` invokes ``Server.Func``, but the body of ``Server.Func`` + has not been elaborated yet. + +.. index:: pragma Elaborate_All (Unit) + +* *pragma Elaborate_All (Unit)* + + Pragma ``Elaborate_All`` is placed in the context clauses of a unit, after + a |with| clause. It guarantees that both the spec and body of its argument + will be elaborated prior to the unit with the pragma, as well as all units + |withed| by the spec and body of the argument, recursively. Note that other + unrelated units may be elaborated in between the spec and the body. + + :: + + package Math is + function Factorial (Val : Natural) return Natural; + end Math; + + :: + + package body Math is + function Factorial (Val : Natural) return Natural is + begin + ...; + end Factorial; + end Math; + + :: + + package Computer is + type Operation_Kind is (None, Op_Factorial); + + function Compute + (Val : Natural; + Op : Operation_Kind) return Natural; + end Computer; + + :: + + with Math; + package body Computer is + function Compute + (Val : Natural; + Op : Operation_Kind) return Natural + is + if Op = Op_Factorial then + return Math.Factorial (Val); + end if; + + return 0; + end Compute; + end Computer; + + :: + + with Computer; + pragma Elaborate_All (Computer); + package Client is + Val : constant Natural := + Computer.Compute (123, Computer.Op_Factorial); + end Client; + + In the example above, pragma ``Elaborate_All`` can result in the following + elaboration order: + + :: + + spec of Math + body of Math + spec of Computer + body of Computer + spec of Client + + Note that there are several allowable suborders for the specs and bodies of + ``Math`` and ``Computer``, but the point is that these specs and bodies will + be elaborated prior to ``Client``. + + Removing pragma ``Elaborate_All`` could result in the following incorrect + elaboration order + + :: + + spec of Math + spec of Computer + body of Computer + spec of Client + body of Math + + where ``Client`` invokes ``Computer.Compute``, which in turn invokes + ``Math.Factorial``, but the body of ``Math.Factorial`` has not been + elaborated yet. + +All pragmas shown above can be summarized by the following rule: + +*If a client unit elaborates a server target directly or indirectly, then if +the server unit requires a body and does not have pragma Pure, Preelaborate, +or Elaborate_Body, then the client unit should have pragma Elaborate or +Elaborate_All for the server unit.* + +If the rule outlined above is not followed, then a program may fall in one of +the following states: + +* *No elaboration order exists* + + In this case a compiler must diagnose the situation, and refuse to build an + executable program. + +* *One or more incorrect elaboration orders exist* + + In this case a compiler can build an executable program, but + ``Program_Error`` will be raised when the program is run. + +* *Several elaboration orders exist, some correct, some incorrect* + + In this case the programmer has not controlled the elaboration order. As a + result, a compiler may or may not pick one of the correct orders, and the + program may or may not raise ``Program_Error`` when it is run. This is the + worst possible state because the program may fail on another compiler, or + even another version of the same compiler. + +* *One or more correct orders exist* + + In this case a compiler can build an executable program, and the program is + run successfully. This state may be guaranteed by following the outlined + rules, or may be the result of good program architecture. + +Note that one additional advantage of using ``Elaborate`` and ``Elaborate_All`` +is that the program continues to stay in the last state (one or more correct +orders exist) even if maintenance changes the bodies of targets. + +.. _Controlling_the_Elaboration_Order_in_GNAT: + +Controlling the Elaboration Order in GNAT +========================================= + +In addition to Ada semantics and rules synthesized from them, GNAT offers +three elaboration models to aid the programmer with specifying the correct +elaboration order and to diagnose elaboration problems. + +.. index:: Dynamic elaboration model + +* *Dynamic elaboration model* + + This is the most permissive of the three elaboration models. When the + dynamic model is in effect, GNAT assumes that all code within all units in + a partition is elaboration code. GNAT performs very few diagnostics and + generates run-time checks to verify the elaboration order of a program. This + behavior is identical to that specified by the Ada Reference Manual. The + dynamic model is enabled with compiler switch :switch:`-gnatE`. + +.. index:: Static elaboration model + +* *Static elaboration model* + + This is the middle ground of the three models. When the static model is in + effect, GNAT performs extensive diagnostics on a unit-by-unit basis for all + scenarios that elaborate or execute internal targets. GNAT also generates + run-time checks for all external targets and for all scenarios that may + exhibit ABE problems. Finally, GNAT installs implicit ``Elaborate`` and + ``Elaborate_All`` pragmas for server units based on the dependencies of + client units. The static model is the default model in GNAT. + +.. index:: SPARK elaboration model + +* *SPARK elaboration model* + + This is the most conservative of the three models and enforces the SPARK + rules of elaboration as defined in the SPARK Reference Manual, section 7.7. + The SPARK model is in effect only when a scenario and a target reside in a + region subject to SPARK_Mode On, otherwise the dynamic or static model is in + effect. + +.. _Common_Elaboration_Model_Traits": + +Common Elaboration-model Traits +=============================== + +All three GNAT models are able to detect elaboration problems related to +dispatching calls and a particular kind of ABE referred to as *guaranteed ABE*. + +* *Dispatching calls* + + GNAT installs run-time checks for each primitive subprogram of each tagged + type defined in a partition on the assumption that a dispatching call + invoked at elaboration time will execute one of these primitives. As a + result, a dispatching call that executes a primitive whose body has not + been elaborated yet will raise exception ``Program_Error`` at run time. The + checks can be suppressed using pragma ``Suppress (Elaboration_Check)``. + +* *Guaranteed ABE* + + A guaranteed ABE arises when the body of a target is not elaborated early + enough, and causes all scenarios that directly execute the target to fail. + + :: + + package body Guaranteed_ABE is + function ABE return Integer; + + Val : constant Integer := ABE; + + function ABE return Integer is + begin + ... + end ABE; + end Guaranteed_ABE; + + In the example above, the elaboration of ``Guaranteed_ABE``'s body elaborates + the declaration of ``Val``. This invokes function ``ABE``, however the body + of ``ABE`` has not been elaborated yet. GNAT emits similar diagnostics in all + three models: + + :: + + 1. package body Guaranteed_ABE is + 2. function ABE return Integer; + 3. + 4. Val : constant Integer := ABE; + | + >>> warning: cannot call "ABE" before body seen + >>> warning: Program_Error will be raised at run time + + 5. + 6. function ABE return Integer is + 7. begin + 8. ... + 9. end ABE; + 10. end Guaranteed_ABE; + +Note that GNAT emits warnings rather than hard errors whenever it encounters an +elaboration problem. This is because the elaboration model in effect may be too +conservative, or a particular scenario may not be elaborated or executed due to +data and control flow. The warnings can be suppressed with compiler switch +:switch:`-gnatws`. + +.. _Dynamic_Elaboration_Model_in_GNAT: + +Dynamic Elaboration Model in GNAT +================================= + +The dynamic model assumes that all code within all units in a partition is +elaboration code. As a result, run-time checks are installed for each scenario +regardless of whether the target is internal or external. The checks can be +suppressed using pragma ``Suppress (Elaboration_Check)``. This behavior is +identical to that specified by the Ada Reference Manual. The following example +showcases run-time checks installed by GNAT to verify the elaboration state of +package ``Dynamic_Model``. + +:: + + with Server; + package body Dynamic_Model is + procedure API is + begin + ... + end API; + + <check that the body of Server.Gen is elaborated> + package Inst is new Server.Gen; + + T : Server.Task_Type; + + begin + <check that the body of Server.Task_Type is elaborated> + + <check that the body of Server.Proc is elaborated> + Server.Proc; + end Dynamic_Model; + +The checks verify that the body of a target has been successfully elaborated +before a scenario activates, calls, or instantiates a target. + +Note that no scenario within package ``Dynamic_Model`` calls procedure ``API``. +In fact, procedure ``API`` may not be invoked by elaboration code within the +partition, however the dynamic model assumes that this can happen. + +The dynamic model emits very few diagnostics, but can make suggestions on +missing ``Elaborate`` and ``Elaborate_All`` pragmas for library-level +scenarios. This information is available when compiler switch :switch:`-gnatel` +is in effect. + +:: + + 1. with Server; + 2. package body Dynamic_Model is + 3. Val : constant Integer := Server.Func; + | + >>> info: call to "Func" during elaboration + >>> info: missing pragma "Elaborate_All" for unit "Server" + + 4. end Dynamic_Model; + +.. _Static_Elaboration_Model_in_GNAT: + +Static Elaboration Model in GNAT +================================ + +In contrast to the dynamic model, the static model is more precise in its +analysis of elaboration code. The model makes a clear distinction between +internal and external targets, and resorts to different diagnostics and +run-time checks based on the nature of the target. + +* *Internal targets* + + The static model performs extensive diagnostics on scenarios which elaborate + or execute internal targets. The warnings resulting from these diagnostics + are enabled by default, but can be suppressed using compiler switch + :switch:`-gnatws`. + + :: + + 1. package body Static_Model is + 2. generic + 3. with function Func return Integer; + 4. package Gen is + 5. Val : constant Integer := Func; + 6. end Gen; + 7. + 8. function ABE return Integer; + 9. + 10. function Cause_ABE return Boolean is + 11. package Inst is new Gen (ABE); + | + >>> warning: in instantiation at line 5 + >>> warning: cannot call "ABE" before body seen + >>> warning: Program_Error may be raised at run time + >>> warning: body of unit "Static_Model" elaborated + >>> warning: function "Cause_ABE" called at line 16 + >>> warning: function "ABE" called at line 5, instance at line 11 + + 12. begin + 13. ... + 14. end Cause_ABE; + 15. + 16. Val : constant Boolean := Cause_ABE; + 17. + 18. function ABE return Integer is + 19. begin + 20. ... + 21. end ABE; + 22. end Static_Model; + + The example above illustrates an ABE problem within package ``Static_Model``, + which is hidden by several layers of indirection. The elaboration of package + body ``Static_Model`` elaborates the declaration of ``Val``. This invokes + function ``Cause_ABE``, which instantiates generic unit ``Gen`` as ``Inst``. + The elaboration of ``Inst`` invokes function ``ABE``, however the body of + ``ABE`` has not been elaborated yet. + +* *External targets* + + The static model installs run-time checks to verify the elaboration status + of server targets only when the scenario that elaborates or executes that + target is part of the elaboration code of the client unit. The checks can be + suppressed using pragma ``Suppress (Elaboration_Check)``. + + :: + + with Server; + package body Static_Model is + generic + with function Func return Integer; + package Gen is + Val : constant Integer := Func; + end Gen; + + function Call_Func return Boolean is + <check that the body of Server.Func is elaborated> + package Inst is new Gen (Server.Func); + begin + ... + end Call_Func; + + Val : constant Boolean := Call_Func; + end Static_Model; + + In the example above, the elaboration of package body ``Static_Model`` + elaborates the declaration of ``Val``. This invokes function ``Call_Func``, + which instantiates generic unit ``Gen`` as ``Inst``. The elaboration of + ``Inst`` invokes function ``Server.Func``. Since ``Server.Func`` is an + external target, GNAT installs a run-time check to verify that its body has + been elaborated. + + In addition to checks, the static model installs implicit ``Elaborate`` and + ``Elaborate_All`` pragmas to guarantee safe elaboration use of server units. + This information is available when compiler switch :switch:`-gnatel` is in + effect. + + :: + + 1. with Server; + 2. package body Static_Model is + 3. generic + 4. with function Func return Integer; + 5. package Gen is + 6. Val : constant Integer := Func; + 7. end Gen; + 8. + 9. function Call_Func return Boolean is + 10. package Inst is new Gen (Server.Func); + | + >>> info: instantiation of "Gen" during elaboration + >>> info: in instantiation at line 6 + >>> info: call to "Func" during elaboration + >>> info: in instantiation at line 6 + >>> info: implicit pragma "Elaborate_All" generated for unit "Server" + >>> info: body of unit "Static_Model" elaborated + >>> info: function "Call_Func" called at line 15 + >>> info: function "Func" called at line 6, instance at line 10 + + 11. begin + 12. ... + 13. end Call_Func; + 14. + 15. Val : constant Boolean := Call_Func; + | + >>> info: call to "Call_Func" during elaboration + + 16. end Static_Model; + + In the example above, the elaboration of package body ``Static_Model`` + elaborates the declaration of ``Val``. This invokes function ``Call_Func``, + which instantiates generic unit ``Gen`` as ``Inst``. The elaboration of + ``Inst`` invokes function ``Server.Func``. Since ``Server.Func`` is an + external target, GNAT installs an implicit ``Elaborate_All`` pragma for unit + ``Server``. The pragma guarantees that both the spec and body of ``Server``, + along with any additional dependencies that ``Server`` may require, are + elaborated prior to the body of ``Static_Model``. + +.. _SPARK_Elaboration_Model_in_GNAT: + +SPARK Elaboration Model in GNAT +=============================== + +The SPARK model is identical to the static model in its handling of internal +targets. The SPARK model, however, requires explicit ``Elaborate`` or +``Elaborate_All`` pragmas to be present in the program when a target is +external, and compiler switch :switch:`-gnatd.v` is in effect. + +:: + + 1. with Server; + 2. package body SPARK_Model with SPARK_Mode is + 3. Val : constant Integer := Server.Func; + | + >>> call to "Func" during elaboration in SPARK + >>> unit "SPARK_Model" requires pragma "Elaborate_All" for "Server" + >>> body of unit "SPARK_Model" elaborated + >>> function "Func" called at line 3 + + 4. end SPARK_Model; + +.. _Mixing_Elaboration_Models: + +Mixing Elaboration Models +========================= + +It is possible to mix units compiled with a different elaboration model, +however the following rules must be observed: + +* A client unit compiled with the dynamic model can only |with| a server unit + that meets at least one of the following criteria: + + - The server unit is compiled with the dynamic model. + + - The server unit is a GNAT implementation unit from the Ada, GNAT, + Interfaces, or System hierarchies. + + - The server unit has pragma ``Pure`` or ``Preelaborate``. + + - The client unit has an explicit ``Elaborate_All`` pragma for the server + unit. + +These rules ensure that elaboration checks are not omitted. If the rules are +violated, the binder emits a warning: + +:: + + warning: "x.ads" has dynamic elaboration checks and with's + warning: "y.ads" which has static elaboration checks + +The warnings can be suppressed by binder switch :switch:`-ws`. + +.. _Elaboration_Circularities: + +Elaboration Circularities +========================= + +If the binder cannot find an acceptable elaboration order, it outputs detailed +diagnostics describing an **elaboration circularity**. + +:: + + package Server is + function Func return Integer; + end Server; + +:: + + with Client; + package body Server is + function Func return Integer is + begin + ... + end Func; + end Server; + +:: + + with Server; + package Client is + Val : constant Integer := Server.Func; + end Client; + +:: + + with Client; + procedure Main is begin null; end Main; + +:: + + error: elaboration circularity detected + info: "server (body)" must be elaborated before "client (spec)" + info: reason: implicit Elaborate_All in unit "client (spec)" + info: recompile "client (spec)" with -gnatel for full details + info: "server (body)" + info: must be elaborated along with its spec: + info: "server (spec)" + info: which is withed by: + info: "client (spec)" + info: "client (spec)" must be elaborated before "server (body)" + info: reason: with clause + +In the example above, ``Client`` must be elaborated prior to ``Main`` by virtue +of a |with| clause. The elaboration of ``Client`` invokes ``Server.Func``, and +static model generates an implicit ``Elaborate_All`` pragma for ``Server``. The +pragma implies that both the spec and body of ``Server``, along with any units +they |with|, must be elaborated prior to ``Client``. However, ``Server``'s body +|withs| ``Client``, implying that ``Client`` must be elaborated prior to +``Server``. The end result is that ``Client`` must be elaborated prior to +``Client``, and this leads to a circularity. + +.. _Resolving_Elaboration_Circularities: + +Resolving Elaboration Circularities +=================================== + +When faced with an elaboration circularity, a programmer has several options +available. + +* *Fix the program* + + The most desirable option from the point of view of long-term maintenance + is to rearrange the program so that the elaboration problems are avoided. + One useful technique is to place the elaboration code into separate child + packages. Another is to move some of the initialization code to explicitly + invoked subprograms, where the program controls the order of initialization + explicitly. Although this is the most desirable option, it may be impractical + and involve too much modification, especially in the case of complex legacy + code. + +* *Switch to more permissive elaboration model* + + If the compilation was performed using the static model, enable the dynamic + model with compiler switch :switch:`-gnatE`. GNAT will no longer generate + implicit ``Elaborate`` and ``Elaborate_All`` pragmas, resulting in a behavior + identical to that specified by the Ada Reference Manual. The binder will + generate an executable program that may or may not raise ``Program_Error``, + and it is the programmer's responsibility to ensure that it does not raise + ``Program_Error``. + +* *Suppress all elaboration checks* + + The drawback of run-time checks is that they generate overhead at run time, + both in space and time. If the programmer is absolutely sure that a program + will not raise an elaboration-related ``Program_Error``, then using the + pragma ``Suppress (Elaboration_Check)`` globally (as a configuration pragma) + will eliminate all run-time checks. + +* *Suppress elaboration checks selectively* + + If a scenario cannot possibly lead to an elaboration ``Program_Error``, + and the binder nevertheless complains about implicit ``Elaborate`` and + ``Elaborate_All`` pragmas that lead to elaboration circularities, it + is possible to suppress the generation of implicit ``Elaborate`` and + ``Elaborate_All`` pragmas, as well as run-time checks. Clearly this can + be unsafe, and it is the responsibility of the programmer to make sure + that the resulting program has no elaboration anomalies. Pragma + ``Suppress (Elaboration_Check)`` can be used with different levels of + granularity to achieve these effects. + + - *Target suppression* + + When the pragma is placed in a declarative part, without a second argument + naming an entity, it will suppress implicit ``Elaborate`` and + ``Elaborate_All`` pragma generation, as well as run-time checks, on all + targets within the region. + + :: + + package Range_Suppress is + pragma Suppress (Elaboration_Check); + + function Func return Integer; + + generic + procedure Gen; + + pragma Unsuppress (Elaboration_Check); + + task type Tsk; + end Range_Suppress; + + In the example above, a pair of Suppress/Unsuppress pragmas define a region + of suppression within package ``Range_Suppress``. As a result, no implicit + ``Elaborate`` and ``Elaborate_All`` pragmas, nor any run-time checks, will + be generated by callers of ``Func`` and instantiators of ``Gen``. Note that + task type ``Tsk`` is not within this region. + + An alternative to the region-based suppression is to use multiple + ``Suppress`` pragmas with arguments naming specific entities for which + elaboration checks should be suppressed: + + :: + + package Range_Suppress is + function Func return Integer; + pragma Suppress (Elaboration_Check, Func); + + generic + procedure Gen; + pragma Suppress (Elaboration_Check, Gen); + + task type Tsk; + end Range_Suppress; + + - *Scenario suppression* + + When the pragma ``Suppress`` is placed in a declarative or statement + part, without an entity argument, it will suppress implicit ``Elaborate`` + and ``Elaborate_All`` pragma generation, as well as run-time checks, on + all scenarios within the region. + + :: + + with Server; + package body Range_Suppress is + pragma Suppress (Elaboration_Check); + + function Func return Integer is + begin + return Server.Func; + end Func; + + procedure Gen is + begin + Server.Proc; + end Gen; + + pragma Unsuppress (Elaboration_Check); + + task body Tsk is + begin + Server.Proc; + end Tsk; + end Range_Suppress; + + In the example above, a pair of Suppress/Unsuppress pragmas define a region + of suppression within package body ``Range_Suppress``. As a result, the + calls to ``Server.Func`` in ``Func`` and ``Server.Proc`` in ``Gen`` will + not generate any implicit ``Elaborate`` and ``Elaborate_All`` pragmas or + run-time checks. + +.. _Resolving_Task_Issues: + +Resolving Task Issues +===================== + +The model of execution in Ada dictates that elaboration must first take place, +and only then can the main program be started. Tasks which are activated during +elaboration violate this model and may lead to serious concurrent problems at +elaboration time. + +A task can be activated in two different ways: + +* The task is created by an allocator in which case it is activated immediately + after the allocator is evaluated. + +* The task is declared at the library level or within some nested master in + which case it is activated before starting execution of the statement + sequence of the master defining the task. + +Since the elaboration of a partition is performed by the environment task +servicing that partition, any tasks activated during elaboration may be in +a race with the environment task, and lead to unpredictable state and behavior. +The static model seeks to avoid such interactions by assuming that all code in +the task body is executed at elaboration time, if the task was activated by +elaboration code. + +:: + + package Decls is + task Lib_Task is + entry Start; + end Lib_Task; + + type My_Int is new Integer; + + function Ident (M : My_Int) return My_Int; + end Decls; + +:: + + with Utils; + package body Decls is + task body Lib_Task is + begin + accept Start; + Utils.Put_Val (2); + end Lib_Task; + + function Ident (M : My_Int) return My_Int is + begin + return M; + end Ident; + end Decls; + +:: + + with Decls; + package Utils is + procedure Put_Val (Arg : Decls.My_Int); + end Utils; + +:: + + with Ada.Text_IO; use Ada.Text_IO; + package body Utils is + procedure Put_Val (Arg : Decls.My_Int) is + begin + Put_Line (Arg'Img); + end Put_Val; + end Utils; + +:: + + with Decls; + procedure Main is + begin + Decls.Lib_Task.Start; + end Main; + +When the above example is compiled with the static model, an elaboration +circularity arises: + +:: + + error: elaboration circularity detected + info: "decls (body)" must be elaborated before "decls (body)" + info: reason: implicit Elaborate_All in unit "decls (body)" + info: recompile "decls (body)" with -gnatel for full details + info: "decls (body)" + info: must be elaborated along with its spec: + info: "decls (spec)" + info: which is withed by: + info: "utils (spec)" + info: which is withed by: + info: "decls (body)" + +In the above example, ``Decls`` must be elaborated prior to ``Main`` by virtue +of a with clause. The elaboration of ``Decls`` activates task ``Lib_Task``. The +static model conservatibely assumes that all code within the body of +``Lib_Task`` is executed, and generates an implicit ``Elaborate_All`` pragma +for ``Units`` due to the call to ``Utils.Put_Val``. The pragma implies that +both the spec and body of ``Utils``, along with any units they |with|, +must be elaborated prior to ``Decls``. However, ``Utils``'s spec |withs| +``Decls``, implying that ``Decls`` must be elaborated before ``Utils``. The end +result is that ``Utils`` must be elaborated prior to ``Utils``, and this +leads to a circularity. + +In reality, the example above will not exhibit an ABE problem at run time. +When the body of task ``Lib_Task`` is activated, execution will wait for entry +``Start`` to be accepted, and the call to ``Utils.Put_Val`` will not take place +at elaboration time. Task ``Lib_Task`` will resume its execution after the main +program is executed because ``Main`` performs a rendezvous with +``Lib_Task.Start``, and at that point all units have already been elaborated. +As a result, the static model may seem overly conservative, partly because it +does not take control and data flow into account. + +When faced with a task elaboration circularity, a programmer has several +options available: + +* *Use the dynamic model* + + The dynamic model does not generate implicit ``Elaborate`` and + ``Elaborate_All`` pragmas. Instead, it will install checks prior to every + call in the example above, thus verifying the successful elaboration of + ``Utils.Put_Val`` in case the call to it takes place at elaboration time. + The dynamic model is enabled with compiler switch :switch:`-gnatE`. + +* *Isolate the tasks* + + Relocating tasks in their own separate package could decouple them from + dependencies that would otherwise cause an elaboration circularity. The + example above can be rewritten as follows: + + :: + + package Decls1 is -- new + task Lib_Task is + entry Start; + end Lib_Task; + end Decls1; + + :: + + with Utils; + package body Decls1 is -- new + task body Lib_Task is + begin + accept Start; + Utils.Put_Val (2); + end Lib_Task; + end Decls1; + + :: + + package Decls2 is -- new + type My_Int is new Integer; + function Ident (M : My_Int) return My_Int; + end Decls2; + + :: + + with Utils; + package body Decls2 is -- new + function Ident (M : My_Int) return My_Int is + begin + return M; + end Ident; + end Decls2; + + :: + + with Decls2; + package Utils is + procedure Put_Val (Arg : Decls2.My_Int); + end Utils; + + :: + + with Ada.Text_IO; use Ada.Text_IO; + package body Utils is + procedure Put_Val (Arg : Decls2.My_Int) is + begin + Put_Line (Arg'Img); + end Put_Val; + end Utils; + + :: + + with Decls1; + procedure Main is + begin + Decls1.Lib_Task.Start; + end Main; + +* *Declare the tasks* + + The original example uses a single task declaration for ``Lib_Task``. An + explicit task type declaration and a properly placed task object could avoid + the dependencies that would otherwise cause an elaboration circularity. The + example can be rewritten as follows: + + :: + + package Decls is + task type Lib_Task is -- new + entry Start; + end Lib_Task; + + type My_Int is new Integer; + + function Ident (M : My_Int) return My_Int; + end Decls; + + :: + + with Utils; + package body Decls is + task body Lib_Task is + begin + accept Start; + Utils.Put_Val (2); + end Lib_Task; + + function Ident (M : My_Int) return My_Int is + begin + return M; + end Ident; + end Decls; + + :: + + with Decls; + package Utils is + procedure Put_Val (Arg : Decls.My_Int); + end Utils; + + :: + + with Ada.Text_IO; use Ada.Text_IO; + package body Utils is + procedure Put_Val (Arg : Decls.My_Int) is + begin + Put_Line (Arg'Img); + end Put_Val; + end Utils; + + :: + + with Decls; + package Obj_Decls is -- new + Task_Obj : Decls.Lib_Task; + end Obj_Decls; + + :: + + with Obj_Decls; + procedure Main is + begin + Obj_Decls.Task_Obj.Start; -- new + end Main; + +* *Use restriction No_Entry_Calls_In_Elaboration_Code* + + The issue exhibited in the original example under this section revolves + around the body of ``Lib_Task`` blocking on an accept statement. There is + no rule to prevent elaboration code from performing entry calls, however in + practice this is highly unusual. In addition, the pattern of starting tasks + at elaboration time and then immediately blocking on accept or select + statements is quite common. + + If a programmer knows that elaboration code will not perform any entry + calls, then the programmer can indicate that the static model should not + process the remainder of a task body once an accept or select statement has + been encountered. This behavior can be specified by a configuration pragma: + + :: + + pragma Restrictions (No_Entry_Calls_In_Elaboration_Code); + + In addition to the change in behavior with respect to task bodies, the + static model will verify that no entry calls take place at elaboration time. + +.. _Elaboration_Related_Compiler_Switches: + +Elaboration-related Compiler Switches +===================================== + +GNAT has several switches that affect the elaboration model and consequently +the elaboration order chosen by the binder. + +.. index:: -gnatdE (gnat) + +:switch:`-gnatdE` + Elaboration checks on predefined units + + When this switch is in effect, GNAT will consider scenarios and targets that + come from the Ada, GNAT, Interfaces, and System hierarchies. This switch is + useful when a programmer has defined a custom grandchild of those packages. + +.. index:: -gnatd.G (gnat) + +:switch:`-gnatd.G` + Ignore calls through generic formal parameters for elaboration + + When this switch is in effect, GNAT will ignore calls that invoke generic + actual entries, operators, or subprograms via generic formal subprograms. As + a result, GNAT will not generate implicit ``Elaborate`` and ``Elaborate_All`` + pragmas, and run-time checks for such calls. Note that this switch does not + overlap with :switch:`-gnatdL`. + + :: + + package body Ignore_Calls is + function ABE return Integer; + + generic + with function Gen_Formal return Integer; + package Gen is + Val : constant Integer := Gen_Formal; + end Gen; + + package Inst is new Gen (ABE); + + function ABE return Integer is + begin + ... + end ABE; + end Ignore_Calls; + + In the example above, the call to function ``ABE`` will be ignored because it + occurs during the elaboration of instance ``Inst``, through a call to generic + formal subprogram ``Gen_Formal``. + +.. index:: -gnatdL (gnat) + +:switch:`-gnatdL` + Ignore external calls from instances for elaboration + + When this switch is in effect, GNAT will ignore calls that originate from + within an instance and directly target an entry, operator, or subprogram + defined outside the instance. As a result, GNAT will not generate implicit + ``Elaborate`` and ``Elaborate_All`` pragmas, and run-time checks for such + calls. Note that this switch does not overlap with :switch:`-gnatd.G`. + + :: + + package body Ignore_Calls is + function ABE return Integer; + + generic + package Gen is + Val : constant Integer := ABE; + end Gen; + + package Inst is new Gen; + + function ABE return Integer is + begin + ... + end ABE; + end Ignore_Calls; + + In the example above, the call to function ``ABE`` will be ignored because it + originates from within an instance and targets a subprogram defined outside + the instance. + +.. index:: -gnatd.o (gnat) + +:switch:`-gnatd.o` + Conservative elaboration order for indirect calls + + When this switch is in effect, GNAT will treat ``'Access`` of an entry, + operator, or subprogram as an immediate call to that target. As a result, + GNAT will generate implicit ``Elaborate`` and ``Elaborate_All`` pragmas as + well as run-time checks for such attribute references. + + :: + + 1. package body Attribute_Call is + 2. function Func return Integer; + 3. type Func_Ptr is access function return Integer; + 4. + 5. Ptr : constant Func_Ptr := Func'Access; + | + >>> warning: cannot call "Func" before body seen + >>> warning: Program_Error may be raised at run time + >>> warning: body of unit "Attribute_Call" elaborated + >>> warning: "Access" of "Func" taken at line 5 + >>> warning: function "Func" called at line 5 + + 6. + 7. function Func return Integer is + 8. begin + 9. ... + 10. end Func; + 11. end Attribute_Call; + + In the example above, the elaboration of declaration ``Ptr`` is assigned + ``Func'Access`` before the body of ``Func`` has been elaborated. + +.. index:: -gnatd.U (gnat) + +:switch:`-gnatd.U` + Ignore indirect calls for static elaboration + + When this switch is in effect, GNAT will ignore ``'Access`` of an entry, + operator, or subprogram when the static model is in effect. + +.. index:: -gnatd.v (gnat) + +:switch:`-gnatd.v` + Enforce SPARK elaboration rules in SPARK code + + When this switch is in effect, GNAT will enforce the SPARK rules of + elaboration as defined in the SPARK Reference Manual, section 7.7. As a + result, constructs which violate the SPARK elaboration rules are no longer + accepted, even if GNAT is able to statically ensure that these constructs + will not lead to ABE problems. + +.. index:: -gnatd.y (gnat) + +:switch:`-gnatd.y` + Disable implicit pragma Elaborate[_All] on task bodies + + When this switch is in effect, GNAT will not generate ``Elaborate`` and + ``Elaborate_All`` pragmas if the need for the pragma came directly or + indirectly from a task body. + + :: + + with Server; + package body Disable_Task is + task T; + + task body T is + begin + Server.Proc; + end T; + end Disable_Task; + + In the example above, the activation of single task ``T`` invokes + ``Server.Proc``, which implies that ``Server`` requires ``Elaborate_All``, + however GNAT will not generate the pragma. + +.. index:: -gnatE (gnat) + +:switch:`-gnatE` + Dynamic elaboration checking mode enabled + + When this switch is in effect, GNAT activates the dynamic elaboration model. + +.. index:: -gnatel (gnat) + +:switch:`-gnatel` + Turn on info messages on generated Elaborate[_All] pragmas + + When this switch is in effect, GNAT will emit the following supplementary + information depending on the elaboration model in effect. + + - *Dynamic model* + + GNAT will indicate missing ``Elaborate`` and ``Elaborate_All`` pragmas for + all library-level scenarios within the partition. + + - *Static model* + + GNAT will indicate all scenarios executed during elaboration. In addition, + it will provide detailed traceback when an implicit ``Elaborate`` or + ``Elaborate_All`` pragma is generated. + + - *SPARK model* + + GNAT will indicate how an elaboration requirement is met by the context of + a unit. This diagnostic requires compiler switch :switch:`-gnatd.v`. + + :: + + 1. with Server; pragma Elaborate_All (Server); + 2. package Client with SPARK_Mode is + 3. Val : constant Integer := Server.Func; + | + >>> info: call to "Func" during elaboration in SPARK + >>> info: "Elaborate_All" requirement for unit "Server" met by pragma at line 1 + + 4. end Client; + +.. index:: -gnatw.f (gnat) + +:switch:`-gnatw.f` + Turn on warnings for suspicious Subp'Access + + When this switch is in effect, GNAT will treat ``'Access`` of an entry, + operator, or subprogram as a potential call to the target and issue warnings: + + :: + + 1. package body Attribute_Call is + 2. function Func return Integer; + 3. type Func_Ptr is access function return Integer; + 4. + 5. Ptr : constant Func_Ptr := Func'Access; + | + >>> warning: "Access" attribute of "Func" before body seen + >>> warning: possible Program_Error on later references + >>> warning: body of unit "Attribute_Call" elaborated + >>> warning: "Access" of "Func" taken at line 5 + + 6. + 7. function Func return Integer is + 8. begin + 9. ... + 10. end Func; + 11. end Attribute_Call; + + In the example above, the elaboration of declaration ``Ptr`` is assigned + ``Func'Access`` before the body of ``Func`` has been elaborated. + +.. _Summary_of_Procedures_for_Elaboration_Control: + +Summary of Procedures for Elaboration Control +============================================= + +A programmer should first compile the program with the default options, using +none of the binder or compiler switches. If the binder succeeds in finding an +elaboration order, then apart from possible cases involing dispatching calls +and access-to-subprogram types, the program is free of elaboration errors. +If it is important for the program to be portable to compilers other than GNAT, +then the programmer should use compiler switch :switch:`-gnatel` and consider +the messages about missing or implicitly created ``Elaborate`` and +``Elaborate_All`` pragmas. + +If the binder reports an elaboration circularity, the programmer has several +options: + +* Ensure that warnings are enabled. This will allow the static model to output + trace information of elaboration issues. The trace information could shed + light on previously unforeseen dependencies, as well as their origins. + +* Use switch :switch:`-gnatel` to obtain messages on generated implicit + ``Elaborate`` and ``Elaborate_All`` pragmas. The trace information could + indicate why a server unit must be elaborated prior to a client unit. + +* If the warnings produced by the static model indicate that a task is + involved, consider the options in the section on resolving task issues as + well as compiler switch :switch:`-gnatd.y`. + +* If the warnings produced by the static model indicate that an generic + instantiations are involved, consider using compiler switches + :switch:`-gnatd.G` and :switch:`-gnatdL`. + +* If none of the steps outlined above resolve the circularity, recompile the + program using the dynamic model by using compiler switch :switch:`-gnatE`. + +.. _Inspecting_the_Chosen_Elaboration_Order: + +Inspecting the Chosen Elaboration Order +======================================= + +To see the elaboration order chosen by the binder, inspect the contents of file +`b~xxx.adb`. On certain targets, this file appears as `b_xxx.adb`. The +elaboration order appears as a sequence of calls to ``Elab_Body`` and +``Elab_Spec``, interspersed with assignments to `Exxx` which indicates that a +particular unit is elaborated. For example: + +:: + + System.Soft_Links'Elab_Body; + E14 := True; + System.Secondary_Stack'Elab_Body; + E18 := True; + System.Exception_Table'Elab_Body; + E24 := True; + Ada.Io_Exceptions'Elab_Spec; + E67 := True; + Ada.Tags'Elab_Spec; + Ada.Streams'Elab_Spec; + E43 := True; + Interfaces.C'Elab_Spec; + E69 := True; + System.Finalization_Root'Elab_Spec; + E60 := True; + System.Os_Lib'Elab_Body; + E71 := True; + System.Finalization_Implementation'Elab_Spec; + System.Finalization_Implementation'Elab_Body; + E62 := True; + Ada.Finalization'Elab_Spec; + E58 := True; + Ada.Finalization.List_Controller'Elab_Spec; + E76 := True; + System.File_Control_Block'Elab_Spec; + E74 := True; + System.File_Io'Elab_Body; + E56 := True; + Ada.Tags'Elab_Body; + E45 := True; + Ada.Text_Io'Elab_Spec; + Ada.Text_Io'Elab_Body; + E07 := True; + +Note also binder switch :switch:`-l`, which outputs the chosen elaboration +order and provides a more readable form of the above: + +:: + + ada (spec) + interfaces (spec) + system (spec) + system.case_util (spec) + system.case_util (body) + system.concat_2 (spec) + system.concat_2 (body) + system.concat_3 (spec) + system.concat_3 (body) + system.htable (spec) + system.parameters (spec) + system.parameters (body) + system.crtl (spec) + interfaces.c_streams (spec) + interfaces.c_streams (body) + system.restrictions (spec) + system.restrictions (body) + system.standard_library (spec) + system.exceptions (spec) + system.exceptions (body) + system.storage_elements (spec) + system.storage_elements (body) + system.secondary_stack (spec) + system.stack_checking (spec) + system.stack_checking (body) + system.string_hash (spec) + system.string_hash (body) + system.htable (body) + system.strings (spec) + system.strings (body) + system.traceback (spec) + system.traceback (body) + system.traceback_entries (spec) + system.traceback_entries (body) + ada.exceptions (spec) + ada.exceptions.last_chance_handler (spec) + system.soft_links (spec) + system.soft_links (body) + ada.exceptions.last_chance_handler (body) + system.secondary_stack (body) + system.exception_table (spec) + system.exception_table (body) + ada.io_exceptions (spec) + ada.tags (spec) + ada.streams (spec) + interfaces.c (spec) + interfaces.c (body) + system.finalization_root (spec) + system.finalization_root (body) + system.memory (spec) + system.memory (body) + system.standard_library (body) + system.os_lib (spec) + system.os_lib (body) + system.unsigned_types (spec) + system.stream_attributes (spec) + system.stream_attributes (body) + system.finalization_implementation (spec) + system.finalization_implementation (body) + ada.finalization (spec) + ada.finalization (body) + ada.finalization.list_controller (spec) + ada.finalization.list_controller (body) + system.file_control_block (spec) + system.file_io (spec) + system.file_io (body) + system.val_uns (spec) + system.val_util (spec) + system.val_util (body) + system.val_uns (body) + system.wch_con (spec) + system.wch_con (body) + system.wch_cnv (spec) + system.wch_jis (spec) + system.wch_jis (body) + system.wch_cnv (body) + system.wch_stw (spec) + system.wch_stw (body) + ada.tags (body) + ada.exceptions (body) + ada.text_io (spec) + ada.text_io (body) + text_io (spec) + gdbstr (body)