Next: , Previous: Controlling Elaboration in GNAT - External Calls, Up: Elaboration Order Handling in GNAT


11.6 Default Behavior in GNAT - Ensuring Safety

The default behavior in GNAT ensures elaboration safety. In its default mode GNAT implements the rule we previously described as the right approach. Let's restate it:

`If a unit has elaboration code that can directly or indirectly make a call to a subprogram in a |withed| unit, or instantiate a generic package in a |withed| unit, then if the |withed| unit does not have pragma `Pure` or `Preelaborate`, then the client should have an `Elaborate_All` pragma for the |withed| unit.'

`In the case of instantiating a generic subprogram, it is always sufficient to have only an `Elaborate` pragma for the |withed| unit.'

By following this rule a client is assured that calls and instantiations can be made without risk of an exception.

In this mode GNAT traces all calls that are potentially made from elaboration code, and puts in any missing implicit Elaborate and Elaborate_All pragmas. The advantage of this approach is that no elaboration problems are possible if the binder can find an elaboration order that is consistent with these implicit Elaborate and Elaborate_All pragmas. The disadvantage of this approach is that no such order may exist.

If the binder does not generate any diagnostics, then it means that it has found an elaboration order that is guaranteed to be safe. However, the binder may still be relying on implicitly generated Elaborate and Elaborate_All pragmas so portability to other compilers than GNAT is not guaranteed.

If it is important to guarantee portability, then the compilations should use the `-gnatel' (info messages for elaboration pragmas) switch. This will cause info messages to be generated indicating the missing Elaborate and Elaborate_All pragmas. Consider the following source program:

    with k;
    package j is
      m : integer := k.r;
    end;

where it is clear that there should be a pragma Elaborate_All for unit k. An implicit pragma will be generated, and it is likely that the binder will be able to honor it. However, if you want to port this program to some other Ada compiler than GNAT. it is safer to include the pragma explicitly in the source. If this unit is compiled with the `-gnatel' switch, then the compiler outputs an information message:

    1. with k;
    2. package j is
    3.   m : integer := k.r;
                         |
       >>> info: call to "r" may raise Program_Error
       >>> info: missing pragma Elaborate_All for "k"
    
    4. end;

and these messages can be used as a guide for supplying manually the missing pragmas. It is usually a bad idea to use this option during development. That's because it will tell you when you need to put in a pragma, but cannot tell you when it is time to take it out. So the use of pragma Elaborate_All may lead to unnecessary dependencies and even false circularities.

This default mode is more restrictive than the Ada Reference Manual, and it is possible to construct programs which will compile using the dynamic model described there, but will run into a circularity using the safer static model we have described.

Of course any Ada compiler must be able to operate in a mode consistent with the requirements of the Ada Reference Manual, and in particular must have the capability of implementing the standard dynamic model of elaboration with run-time checks.

In GNAT, this standard mode can be achieved either by the use of the `-gnatE' switch on the compiler (`gcc' or `gnatmake') command, or by the use of the configuration pragma:

    pragma Elaboration_Checks (DYNAMIC);

Either approach will cause the unit affected to be compiled using the standard dynamic run-time elaboration checks described in the Ada Reference Manual. The static model is generally preferable, since it is clearly safer to rely on compile and link time checks rather than run-time checks. However, in the case of legacy code, it may be difficult to meet the requirements of the static model. This issue is further discussed in What to Do If the Default Elaboration Behavior Fails.

Note that the static model provides a strict subset of the allowed behavior and programs of the Ada Reference Manual, so if you do adhere to the static model and no circularities exist, then you are assured that your program will work using the dynamic model, providing that you remove any pragma Elaborate statements from the source.