CVS difference for ai05s/ai05-0051-1.txt

Differences between 1.2 and version 1.3
Log of other versions for file ai05s/ai05-0051-1.txt

--- ai05s/ai05-0051-1.txt	2007/10/31 02:24:49	1.2
+++ ai05s/ai05-0051-1.txt	2007/11/07 06:32:42	1.3
@@ -1,4 +1,4 @@
-!standard 6.5(21/2)                              07-10-30    AI05-0051-1/02
+!standard 6.5(21/2)                              07-10-31    AI05-0051-1/03
 !class binding interpretation 07-05-04
 !status work item 07-05-04
 !status received 07-04-19
@@ -9,8 +9,10 @@
 
 !summary
 
-*TBD*
+(see recommendation)
 
+!question
+
 How do the various accessibility rules pertaining to function results
 apply in the case of a dispatching call to a function where the accessibility
 level of the function named in the call differs from the accessibility
@@ -18,12 +20,106 @@
 
 !recommendation
 
-Scream, lest your head explode.
+The accessibility level against which to perform run-time accessibility
+checks at the return statement of a dispatching function is determined by the
+level of the function named at the call-site, even if that is different
+from the accessibility level of the function body reached by the dispatching
+call.  If the function has an access result, and the expression of the
+return statement is an (anonymous) allocator, then this accessibility level
+in turn determines the lifetime of the allocated object.
+
+Similar rules would apply for calls through an access-to-subprogram
+value.  The caller's view would determine the accessibility level
+to use for run-time accessibility checks.
 
 !wording
+
+Add after 3.10.2(10.1):
 
-*TBD*
+    Within a return statement that applies to a function with an
+    access result, the accessibility level of the anonymous result
+    access type is determined by the accessibility level of the view
+    of the function named at the point of call.  For the purposes of
+    determining whether this level is statically deeper than another,
+    it is presumed to be the same as the level of the function
+    containing the return statement. [Redundant: Note that for a
+    dispatching call or a call through an access-to-subprogram value,
+    the level of the function named at the point of call might be
+    different from that of the function containing the return
+    statement.]
+    
+Modify 3.10.2(15) as follows:
 
+    The accessibility level of a view of an object or subprogram
+    denoted by a dereference of an access value is the same as that of
+    the access type{, except in the case where the dereference is the
+    name or prefix of a function_call, and the access-to-subprogram
+    value is an access parameter.  In this case, the accessibility
+    level of the view of the function denoted by the dereference is
+    that of the master containing the access parameter}.
+    
+  AARM NOTE: 
+      This is important so that a call through an access-to-subprogram
+      parameter on a function with an access result, a classwide
+      result, or a result with access discriminants, has some
+      reasonable, non-infinitely-deep, accessibility level.  We gave
+      such access-to-subprogram parameters infinitely deep
+      accessibility levels to prevent the access values from being
+      converted to named access-to-subprogram types, but once they
+      have been called and return a value, we need to have something
+      useful in the way of an accessibility level to use when their
+      results have an associated level.  Since the
+      access-to-subprogram parameter is clearly denoting a function
+      from some scope dynamically enclosing the master containing the
+      access parameter, it is safe to give it an accessibility level
+      of that master.
+
+Modify 6.5(8/2) as follows:
+
+    If the result type of a function is a specific tagged type, the
+    tag of the return object is that of the result type. If the result
+    type is class-wide, the tag of the return object is that of the
+    value of the expression. A check is made that the accessibility
+    level of the type identified by the tag of the result is not
+    deeper than that of the [master that elaborated the function
+    body.] {view of the function named at the point of call. 
+    [Redundant: Note that for a dispatching call or a call through an
+    access-to-subprogram value, this level might be different from
+    that of the function containing the return statement.]}  If this
+    check fails, Program_Error is raised.
+
+Modify 6.5(21/2) as follows:
+
+    If the result subtype of a function has one or more unconstrained
+    access discriminants, a check is made that the accessibility level
+    of the anonymous access type of each access discriminant, as
+    determined by the expression or the return_subtype_indication of
+    the function, is not deeper than that of the [master that
+    elaborated the function body.] {view of the function named at the
+    point of call.  [Redundant: Note that for a dispatching call or a
+    call through an access-to-subprogram value, this level might be
+    different from that of the function containing the return
+    statement.]}  If this check fails, Program_Error is raised.
+    
+    
+Modify 7.6.1(11/2) as follows:
+
+    The order in which the finalization of a master performs
+    finalization of objects is as follows: Objects created by
+    declarations in the master are finalized in the reverse order of
+    their creation. For objects that were created by allocators for
+    [an] {a named} access type whose ultimate ancestor is declared in
+    the master, this rule is applied as though each such object that
+    still exists had been created in an arbitrary order at the first
+    freezing point (see 13.14) of the ultimate ancestor type; the
+    finalization of these objects is called the finalization of the
+    collection. {Objects created by allocators for an anonymous access
+    type that are not coextensions of some other object, are finalized
+    in an arbitrary order during the finalization of their associated
+    master.}  After the finalization of a master is complete, the
+    objects finalized as part of its finalization cease to exist, as
+    do any types and subtypes defined and created within the master.
+    
 !discussion
 
 In most cases, the dynamic semantics of access result types follow easily
@@ -47,7 +143,7 @@
 function has been invoked via a dispatching call to the operation of
 the parent type?
 
-Tuck has pointed out that this is an instance of a more general problem
+This is an instance of a more general problem
 associated with uses of the accessibility level of a function body
 in the case where this level does not match the accessibility level
 of the function named in the (dispatching) call.
@@ -151,29 +247,95 @@
       Nested;
     end;
     
-Tuck suggests an implementation model where these problematic dispatching
+This AI presumes an implementation model where these problematic dispatching
 operations of nested extensions expect an accessibility level to be
 passed in to indicate the accessibility level of the function declaration
 named in the call; that level is then used for anonymous-typed allocators
 at the point of return, and for accessibility checks.
-
-This seems like a good approach, but it is not implicit in the current RM.
-Wording changes would be needed - a "clarification" would not suffice.
-
-Furthermore, there are some aspects of this problem that might still
-need resolution even if this proposal were adopted:
-
-1) In the case of a dispatching call to a function with an
-   access result type which returns an allocator, exactly when is the
-   allocated object finalized? This remains a valid (albeit obscure)
-   question even in the case where the parent type and the extension
-   type have the same accessibility level. 7.6.1(11.2) refers to
-   "the first freezing point of the ultimate ancestor type", but
-   is this the freezing point of the access type associated with the
-   function named in the call or with the function whose body is executed?
 
-2) The problem of AI05-0075-1.
+Once we accept that we need to pass in an accessibility level to any
+function that has a class-wide, access-discriminated, or access result
+return type, and is, or might become through renaming, a dispatching
+operation, we conclude that this model might as well be adopted
+universally for functions with such a result type.  In particular,
+because with a call through an access-to-subprogram, it is hard to
+know whether you might reach a dispatching function, some sort of
+level would need to passed whenever making a call through an
+access-to-subprogram.  And since essentially any function might be
+called through an access-to-subprogram value, all functions with such
+a result type will need to expect a passed-in accessibility level.
+
+Once we accept we are always passing in a level for these kinds of
+functions, we need to decide what are the implications for calls
+through access-to-subprogram values.  Since the level of the function
+named by the dereference of an access-to-subprogram value is always at
+least as deep as that of the actual designated function, passing in a
+deeper level will never cause a failure of a run-time accessibility
+check when a corresponding static accessibility check passed.  For the
+cases where there is no static accessibility check, such as with an
+access parameter, this may eliminate run-time check failures exactly
+in cases where they are safe, since code calling through a more deeply
+nested access-to-subprogram type is set up to handle more deeply
+nested results.
 
+Here is an example of where these dynamic levels would make
+a difference:
+    
+           
+    procedure Getting_Fancy(
+      Y : access T;
+      ATF : access function(X : access T) return access T) is
+      
+        G : access T;
+    begin  
+        G := ATF.all(Y);  
+           -- passes in "result level" of master Getting_Fancy
+    end Getting_Fancy;
+    
+         ... 
+    
+    function Identity(X : access T) return access T is
+    begin
+         return X;  -- run-time accessibility check
+                    -- of level of X against "result level" 
+                    -- passed in to be sure X is no deeper
+    end Identity;
+         
+For access-to-subprogram parameters, which have by definition an
+infinitely deep accessibility level, we specify (in 3.10.2(15)) that
+the level of a dereference used to name a function in a call is that
+of the level of the master containing the access parameter.  This is
+essentially the same rule when you take 'Access of a tagged parameter.
+It is treated like a local variable of the subprogram.  So in a
+corresponding way, we treat the call as though it were via an
+access-to-subprogram type declared local to the subprogram containing
+the access parameter.
+
+We need to make the dynamic accessibility level of an access result
+type reflect this same set of rules, so we add a paragraph in 3.10.2
+to specify that the accessibility level comes from the caller's view
+of things.  This is important because if the return expression is an
+(anonymous) allocator, we need to know its accessibility level.
+
+We relax the rules for order of finalization of objects (other than
+coextensions) created by anonymous allocators, since tying them to a
+particular freezing point is tricky, and doesn't seem to be of great
+value to the user.  All that really matters is that they get finalized
+in the master determined by their accessibility level, and that is
+already specified by 7.6.1(4).  For named access types, there is the
+concern that their collections be finalized before any corresponding
+storage pool object gets finalized, but there is no similar
+consideration for non-coextension anonymous allocations, since they
+always use the "default" storage pool.
+
+Note that in some of this wording, we have stopped using the phrase
+"the master that elaborated the function body" and simply talked about
+the level of the (view of the) function.  By definition, the level of
+a declared entity is that of the master that elaborates it, so talking
+about the master that elaborates the function body is a long-winded
+way of saying the level of the function.  By simplifying the wording,
+it is easier to talk about the function "named" at the point of the
+call. 
 
 !ACATS test
 
@@ -433,5 +595,617 @@
 pass in for access parameters is never used for the *target*
 of a conversion, only for the *operand*, so the same logic
 might not work...  Hmmm...
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 31, 2007  12:34 AM
+
+Here is an AI [version /03 - ED.] that Steve started, and
+I finished, which attempts to deal with the case where, from
+an accessibility level point of view, a caller
+has one view of a function, and the return statement
+has a different view.  This can happen in four ways:
+
+
+    1) In a dispatching call, where the caller
+       is calling an operation of a parent
+       type T1, and is actually reaching an
+       overriding defined for a nested extension T2.
+       (caller view is not as deep as called function)
+
+    2) In a dispatching call, where the caller
+       is calling an operation of a nested
+       extension T2, and is actually reaching
+       an inherited operation from a parent T1.
+       (caller view is deeper than called function)
+
+    3) In a call through an access-to-subprogram
+       value, where the access type is declared at
+       a deeper level than the designated subprogram.
+       (caller view is deeper than called function)
+
+    4) In a call through an access-to-subprogram
+       value that is an access parameter, which
+       has an "infinite" accessibility level, clearly
+       deeper than the designated subprogram.
+       (caller view is *much* deeper than called function)
+
+After much head scratching and trying various solutions,
+we settled on uniformly using the caller's view for
+the run-time accessibility checks performed at a return
+statement.  This also means that the caller has an
+accurate view of the accessibility characteristics
+of the returned object.  In addition it means that
+if an access parameter is passed by the caller, the
+level of the access parameter can be meaningfully
+compared with the "result" level passed in, in case
+the access parameter is used as part of the result
+in one way or another (e.g. as an access discriminant,
+or as the access result).
+
+Case (4) represented an existing hole in 3.10.2, where
+we hadn't properly figured out the accessibility
+characteristics of results returned from calls through
+an access-to-subprogram parameter.  In this AI, we
+suggest that rather than the result of such a call
+also having an "infinite" accessibility level, it
+should have a level corresponding to the master containing
+the access parameter, as though the access value were
+of an access-to-subprogram type declared local to the
+master with the access parameter.
+
+Anyway, I am giving away too much in the cover letter.
+Time to read the AI!
+
+****************************************************************
+
+From: Stephen W. Baird
+Sent: Wednesday, October 31, 2007  6:12 PM
+
+> The accessibility level against which to perform
+> run-time accessibility checks at the return statement
+> of a dispatching function is determined by the
+> level of the function named at the call-site, even if
+> that is different from the accessibility level of the
+> function body reached by the dispatching call.  If the
+> function has an access result, and the expression of the
+> return statement is an (anonymous) allocator, then this
+> accessibility level in turn determines the lifetime of
+> the allocated object.
+
+I think this means that if a function with an anonymous
+access result type returns an allocator, then the allocated
+object may have a different master than if the function
+had returned a recursive call which returned an allocator.
+This makes me nervous. Is this what we want?
+
+If a caller makes a dispatching call on a subprogram
+declared in a less nested scope than the scope of the
+executed function body and the callee then attempts to
+return the result of a nondispatching recursive call,
+is Program_Error raised because the recursive
+call might have successfully returned a "bad" reference?
+
+It seems odd to have a simple recursive call like
+    function F return access Integer is
+    begin
+      if ... then
+        return F;
+      end if;
+      ...
+    end F;
+failing the accessibility check associated with an
+access type conversion. It seems like the source type
+and the target type are the same, but this AI
+suggests that they aren't (at least dynamically).
+
+I suspect that I'm just confused; this stuff is tricky.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 31, 2007  7:19 PM
+
+> I think this means that if a function with an anonymous
+> access result type returns an allocator, then the allocated
+> object may have a different master than if the function
+> had returned a recursive call which returned an allocator.
+> This makes me nervous. Is this what we want?
+
+Probably not.
+
+I think we need to presume that when calling such
+a function in a return statement, the level against
+which the returned value is being checked must be
+passed on to the called function.  That is, in:
+
+    return Func(...);
+
+if Func has a result type that is classwide,
+access-discriminated, or an anonymous access
+type, then if a level is passed into the
+enclosing function, the same level should be
+passed to Func.  I suspect AI05-51 will need
+some extra wording to that effect, though
+conceivably it may be implied by something
+already in the AI.
+
+> 
+> If a caller makes a dispatching call on a subprogram
+> declared in a less nested scope than the scope of the
+> executed function body and the callee then attempts to
+> return the result of a nondispatching recursive call,
+> is Program_Error raised because the recursive
+> call might have successfully returned a "bad" reference?
+> 
+> It seems odd to have a simple recursive call like
+>     function F return access Integer is
+>     begin
+>       if ... then
+>         return F;
+>       end if;
+>       ...
+>     end F;
+> failing the accessibility check associated with an
+> access type conversion. It seems like the source type
+> and the target type are the same, but this AI
+> suggests that they aren't (at least dynamically).
+
+I think your example would work as desired if the
+return statement passes along the dynamic accessibility
+level it received implicitly.
+
+> I suspect that I'm just confused; this stuff is tricky.
+
+I think you have identified an important additional
+requirement, namely that the return statement passes
+along the dynamic accessibility level.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 31, 2007  8:38 PM
+
+> ...
+> I think we need to presume that when calling such
+> a function in a return statement, the level against
+> which the returned value is being checked must be
+> passed on to the called function.  That is, in:
+> 
+>    return Func(...);
+> 
+> if Func has a result type that is classwide,
+> access-discriminated, or an anonymous access
+> type, then if a level is passed into the
+> enclosing function, the same level should be
+> passed to Func.  I suspect AI05-51 will need
+> some extra wording to that effect, though
+> conceivably it may be implied by something
+> already in the AI.
+
+I think the paragraph proposed in the AI to follow
+3.10.2(10.1) could be rewritten roughly as follows:
+
+     Within a return statement that applies to a
+     function with a result subtype that is an access
+     result, that is class-wide, or that has one or more
+     unconstrained access discriminants, the (dynamic)
+     accessibility level of this function, and other
+     functions with such a result subtype elaborated by
+     the same master, are considered to have the same
+     accessibility level as that of the view of the
+     function named at the point of call. [Redundant:
+     Note that for a dispatching call or a call through
+     an access-to-subprogram value, the level of the
+     function named at the point of call might be
+     different from that of the function containing the
+     return statement.]
+
+The basic idea is that within the return statement,
+the function and all other similar functions act
+as though there were of the same accessibility
+level as the function named at the call site.
+That means that any function that has a level
+passed in, and that is of the same level as
+the function with the return statement, will
+be passed in the same dynamic level.
+
+****************************************************************
+
+From: Stephen W. Baird
+Sent: Thursday, November 1, 2007  4:07 PM
+
+This seems like it is getting way too complicated.  I don't like this
+call-site sensitivity (if you call this function from here, it means
+something different than if you call it from there).
+
+Before looking at any of the details of this proposal,
+let's back up and look at why access result types were introduced.
+They were only intended to be a notational convenience, to spare the
+user the inconvenience of declaring a named access type.
+We were introducing anonymous access types in other places and
+access result types for functions fit in nicely with these other changes.
+They were not intended to have any interesting dynamic semantics,
+nor was it realized at the time that they would have to.
+
+Now we've realized that there are some fairly complicated problems in
+this area, I'd like to at least consider the possibility of solving them 
+all
+by statically disallowing the problematic cases.  We could introduce a 
+rule that the profile of a dispatching function or of an 
+access-to-function type
+cannot have an (anonymous) access result type. Or,  if that is too
+restrictive, we could impose more stringent restrictions on the use of the
+'Access attribute for subprograms if the profile has an access result 
+type,
+along with similar restrictions for nested extensions if there is a 
+primitive
+operation with an access result type. The point is that we could devise
+rules of some sort for statically disallowing the problematic cases.
+
+What do folks think about this general approach?
+
+Ok, now for a more specific point about this proposal.
+
+In implementation terms, the general idea is that within a return 
+statement
+that is returning from a function which was passed an
+accessibility_level/storage_pool/whatever descriptor,  you pass the
+descriptor reference along  whenever you call any  function that also
+takes such a descriptor parameter.
+
+Consider the following example:
+
+ function F (Controlling_Operand : Some_Tagged_Type;
+                      Flag                : Boolean := False)  return 
+access Designated is 
+    begin
+        return Result : access Designated do
+            declare
+                task T;
+                task body T is
+                    procedure P is
+                    begin
+                        if Flag then
+                            Result := new Designated;
+                        else
+                            Result := F (not Flag);
+                        end if;
+                    end P;
+                begin
+                    P;
+                end T;
+            begin
+                null;
+            end;
+        end return;
+    end F;
+ 
+This example demonstrates (I think) that when you say "within a
+return statement", you really mean it. The rule even applies inside
+of nested procedures, tasks, etc. But that would mean that it would
+even apply inside of a nested return statement (returning from a nested
+function), and so now you have contradictory requrements (I think)
+imposed by the two enclosing return statements. The simple
+solution (let the innermost return statement win) doesn't work.
+Consider modifying the example so that a recursive call to F
+    Result := new F (not Flag);
+occurs within a return statement within a function declared within
+the declare block that is declared within F's (one and only)
+return statement. 
+
+I expect that we can work this particular corner case out, but  it
+seems likely that there are other dragons lurking in the vicinity.
+
+****************************************************************
+
+From: Stephen W. Baird
+Sent: Thursday, November 1, 2007  5:05 PM
+
+A correction to the example of my previous message on this thread:
+   The recursive call to F lacks a value for
+   the Controlling_Operand parameter. I intended
+   to pass along the existing parameter in
+   a nondispatching call:
+      Result := F (Controlling_Operand, not Flag);
+
+****************************************************************
+
+From: John Barnes
+Sent: Thursday, November 1, 2007  4:35 PM
+
+As time has gone on I am becoming to feel that anonymous access types in
+general (that is universally) were perhaps a mistake. I know I had great
+trouble weaving them into my book. Personnally I would now never use them.
+Ada prides itself in being precise and anon types seem to have slid us down
+a slippery slope of confusion leading to accessibility problems.
+
+Of course anonymous access to subprogram parameters are important but they
+are just essentially subprogram parameters as in Algol 60 so that is no
+problem.
+
+
+Anyway. So I am very sympathetic to Steve's view. Too late too late the
+virgin cried no doubt!
+
+See y'all next week. Or a subset thereof.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, November 1, 2007  9:41 PM
+
+> ...  We could introduce a 
+> rule that the profile of a dispatching function or of an access-to-function type
+> cannot have an (anonymous) access result type. Or,  if that is too
+> restrictive, we could impose more stringent restrictions on the use of the
+> 'Access attribute for subprograms if the profile has an access result type,
+> along with similar restrictions for nested extensions if there is a primitive
+> operation with an access result type. The point is that we could devise
+> rules of some sort for statically disallowing the problematic cases.
+> 
+> What do folks think about this general approach?
+
+I think it depends how draconian is the restriction.
+Disallowing them altogether for dispatching functions
+would seems pretty draconian.  Disallowing nested
+extensions of types with such functions is less
+draconian.  I think once you do that, then you
+can eliminate the issue with calling through
+access-to-subprogram values, because such functions
+no longer need to be passed a level.
+
+But remember, we also have the same issue for functions
+returning class-wide types and types with unconstrained
+access discriminants, though perhaps those aren't as bad.
+
+> Ok, now for a more specific point about this proposal.
+> 
+> In implementation terms, the general idea is that within a return 
+> statement that is returning from a function which was passed an
+> accessibility_level/storage_pool/whatever descriptor,  you pass the
+> descriptor reference along  whenever you call any  function that also
+> takes such a descriptor parameter.
+
+Only if the function called in the return statement
+is at the *same* level as the function to which
+the return statement applies.
+
+> Consider the following example:
+> 
+>  function F (Controlling_Operand : Some_Tagged_Type;
+>                       Flag                : Boolean := False)  return 
+> access Designated is 
+>     begin
+>         return Result : access Designated do
+>             declare
+>                 task T;
+>                 task body T is
+>                     procedure P is
+>                     begin
+>                         if Flag then
+>                             Result := new Designated;
+>                         else
+>                             Result := F (not Flag);
+>                         end if;
+>                     end P;
+>                 begin
+>                     P;
+>                 end T;
+>             begin
+>                 null;
+>             end;
+>         end return;
+>     end F;
+>  
+> This example demonstrates (I think) that when you say "within a
+> return statement", you really mean it. The rule even applies inside
+> of nested procedures, tasks, etc. But that would mean that it would
+> even apply inside of a nested return statement (returning from a nested
+> function), and so now you have contradictory requrements (I think)
+> imposed by the two enclosing return statements.
+
+Not true, because the rule only applies if the called
+function is at the same level as the function to which the
+return statement applies.  If you have a nested return
+statement, clearly the function called could only match
+at most one of them, and it is that one whose dynamic level
+is passed along.
+
+> ... The simple
+> solution (let the innermost return statement win) doesn't work.
+> Consider modifying the example so that a recursive call to F
+>     Result := new F (not Flag);
+> occurs within a return statement within a function declared within
+> the declare block that is declared within F's (one and only)
+> return statement. 
+> 
+> I expect that we can work this particular corner case out, but  it
+> seems likely that there are other dragons lurking in the vicinity.
+
+I don't think this particular one is a problem.
+But I will never underestimate your amazing ability
+to find bizarro cases.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, November 5, 2007  3:10 PM
+
+> > What do folks think about this general approach?
+>
+> I think it depends how draconian is the restriction.
+> Disallowing them altogether for dispatching functions
+> would seems pretty draconian.  Disallowing nested
+> extensions of types with such functions is less
+> draconian.  I think once you do that, then you
+> can eliminate the issue with calling through
+> access-to-subprogram values, because such functions
+> no longer need to be passed a level.
+
+I am sympathetic to the notion of finding a way to disallow the
+problematic cases statically, if only because Tuck's proposed rule
+caused my brain to explode.  However, I foresee difficulties with
+privacy and perhaps the contract model.  If the function with an
+anonymous access result is declared in a private part, how do you
+disallow nested extensions outside of the package?  Perhaps other
+rules of the language prevent problems in this case, but I wouldn't
+bet on it.
+
+****************************************************************
+
+From: Stephen W. Baird
+Sent: Monday, November 5, 2007  3:51 PM
+
+Another option would be to introduce a rule that the Storage_Size of an
+access result type is "defined by the language to be zero" (4.8(5.3/2)).
+
+This would only help with the allocator-related problems mentioned
+in the AI, but it still might turn out to be a useful part of a more 
+complete solution if it isn't rejected as being too restrictive.
+
+In any case, this rule  doesn't seem to suffer from any of the contract
+model difficulties that you describe.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, November 5, 2007  9:40 PM
+
+> I am sympathetic to the notion of finding a way to disallow the
+> problematic cases statically, if only because Tuck's proposed rule
+> caused my brain to explode.  ...
+
+My brain was exploding when I proposed it as well.
+
+How about this alternative:
+
+A) Don't do anything special (at the call site)
+for dispatching operations that return classwide
+or access-discriminated result types.  Instead,
+just use the tag of the controlling operand to
+determine the run-time accessibility level of the result
+of calling such a dispatching function.  For example:
+
+     type T is tagged null record;
+     type Has_Acc_Discrim(D : access Q) is null record;
+
+     function Gizmo(X : T) return Has_Acc_Discrim;
+
+If Gizmo is a dispatching operation of T, then when
+we make a dispatching call on it using an actual
+parameter of type T'Class, we dispatch to a routine
+that is associated with the type identified by the
+tag of the actual.  E.g:
+
+    Y : T2;
+
+    HAD_Obj : Has_Acc_Discrim renames Gizmo(T'Class(Y));
+
+So what is the run-time accessibility level associated
+with HAD_Obj?  With this model, it is determined by the
+run-time tag of the actual controlling operand, in this
+case "T'Class(Y)", i.e. the level implied by T2'Tag.
+We know that all controlling operands have the same tag,
+so there is no ambiguity.  If the corresponding operation
+is actually inherited for the given descendant, that
+is OK, because the actual accessibility level of the
+return object is no deeper than that implied by the
+controlling tag.
+
+B) For dispatching operations with access result,
+we need to worry about two things, one, what sort of
+run-time accessibility check is performed, and two, what
+storage pool is used if the return statement consists
+of an allocator.  I would propose we model an access result
+like "return access Q" roughly like "return Has_Acc_Discrim".
+That is, we treat the access result as though it
+were an access discriminant of an imaginary "wrapper"
+type.  The context of the call-site would determine the
+storage pool to be used for an anonymous allocator
+in the return statement.  The accessibility level
+check would be the same as that given above for A,
+namely we check against the level of the master
+of the function body, and the caller presumes the
+level is that of the actual controlling tag.
+
+To be more precise what I mean by using the context
+of the call-site to determine the storage pool,
+if the result of the call is converted explicitly
+or implicitly to another access type, the storage
+pool of that target access type is passed in as the
+storage pool for the access result.  If the result of
+the call is dereferenced, then it is treated the same
+way a function returning an object with access
+discrims, and the context of the usage of the
+dereference determines the storage pool.
+
+The reason I like this rule is that it means that there
+is some chance you can avoid storage leaks associated
+with access results, while also solving the problem
+associated with calls on dispatching operations
+on nested type extensions.  The current rule pretty much
+guarantees storage leaks, since the default storage pool
+from which the anonymous allocator allocates does
+not support reclamation, and it is at a level that
+means the result will often live forever.  By instead
+determining the storage pool by the usage of the
+result, we can avoid the storage leak, while still
+remaining safe with respect to accessibility.
+
+For example:
+
+    function Gizmo2(X : T) return access Q;
+
+    ...
+
+    type Z is access Q;
+
+    R : Z := Gizmo2(blah);
+      -- pass in storage pool associated with Z
+      -- to be used by anonymous allocator
+
+    S : Z := new Q'(Gizmo2(blurfo).all);
+      -- again, here we pass in storage pool
+      -- associated with Z, as we would have
+      -- if Gizmo2 returned an object with
+      -- access discrims
+
+    V : access Q := Gizmo2(blech);
+      -- pass in a storage pool associated with
+      -- the implicit access type of V, essentially
+      -- the local frame
+
+      ...
+
+    return Gizmo2(belch);
+      -- pass in the storage pool associated with
+      -- the result type, which if it is also "access Q"
+      -- means the same storage pool passed into the
+      -- enclosing function.
+
+------------
+
+I think the above approach gives an answer to the
+interesting questions, such as:
+
+   1) what run-time accessibility check is performed
+      at a return statement when the result type is
+      classwide, access-discriminated, or an access result?
+     Answer: exactly what we currently say in Ada 2005 --
+      check against the level of the master that elab'ed
+      the function body.
+
+   2) what run-time accessibility level does the result of
+      a call on a dispatching function have?
+     Answer: the same as that of the controlling tag
+      of the call.
+
+   3) What storage pool should be used for access results?
+     Answer: a storage pool passed in from the caller,
+      determined by the context of the call, using a model
+      where we treat the result as though it were an
+      access discriminant of a "wrapper" result type.
 
-****************************************************************
\ No newline at end of file
+****************************************************************

Questions? Ask the ACAA Technical Agent