!standard 3.10.2(5) 20-01-13 AI12-0345-1/02 !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 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 the body of F. 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. ****************************************************************