Version 1.4 of ai12s/ai12-0345-1.txt

Unformatted version of ai12s/ai12-0345-1.txt version 1.4
Other versions for file ai12s/ai12-0345-1.txt

!standard 3.10.2(5)          20-01-15 AI12-0345-1/03
!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 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}:
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.
Delete AARM 3.10.2(10.d.6/3):
- when the function has an explicitly aliased parameter.
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 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); -- (1) begin if Glob then return F2 (C'access); -- Program_Error raised. else return F2 (A.Comp'access); -- Program_Error raised. 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); -- (2) begin if Glob then return F5 (C); -- Illegal. else return F5 (A.Comp); -- OK. 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; -- Illegal. else return F8 (A).Comp'access; -- OK. 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.
!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.

****************************************************************

Questions? Ask the ACAA Technical Agent