Ada Conformity Assessment Authority      Home Conformity Assessment   Test Suite ARGAda Standard
Annotated Ada Reference Manual (Ada 2022)Legal Information
Contents   Index   References   Search   Previous   Next 

3.10.1 Incomplete Type Declarations

There are no particular limitations on the designated type of an access type. In particular, the type of a component of the designated type can be another access type, or even the same access type. This permits mutually dependent and recursive access types. An incomplete_type_declaration can be used to introduce a type to be used as a designated type, while deferring its full definition to a subsequent full_type_declaration.


{AI95-00326-01} incomplete_type_declaration ::= 
   type defining_identifier [discriminant_part] [is tagged];

Static Semantics

 {AI95-00326-01} {AI12-0137-1} An incomplete_type_declaration declares an incomplete view of a type and its first subtype; the first subtype is unconstrained if a discriminant_part appears. If the incomplete_type_declaration includes the reserved word tagged, it declares a tagged incomplete view. If T denotes a tagged incomplete view, then T'Class denotes a tagged incomplete view. [An incomplete view of a type is a limited view of the type (see 7.5).]
 {AI95-00326-01} Given an access type A whose designated type T is an incomplete view, a dereference of a value of type A also has this incomplete view except when: 
Discussion: {AI05-0208-1} Whether the designated type is an incomplete view (and thus whether this set of rules applies) is determined by the view of the type at the declaration of the access type; it does not change during the life of the type. 
it occurs within the immediate scope of the completion of T, or
{AI05-0208-1} it occurs within the scope of a nonlimited_with_clause that mentions a library package in whose visible part the completion of T is declared, or
{AI05-0208-1} it occurs within the scope of the completion of T and T is an incomplete view declared by an incomplete_type_declaration.
 {AI05-0162-1} In these cases, the dereference has the view of T visible at the point of the dereference. 
Discussion: We need the “in whose visible part” rule so that the second rule doesn't trigger in the body of a package with a with of a child unit: 
package P is
   type T;
   type PtrT is access T;
end P;
private package P.C is
   Ptr : PtrT;
end P.C;
{AI05-0005-1} with P.C;
package body P is
    -- Ptr.all'Size is not legal here, but we are within the scope
    -- of a nonlimited_with_clause for P.
type T is ...
    --  Ptr.all'Size is legal here.
end P;
 {AI95-00412-01} {AI05-0162-1} {AI05-0208-1} Similarly, if a subtype_mark denotes a subtype_declaration defining a subtype of an incomplete view T, the subtype_mark denotes an incomplete view except under the same three circumstances given above, in which case it denotes the view of T visible at the point of the subtype_mark.

Legality Rules

{AI05-0162-1} An incomplete_type_declaration requires a completion, which shall be a type_declaration other than an incomplete_type_declaration. [If the incomplete_type_declaration occurs immediately within either the visible part of a package_specification or a declarative_part, then the type_declaration shall occur later and immediately within this visible part or declarative_part. If the incomplete_type_declaration occurs immediately within the private part of a given package_specification, then the type_declaration shall occur later and immediately within either the private part itself, or the declarative_part of the corresponding package_body.]
Proof: This is implied by the next AARM-only rule, plus the rules in 3.11.1, “Completions of Declarations” which require a completion to appear later and immediately within the same declarative region. 
To be honest: If the incomplete_type_declaration occurs immediately within the visible part of a package_specification, then the completing type_declaration shall occur immediately within this visible part. 
To be honest: If the implementation supports it, an incomplete_type_declaration can be imported (using aspect Import, see B.1), in which case no explicit completion is allowed. 
{AI95-00326-01} {AI05-0162-1} If an incomplete_type_declaration includes the reserved word tagged, then a type_declaration that completes it shall declare a tagged type. If an incomplete_type_declaration has a known_discriminant_part, then a type_declaration that completes it shall have a fully conforming (explicit) known_discriminant_part (see 6.3.1). [If an incomplete_type_declaration has no discriminant_part (or an unknown_discriminant_part), then a corresponding type_declaration is nevertheless allowed to have discriminants, either explicitly, or inherited via derivation.]
{AI95-00326-01} A name that denotes an incomplete view of a type may be used as follows: 
{AI05-0098-1} as the subtype_mark in the subtype_indication of an access_to_object_definition; [the only form of constraint allowed in this subtype_indication is a discriminant_constraint [(a null_exclusion is not allowed)];] 
Implementation Note: We now allow discriminant_constraints even if the full type is deferred to the package body. However, there is no particular implementation burden because we have dropped the concept of the dependent compatibility check. In other words, we have effectively repealed AI83-00007. 
{AI95-00326-01} {AI95-00412-01} as the subtype_mark in the subtype_indication of a subtype_declaration; the subtype_indication shall not have a null_exclusion or a constraint;
{AI95-00326-01} {AI05-0151-1} as the subtype_mark in an access_definition for an access-to-object type; 
To be honest: This does not mean any random subtype_mark in a construct that makes up an access_definition, such as a formal_part, just the one given directly in the syntax of access_definition.
{AI05-0151-1} as the subtype_mark defining the subtype of a parameter or result in a profile occurring within a basic_declaration;
Ramification: But not in the profile for a body or entry. 
{AI05-0213-1} as a generic actual parameter whose corresponding generic formal parameter is a formal incomplete type (see 12.5.1).
 {AI95-00326-01} If such a name denotes a tagged incomplete view, it may also be used:
{AI95-00326-01} {AI05-0151-1} as the subtype_mark defining the subtype of a parameter in the profile for a subprogram_body, entry_body, or accept_statement;
{AI95-00326-01} as the prefix of an attribute_reference whose attribute_designator is Class; such an attribute_reference is restricted to the uses allowed here; it denotes a tagged incomplete view. 
This paragraph was deleted.{AI95-00326-01}
 This paragraph was deleted.{AI95-00326-01} {AI05-0151-1}
This paragraph was deleted.{AI95-00326-01} {AI05-0098-1} {AI05-0151-1}
This paragraph was deleted.
 {AI95-00326-01} If any of the above uses occurs as part of the declaration of a primitive subprogram of the incomplete view, and the declaration occurs immediately within the private part of a package, then the completion of the incomplete view shall also occur immediately within the private part; it shall not be deferred to the package body. 
Reason: This fixes a hole in Ada 95 where a dispatching operation with an access parameter could be declared in a private part and a dispatching call on it could occur in a child even though there is no visibility on the full type, requiring access to the controlling tag without access to the representation of the type. 
 {AI95-00326-01} No other uses of a name that denotes an incomplete view of a type are allowed.
{AI95-00326-01} {AI05-0151-1} A prefix that denotes an object shall not be of an incomplete view. An actual parameter in a call shall not be of an untagged incomplete view. The result object of a function call shall not be of an incomplete view. A prefix shall not denote a subprogram having a formal parameter of an untagged incomplete view, nor a return type that is an incomplete view. 
Reason: We used to disallow all dereferences of an incomplete type. Now we only disallow such dereferences when used as a prefix. Dereferences used in other contexts do not pose a problem since normal type matching will preclude their use except when the full type is “nearby” as context (for example, as the expected type).
This also disallows prefixes that are directly of an incomplete view. For instance, a parameter P can be declared of a tagged incomplete type, but we don't want to allow P'Size, P'Alignment, or the like, as representation values aren't known for an incomplete view.
We say “denotes an object” so that prefixes that directly name an incomplete view are not covered; the previous rules cover such cases, and we certainly don't want to ban Incomp'Class.
{AI05-0151-1} As subprogram profiles now may include any kind of incomplete type, we also disallow passing objects of untagged incomplete types in subprogram calls (as the parameter passing method is not known as it is for tagged types) and disallow returning any sort of incomplete objects (since we don't know how big they are). 
  {AI12-0155-1} The controlling operand or controlling result of a dispatching call shall not be of an incomplete view if the operand or result is dynamically tagged.
Reason: This rule is needed to prevent the following case:
package Pack is
   type T is tagged;
   function F return access T'Class;
   function G (X : access T) return Integer;
   I : Integer := G (F);                 -- Illegal by above rule.
   type T is tagged null record;
end Pack;
If this was not illegal, the compiler would have to generate a dispatching call on G without necessarily knowing where the tag of type T is stored (the completion of T might not be until the body of Pack). The fact that any such call will raise Program_Error does not absolve us of detecting the problem; see the Language Design Principles in 13.14. 
Paragraph 11 was deleted. 

Dynamic Semantics

The elaboration of an incomplete_type_declaration has no effect. 
Reason: An incomplete type has no real existence, so it doesn't need to be "created" in the usual sense we do for other types. It is roughly equivalent to a "forward;" declaration in Pascal. Private types are different, because they have a different set of characteristics from their full type. 
NOTE 1   {AI12-0447-1} Within a declarative_part, an incomplete_type_declaration and a corresponding full_type_declaration cannot be separated by an intervening body. This is because, by the rules given in 13.14, a type is illegal if it is not has to be completely defined before it is frozen, and a body freezes all types declared prior to it in the same declarative_part (see 13.14).
NOTE 2   {AI05-0151-1} {AI05-0269-1} A name that denotes an object of an incomplete view is defined to be of a limited type. Hence, the target of an assignment statement cannot be of an incomplete view.


Example of a recursive type: 
type Cell;  --  incomplete type declaration
type Link is access Cell;
type Cell is
      Value  : Integer;
      Succ   : Link;
      Pred   : Link;
   end record;
Head   : Link  := new Cell'(0, nullnull);
Next   : Link  := Head.Succ;
Examples of mutually dependent access types:
{AI95-00433-01} type Person(<>);    -- incomplete type declaration
type Car is tagged; -- incomplete type declaration
{AI95-00433-01} type Person_Name is access Person;
type Car_Name    is access all Car'Class;
{AI95-00433-01} type Car is tagged
      Number  : Integer;
      Owner   : Person_Name;
   end record;
type Person(Sex : Gender) is
      Name     : String(1 .. 20);
      Birth    : Date;
      Age      : Integer range 0 .. 130;
      Vehicle  : Car_Name;
      case Sex is
         when M => Wife           : Person_Name(Sex => F);
         when F => Husband        : Person_Name(Sex => M);
      end case;
   end record;
{AI12-0312-1} My_Car, Your_Car, Next_Car : Car_Name := new Car;  -- see 4.8
Casey George : Person_Name := new Person(M);
Casey George.Vehicle := Your_Car;

Extensions to Ada 83

The full_type_declaration that completes an incomplete_type_declaration may have a known_discriminant_part even if the incomplete_type_declaration does not.
A discriminant_constraint may be applied to an incomplete type, even if its completion is deferred to the package body, because there is no “dependent compatibility check” required any more. Of course, the constraint can be specified only if a known_discriminant_part was given in the incomplete_type_declaration. As mentioned in the previous paragraph, that is no longer required even when the full type has discriminants. 

Wording Changes from Ada 83

Dereferences producing incomplete types were not explicitly disallowed in RM83, though AI83-00039 indicated that it was not strictly necessary since troublesome cases would result in Constraint_Error at run time, since the access value would necessarily be null. However, this introduces an undesirable implementation burden, as illustrated by Example 4 of AI83-00039: 
package Pack is
    type Pri is private;
    type Sep;
    type Pri is access Sep;
    X : Pri;
end Pack;
package body Pack is -- Could be separately compiled!
    type Sep is ...;
    X := new Sep;
end Pack;
pragma Elaborate(Pack);
private package Pack.Child is
    I : Integer := X.all'Size; -- Legal, by AI-00039.
end Pack.Child;
Generating code for the above example could be a serious implementation burden, since it would require all aliased objects to store size dope, and for that dope to be in the same format for all kinds of types (or some other equivalently inefficient implementation). On the contrary, most implementations allocate dope differently (or not at all) for different designated subtypes. 

Incompatibilities With Ada 95

{AI95-00326-01} It is now illegal to use an incomplete view (type) as the parameter or result of an access-to-subprogram type unless the incomplete view is completed in the same declaration list as the use. This was allowed in Ada 95 for incomplete types where the completion was deferred to the body. By disallowing this rare use of incomplete views, we can allow the use of incomplete views in many more places, which is especially valuable for limited views.
{AI95-00326-01} It is now illegal to use an incomplete view (type) in a primitive subprogram of the type unless the incomplete view is completed in the package specification. This was allowed in Ada 95 for incomplete types where the completion was deferred to the body (the use would have to be in an access parameter). This incompatibility was caused by the fix for the hole noted in Legality Rules above. 

Extensions to Ada 95

{AI95-00326-01} Tagged incomplete types are new. They are allowed in parameter declarations as well as the usual places, as tagged types are always by-reference types (and thus there can be no code generation issue).
{AI95-00412-01} A subtype_declaration can be used to give a new name to an incomplete view of a type. This is valuable to give shorter names to entities imported with a limited_with_clause.

Wording Changes from Ada 95

{AI95-00326-01} The description of incomplete types as incomplete views is new. Ada 95 defined these as separate types, but neglected to give any rules for matching them with other types. Luckily, implementers did the right thing anyway. This change also makes it easier to describe the meaning of a limited view. 

Extensions to Ada 2005

{AI05-0098-1} Correction: Fixed the definition so that an anonymous access-to-subprogram type can use an incomplete view in the same way that a named access-to-subprogram type can.
{AI05-0151-1} Incomplete types now can be used in subprogram declarations. The type has to be complete before any calls or the body is declared. This reduces the places where access types are required for types imported from limited views of packages.
{AI05-0162-1} Incomplete types now can be completed by private types and private extensions. Since this can already happen for limited views, there is no remaining reason to disallow it for explicitly declared incomplete types. 

Wording Changes from Ada 2005

{AI05-0208-1} Correction: Changed the rules of uses of dereferences of incomplete views such that it does not introduce an unintentional incompatibility with Ada 83 and Ada 95.
{AI05-0213-1} Incomplete types now can be used as actuals to formal incomplete types (see 12.5.1). 

Wording Changes from Ada 2012

{AI12-0137-1} {AI12-0005-1} Corrigendum: Changed the wording to clarify that the class-wide type associated with a specific tagged type that has an incomplete view is also an incomplete view. While this was previously undefined, an interpretation where it is not an incomplete view is leads to semantic nonsense, and thus we don't consider this a potential incompatibility, as compilers most likely are doing the right thing.
{AI12-0155-1} Correction: Added a rule preventing a dispatching call on an incomplete type before the completion. This is not an incompatibility as previously this was prevented by the freezing rules. However, that violated the intended design of the freezing rules, so we've now changed to an explicit Legality Rule here, and eliminated the associated freezing rules. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe