Next: , Previous: Mixing Elaboration Models, Up: Elaboration Order Handling in GNAT


11.10 What to Do If the Default Elaboration Behavior Fails

If the binder cannot find an acceptable order, it outputs detailed diagnostics. For example:

    error: elaboration circularity detected
    info:   "proc (body)" must be elaborated before "pack (body)"
    info:     reason: Elaborate_All probably needed in unit "pack (body)"
    info:     recompile "pack (body)" with -gnatel
    info:                             for full details
    info:       "proc (body)"
    info:         is needed by its spec:
    info:       "proc (spec)"
    info:         which is withed by:
    info:       "pack (body)"
    info:  "pack (body)" must be elaborated before "proc (body)"
    info:     reason: pragma Elaborate in unit "proc (body)"

In this case we have a cycle that the binder cannot break. On the one hand, there is an explicit pragma Elaborate in proc for pack. This means that the body of pack must be elaborated before the body of proc. On the other hand, there is elaboration code in pack that calls a subprogram in proc. This means that for maximum safety, there should really be a pragma Elaborate_All in pack for proc which would require that the body of proc be elaborated before the body of pack. Clearly both requirements cannot be satisfied. Faced with a circularity of this kind, you have three different options.

It is hard to generalize on which of these four approaches should be taken. Obviously if it is possible to fix the program so that the default treatment works, this is preferable, but this may not always be practical. It is certainly simple enough to use `-gnatE' but the danger in this case is that, even if the GNAT binder finds a correct elaboration order, it may not always do so, and certainly a binder from another Ada compiler might not. A combination of testing and analysis (for which the information messages generated with the `-gnatel' switch can be useful) must be used to ensure that the program is free of errors. One switch that is useful in this testing is the `-p (pessimistic elaboration order)' switch for gnatbind. Normally the binder tries to find an order that has the best chance of avoiding elaboration problems. However, if this switch is used, the binder plays a devil's advocate role, and tries to choose the order that has the best chance of failing. If your program works even with this switch, then it has a better chance of being error free, but this is still not a guarantee.

For an example of this approach in action, consider the C-tests (executable tests) from the ACATS suite. If these are compiled and run with the default treatment, then all but one of them succeed without generating any error diagnostics from the binder. However, there is one test that fails, and this is not surprising, because the whole point of this test is to ensure that the compiler can handle cases where it is impossible to determine a correct order statically, and it checks that an exception is indeed raised at run time.

This one test must be compiled and run using the `-gnatE' switch, and then it passes. Alternatively, the entire suite can be run using this switch. It is never wrong to run with the dynamic elaboration switch if your code is correct, and we assume that the C-tests are indeed correct (it is less efficient, but efficiency is not a factor in running the ACATS tests.)