!standard 3.10.2(10.3/5) 20-09-09 AI12-0390-1/03 !standard 3.10.2(10.4/3) !class binding interpretation 20-08-31 !status Amendment 1-2012 20-09-09 !status ARG Approved 14-0-0 20-09-09 !status work item 20-08-31 !status received 20-08-28 !priority Low !difficulty Easy !qualifier Omission !subject Conversions of anonymous access function results !summary Function call with anonymous access result behaves like an allocator with respect to accessibility. !question The following is an excerpt from ACATS test C3A0025: declare function Func_1 (...) return not null access SubStr is begin ...; end Func_1; Obj : access SubStr; begin begin Obj := Func_1 (...); 1) a strict reading of the RM leads to the conclusion that this construct is illegal (see Discussion); and 2) this is not what anyone intended. We have this same problem in other cases involving converting the anonymous type of a function call to another anonymous access type. For example, the target type of the conversion might be the anonymous access type of a non-discriminant component, or of an object renaming, or of the return object of an extended return statement. Should this be fixed? (Yes.) !recommendation (See Summary.) !wording Replace 3.10.2(10.3/5) and 3.10.2(10.4/3): If the result is of an anonymous access type and is converted to a named access type the operand of an explicit conversion, the master is that of the target type of the conversion; If the result is of an anonymous access type and defines an access discriminant, the master is the same as that for an object created by an anonymous allocator that defines an access discriminant (see below for the allocator rules; those rules apply even if the access result is of an access-to-subprogram type). with: If the result is of an anonymous access type and is converted to a (named or anonymous) access type, the master is determined following the rules given below for determining the master of an object created by an allocator (even if the access result is of an access-to-subprogram type); !discussion Tucker Taft noted: The point is that if the result is converted to a different anonymous access type, the level of the master is that of this other anonymous access type, where for a [stand-alone object of an anonymous access type] we define this to be the level of its declaration. The access discriminant is just a special case of this as well. The key point here is that the same rule applies to all anonymous access types. The current Standard wording does not capture this intent. --- Here is the chain of reasoning leading to the the conclusion that the C3A0025 construct is currently illegal: As per 5.6, an assignment statement involves a conversion: The value of the expression is converted to the subtype of the target. So the RHS in the assignment statement in the example is converted to the subtype of Obj. We have a 4.6 legality rule for type conversions: The accessibility level of the operand type shall not be statically deeper than that of the target type, unless the target type is an anonymous access type of a stand-alone object. If the target type is that of such a stand-alone object, the accessibility level of the operand type shall not be statically deeper than that of the declaration of the stand-alone object. This rule is being violated (specifically, the second sentence). The level of the declaration of Obj is clear. Nothing needs to be said about that. What is the accessibility level of the operand type of the conversion? We start with 3.10.2(10.7): In the case of a call to a function whose result type is an anonymous access type, the accessibility level of the type of the result of the function call is also determined by the point of call as described above. So how do those rules "described above" apply in this case? 3.10.2(10.1) introduces a bulleted-list of rules: The accessibility level of the result of a function call is that of the master of the function call, which is determined by the point of call as follows: We'll look at the bulleted list items one by one. First, we've got: If the result is used (in its entirety) to directly initialize part of an object, ... That doesn't apply here; if there is any doubt, note the accompanying AARM text: Similarly, an assignment_statement is not an initialization of an object, so this bullet does not apply. Next comes: If the result is of an anonymous access type and is converted to a named access type ... If the result is of an anonymous access type and defines an access discriminant ... The result is of an anonymous access type, but it is being converted to the anonymous access type of a saooaaat, so neither of these apply. Next up: 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 No return statements in sight, so that doesn't apply. Which leaves us with In other cases, the master of the call is that of the innermost master that evaluates the function call. The "innermost master" in this case is the assignment statement. The level of the assignment statement is statically deeper than the level of the declaration of Obj, and therefore the implicit type conversion is illegal. !corrigendum 3.10.2(10.3/5) @drepl @xinbull @dby @xinbull !corrigendum 3.10.2(10.4/3) @ddel @xinbull !ASIS No ASIS effect. !ACATS test No additional ACATS test needed (the original problem comes from an existing ACATS test). !appendix From: Steve Baird Sent: Tuesday, August 25, 2020 6:29 PM The following is an excerpt from ACATS test C3A0025: declare function Func_1 (...) return not null access SubStr is begin ...; end Func_1; Obj : access SubStr; begin begin Obj := Func_1 (...); I believe 1) a strict reading of the RM leads to the conclusion that this construct is illegal; and 2) this is not what anyone intended; and 3) the RM fix is fairly straightforward and might result in reducing, not increasing, the RM's accessibility-related wording (thanks to Tuck for his suggestions in this area). === First, point #1. As per 5.6, an assignment statement involves a conversion: The value of the expression is converted to the subtype of the target. So the RHS in the assignment statement in the example is converted to the subtype of Obj. We have a 4.6 legality rule for type conversions: The accessibility level of the operand type shall not be statically deeper than that of the target type, unless the target type is an anonymous access type of a stand-alone object. If the target type is that of such a stand-alone object, the accessibility level of the operand type shall not be statically deeper than that of the declaration of the stand-alone object. I believe this rule is being violated (specifically, the second sentence). The level of the declaration of Obj is clear. Nothing needs to be said about that. What is the accessibility level of the operand type of the conversion? We start with 3.10.2(10.7): In the case of a call to a function whose result type is an anonymous access type, the accessibility level of the type of the result of the function call is also determined by the point of call as described above. So how do those rules "described above" apply in this case? 3.10.2(10.1) introduces a bulleted-list of rules: The accessibility level of the result of a function call is that of the master of the function call, which is determined by the point of call as follows: We'll look at the bulleted list items one by one. First, we've got: If the result is used (in its entirety) to directly initialize part of an object, ... That doesn't apply here; if there is any doubt, note the accompanying AARM text: Similarly, an assignment_statement is not an initialization of an object, so this bullet does not apply. Next comes: If the result is of an anonymous access type and is converted to a named access type ... If the result is of an anonymous access type and defines an access discriminant ... The result is of an anonymous access type, but it is being converted to the anonymous access type of a saooaaat, so neither of these apply. Next up: 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 No return statements in sight, so that doesn't apply. Which leaves us with In other cases, the master of the call is that of the innermost master that evaluates the function call. The "innermost master" in this case is the assignment statement. The level of the assignment statement is statically deeper than the level of the declaration of Obj, and therefore the implicit type conversion is illegal. ==== Point #2: This is a C-test. Clearly the author of the test (who turns out to be Randy) expected it to be legal. It seems like a useful and reasonable case. My unconfirmed guess is that the impact on users would be noticeable if compilers started correctly disallowing this case. On the other hand, Randy pointed out to me in private correspondence that he was not particularly trying to test this construct (the test in question is mostly about null exclusions) and that in using this construct he was not implicitly claiming that it is a useful pattern. So it is worth noting that the status quo is well-defined and does represent a viable alternative; "insufficiently broken" is a defensible position to take with respect to this issue. If we decide that no RM changes are needed then presumably the test would need to be changed. ==== Point #3: I mentioned to Tuck that we have this same problem in other cases involving converting the anonymous type of a function call to another anonymous access type. For example, the target type of the conversion might be the anonymous access type of a non-discriminant component, or of an object renaming, or of the return object of an extended return statement (although in that last case, one might argue that the existing "the call itself defines the result of a function" rule applies; does an assignment to an extended return object of an anonymous access type "define the result" of the enclosing function?). Tuck put his finger on the problem: > The point is that if the result is converted to a different anonymous > access type, the level of the master is that of this other anonymous > access type, where for a saooaat we define this to be the level of its > declaration. The access discriminant is just a special case of this as > well. One approach would be to combine the two "If the result is of an anonymous access type ..." rules in 3.10.2 If the result is of an anonymous access type and is converted to a named access type the operand of an explicit conversion, the master is that of the target type of the conversion; If the result is of an anonymous access type and defines an access discriminant, the master is the same as that for an object created by an anonymous allocator that defines an access discriminant (even if the access result is of an access-to-subprogram type). into a more general unification something like If the result is of an anonymous access type and is converted to a (named or anonymous) access type, the master is determined following the rules for determining the master of an object created by an allocator (even if the access result is of an access-to-subprogram type). === Thanks to Randy and Tuck for preliminary feedback. Opinions? **************************************************************** From: Tucker Taft Sent: Tuesday, August 25, 2020 8:48 PM > ... > One approach would be to combine the two "If the result is of an > anonymous access type ..." rules in 3.10.2 > > If the result is of an anonymous access type and is converted to a > named access type the operand of an explicit conversion, the master is > that of the target type of the conversion; > > If the result is of an anonymous access type and defines an access > discriminant, the master is the same as that for an object created by > an anonymous allocator that defines an access discriminant (even if > the access result is of an access-to-subprogram type). > > into a more general unification something like > > If the result is of an anonymous access type and is converted to > a (named or anonymous) access type, the master is determined > following the rules for determining the master of an object created > by an allocator (even if the access result is of an > access-to-subprogram type). I do think this is a cleaner approach, though I don't love referring to the allocator rules, but we were already doing that, so this isn't a new issue, and makes sense for a minimal fix. At some point we could perhaps factor out the rules and give it a name, such as the "master of an anonymous construct" or some such thing. Until then, I think it might be helpful to add "-- see below for the allocator rules" at the end of the parenthetical statement. Or alternatively, at some point we could move the allocator rules to the definition of the master of the function call, and then have the anonymous allocator say something like "following the rules for determining the master of a function call" which avoids the awkwardness introduced by access-to-subprogram types, and avoids the forward reference. **************************************************************** From: Jeff Cousins Sent: Friday, August 28, 2020 10:44 AM Your logic seems sound Steve, **************************************************************** From: Steve Baird Sent: Monday, August 31, 2020 5:57 PM Here is an AI for this one, pretty much just writing up as a binding interpretation what has already been discussed. [This is version /01 of this AI - Editor.] **************************************************************** From: Tucker Taft Sent: Tuesday, August 31, 2020 7:35 PM Minor typo below. > ... > > !wording ... I believe the following sentence belongs at the end of the !problem: > The problem is that the current RM wording does not capture this intent. **************************************************************** From WG 9 review issue #51 - Tucker Taft In 3.10.2(10.3/5) we refer to the rules about allocators. I would suggest we at least say "(see below)" since one would typically presume we had already defined the rules about allocators at the point of reference, or that one should look up "allocators" in the table of contents. In fact, the rules are in 3.10.2, but later. Of course ideally we could point to the actual paragraphs where these rules are given (3.10.2(14/3-14.2/3)), but "(see below)" is probably the best we can do. Hence: If the result is of an anonymous access type and is converted to a (named or anonymous) access type, the master is determined following the rules{ given below} for determining the master of an object created by an allocator (even if the access result is of an access-to-subprogram type); [Editor's reply:] After saying "see below" twice, you suggest different wording. Way to be confusing! ;-) Anyway, the change seems harmless, and might help someone (although how much anyone reading the Heart of Darkness can be helped is debatable. :-) Treated this as an Editorial Review on AI12-0390-1, which is the source of this iteration of this rule. ****************************************************************