4.8 Allocators
1
[The evaluation of an
allocator
creates an object and yields an access value that designates the object.
]
Syntax
2/3
2.1/3
2.2/3
2.a/3
Reason: 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
3/3
{
8652/0010}
{
AI95-00127-01}
{
AI05-0111-3}
The expected type for an
allocator
shall be a single access-to-object type
with whose
designated type
D such that either D
covers the type determined by the
subtype_mark
of the
subtype_indication
or
qualified_expression,
or the expected type is anonymous and the determined type is D'Class.
A subpool_handle_name
is expected to be of any type descended from Subpool_Handle, the type
used to identify a subpool, declared in package System.Storage_Pools.Subpools
(see 13.11.4).
3.a
3.a.1/1
Legality Rules
4
4.a
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.)
5/2
{
AI95-00287-01}
If the type of the
allocator
is an access-to-constant type, the
allocator
shall be an initialized allocator.
If the designated
type is limited, the allocator
shall be an uninitialized allocator.
5.a/2
This paragraph
was deleted.Ramification: {
AI95-00287-01}
For an access-to-constant type whose designated
type is limited, allocators
are illegal. The Access attribute is legal for such a type, however.
5.1/3
5.2/3
5.b/2
Reason: This prevents
the allocated object from outliving its type.
5.3/3
5.c/2
Reason: This prevents
the allocated object from outliving its discriminants.
5.4/3
{
AI95-00366-01}
{
AI05-0052-1}
{
AI05-0157-1}
An allocator
shall not be of an access type for which the Storage_Size has been specified
by a static expression with value zero or is defined by the language
to be zero. In
addition to the places where Legality Rules normally apply (see 12.3),
this rule applies also in the private part of an instance of a generic
unit. This rule does not apply in the body of a generic unit or within
a body declared within the declarative region of a generic unit, if the
type of the allocator is a descendant of a formal access type declared
within the formal part of the generic unit.
5.d/2
Reason: An allocator
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.
5.e/3
{
AI05-0157-1}
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,allocators
are not allowed, so we don't need to consider them. So we don't need
an assume-the-best rule here. The
last sentence covers the case of children of generics, and formal access
types of formal packages of the generic unit.
5.5/3
{
AI05-0052-1}
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).
5.f/3
Reason: 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
limited.
5.6/3
{
AI05-0052-1}
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.
5.g/3
Discussion: This
applies to all of the Legality Rules of this clause.
Static Semantics
6/3
{
AI95-00363-01}
{
AI05-0041-1}
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 a partial view of the
designated type that is constrained;
otherwise, the created always constrained;
if the designated subtype is constrained, then it provides the constraint
of the created object; otherwise, the object is constrained by
its initial value [(even if the designated subtype is unconstrained with
defaults)].
6.a
Discussion: See AI83-00331.
6.b/2
Reason: {
AI95-00363-01}
All objects created by an
allocator allocator
are aliased, and
most all
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.
6.c/2
Discussion: {
AI95-00363-01}
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.
Dynamic Semantics
7/2
7.a
Ramification: The conversion might raise
Constraint_Error.
8
For the evaluation of an uninitialized
allocator
, the elaboration of the subtype_indication
is performed first. Then:
9/2
{
AI95-00373-01}
If the designated type is elementary, an object of
the designated subtype is created and any implicit initial value is assigned;
10/2
{
8652/0002}
{
AI95-00171-01}
{
AI95-00373-01}
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; any per-object constraints on subcomponents
are elaborated (see
3.8) and
any implicit initial values for the subcomponents of the object are obtained
as determined by the
subtype_indication
to determine its nominal subtype and
assigned to the corresponding subcomponents.
A
check is made that the value of the object belongs to the designated
subtype.
Constraint_Error is raised if this check
fails. This check and the initialization of the object are performed
in an arbitrary order.
10.a
Discussion: AI83-00150.
10.1/3
10.b/3
Reason: {
AI95-00344-01}
{
AI05-0024-1}
The master accessibility
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).
10.b.1/3
{
AI05-0024-1}
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. For example:
10.b.2/3
task body TT is
type Acc_TC is access T'Class;
P : Acc_TC;
begin
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.
end E;
10.c/2
{
AI95-00416-01}
The accessibility check on access discriminants
prevents the allocated object from outliving its discriminants.
10.2/2
{
AI95-00280-01}
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
(see 7.6.1) has started, Program_Error is
raised.
10.d/2
Reason: If the
object has a controlled or protected part, its finalization is likely
to be non-trivial. 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.
10.e/2
Discussion: 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.
10.3/2
{
AI95-00280-01}
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
(see 9.3), then Program_Error is raised.
10.f/2
Reason: A task
created after waiting for tasks has finished could depend on freed data
structures, and certainly would never be awaited.
10.4/3
{
AI05-0111-3}
If the allocator
includes a subpool_handle_name,
Constraint_Error is raised if the subpool handle is null. Program_Error
is raised if the subpool does not belong (see 13.11.4)
to the storage pool of the access type of the allocator.
10.g/3
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.
10.h/3
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.)
11
[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
11.1/2
{
AI95-00280-01}
It is a bounded error if the
finalization of the collection of the type (see 7.6.1)
of the allocator
has started. If the error is detected, Program_Error is raised. Otherwise,
the allocation proceeds normally.
11.a/2
Discussion: This
check is required in some cases; see above.
12
24 Allocators cannot create objects of
an abstract type. See
3.9.3.
13
25 If any part of the created object is
controlled, the initialization includes calls on corresponding Initialize
or Adjust procedures. See
7.6.
14
26 As explained in
13.11,
“
Storage Management”, the storage
for an object allocated by an
allocator
comes from a storage pool (possibly user defined).
The
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.
15/3
27 {
AI05-0229-1}
Implementations are permitted, but not required, to provide garbage collection
(see 13.11.3).
15.a
15.b
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
16
Examples of allocators:
17
new Cell'(0,
null,
null)
-- initialized explicitly, see 3.10.1
new Cell'(Value => 0, Succ =>
null, Pred =>
null)
-- initialized explicitly
new Cell
-- not initialized
18
new Matrix(1 .. 10, 1 .. 20) -- the bounds only are given
new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- initialized explicitly
19
new Buffer(100) -- the discriminant only is given
new Buffer'(Size => 80, Pos => 0, Value => (1 .. 80 => 'A')) -- initialized explicitly
20
Expr_Ptr'(
new Literal)
-- allocator for access-to-class-wide type, see 3.9.1
Expr_Ptr'(
new Literal'(Expression
with 3.5))
-- initialized explicitly
Incompatibilities With Ada 83
20.a/1
The
subtype_indication
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
e affect
on the subtype of the created object.
Extensions to Ada 83
20.b
Allocators creating objects
of type
T are now overloaded on access types designating
T'Class
and all class-wide types that cover
T.
20.c
Implicit array subtype conversion (sliding)
is now performed as part of an initialized allocator.
Wording Changes from Ada 83
20.d
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.
20.e
Discussion of storage management issues, such
as garbage collection and the raising of Storage_Error, has been moved
to
13.11, “
Storage
Management”.
Inconsistencies With Ada 95
20.f/2
{
AI95-00363-01}
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
20.g/2
{
AI95-00366-01}
An allocator
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
20.h/2
20.i/2
Wording Changes from Ada 95
20.j/2
{
8652/0002}
{
AI95-00171-01}
Corrigendum: Clarified the elaboration of
per-object constraints for an uninitialized allocator.
20.k/2
{
AI95-00280-01}
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
case.
20.l/2
{
AI95-00344-01}
Added accessibility checks to class-wide allocators.
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
object).
20.m/2
{
AI95-00373-01}
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.
20.n/2
{
AI95-00416-01}
Added accessibility checks to access discriminants
of allocators.
These checks could not fail in Ada 95 as the discriminants always have
the accessibility of the object.
Incompatibilities With Ada 2005
20.o/3
{
AI05-0052-1}
Correction: 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.
20.p/3
{
AI05-0104-1}
Correction: Added a rule to make null_exclusions
illegal for uninitialized allocators,
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
20.q/3
Wording Changes from Ada 2005
20.r/3
{
AI05-0024-1}
Correction: Corrected the master check for
tags since the masters may be for different tasks and thus incomparable.
20.s/3
{
AI05-0041-1}
Correction: 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.
20.t/3
{
AI05-0051-1}
{
AI05-0234-1}
Correction: 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