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]