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
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:
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
In these cases, the dereference has the view of T
visible at the
point of the dereference.
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 PtrT is access T;
private package P.C is
Ptr : PtrT;
-- Ptr.all'Size is not legal here, but we are within the scope
-- of a nonlimited_with_clause for P.
-- Ptr.all'Size is legal here.
This is implied by the next AARM-only
rule, plus the rules in 3.11.1
” which require a completion to appear later
and immediately within the same declarative region.
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.
denotes an incomplete view of a type may be used as follows:
We now allow discriminant_constraint
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
Ramification: But not in the profile
for a body or entry.
as a generic actual parameter whose corresponding generic formal parameter
is a formal incomplete type (see 12.5.1
If such a name
denotes a tagged incomplete view, it may also be used:
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.
No other uses of a name
that denotes an incomplete view of a type are allowed.
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.
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 prefix
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
'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.
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).
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.
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;
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
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.
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
Example of a recursive
type Cell; -- incomplete type declaration
type Link is access Cell;
type Cell is
Value : Integer;
Succ : Link;
Pred : Link;
Head : Link := new Cell'(0, null, null);
Next : Link := Head.Succ;
Examples of mutually dependent access types:
Person(<>); -- incomplete type declaration
Car is tagged
; -- incomplete type declaration
Person_Name is access
Car_Name is access all
Car is tagged
Number : Integer;
Owner : Person_Name;
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);
My_Car, Your_Car, Next_Car : Car_Name := new
Car; -- see 4.8
George : Person_Name := new
George.Vehicle := Your_Car;
Extensions to Ada 83
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
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 Pri is access Sep;
X : Pri;
package body Pack is -- Could be separately compiled!
type Sep is ...;
X := new Sep;
private package Pack.Child is
I : Integer := X.all'Size; -- Legal, by AI-00039.
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
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.
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
Extensions to Ada 95
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
Wording Changes from Ada 95
The description of incomplete types as incomplete views
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
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.
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.
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
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.
Incomplete types now can be used as actuals to formal incomplete types
Wording Changes from Ada 2012
Corrigndum: 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.
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
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe