[The evaluation of an allocator
creates an object and yields an access value that designates the object.
Such an uninitialized allocator
would necessarily raise Constraint_Error, as the default value is null
Also note that the syntax does not allow a null_exclusion
in an initialized allocator
so it makes sense to make the uninitialized case illegal as well.
Name Resolution Rules
Ramification: For example, ... new
S'Class ... (with no initialization expression) is illegal, but ... new
S'Class'(X) ... is legal, and takes its tag and constraints from the
initial value X. (Note that the former case cannot have a constraint.)
Reason: This prevents the allocated object
from outliving its type.
Reason: This prevents the allocated object
from outliving its discriminants.
for an access type that has Storage_Size specified to be zero is required
to raise Storage_Error anyway. It's better to detect the error at compile-time,
as the allocator
might be executed infrequently. This also simplifies the rules for Pure
units, where we do not want to allow any allocators for library-level
access types, as they would represent state.
We don't need a special rule to cover generic formals (unlike many other
similar Legality Rules). There are only two cases of interest. For formal
access types, the Storage_Size property is not known in the generic,
and surely isn't static, so this Legality Rule can never apply. For a
formal derived type, this Legality Rule can only be triggered by a parent
type having one of the appropriate properties. But Storage_Size can never
be specified for a derived access type, so it always has the same value
for all child types; additionally, a type derived from a remote access
type (which has Storage_Size defined to be zero) is also a remote access
type. That means that any actual that would match the formal derived
type necessarily has the same Storage_Size properties, so it is harmless
(and preferable) to check them in the body - they are always known in
that case. For other formal types,allocator
are not allowed, so we don't need to consider them. So we don't need
an assume-the-best rule here.
If the designated type of the type of the allocator
is limited, then the allocator
shall not be used to define the value of an access discriminant, unless
the discriminated type is immutably limited (see 7.5
Because coextensions work very
much like parts, we don't want users creating limited coextensions for
nonlimited types. This would be similar to extending a nonlimited type
with a limited component. We check this on the allocator
Note that there is an asymmetry in what types are considered limited;
this is required to preserve privacy. We have to assume that the designated
type might be limited as soon as we see a limited partial view, but we
want to ensure that the containing object is of a type that is always
In addition to the places where Legality Rules normally
apply (see 12.3
), these rules apply also in
the private part of an instance of a generic unit.
Discussion: This applies to all of the
Legality Rules of this subclause.
If the designated type of the type of the allocator
is elementary, then the subtype of the created object is the designated
subtype. If the designated type is composite, then the subtype of the
created object is the designated subtype when the designated subtype
is constrained or there is an ancestor of the designated type that has
a constrained partial view; otherwise, the created object is constrained
by its initial value [(even if the designated subtype is unconstrained
Discussion: See AI83-00331.
All objects created by an allocator
are aliased, and most aliased composite objects need to be constrained
so that access subtypes work reasonably. Problematic access subtypes
are prohibited for types with a constrained partial view.
If there is a constrained partial view of the type, this allows the objects
to be unconstrained. This eliminates privacy breaking (we don't want
the objects to act differently simply because they're allocated). Such
a created object is effectively constrained by its initial value if the
access type is an access-to-constant type, or the designated type is
limited (in all views), but we don't need to state that here. It is implicit
in other rules. Note, however, that a value of an access-to-constant
type can designate a variable object via 'Access or conversion, and the
variable object might be assigned by some other access path, and that
assignment might alter the discriminants.
For the evaluation of an initialized allocator, the
evaluation of the qualified_expression
is performed first.
of the designated type is created and the value of the qualified_expression
is converted to the designated subtype and assigned to the object.
Ramification: The conversion might raise
For the evaluation of an uninitialized
allocator, the elaboration of the subtype_indication
is performed first. Then:
If the designated type is elementary, an object of
the designated subtype is created and any implicit initial value is assigned;
If the designated type is composite, an object of the designated type
is created with tag, if any, determined by the subtype_mark
of the subtype_indication
This object is then initialized by default (see 3.3.1
using the subtype_indication
to determine its nominal subtype.
check is made that the value of the object belongs to the designated
Constraint_Error is raised if this check
fails. This check and the initialization of the object are performed
in an arbitrary order.
The master check on class-wide types prevents the allocated object from
outliving its type. We need the run-time check in instance bodies, or
when the type of the qualified_expression
is class-wide (other cases are statically detected).
We can't use the normal accessibility level “deeper than”
check here because we may have “incomparable” levels if the
appropriate master and the type declaration belong to two different tasks.
This can happen when checking the master of the tag for an allocator
initialized by a parameter passed in to an accept statement, if the type
of the allocator is an access type declared in the enclosing task body.
task body TT is
type Acc_TC is access T'Class;
P : Acc_TC;
accept E(X : T'Class) do
P := new T'Class'(X);
-- Master check on tag of X.
-- Can't use "accessibility levels" since they might be incomparable.
-- Must revert to checking that the master of the type identified by
-- X'tag includes the elaboration of Acc_TC, so it is sure to outlive it.
The accessibility check on access discriminants prevents the allocated
object from outliving its discriminants.
If the object to be created by an allocator
has a controlled or protected part, and the finalization of the collection
of the type of the allocator
) has started, Program_Error is
Reason: If the object has a controlled
or protected part, its finalization is likely to be nontrivial. If the
allocation was allowed, we could not know whether the finalization would
actually be performed. That would be dangerous to otherwise safe abstractions,
so we mandate a check here. On the other hand, if the finalization of
the object will be trivial, we do not require (but allow) the check,
as no real harm could come from late allocation.
This check can only fail
if an allocator
is evaluated in code reached from a Finalize routine for a type declared
in the same master. That's highly unlikely; Finalize routines are much
more likely to be deallocating objects than allocating them.
If the object to be created by an allocator
contains any tasks, and the master of the type of the allocator
is completed, and all of the dependent tasks of the master are terminated
), then Program_Error is raised.
Reason: A task created after waiting
for tasks has finished could depend on freed data structures, and certainly
would never be awaited.
If the allocator
includes a subpool_handle_name
Constraint_Error is raised if the subpool handle is null
is raised if the subpool does not belong
to the storage pool of the access type of the allocator
Implementation Note: This can be implemented
by comparing the result of Pool_of_Subpool to a reference to the storage
pool object. Pool_of_Subpool's parameter is not null, so the check
for null falls out naturally.
Reason: This detects cases where the
subpool belongs to another pool, or to no pool at all. This includes
detecting dangling subpool handles so long as the subpool object (the
object designated by the handle) still exists. (If the subpool object
has been deallocated, execution is erroneous; it is likely that this
check will still detect the problem, but there cannot be a guarantee.)
[If the created object contains any tasks, they are
activated (see 9.2
).] Finally, an access value
that designates the created object is returned.
Bounded (Run-Time) Errors
It is a bounded error if the finalization of the
collection of the type (see 7.6.1
) of the
has started. If the error is detected, Program_Error is raised. Otherwise,
the allocation proceeds normally.
Discussion: This check is required in
some cases; see above.
24 Allocators cannot create objects of
an abstract type. See 3.9.3
25 If any part of the created object is
controlled, the initialization includes calls on corresponding Initialize
or Adjust procedures. See 7.6
26 As explained in 13.11
”, the storage
for an object allocated by an allocator
comes from a storage pool (possibly user defined).
exception Storage_Error is raised by an allocator
if there is not enough storage. Instances of Unchecked_Deallocation may
be used to explicitly reclaim storage.
Implementations are permitted, but not required, to provide garbage collection.
Discussion: By default, the implementation
provides the storage pool. The user may exercise more control over storage
management by associating a user-defined pool with an access type.
Examples of allocators:
) -- initialized explicitly, see 3.10.1
Cell'(Value => 0, Succ => null
, Pred => null
) -- initialized explicitly
Cell -- not initialized
new Matrix(1 .. 10, 1 .. 20) -- the bounds only are given
new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- initialized explicitly
new Buffer(100) -- the discriminant only is given
new Buffer'(Size => 80, Pos => 0, Value => (1 .. 80 => 'A')) -- initialized explicitly
Literal) -- allocator for access-to-class-wide type, see 3.9.1
3.5)) -- initialized explicitly
Incompatibilities With Ada 83
of an uninitialized allocator may not have an explicit constraint
if the designated type is an access type. In Ada 83, this was permitted
even though the constraint
had no effect on the subtype of the created object.
Extensions to Ada 83
Allocators creating objects
of type T
are now overloaded on access types designating T'
and all class-wide types that cover T
Implicit array subtype conversion (sliding)
is now performed as part of an initialized allocator.
Wording Changes from Ada 83
We have used a new organization, inspired by
the ACID document, that makes it clearer what is the subtype of the created
object, and what subtype conversions take place.
Discussion of storage management issues, such
as garbage collection and the raising of Storage_Error, has been moved
Inconsistencies With Ada 95
If the designated type has a constrained partial
view, the allocated object can be unconstrained. This might cause the
object to take up a different amount of memory, and might cause the operations
to work where they previously would have raised Constraint_Error. It's
unlikely that the latter would actually matter in a real program (Constraint_Error
usually indicates a bug that would be fixed, not left in a program.)
The former might cause Storage_Error to be raised at a different time
than in an Ada 95 program.
Incompatibilities With Ada 95
for an access type that has Storage_Size specified to be zero is now
illegal. Ada 95 allowed the allocator
but it had to raise Storage_Error if executed. The primary impact of
this change should be to detect bugs.
Extensions to Ada 95
Wording Changes from Ada 95
Clarified the elaboration of per-object constraints
for an uninitialized allocator.
Program_Error is now raised if the allocator
occurs after the finalization of the collection or the waiting for tasks.
This is not listed as an incompatibility as the Ada 95 behavior was unspecified,
and Ada 95 implementations tend to generate programs that crash in this
Added accessibility checks to class-wide allocator
These checks could not fail in Ada 95 (as all of the designated types
had to be declared at the same level, so the access type would necessarily
have been at the same level or more nested than the type of allocated
Revised the description of evaluation of uninitialized allocators to
use “initialized by default” so that the ordering requirements
are the same for all kinds of objects that are default-initialized.
Added accessibility checks to access discriminants of allocator
These checks could not fail in Ada 95 as the discriminants always have
the accessibility of the object.
Incompatibilities With Ada 2005
Added a rule to prevent limited
coextensions of nonlimited types. Allowing this would have far-reaching
implementation costs. Because of those costs, it seems unlikely that
any implementation ever supported it properly and thus it is unlikely
that any existing code depends on this capability.
Added a rule to make null_exclusion
illegal for uninitialized allocator
as such an allocator
would always raise Constraint_Error. Programs that depend on the unconditional
raising of a predefined exception should be very rare.
Extensions to Ada 2005
Wording Changes from Ada 2005
Corrected the master check for tags since the masters
may be for different tasks and thus incomparable.
Corrected the rules for when a designated object is
constrained by its initial value so that types derived from a partial
view are handled properly.
Corrected the accessibility check for access discriminants
so that it does not depend on the designated type (which might not have
discriminants when the allocated type does).
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe