3.10.2 Operations of Access Types
1
[The attribute Access is used to create access values
designating aliased objects and non-intrinsic subprograms. The “accessibility”
rules prevent dangling references (in the absence of uses of certain
unchecked features — see Section 13).]
Language Design Principles
1.a
It should be possible for an access value to
designate an object declared by an object declaration, or a subcomponent
thereof. In implementation terms, this means pointing at stack-allocated
and statically allocated data structures. However, dangling references
should be prevented, primarily via compile-time rules, so long as features
like Unchecked_Access and Unchecked_Deallocation are not used.
1.b
In order to create such access values, we require
that the access type be a general access type, that the designated object
be aliased, and that the accessibility rules be obeyed.
Name Resolution Rules
2/2
{
AI95-00235-01}
{expected type (access attribute_reference)
[partial]} For an
attribute_reference
with
attribute_designator Access (or Unchecked_Access
— see
13.10), the expected type shall
be a single access type
A such that: [;
the prefix of such an attribute_reference
is never interpreted as an implicit_dereference].
{expected profile (Access attribute_reference
prefix) [partial]} If the expected type
is an access-to-subprogram type, then the expected profile of the prefix
is the designated profile of the access type.
2.1/2
- {AI95-00235-01}
A is an access-to-object type with designated
type D and the type of the prefix is
D'Class or is covered by D, or
2.2/2
- {AI95-00235-01}
A is an access-to-subprogram type whose
designated profile is type conformant with that of the prefix.
2.3/2
{
AI95-00235-01}
[The prefix of such
an attribute_reference is never interpreted
as an implicit_dereference or a parameterless
function_call (see 4.1.4).]
{expected profile (Access attribute_reference
prefix) [partial]} {expected
type (Access attribute_reference prefix) [partial]} The
designated type or profile of the expected type of the attribute_reference
is the expected type or profile for the prefix.
2.a
Discussion: Saying that the expected
type shall be a "single access type" is our "new"
way of saying that the type has to be determinable from context using
only the fact that it is an access type. See
4.2
and
8.6. Specifying the expected profile only
implies type conformance. The more stringent subtype conformance is required
by a Legality Rule. This is the only Resolution Rule that applies to
the
name in a
prefix
of an
attribute_reference. In all other cases,
the
name has to be resolved without using
context. See
4.1.4.
2.b/2
{
AI95-00235-01}
Saying “single access type” is a bit
of a fudge. Both the context and the prefix
may provide both multiple types; “single” only means that
a single, specific interpretation must remain after resolution. We say
“single” here to trigger the Legality Rules of 8.6.
The resolution of an access attribute is similar to that of an assignment_statement.
For example:
2.c/2
type Int_Ptr is access all Integer;
type Char_Ptr is access all Character;
type Float_Ptr is access all Float;
2.d/2
function Zap (Val : Int_Ptr) return Float; -- (1)
function Zap (Val : Float_Ptr) return Float; -- (2)
function Zop return Int_Ptr; -- (3)
function Zop return Char_Ptr; -- (4)
2.e/2
Result : Float := Zap (Zop.all'Access); -- Resolves to Zap (1) and Zop (3).
Static Semantics
3/2
{
AI95-00162-01}
{accessibility level} {level
(accessibility)} {deeper
(accessibility level)} {depth
(accessibility level)} {dangling
references (prevention via accessibility rules)} {lifetime}
[The accessibility rules, which prevent dangling
references, are written in terms of
accessibility levels, which
reflect the run-time nesting of
masters. As explained in
7.6.1,
a master is the execution of a
certain construct,
such as,task_body,
a block_statement, a
subprogram_body,
an entry_body, or an accept_statement.
An accessibility level is
deeper than another if it is more deeply
nested at run time. For example, an object declared local to a called
subprogram has a deeper accessibility level than an object declared local
to the calling subprogram. The accessibility rules for access types require
that the accessibility level of an object designated by an access value
be no deeper than that of the access type. This ensures that the object
will live at least as long as the access type, which in turn ensures
that the access value cannot later designate an object that no longer
exists. The Unchecked_Access attribute may be used to circumvent the
accessibility rules.]
4
{statically deeper}
{deeper (statically)}
[A given accessibility level is said to be
statically
deeper than another if the given level is known at compile time (as
defined below) to be deeper than the other for all possible executions.
In most cases, accessibility is enforced at compile time by Legality
Rules. Run-time accessibility checks are also used, since the Legality
Rules do not cover certain cases involving access parameters and generic
packages.]
5
Each master, and each
entity and view created by it, has an accessibility level:
6
- The accessibility level of a given
master is deeper than that of each dynamically enclosing master, and
deeper than that of each master upon which the task executing the given
master directly depends (see 9.3).
7/2
- {AI95-00162-01}
{AI95-00416-01}
An entity or view defined created
by a declaration and created as part of its elaboration
has the same accessibility level as the innermost enclosing
master of the declaration except
in the cases of renaming and derived access types described below. A
parameter of a master has the same accessibility level as the master.
7.a/2
Reason: {
AI95-00416-01}
This rule defines the “normal” accessibility
of entities. In the absence of special rules below, we intend for this
rule to apply.
7.b/2
Discussion: {
AI95-00416-01}
This rule defines the accessibility of all named
access types, as well as the accessibility level of all anonymous access
types other than those for access parameters and access discriminants.
Special rules exist for the accessibility level of such anonymous types.
Components, stand-alone objects, and function results whose (anonymous)
type is defined by an access_definition have
accessibility levels corresponding to named access types defined at the
same point.
7.c/2
Ramification: {
AI95-00230-01}
Because accessibility level is determined by where
the access_definition is elaborated, for a
type extension, the anonymous access types of components (other than
access discriminants) inherited from the parent have the same accessibility
as they did in the parent; those in the extension part have the accessibility
determined by the scope where the type extension is declared. Similarly,
the types of the non-discriminant access components of a derived untagged
type have the same accessibility as they did in the parent.
8
- The accessibility level of a view
of an object or subprogram defined by a renaming_declaration
is the same as that of the renamed view.
9/2
- {AI95-00416-01}
The accessibility level of a view conversion, qualified_expression,
or parenthesized expression, is the same as that of the operand.
10/2
- {AI95-00318-02}
{AI95-00416-01}
The For a function
whose result type is a return-by-reference type, the accessibility level
of the result object is the same as that of the master that elaborated
the function body. For any other function, the accessibility level
of an aggregate or the
result of a function call [(or equivalent use of
an operator)] that is used (in its entirety) to directly initialize part
of an object is that of the object being
initialized. In other contexts, the accessibility level of an aggregate
or the result of a function call is that of the innermost master that
evaluates the aggregate or execution
of the called function call.
10.a/2
To be honest: {
AI95-00416-01}
The first sentence is talking about a static use
of the entire return object - a slice that happens to be the entire return
object doesn't count. On the other hand, this is intended to allow parentheses
and qualified_expressions.
10.b/2
Ramification: {
AI95-00416-01}
If the function is used as a prefix,
the second sentence applies. Similarly, an assignment_statement
is not an initialization of an object, so the second sentence applies.
10.c
The “innermost master
which evaluated the function call” does not include the function
call itself (which might be a master).
10.d
We really mean the innermost
master here, which could be a very short lifetime. Consider a function
call used as a parameter of a procedure call. In this case the innermost
master which evaluated the function call is the procedure call.
10.1/2
- {AI95-00416-01}
Within a return statement, the accessibility level
of the return object is that of the execution of the return statement.
If the return statement completes normally by returning from the function,
then prior to leaving the function, the accessibility level of the return
object changes to be a level determined by the point of call, as does
the level of any coextensions (see below) of the return object.
10.d.1/2
Reason: We define
the accessibility level of the return object during the return statement
to be that of the return statement itself so that the object may be designated
by objects local to the return statement, but not by objects outside
the return statement. In addition, the intent is that the return object
gets finalized if the return statement ends without actually returning
(for example, due to propagating an exception, or a goto). For a normal
return, of course, no finalization is done before returning.
11
- The accessibility level of a derived
access type is the same as that of its ultimate ancestor.
11.1/2
- {AI95-00230-01}
The accessibility level of the anonymous access
type defined by an access_definition of an
object_renaming_declaration is the same as
that of the renamed view.
12/2
- {AI95-00230-01}
{AI95-00416-01}
The accessibility level of the anonymous
access type of an access discriminant in the subtype_indication
or qualified_expression of an allocator,
or in the expression or return_subtype_indication
of a return statement is determined as follows: is
the same as that of the containing object or associated constrained subtype.
12.1/2
- If the
value of the access discriminant is determined by a discriminant_association
in a subtype_indication, the accessibility
level of the object or subprogram designated by the associated value
(or library level if the value is null);
12.a/2
Discussion:
This deals with the following cases, when they occur in the context
of an allocator or return statement:
12.b/2
- An
extension_aggregate where the ancestor_part
is a subtype_mark denoting a constrained subtype;
12.c/2
- An
uninitialized allocator where the subtype_indication
defines a constrained subtype;
12.d/2
- A
discriminant of an object with a constrained nominal subtype, including
constrained components, the result of calling a function with a constrained
result subtype, the dereference of an access-to-constrained subtype,
etc.
12.2/2
- If the
value of the access discriminant is determined by a component_association
in an aggregate, the accessibility level of
the object or subprogram designated by the associated value (or library
level if the value is null);
12.e/2
Discussion: In
this bullet, the aggregate has to occur in
the context of an allocator or return statement,
while the subtype_indication of the previous
bullet can occur anywhere (it doesn't have to be directly given in the
allocator or return statement).
12.3/2
- In other
cases, where the value of the access discriminant is determined by an
object with an unconstrained nominal subtype, the accessibility level
of the object.
12.e.1/2
Discussion: {
AI95-00416-01}
In other words, if you know the value of the discriminant
for an allocator or return statement from
a discriminant constraint or an aggregate
component association, then that determines the accessibility level;
if you don't know it, then it is based on the object itself.
12.4/2
- {AI95-00416-01}
The accessibility level of the anonymous access
type of an access discriminant in any other context is that of the enclosing
object.
13/2
- {AI95-00162-01}
{AI95-00254-01}
The accessibility level of the anonymous access type of an access parameter specifying an access-to-object type is the same as that of the
view designated by the actual. If the actual is
an allocator, this is the accessibility level
of the execution of the called subprogram.
13.1/2
- {AI95-00254-01}
The accessibility level of the anonymous access
type of an access parameter specifying an access-to-subprogram type is
deeper than that of any master; all such anonymous access types have
this same level.
13.a/2
Reason: {downward
closure} {closure (downward)} These
represent “downward closures” and thus require passing of
static links or global display information (along with generic sharing
information if the implementation does sharing) along with the address
of the subprogram. We must prevent conversions of these to types with
“normal” accessibility, as those typically don't include
the extra information needed to make a call.
14/2
- {AI95-00416-01}
The accessibility level of an object created
by an allocator is the same as that of the
access type, except for an allocator
of an anonymous access type that defines the value of an access parameter
or an access discriminant. For an allocator
defining the value of an access parameter, the accessibility level is
that of the innermost master of the call. For one defining an access
discriminant, the accessibility level is determined as follows:.
14.1/2
- {AI95-00416-01}
for an allocator used
to define the constraint in a subtype_declaration,
the level of the subtype_declaration;
14.2/2
- {AI95-00416-01}
for an allocator used
to define the constraint in a component_definition,
the level of the enclosing type;
14.3/2
- {AI95-00416-01}
for an allocator used
to define the discriminant of an object, the level of the object.
14.4/2
{AI95-00416-01}
{coextension (of
an object)} In this last case, the allocated
object is said to be a coextension of the object whose discriminant
designates it, as well as of any object of which the discriminated object
is itself a coextension or subcomponent. All coextensions of an object
are finalized when the object is finalized (see 7.6.1).
14.a.1/2
Ramification: The
rules of access discriminants are such that when the space for an object
with a coextension is reclaimed, the space for the coextensions can be
reclaimed. Hence, there is implementation advice (see 13.11) that an
object and its coextensions all be allocated from the same storage pool
(or stack frame, in the case of a declared object).
15
- The accessibility level of a view
of an object or subprogram denoted by a dereference of an access value
is the same as that of the access type.
16
- The accessibility level of a component,
protected subprogram, or entry of (a view of) a composite object is the
same as that of (the view of) the composite object.
16.1/2
{
AI95-00416-01}
In the above rules, the operand of a view conversion,
parenthesized expression or qualified_expression
is considered to be used in a context if the view conversion, parenthesized
expression or qualified_expression itself
is used in that context.
17
{statically
deeper} {deeper
(statically)} One accessibility level
is defined to be
statically deeper than another in the following
cases:
18
- For a master that is statically nested
within another master, the accessibility level of the inner master is
statically deeper than that of the outer master.
18.a
To be honest: Strictly speaking, this
should talk about the constructs (such as subprogram_bodies)
being statically nested within one another; the masters are really the
executions of those constructs.
18.b
To be honest: If a given accessibility
level is statically deeper than another, then each level defined to be
the same as the given level is statically deeper than each level defined
to be the same as the other level.
18.1/2
- {AI95-00254-01}
The accessibility level of the anonymous access
type of an access parameter specifying an access-to-subprogram type is
statically deeper than that of any master; all such anonymous access
types have this same level.
18.c/2
Ramification: This
rule means that it is illegal to convert an access parameter specifying
an access to subprogram to a named access to subprogram type, but it
is allowed to pass such an access parameter to another access parameter
(the implicit conversion's accessibility will succeed).
19/2
- {AI95-00254-01}
The statically deeper relationship does not apply to the accessibility
level of the anonymous type of an access parameter specifying an access-to-object type; that is, such an accessibility
level is not considered to be statically deeper, nor statically shallower,
than any other.
20
- For determining whether one level
is statically deeper than another when within a generic package body,
the generic package is presumed to be instantiated at the same level
as where it was declared; run-time checks are needed in the case of more
deeply nested instantiations.
21
- For determining whether one level
is statically deeper than another when within the declarative region
of a type_declaration, the current instance
of the type is presumed to be an object created at a deeper level than
that of the type.
21.a
Ramification: In other words, the rules
are checked at compile time of the type_declaration,
in an assume-the-worst manner.
22
{library level}
{level (library)}
The accessibility level of all library units is called
the
library level; a library-level declaration or entity is one
whose accessibility level is the library level.
22.a
Ramification: Library_unit_declarations
are library level. Nested declarations are library level if they are
nested only within packages (possibly more than one), and not within
subprograms, tasks, etc.
22.b/2
To be honest:
The definition of the accessibility level of the anonymous type of
an access parameter specifying an access-to-object
type cheats a bit, since it refers to the view designated by the
actual, but access values designate objects, not views of objects. What
we really mean is the view that “would be” denoted by an
expression “X.all”, where X is the actual, even though
such an expression is a figment of our imagination. The definition is
intended to be equivalent to the following more verbose version: The
accessibility level of the anonymous type of an access parameter is as
follows:
22.c
- if the actual is an expression
of a named access type — the accessibility level of that type;
22.d
- if the actual is an allocator
— the accessibility level of the execution of the called subprogram;
22.e/1
- if the actual is a reference
to the Access attribute — the accessibility level of the view denoted
by the prefix prefix;
22.f
- if the actual is a reference
to the Unchecked_Access attribute — library accessibility level;
22.g
- if the actual is an access parameter
— the accessibility level of its type.
22.h
Note that the allocator
case is explicitly mentioned in the RM95, because otherwise the definition
would be circular: the level of the anonymous type is that of the view
designated by the actual, which is that of the access type.
22.i
Discussion: A deeper accessibility level
implies a shorter maximum lifetime. Hence, when a rule requires X to
have a level that is “not deeper than” Y's level, this requires
that X has a lifetime at least as long as Y. (We say “maximum lifetime”
here, because the accessibility level really represents an upper bound
on the lifetime; an object created by an allocator
can have its lifetime prematurely ended by an instance of Unchecked_Deallocation.)
22.j
Package elaborations are not masters, and are
therefore invisible to the accessibility rules: an object declared immediately
within a package has the same accessibility level as an object declared
immediately within the declarative region containing the package. This
is true even in the body of a package; it jibes with the fact that objects
declared in a package_body live as long as
objects declared outside the package, even though the body objects are
not visible outside the package.
22.k
Note that the level of the view denoted
by X.all can be different from the level of the object
denoted by X.all. The former is determined by the type of X; the
latter is determined either by the type of the allocator,
or by the master in which the object was declared. The former is used
in several Legality Rules and run-time checks; the latter is used to
define when X.all gets finalized. The level of a view reflects
what we can conservatively “know” about the object of that
view; for example, due to type_conversions,
an access value might designate an object that was allocated by an allocator
for a different access type.
22.l
Similarly, the level of the view denoted by
X.all.Comp can be different from the level of the object denoted
by X.all.Comp.
22.m
If Y is statically deeper than X, this implies
that Y will be (dynamically) deeper than X in all possible executions.
22.n
Most accessibility
checking is done at compile time; the rules are stated in terms of “statically
deeper than”. The exceptions are:
22.o/2
- Checks involving access parameters of an access-to-object type. The fact that “statically deeper
than” is not defined for the anonymous access type of an access
parameter implies that any rule saying “shall not be statically
deeper than” does not apply to such a type, nor to anything defined
to have “the same” level as such a type.
22.p
- Checks involving entities and
views within generic packages. This is because an instantiation can be
at a level that is more deeply nested than the generic package itself.
In implementations that use a macro-expansion model of generics, these
violations can be detected at macro-expansion time. For implementations
that share generics, run-time code is needed to detect the error.
22.q/2
22.r
Note that run-time checks are not required for
access discriminants, because their accessibility is determined statically
by the accessibility level of the enclosing object.
22.s/2
This The accessibility
level of the result object of a function reflects the time when that
object will be finalized; we don't allow pointers to the object to survive
beyond that time.
22.t
We sometimes use the terms “accessible”
and “inaccessible” to mean that something has an accessibility
level that is not deeper, or deeper, respectively, than something else.
22.u/2
Implementation Note: {
AI95-00318-02}
{
AI95-00344-01}
{
AI95-00416-01}
If an accessibility Legality Rule is satisfied, then the corresponding
run-time check (if any) cannot fail (and a reasonable implementation
will not generate any checking code) unless
one
of the cases requiring run-time checks mentioned previously is access
parameters or shared generic bodies are involved.
22.v
Accessibility levels are defined in terms of
the relations “the same as” and “deeper than”.
To make the discussion more concrete, we can assign actual numbers to
each level. Here, we assume that library-level accessibility is level
0, and each level defined as “deeper than” is one level deeper.
Thus, a subprogram directly called from the environment task (such as
the main subprogram) would be at level 1, and so on.
22.w/2
Accessibility is not enforced at compile time
for access parameters of an access-to-object type.
The “obvious” implementation of the run-time checks would
be inefficient, and would involve distributed overhead; therefore, an
efficient method is given below. The “obvious” implementation
would be to pass the level of the caller at each subprogram call, task
creation, etc. This level would be incremented by 1 for each dynamically
nested master. An Accessibility_Check would be implemented as a simple
comparison — checking that X is not deeper than Y would involve
checking that X <= Y.
22.x
A more efficient method is based on passing
static nesting levels (within constructs that correspond at run
time to masters — packages don't count). Whenever an access parameter
is passed, an implicit extra parameter is passed with it. The extra parameter
represents (in an indirect way) the accessibility level of the anonymous
access type, and, therefore, the level of the view denoted by a dereference
of the access parameter. This is analogous to the implicit “Constrained”
bit associated with certain formal parameters of an unconstrained but
definite composite subtype. In this method, we avoid distributed overhead:
it is not necessary to pass any extra information to subprograms that
have no access parameters. For anything other than an access parameter
and its anonymous type, the static nesting level is known at compile
time, and is defined analogously to the RM95 definition of accessibility
level (e.g. derived access types get their nesting level from their parent).
Checking “not deeper than” is a "<=" test on
the levels.
22.y/2
For each access
parameter of an access-to-object type, the
static depth passed depends on the actual, as follows:
22.z
- If the actual is an expression
of a named access type, pass the static nesting level of that type.
22.aa
- If the actual is an allocator,
pass the static nesting level of the caller, plus one.
22.bb/1
- If the actual is a reference
to the Access attribute, pass the level of the view denoted by the prefix prefix.
22.cc
- If the actual is a reference
to the Unchecked_Access attribute, pass 0 (the library accessibility
level).
22.dd/2
- If the actual is an access parameter of an access-to-object type, usually just pass along the level
passed in. However, if the static nesting level of the formal (access)
parameter is greater than the static nesting level of the actual (access)
parameter, the level to be passed is the minimum of the static nesting
level of the access parameter and the actual level passed in.
22.ee/2
For the Accessibility_Check associated with
a type_conversion of an access parameter of an access-to-object type of a given subprogram to a named access
type, if the target type is statically nested within the subprogram,
do nothing; the check can't fail in this case. Otherwise, check that
the value passed in is <= the static nesting depth of the target type.
The other Accessibility_Checks are handled in a similar manner.
22.ff
This method, using statically known values most
of the time, is efficient, and, more importantly, avoids distributed
overhead.
22.gg
Discussion:
Examples of accessibility:
22.hh
package body Lib_Unit is
type T is tagged ...;
type A0 is access all T;
Global: A0 := ...;
procedure P(X: T) is
Y: aliased T;
type A1 is access all T;
Ptr0: A0 := Global; -- OK.
Ptr1: A1 := X'Access; -- OK.
begin
Ptr1 := Y'Access; -- OK;
Ptr0 := A0(Ptr1); -- Illegal type conversion!
Ptr0 := X'Access; -- Illegal reference to Access attribute!
Ptr0 := Y'Access; -- Illegal reference to Access attribute!
Global := Ptr0; -- OK.
end P;
end Lib_Unit;
22.ii
The above illegal statements are illegal because
the accessibility level of X and Y are statically deeper than the accessibility
level of A0. In every possible execution of any program including this
library unit, if P is called, the accessibility level of X will be (dynamically)
deeper than that of A0. Note that the accessibility levels of X and Y
are the same.
22.jj/2
Here's an example
involving access parameters of an access-to-object
type:
22.kk
procedure Main is
type Level_1_Type is access all Integer;
22.ll
procedure P(X: access Integer) is
type Nested_Type is access all Integer;
begin
... Nested_Type(X) ... -- (1)
... Level_1_Type(X) ... -- (2)
end P;
22.mm
procedure Q(X: access Integer) is
procedure Nested(X: access Integer) is
begin
P(X);
end Nested;
begin
Nested(X);
end Q;
22.nn
procedure R is
Level_2: aliased Integer;
begin
Q(Level_2'Access); -- (3)
end R;
22.oo
Level_1: aliased Integer;
begin
Q(Level_1'Access); -- (4)
R;
end Main;
22.pp
The run-time Accessibility_Check at (1) can
never fail, and no code should be generated to check it. The check at
(2) will fail when called from (3), but not when called from (4).
22.qq
Within a type_declaration,
the rules are checked in an assume-the-worst manner. For example:
22.rr
package P is
type Int_Ptr is access all Integer;
type Rec(D: access Integer) is limited private;
private
type Rec_Ptr is access all Rec;
function F(X: Rec_Ptr) return Boolean;
function G(X: access Rec) return Boolean;
type Rec(D: access Integer) is
record
C1: Int_Ptr := Int_Ptr(D); -- Illegal!
C2: Rec_Ptr := Rec'Access; -- Illegal!
C3: Boolean := F(Rec'Access); -- Illegal!
C4: Boolean := G(Rec'Access);
end record;
end P;
22.ss
C1, C2, and C3 are all illegal, because one
might declare an object of type Rec at a more deeply nested place than
the declaration of the type. C4 is legal, but the accessibility level
of the object will be passed to function G, and constraint checks within
G will prevent it from doing any evil deeds.
22.tt
Note that we cannot defer the checks on C1,
C2, and C3 until compile-time of the object creation, because that would
cause violation of the privacy of private parts. Furthermore, the problems
might occur within a task or protected body, which the compiler can't
see while compiling an object creation.
23
The following attribute
is defined for a prefix X that denotes an
aliased view of an object:
24/1
X'Access
{
8652/0010}
{
AI95-00127-01}
X'Access yields an access value that designates the object denoted by
X. The type of X'Access is an access-to-object type, as determined by
the expected type. The expected type shall be a general access type.
{Unchecked_Access attribute: See also
Access attribute} X shall denote an aliased
view of an object[, including possibly the current instance (see
8.6)
of a limited type within its definition, or a formal parameter or generic
formal object of a tagged type]. The view denoted by the
prefix
X shall satisfy the following additional requirements, presuming the
expected type for X'Access is the general access type
A with designated type D:
25
- If A is an access-to-variable
type, then the view shall be a variable; [on the other hand, if A
is an access-to-constant type, the view may be either a constant or a
variable.]
25.a
Discussion: The current instance of a
limited type is considered a variable.
26/2
- {AI95-00363-01}
The view shall not be a subcomponent that depends on discriminants of
a variable whose nominal subtype is unconstrained, unless this subtype
is indefinite, or the variable is constrained by
its initial value aliased.
26.a
Discussion: This restriction is intended
to be similar to the restriction on renaming discriminant-dependent subcomponents.
26.b
Reason: This prevents references to subcomponents
that might disappear or move or change constraints after creating the
reference.
26.c
Implementation
Note: There was some thought to making this restriction more stringent,
roughly: "X shall not denote a subcomponent of a variable with discriminant-dependent
subcomponents, if the nominal subtype of the variable is an unconstrained
definite subtype." This was because in some implementations, it
is not just the discriminant-dependent subcomponents that might move
as the result of an assignment that changed the discriminants of the
enclosing object. However, it was decided not to make this change because
a reasonable implementation strategy was identified to avoid such problems,
as follows:
26.d
- Place non-discriminant-dependent
components with any aliased parts at offsets preceding any discriminant-dependent
components in a discriminated record type with defaulted discriminants.
26.e
- Preallocate the maximum space
for unconstrained discriminated variables with aliased subcomponents,
rather than allocating the initial size and moving them to a larger (heap-resident)
place if they grow as the result of an assignment.
26.f
Note that for objects of a by-reference type,
it is not an error for a programmer to take advantage of the fact that
such objects are passed by reference. Therefore, the above approach is
also necessary for discriminated record types with components of a by-reference
type.
26.g
To make the above strategy work, it is important
that a component of a derived type is defined to be discriminant-dependent
if it is inherited and the parent subtype constraint is defined in terms
of a discriminant of the derived type (see
3.7).
26.h/2
To be honest: {
AI95-00363-01}
If X is a subcomponent that depends on discriminants,
and the subcomponent is a dereference of a general access type whose
designated type is unconstrained and whose discriminants have defaults,
the attribute is illegal. Such a general access type can designate an
unconstrained (stack) object. Since such a type might not designate an
object constrained by its initial value, the 'Access is illegal —
the rule says “is” constrained by its initial value, not
“might be” constrained by its initial value. No other interpretation
makes sense, as we can't have legality depending on something (which
object is designated) that is not known at compile-time, and we surely
can't allow this for unconstrained objects. The wording of the rule should
be much clearer on this point, but this was discovered after the completion
of Amendment 1 when it was too late to fix it.
27/2
- {8652/0010}
{AI95-00127-01}
{AI95-00363-01}
If A is a named access type and D
is a tagged type the designated type of
A is tagged, then the type of the view shall be covered
by D the designated
type; if A is anonymous and D
is tagged, then the type of the view shall be either D'Class or
a type covered by D D;
if D is untagged A's
designated type is not tagged, then the type of the view shall
be D the same,
and either: either
A's designated subtype shall either
statically match the nominal subtype
of the view or be,
or the designated subtype shall be discriminated
and unconstrained; {statically matching
(required) [partial]}
27.1/2
- {AI95-00363-01}
the designated subtype of A shall statically
match the nominal subtype of the view; or{statically
matching (required) [partial]}
27.2/2
- {AI95-00363-01}
D shall be discriminated in its full view
and unconstrained in any partial view, and the designated subtype of
A shall be unconstrained.
27.a
Implementation Note: This ensures that
the dope for an aliased array object can always be stored contiguous
with it, but need not be if its nominal subtype is constrained.
27.a.1/1
27.a.2/2
{
AI95-00363-01}
This does not require that types have a partial
view in order to allow an access attribute of an unconstrained discriminated
object, only that any partial view that does exist is unconstrained.
28
- The accessibility level of
the view shall not be statically deeper than that of the access type
A. 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. {accessibility
rule (Access attribute) [partial]} {generic
contract issue [partial]}
28.a
Ramification: In an instance body, a
run-time check applies.
28.b/2
{
AI95-00230-01}
If
A is an anonymous
access-to-object type
of an access parameter access type,
then the view can never have a deeper accessibility level than
A.
The same is true for an anonymous access-to-object type of an access
discriminant, except when X'Access is used to initialize an access
discriminant of an object created by an
allocator.
The latter case is illegal if the accessibility level of X is statically
deeper than that of the access type of the
allocator;
a run-time check is needed in the case where the initial value comes
from an access parameter.
Other anonymous access-to-object
types have "normal" accessibility checks.
29
{Accessibility_Check
[partial]} {check,
language-defined (Accessibility_Check)} {Program_Error
(raised by failure of run-time check)} A
check is made that the accessibility level of X is not deeper than that
of the access type
A. If this check fails, Program_Error is raised.
29.a/2
Ramification: The check is needed for
access parameters of an access-to-object type
and in instance bodies.
29.b/2
Implementation Note: This check requires
that some indication of lifetime is passed as an implicit parameter along
with access parameters of an access-to-object type.
No such requirement applies to other anonymous
access types access discriminants,
since the checks associated with them are all compile-time checks.
30
{implicit subtype
conversion (Access attribute) [partial]} If
the nominal subtype of X does not statically match the designated subtype
of
A, a view conversion of X to the designated subtype is evaluated
(which might raise Constraint_Error — see
4.6)
and the value of X'Access designates that view.
31
The following attribute is defined for a prefix
P that denotes a subprogram:
32/2
P'Access
{
AI95-00229-01}
{
AI95-00254-01}
P'Access yields an access value that designates the subprogram denoted
by P. The type of P'Access is an access-to-subprogram type (
S),
as determined by the expected type.
{accessibility
rule (Access attribute) [partial]} The
accessibility level of P shall not be statically deeper than that of
S.
{generic contract issue
[partial]} 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. The profile of P shall be subtype-conformant with the designated
profile of
S, and shall not be Intrinsic.
{subtype
conformance (required)} If the subprogram
denoted by P is declared within a generic
unit,
and the expression P'Access occurs within the body of that generic unit
or within the body of a generic unit declared within the declarative
region of the generic unit, then the ultimate ancestor of S shall
be either a non-formal type declared within the generic unit or an anonymous
access type of an access parameter. body,
S shall be declared within the generic body.
32.a/2
Discussion: {
AI95-00229-01}
The part about generic bodies is worded in terms of the denoted subprogram,
not the denoted view; this implies that renaming is invisible to this
part of the rule.
“Declared within the declarative
region of the generic” is referring to child and nested generic
units. This rule is partly to prevent contract model problems
with respect to the accessibility rules, and partly to ease shared-generic-body
implementations, in which a subprogram declared in an instance needs
to have a different calling convention from other subprograms with the
same profile.
32.b
Overload resolution ensures only that the profile
is type-conformant. This rule specifies that subtype conformance is required
(which also requires matching calling conventions). P cannot denote an
entry because access-to-subprogram types never have the entry
calling convention. P cannot denote an enumeration literal or an attribute
function because these have intrinsic calling conventions.
33
85 The Unchecked_Access attribute yields
the same result as the Access attribute for objects, but has fewer restrictions
(see
13.10). There are other predefined operations
that yield access values: an
allocator can
be used to create an object, and return an access value that designates
it (see
4.8); evaluating the literal
null
yields a null access value that designates no entity at all (see
4.2).
34/2
86 {
AI95-00230-01}
{predefined operations (of an access
type) [partial]} The predefined operations
of an access type also include the assignment operation, qualification,
and membership tests. Explicit conversion is allowed between general
access types with matching designated subtypes; explicit conversion is
allowed between access-to-subprogram types with subtype conformant profiles
(see
4.6).
{subtype
conformance [partial]} Named access types
have predefined equality operators; anonymous access types do not
,
but they can use the predefined equality operators for universal_access
(see
4.5.2).
34.a/2
Reason: {
AI95-00230-01}
Anonymous access types can use the universal access
equality operators declared in Standard, while named access types cannot
for compatibility reasons. By not having equality operators for
anonymous access types, we eliminate the need to specify exactly where
the predefined operators for anonymous access types would be defined,
as well as the need for an implementer to insert an implicit declaration
for "=", etc. at the appropriate place in their symbol table.
Note that
":=", 'Access
,
and ".
all" are defined
, and ":="
is defined though useless since all instances are constant. The literal
null is also defined for the purposes of overload resolution,
but is disallowed by a Legality Rules of this subclause.
35
87 The object or subprogram designated
by an access value can be named with a dereference, either an
explicit_dereference
or an
implicit_dereference. See
4.1.
36
88 A call through the dereference of an
access-to-subprogram value is never a dispatching call.
36.a
37/2
89 {
AI95-00254-01}
{downward closure} {closure
(downward)} The The
accessibility rules imply that it is not possible to use the Access
attribute
for subprograms and parameters of an
anonymous access-to-subprogram type may together be used to implement
“downward closures” — that is, to pass a more-nested
subprogram as a parameter to a less-nested subprogram, as might be
appropriate desired
for example for an iterator abstraction
or numerical integration. Downward. Instead,
downward closures can
also be implemented
using generic formal subprograms (see
12.6).
Note that Unchecked_Access is not allowed for subprograms.
38
90 Note that using an access-to-class-wide
tagged type with a dispatching operation is a potentially more structured
alternative to using an access-to-subprogram type.
39
91 An implementation may consider two access-to-subprogram
values to be unequal, even though they designate the same subprogram.
This might be because one points directly to the subprogram, while the
other points to a special prologue that performs an Elaboration_Check
and then jumps to the subprogram. See
4.5.2.
39.a
Ramification: If equality of access-to-subprogram
values is important to the logic of a program, a reference to the Access
attribute of a subprogram should be evaluated only once and stored in
a global constant for subsequent use and equality comparison.
Examples
40
Example of use of
the Access attribute:
41
Martha : Person_Name :=
new Person(F); --
see 3.10.1
Cars :
array (1..2)
of aliased Car;
...
Martha.Vehicle := Cars(1)'Access;
George.Vehicle := Cars(2)'Access;
Extensions to Ada 83
41.a
{
extensions to Ada 83}
We
no longer make things like 'Last and ".component" (basic) operations
of an access type that need to be "declared" somewhere. Instead,
implicit dereference in a
prefix takes care
of them all. This means that there should never be a case when X.
all'Last
is legal while X'Last is not. See AI83-00154.
Incompatibilities With Ada 95
41.b/2
{
AI95-00363-01}
{incompatibilities with Ada 95}
Aliased variables are not necessarily constrained in Ada 2005 (see 3.6).
Therefore, a subcomponent of an aliased variable may disappear or change
shape, and taking 'Access of such a subcomponent thus is illegal, while
the same operation would have been legal in Ada 95. Note that most allocated
objects are still constrained by their initial value (see 4.8),
and thus legality of 'Access didn't change for them. For example:
41.c/2
type T1 (D1 : Boolean := False) is
record
case D1 is
when False =>
C1 : aliased Integer;
when True =>
null;
end case;
end record;
type Acc_Int is access all Integer;
41.d/2
A_T : aliased T1;
Ptr : Acc_Int := A_T.C1'Access; -- Illegal in Ada 2005, legal in Ada 95
A_T := (D1 => True); -- Raised Constraint_Error in Ada 95, but does not
-- in Ada 2005, so Ptr would become invalid when this
-- is assigned (thus Ptr is illegal).
41.e/2
{
AI95-00363-01}
If a discriminated full type has a partial view
(private type) that is constrained, we do not allow 'Access on objects
to create a value of an object of an access-to-unconstrained type. Ada
95 allowed this attribute and various access subtypes, requiring that
the heap object be constrained and thus making details of the implementation
of the private type visible to the client of the private type. See 4.8
for more on this topic.
41.f/2
{
AI95-00229-01}
{
AI95-00254-01}
Amendment Correction: Taking 'Access of
a subprogram declared in a generic unit in the body of that generic is
no longer allowed. Such references can easily be used to create dangling
pointers, as Legality Rules are not rechecked in instance bodies. At
the same time, the rules were loosened a bit where that is harmless,
and also to allow any routine to be passed to an access parameter of
an access-to-subprogram type. The now illegal uses of 'Access can almost
always be moved to the private part of the generic unit, where they are
still legal (and rechecked upon instantiation for possibly dangling pointers).
Extensions to Ada 95
41.g/2
{
8652/0010}
{
AI95-00127-01}
Corrigendum: {extensions to Ada 95}
Access attributes of objects of class-wide types
can be used as the controlling parameter in a dispatching calls (see
3.9.2). This was an oversight in Ada 95.
41.h/2
{
AI95-00235-01}
Amendment Correction: The type of the prefix
can now be used in resolving Access attributes. This allows more uses
of the Access attribute to resolve. For example:
41.i/2
type Int_Ptr is access all Integer;
type Float_Ptr is access all Float;
41.j/2
function Zap (Val : Int_Ptr) return Float;
function Zap (Val : Float_Ptr) return Float;
41.k/2
Value : aliased Integer := 10;
41.l/2
Result1 : Float := Zap (Value'access); -- Ambiguous in Ada 95; resolves in Ada 2005.
Result2 : Float := Zap (Int_Ptr'(Value'access)); -- Resolves in Ada 95 and Ada 2005.
41.m/2
This change is upward
compatible; any expression that does not resolve by the new rules would
have failed a Legality Rule.
Wording Changes from Ada 95
41.n/2
{
AI95-00162-01}
Adjusted the wording to reflect the fact that expressions
and function calls are masters.
41.o/2