Next: Resolving Task Issues, Previous: Elaboration Circularities, Up: Elaboration Order Handling in GNAT [Contents][Index]
When faced with an elaboration circularity, a programmer has several options available.
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.
If the compilation was performed using the static model, enable the dynamic
model with compiler 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.
If the compilation was performed using a post-18.x version of GNAT, consider using the legacy elaboration model, in the following order:
-gnatH.
-gnatH -gnatE.
-gnatH -gnatJ.
-gnatH -gnatJ -gnatE.
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.
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.
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;
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.
Next: Resolving Task Issues, Previous: Elaboration Circularities, Up: Elaboration Order Handling in GNAT [Contents][Index]