Version 1.2 of ai12s/ai12-0345-1.txt
!standard 3.10.2(13.4/4) 19-09-30 AI12-0345-1/01
!standard 13.11.4(21/3)
!standard 13.11.4(31/3)
!class binding interpretation 19-09-30
!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
Replace 3.10.2(13.4/4) with:
The accessibility level of an explicitly aliased (see 6.1) formal parameter
in a function body the same as any other formal parameter, except that it is
defined to match the level of the master of the call when compared to the
level of the return object of the function.
AARM Reason: We make checks on the actual object for an explicitly aliased
parameter of a function to ensure that it can be returned, so we define that
no checks are ever needed in that case. For all other uses, it acts the same
as any other parameter (that is, it is treated as local to the function).
AARM Implementation Note: If the dynamic level of an explicitly aliased
parameter is needed for some purpose, it is local to the function -- it is
never necessary to pass in the actual level of the call for explicitly aliased
parameters. Note that the matching defined here can be implemented by simply
omitting any check in the case where one is matching an explicitly aliased
parameter to the master of the call.
!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.
Therefore, we reword the dynamic accessibility of explicitly aliased parameters
to match the intended model exactly.
---
An alternative model was proposed where the dynamic accessibility of an
explicitly aliased parameter would be that of the return object, if the
implementation would have to pass the level along with a call. This model
would also have no additional cost, but it would have a maintenance hazard,
as the accessibility of the parameter could change if the return type is
changed (possibly even if only the private components of some hidden part
of the return type is changed). This could cause working code to suddenly
start raising Program_Error rather mysteriously.
[Author's note: Steve's proposal makes large changes to the accessibility
model for explicitly aliased parameters. That seems dangerous, accessibility
is confusing enough without changing wording that we have some (small? :-)
level of confidence in. I'd prefer to change as little as possible, especially
as the intent was that no one could ever see the (real) dynamic accessibility
level of an explicitly aliased parameter.
Steve didn't provide any of the examples that caused this discussion (I have
to assume there were some, so it's impossible to tell if the "easy"]
!ASIS
No ASIS effect.
!ACATS test
!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.
****************************************************************
Questions? Ask the ACAA Technical Agent