Version 1.7 of ai12s/ai12-0345-1.txt
!standard 3.10.2(5) 21-05-27 AI12-0345-1/04
!standard 3.10.2(7/4)
!standard 3.10.2(10.5/3)
!standard 3.10.2(13.4/4)
!standard 3.10.2(19.2/5)
!standard 3.10.2(21)
!class binding interpretation 19-09-30
!status Amendment 1-2012 20-01-15
!status WG9 Approved 22-06-22
!status ARG Approved 10-0-4 20-01-15
!status work item 19-09-30
!status received 19-09-17
!priority Low
!difficulty Easy
!qualifier Omission
!subject Dynamic accessibility of explicitly aliased parameters
!summary
An explicitly aliased parameter has the accessibility of a normal parameter
in all cases except when compared to the master of the call (which is defined
to pass).
!question
3.10.2(13.4/4) says:
The accessibility level of an explicitly aliased (see 6.1) formal parameter
in a function body is determined by the point of call; it is the same level
that the return object ultimately will have.
This implies that the dynamic level has to be passed in for all such
functions, in case the parameter is used in a context that requires a dynamic
level (for instance, as an access parameter). Is this intended? (No.)
!recommendation
(See Summary.)
!wording
Modify 3.10.2(5):
Each master, and each entity and view created by it, has an
accessibility level{; when two levels are defined to be the same, the
accessibility levels of the two associated entities are said to be
tied to each other. Accessibility levels are defined as follows}:
Modify 3.10.2(7/4):
An entity or view defined by a declaration and created as part of its
elaboration has the same accessibility level as the innermost master
of the declaration except in the cases of renaming and derived access
types described below. [Other than for an explicitly aliased parameter
of a function or generic function, a]{A} formal parameter of a callable
entity has the same accessibility level as the master representing
the invocation of the entity.
Modify 3.10.2(10.5/3):
If the call itself defines the result of a function to which one of the
above rules applies,{ or has an accessibility level that is tied to the
result of such a function,} these rules are applied recursively;
Delete AARM 3.10.2(10.d.6/3):
- when the function has an explicitly aliased parameter.
Delete 3.10.2(13.4/4):
The accessibility level of an explicitly aliased (see 6.1) formal
parameter in a function body is determined by the point of call; it
is the same level that the return object ultimately will have.
Delete 3.10.2(19.2/5):
Inside a return statement that applies to a function or generic function F,
or inside the return expression of an expression function F, when
determining whether the accessibility level of an explicitly aliased
parameter of F is statically deeper than the level of the return object of
F, the level of the return object is considered to be the same as that of
the level of the explicitly aliased parameter; for statically comparing
with the level of other entities, an explicitly aliased parameter of F is
considered to have the accessibility level of a parameter of F that is
not explicitly aliased.
Delete AARM 3.10.2(19.b/3):
To be honest: This rule has no effect if the previous bullet also applies
(that is, the “a level” is of an explicitly aliased parameter).
Add after 3.10.2(21):
Notwithstanding other rules given above, the accessibility level of an entity
that is tied to that of an explicitly aliased formal parameter of an enclosing
function is considered (both statically and dynamically) to be the same as
that of an entity whose accessibility level is tied to that of the return object
of that function.
AARM Ramification: This rule only applies when the level of an explicitly
aliased parameter of a function is compared to that of the return object of
the function. If a value designating the explicitly aliased parameter is
created and stored in a stand-alone object or passed as a parameter, this
special property is lost (even for the dynamic accessibility of anonymous
access types in these contexts).
!discussion
The intent of the primary designer of explicitly aliased parameters (that
would be the author of this AI) was that explicitly aliased parameters act
the same as any other parameter vis-a-vis accessibility except when
comparing against the "master of the call" (that is, the accessibility of
the return object). In that case, we do accessibility checks on the actual
to ensure that it is safe to return, so no checks are ever needed in the
return.
This model ensures that no dynamic accessibility information is ever needed
for an explicitly aliased parameter, even when the function result needs such
information.
The wording attempted to accomplish this model with a paired static and dynamic
model, assuming/requiring that any cases that would be problematic would be
illegal statically. However, it is clear that both stand-alone objects of an
anonymous access type, and calls using access parameters can store the dynamic
accessibility of an explicitly aliased parameter, and thus it would need to be
passed.
---
After a number of unsuccessful rewordings, we settled on the notion of two
accessibility levels being "tied". When two tied levels are compared, the check
always must pass (and a compiler should generate no check).
The model is that this is ONLY true when tied levels are known at compile-time
to be compared. In particular, storing an access value derived from an
explicitly aliased parameter in a stand-alone object of an anonymous access
type, or passing such a value as an access parameter, loses the "tied"
property. In such cases, the dynamic accessibility of the parameter is local.
---
Here are some examples to show some of the implications of these rules:
type Rec is record
Comp : aliased Integer;
...
end record;
Glob : Boolean := ...;
function F1 (A : aliased in out Rec) return access Integer is
C : aliased Integer;
function F2 (B : access Integer) return access Integer
is (B); --
begin
if Glob then
return F2 (C'access); --
else
return F2 (A.Comp'access); --
end if;
end F1;
The dynamic accessibility check at (1) should fail for either parameter
passed to function F2. Even though the calls to F2 have the master of the
call of F1, the special "tied to an explicitly aliased parameter" property
is lost when the A.Comp'Access value is passed as a parameter.
Contrast this to the similar case using explicitly aliased parameters:
function F4 (A : aliased in out Rec) return access Integer is
C : aliased Integer;
function F5 (B : aliased in out Integer) return access Integer
is (B'access); --
begin
if Glob then
return F5 (C); --
else
return F5 (A.Comp); --
end if;
end F4;
Here, (2) is both statically and dynamically checking "tied" accessibility
levels, so no check of either kind is needed at (2). That works in part as
such checks are moved to the call site of F5. Thus, passing the local object
C is illegal, the static accessibility check on explicitly aliased parameters
fails here. OTOH, the static check for A.Comp succeeds by definition, as it
is comparing "tied" levels.
---
The change to 3.10.2(10.5/3) is intended to handle cases were some part of the
return value is returned. For instance:
function F7 (A : aliased in out Rec) return access Integer is
C : aliased Rec := ...;
function F8 (B : aliased in out Rec) return access Rec
is (B'access);
begin
if Glob then
return F8 (C).Comp'access; --
else
return F8 (A).Comp'access; --
end if;
end F7;
The accessibility of the calls to F8 are now that of F7. This makes the
accessibility of the result sufficient to return from F7. It means that
the static check on the parameter C fails as it is too nested for to be
returned.
The old rule did not apply to this case as it said "used as the return"; here
only a part of the return is used, and that part comes via a dereference.
!corrigendum 3.10.2(5)
Replace the paragraph:
Each master, and each entity and view created by it, has an accessibility
level:
by:
Each master, and each entity and view created by it, has an
accessibility level; when two levels are defined to be the same, the
accessibility levels of the two associated entities are said to be
tied to each other. Accessibility levels are defined as follows:
!corrigendum 3.10.2(7/4)
Replace the paragraph:
- An entity or view defined by a declaration and created as part of
its elaboration has the same accessibility
level as the innermost master of the declaration
except in the cases of renaming and derived access types described below.
Other than for an explicitly aliased parameter of a function or generic function,
a formal parameter of a callable entity has the same accessibility level as the
master representing the invocation of the entity.
by:
- An entity or view defined by a declaration and created as part of its
elaboration has the same accessibility level as the innermost master of the
declaration except in the cases of renaming and derived access types described
below. A formal parameter of a callable entity has the same accessibility
level as the master representing the invocation of the entity.
!corrigendum 3.10.2(10.5/3)
Replace the paragraph:
If the call itself defines the result of a function to which one of the above
rules applies, these rules are applied recursively;
by:
If the call itself defines the result of a function to which one of the
above rules applies, or has an accessibility level that is tied to the
result of such a function, these rules are applied recursively;
!corrigendum 3.10.2(13.4/4)
Delete the paragraph:
The accessibility level of an explicitly aliased (see 6.1) formal
parameter in a function body is determined by the point of call; it
is the same level that the return object ultimately will have.
!corrigendum 3.10.2(19.2/5)
Delete the paragraph:
Inside a return statement that applies to a function or generic function F,
or inside the return expression of an expression function F, when
determining whether the accessibility level of an explicitly aliased
parameter of F is statically deeper than the level of the return object of
F, the level of the return object is considered to be the same as that of
the level of the explicitly aliased parameter; for statically comparing
with the level of other entities, an explicitly aliased parameter of F is
considered to have the accessibility level of a parameter of F that is
not explicitly aliased.
!corrigendum 3.10.2(21)
Insert after the paragraph:
- 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.
the new paragraph:
Notwithstanding other rules given above, the accessibility level of an entity
that is tied to that of an explicitly aliased formal parameter of an enclosing
function is considered (both statically and dynamically) to be the same as
that of an entity whose accessibility level is tied to that of the return object
of that function.
!ASIS
No ASIS effect.
!ACATS test
A B-Test containing the examples above might be useful, as well as a C-Test
that the special level does not persist.
!appendix
From: Steve Baird
Sent: Tuesday, September 17, 2019 6:32 PM
There was some internal discussion within AdaCore a while back about some
possible minor changes to the accessibility rules for explicitly aliased
parameters. This is a description of those changes and their motivation.
No specific wording is proposed; at this point the goal is only to determine
whether it makes sense to produce wording for a more specific proposal.
Tuck believes that this proposal reflects the original intent of the language
designers back when explicitly aliased parameters were added to the language
and so this is just a matter of correcting the RM to reflect that original
intent. In any case, it seems that it would simplify implementations without
costing users any useful functionality.
Dynamic semantics:
The current RM wording distinguishes between a function and
other callable entities (e.g., procedures, entries) in defining
the accessibility level of an explicitly aliased parameter.
Instead, we want to distinguish a function whose result
type requires (at runtime) passing in an accessibility level
parameter from other callable entities. Note that the details of
the rules to capture this distinction, whatever those details
are, have nothing to do with explicitly aliased parameters.
The idea is that if we are already passing in (at the
implementation level) an accessibility level parameter to indicate
the level of the master of the call, then that parameter also
defines the accessibility level of any explicitly aliased
parameters. If we are not already passing in such a parameter,
then the accessibility level of any explicitly aliased parameters
is the same as that of any other parameters (or, for that matter,
of any local variables declared immediately within the callable
entity). Either way, we never have to introduce a new implicit
parameter just for an explicitly aliased parameter - we either
reuse a parameter that was already being passed in for another
reason or we don't need an implicit parameter at all. This
simplifies the implementation.
This relies on the fact (we hope and believe it is a fact) that
if no function-result-accessibility-level implicit parameter is
passed in, then there will be no dynamic accessibility checks
comparing the level of an explicitly aliased parameter with the
level of the function result object. If such a check were
ever performed then it would fail (because in that case the
accessibility level of the explicitly aliased parameter is the
same as that of a local variable) and that would be bad.
We believe this is not a problem because no such check will be
performed.
Some additional details we didn't really discuss, but which
seem worth noting:
There will be some RM wording work in precisely defining the
predicate that determines which category a function falls
into. If the result type is class-wide, or has at least one
access discriminant, or has a subcomponent subtype which is
unconstrained and has at least one access discriminant (yes,
this is possible), then an accessibility level parameter is
needed. Probably also for the case where the result type is
an anonymous access type.
It is proposed that the type of an explicitly
aliased parameter plays no role in determining its
accessibility level. Given a function result type like
type Result_Type (X : access Integer) is null record;
and an explicitly aliased parameter like
Str : aliased String;
one could imagine noticing that the function result couldn't
possibly contain a reference to any part of the parameter and
therefore the accessibility level of the parameter could be
defined as for a parameter of a procedure. That is not what
is being proposed here.
Static semantics:
Scrap the distinction of being in a return
statement/expression vs. not. Keep, at least in effect,
the existing rule
when determining whether the accessibility level of an
explicitly aliased parameter of F is statically deeper than
the level of the return object of F, the level of the return
object is considered to be the same as that of the level of
the explicitly aliased parameter
Note that making this rule apply throughout the entire function
body instead of only within a return statement/expression should
have no effect because no comparisons where the rule makes a
difference are possible outside of a return
statement/expression. Thus, eliminating the distinction
is non-essential semantics-preserving cleanup.
Opinions?
****************************************************************
From: Jeff Cousins
Sent: Thursday, September 19, 2019 7:11 AM
The motivation seems good, and the proposal seems reasonable as far as I
can tell, but it would be a brave man who made any definitive statements
on dynamic accessibility checking.
****************************************************************
From: Richard Wai
Sent: Saturday, September 21, 2019 12:51 PM
> The idea is that if we are already passing in (at the
> implementation level) an accessibility level parameter to indicate
> the level of the master of the call, then that parameter also
> defines the accessibility level of any explicitly aliased
> parameters.
This seems to mean that, for example, procedures with explicitly aliased
parameters would have an accessibility level potentially above the local
level.
So for example, this would be legal (currently not):
declare
type Element is ...;
type Element_Access is access all Element;
type pointer is
Record
Ref: Element_Access;
End record;
procedure Relink (Ptr: in out Pointer; E: aliased in out Element) is
begin
Ptr.Ref := E'Access;
end Relink;
A,B: aliased Element;
Ptr_A, Ptr_B: Pointer;
begin
Ptr_A.Ref := A'Access;
Ptr_B.Ref := B'Access;
Relink (Ptr_B, A);
End;
Am I misunderstanding this? I get the feeling that this is specifically
intended for function and their return objects specifically (kind of as it
was before), but this isn't very clear from what I read..
****************************************************************
From: Gary Dismukes
Sent: Monday, September 23, 2019 11:55 AM
> > The idea is that if we are already passing in (at the
> > implementation level) an accessibility level parameter to indicate
> > the level of the master of the call, then that parameter also
> > defines the accessibility level of any explicitly aliased
> > parameters.
>
> This seems to mean that, for example, procedures with explicitly aliased
> parameters would have an accessibility level potentially above the local
> level.
My understanding is that this would only affect functions whose return type
requires passing in a run-time accessibility level, so doesn't affect
procedures at all.
> So for example, this would be legal (currently not):
No, the legality of your example would not be affected by this rule
change/clarification, AFAIK.
> declare
> type Element is ...;
> type Element_Access is access all Element;
>
> type pointer is
> Record
> Ref: Element_Access;
> End record;
>
> procedure Relink (Ptr: in out Pointer; E: aliased in out Element) is
> begin
> Ptr.Ref := E'Access;
> end Relink;
>
> A,B: aliased Element;
> Ptr_A, Ptr_B: Pointer;
>
> begin
> Ptr_A.Ref := A'Access;
> Ptr_B.Ref := B'Access;
>
> Relink (Ptr_B, A);
> End;
>
> Am I misunderstanding this? I get the feeling that this is specifically
> intended for function and their return objects specifically (kind of as it
> was before), but this isn't very clear from what I read..
It's specifically related to certain functions (not all functions).
As Steve wrote:
> Dynamic semantics:
>
> The current RM wording distinguishes between a function and
> other callable entities (e.g., procedures, entries) in defining
> the accessibility level of an explicitly aliased parameter.
>
> Instead, we want to distinguish a function whose result
> type requires (at runtime) passing in an accessibility level
> parameter from other callable entities. Note that the details of
> the rules to capture this distinction, whatever those details
> are, have nothing to do with explicitly aliased parameters.
****************************************************************
From: Randy Brukardt
Sent: Monday, September 23, 2019 8:56 PM
> There was some internal discussion within AdaCore a while back about
> some possible minor changes to the accessibility rules for explicitly
> aliased parameters. This is a description of those changes and their
> motivation. No specific wording is proposed; at this point the goal is
> only to determine whether it makes sense to produce wording for a more
> specific proposal.
>
> Tuck believes that this proposal reflects the original intent of the
> language designers back when explicitly aliased parameters were added
> to the language and so this is just a matter of correcting the RM to
> reflect that original intent.
> In any case, it seems that it would simplify implementations without
> costing users any useful functionality.
Tucker is mistaken. This is not close to the intent of the rules for
explicitly aliased parameters. The intent of the rules (which I mostly
designed with some input from Tucker to check sanity) was:
* It is *never* necessary to pass any dynamic accessibility with or for
explicitly aliased parameters. This is accomplished by a variety of
rules:
(1) We make any needed dynamic checks at the call site, by requiring that
the actual object for an explicitly aliased parameter of a function has
the accessibility of the function result.
(2) For all purposes except the comparision against the accessibility of the
function result, an explicitly aliased parameter acts the same as a
normal parameter (that is, it has local accessibility).
(3) For the comparision against the accessibility of the function result, no
check is ever needed (it was previously checked). This is both statically
and dynamically (the static part is needed as it would necessarily fail
without a special rule).
-----------
Note that (2) means that procedure parameters never have any special
accessibility.
The wording used "inside of a return statement" to describe case (3), since
there wasn't a way in 2005 to talk about the accessibility of a function
result.
At the time the wording was designed for Ada 2005, SAOAATs had static
accessibility, so the rule of (2) would ban the use of
Explicitly-Aliased-Parameter'Access as the initialization of a SAOAAT.
Changing SAOAATs to have dynamic accessibility breaks this property. This is
a problem with SAOAATs however, and not with the original intent -- this is
fixable by banning the offending SAOAATs inside of extended return statements.
Obviously, there could be other problems with the original wording -- it's
accessibility after all, so one can pretty much assume there is some problem.
But I'm not aware of any.
-----------
The rules that Tucker proposed have the very nasty effect of changing the
accessibility of an explicitly aliased parameter when the type of the function
return is changed -- even if the change is to a private component of the type.
It also cannot be a static rule, since the need for dynamic accessibility can
be hidden inside of a return type (any use of an access discriminant on a
component triggers this requirement, even inside of private components). That
means that call-site accessibility checks always have to be required (for
function parameters). It doesn't help to imply that some other rule is
possible.
I don't see any advantage to using dynamic accessibility for explicitly
aliased parameters in any context. It certainly isn't necessary to support
any of their intended uses. I'll need to see some examples of why that is
necessary before I foist any such overhead on any program.
I could see rewording with current rules to use "master of the call" (a term
that didn't exist when these rules were written) in such a way to avoid having
to talk about being within/without a return statement. Other changes don't
seem to be required (pending some compelling example of an unintended usage).
This topic is clearly not thought out at all, since the entire proposal is
built on a serious misunderstanding of the intent of the rules. It's
unfortunate that no one asked me about this before proposing a seriously
flawed complete replacement of the rules which adds serious dynamic overhead.
Much more discussion is required.
****************************************************************
From: Richard Wai
Sent: Monday, September 23, 2019 10:46 PM
...
> * It is *never* necessary to pass any dynamic accessibility with or
> for explicitly aliased parameters. This is accomplished by a variety of rules:
>
> (1) We make any needed dynamic checks at the call site, by requiring that
> the actual object for an explicitly aliased parameter of a function has
> the accessibility of the function result.
> (2) For all purposes except the comparision against the accessibility
> of the function result, an explicitly aliased parameter acts the same as a
> normal parameter (that is, it has local accessibility).
> (3) For the comparision against the accessibility of the function
> result, no check is ever needed (it was previously checked). This is both
> statically and dynamically (the static part is needed as it would
> necessarily fail without a special rule).
>
> -----------
Perfectly stated. The whole idea of accessibility levels passing into
subprograms dynamically seems like a pretty dangerous idea, even if it is
supposedly transparent to the user. I was a bit thrown off by why the
accessibility check would happen in the subprogram body itself.
I do think the RM could make the role and purpose of explicitly aliased
parameters a little bit more clear to the average user, for what it's worth.
But this proposal seems to be more about allowing awkward implementations.
> This topic is clearly not thought out at all, since the entire
> proposal is built on a serious misunderstanding of the intent of the rules.
> It's unfortunate that no one asked me about this before proposing a
> seriously flawed complete replacement of the rules which adds serious
> dynamic overhead. Much more discussion is required.
I'm with you there..
****************************************************************
From: Tucker Taft
Sent: Thursday, September 26, 2019 3:43 PM
I suspect we are in violent agreement here. Steve's initial attempt
introduced dynamic checks even in cases where there was nothing being passed
in for other reasons. I was trying to eliminate any extra overhead, so there
would only be dynamic checks when we already had the information available.
If we can go further and eliminate the dynamic checks completely at the point
of the return statement, I am all in favor.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 1, 2019 6:27 PM
Attached is the AI I came up with. Not sure if Steve has some examples where
it would be important to have the "right" dynamic level, but I assumed those
don't exist and wrote the simplest possible change.
****************************************************************
[From WG 9 Review #41 - Tucker Taft:]
In 3.10.2(5/5) it seems that the following paragraphs all relate to being
"tied to each other." To avoid that, we should probably alter the lead-in a
bit. Currently we say:
Each master, and each entity and view created by it, has an accessibility
level; when two levels are defined to be the same, the accessibility levels
of the two associated entities are said to be tied to each other:
Better might be:
Each master, and each entity and view created by it, has an accessibility
level, as defined below; in the following, we refer to the accessibility
levels of two entities as being tied to each other if these rules imply
their levels will always be the same:
[Editor's response:]
I don't think any part of 3.10.2(5/5) makes much sense as a Lead-in. This is
way too important to bury in a lead-in to an enless set of bullets. Perhaps
we should have a paragraph introducing the concept of accessibility levels
and "tied", then then a separate lead-in for the specific definitions of
accessibility levels, Maybe something like:
Each master, and each entity and view created by it, has an accessibility
level; when two levels are defined to be the same, the accessibility levels
of the two associated entities are said to be tied to each other{.
Accessibility levels are defined as follows}:
[Tucker's response:]
Your suggestion seems fine to me. I think you could combine your two
paragraphs without losing the importance of the definition, but up to
you to decide!
[Editor's response:]
OK; I think you're right about just adding to the end of 3.10.2(5/5). And
that allows treating this as an Editorial Review on AI12-0345-1. So I did
that.
****************************************************************
Questions? Ask the ACAA Technical Agent