AI22-0051-1

!standard 7.3.3(7/5)                                    23-03-23  AI22-0051-1/03

!standard 10.2.1(5)

!standard 10.2.1(7/5)

!class Binding Interpretation 22-10-26

!status work item 22-10-26

!status received 22-10-26

!priority Medium

!difficulty Medium

!qualifier Omission

!subject Preelaborable_Initialization and contract aspects

!summary

*** TBD.

!issue

A Default_Initial_Condition expression is evaluated when a default-initialized object is created. The aspect Preelaborable_Initialization (P_I) does not take into account any such evaluation when it determines whether a component has P_I. That means that such an evaluation could execute operations not otherwise allowed during the elaboration of a preelaborated package (in particular, calling a function other than the handful allowed for preelaboration). This seems to circumvent the purpose of aspect P_I.

!recommendation

*** TBD.

!wording

*** TBD.

Add after 10.2.1(9.1 /5):

For the purposes of the above rules, checks associated with the aspects Default_Initial_Condition, Type_Invariant, Static_Predicate, or Dynamic_Predicate are ignored.

Add after 10.2.1(11.8 /5):

Implementation Permissions

Any checks associated with the aspects Default_Initial_Condition, Type_Invariant, Static_Predicate, or Dynamic_Predicate that would normally accompany the elaboration of a construct that is part of a preelaborated unit, may be suppressed completely, or deferred until the beginning of the elaboration of the first library unit that is not preelaborated.[a]

!discussion

This problem occurs in a number of cases, not just Default_Initial_Condition.

(1) The Default_Initial_Condition is evaluated for any default-initialized object of the type associated with the aspect (see 7.3.3(7/5)).

(2) The Type_Invariant is evaluated for any default-initialized object of the type associated with the aspect (see 7.3.2(10/4)).

(3) A Dynamic_Predicate can be evaluated for any default-initialized object of a type with a Default_Value (since the value is converted to the appropriate subtype, and that subtype can have a Dynamic_Predicate, see 3.3.1(11.1/5)). [Note: A Static_Predicate cannot evaluate anything that is not preelaborable.]

(4) A Dynamic_Predicate can be evaluated for any default-initialized object of a type with a Default_Component_Value (since the component value is converted to the appropriate subtype, see 3.3.1(13/5)). Case (3) can also happen for an array object (that also is mentioned in 3.3.1(13/5)).

(5) A Dynamic_Predicate can be evaluated for any component of a default-initialized object if the component has a default expression; again, the component is converted to the appropriate subtype, see 3.3.1(13/5).

None of these cases are covered by the current wording in 10.2.1. It might appear that case (5) is covered by 10.2.1(11.3/2), but it is not; that paragraph talks about the evaluation of the default expression; it does not say anything about the subtype conversion that happens afterward.

—-

Possible Solutions:

----

Note that the simple solution of not allowing a type that runs afoul of any of these cases to have Preelaborable_Initialization would make it impossible to have a preelaborable package that uses Default_Initial_Condition (D_I_C). A D_I_C is only allowed on a private type, and as such, any useful D_I_C necessarily has to make at least one function call to query the state of the object. So we need a more complex solution (perhaps singling out D_I_C for special rules).

!example

The Ada.Containers packages illustrate this issue nicely. Following is the specification of the Ada.Containers.Vectors package, showing just the parts relevant to this discussion:

generic
   ...
package Ada.Containers.Vectors
   with Preelaborate, ... is
   type Vector is tagged private
      with ...
           Default_Initial_Condition =>
              Length (Vector) = 0 and then ...,
           Preelaborable_Initialization;

The elaboration of a default-initialized Vector object will finish with the evaluation of the Default_Initial_Condition expression. That will call the function Length. However, that means that such an elaborable construct is not preelaborable by the rules given in 10.2.1(5, 7). Yet we are asserting that this construct is preelaborable by the use of the P_I aspect.

!ACATS test

*** TBD. We’ll need tests for whatever rule is adopted, but we need to decide on a rule before we can say what kind of tests are needed.

!appendix

This AI was promoted from AI12-0420-1, which was put into the Hold state as it was reported too late to find a solution in time to make the deadline for Ada 2022. This AI is associated with Github Issue #30 (https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues/30).

********************************************************************************

[a]This is the wording that Tucker is proposing. (For some reason, when I accepted the change, his comment to that effect disappeared, and if I don't accept the change, it doesn't appear in the exported file, thus not in the long-term version control.)

[b]I believe we should allow implementations to suppress or defer checks associated with D_I_C, Type_Invariants, and Predicates for types with P_I.  The definition of "preelaborable" should ignore the presence of D_I_C, Type_Invariants, and Predicates, and then an Implementation_Permission should permit suppressing or deferring the check.  I don't believe we should *require* that the checks be deferred or suppressed -- that seems to be something that could be left up to the compiler vendor in consultation with their user base.