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

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

--- ai05s/ai05-0051-1.txt	2008/06/16 02:37:08	1.7
+++ ai05s/ai05-0051-1.txt	2008/08/01 04:26:14	1.8
@@ -1,4 +1,4 @@
-!standard 3.10.2(14/2)                              08-06-15    AI05-0051-1/06
+!standard 3.10.2(14/2)                              08-07-19    AI05-0051-1/07
 !standard 3.10.2(14.4/2)
 !standard 3.10.2(19/2)
 !standard 6.5(21/2)
@@ -10,38 +10,52 @@
 !priority Medium
 !difficulty Hard
 !qualifier Clarification
-!subject Accessibility checks on function return
+!subject Accessibility checks for class-wide types and return from nested-extension primitives
 
 !summary
 
-(see recommendation)
+(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
-level of the function whose body is executed?  Similarly, what storage
-pool should be used by an anonymous allocator returned by a function
-with an access result, if the function is reached by a call that
-dispatches to a nested type extension?
+level of the function whose body is executed?  (The caller passes in
+an accessibility level to be used for dynamic checks.)
 
+Similarly, what storage pool should be used by an anonymous allocator
+returned by a function with an access result, if the function is reached
+by a call that dispatches to a nested type extension? (Use a pool identified
+by the caller.)
+
+In the case where the result returned by a function has one or
+more access discriminants, should the runtime check of 6.5(21/2)
+be performed even if the function result type is class-wide and
+does not have the same discriminants as the function result? (Yes.)
+
+Should similar checks be performed for class-wide allocators? (Yes.)
+
+Should compile-time checks analogous to the existing checks of
+4.8(5.2/2) and 6.5(5.6/2) also be performed? (Yes.)
+
 !recommendation
 
 We propose that where accessibility checks are currently required in
 return statements for access discrminants or access results, the dynamic
 check be based on an accessibility level passed in from the caller,
 while the static check would still be based on the accessibility level
-of the master that elaborated the function body. Similarly, the
+of the master that elaborated the function body.  Similarly, the
 storage pool to use for a function access result would be determined
-by information passed in by the caller. This eliminates the
+by information passed in by the caller.  This eliminates the
 problem with dispatching calls, since the passed-in level is unaffected
 by whether the call is a dispatching call to a primitive of a type
 declared at a more nested level than the function named in the call.
 
 Currently, almost all cases where such an accessibility check might be
 performed as part of a return statement, the caller already needs to
-pass in information because the returned object might need to be created
+pass in information because the returned object, or objects designated
+by its access discriminants, might need to be created
 in a place or storage pool determined by the context of the call, or
 might need finalization at a point determined by the caller.
 
@@ -63,6 +77,11 @@
 changed to overcome the problem with dispatching calls to overridings of
 nested extensions.
 
+In answer to the questions about access discriminants, we propose that all
+accessibility checks related to access discriminants be performed based
+on the actual object, rather than on the expected type, in the case
+where the expected type or deignated type is class-wide.
+
 !wording
 
 Modify 3.10.2(14/2) as follows:
@@ -76,7 +95,7 @@
     accessibility level is determined as though the allocator were in
     place of the call of the function; in the special case of a call
     that is the operand of a type conversion, the level is that of the
-    target access type of the conversion.} For an {anonymous}
+    target access type of the conversion.}   For an {anonymous}
     allocator defining the value of an access parameter, the
     accessibility level is that of the innermost master of the call. For
     one defining an access discriminant, the accessibility level is
@@ -89,13 +108,13 @@
       point of call.  If the call is the operand of an explicit type
       conversion, the accessibility level is that of the target access
       type of the conversion.  If the call is an actual parameter of
-      another call, the accessibility level is that of the innermost
-      master of the call.  If the call defines an access discriminant,
-      the level is the same as that given above 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). If the
-      call itself defines the result of a function with an access
-      result, this rule is applied recursively.
+      another call or the prefix of a name, the accessibility level is
+      that of the innermost master of the call.  If the call defines an
+      access discriminant, the level is the same as that given above 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). If the call itself defines the result of a
+      function with an access result, this rule is applied recursively.
 
 Add after 3.10.2(19/2):
 
@@ -106,6 +125,61 @@
       as that of the level of the master that elaborated the function
       body.
 
+Replace 4.8(5.2/2):
+
+    If the designated subtype of the type of the allocator has one or more
+    unconstrained access discriminants, then the accessibility level of the
+    anonymous access type of each access discriminant, as determined by the
+    subtype_indication or qualified_expression of the allocator, shall not
+    be statically deeper than that of the type of the allocator (see 3.10.2).
+                  
+with:
+
+    If the subtype determined by the subtype_indication or
+    qualified_expression of the allocator has one or more access
+    discriminants, then the accessibility level of the anonymous access
+    type of each access discriminant shall not be statically deeper than
+    that of the type of the allocator (see 3.10.2).
+  
+Modify 4.8(10.1/2) as follows:
+
+    For any allocator, if the designated type of the type of the
+    allocator is class-wide, then a check is made that the accessibility
+    level of the type determined by the subtype_indication, or by the
+    tag of the value of the qualified_expression, is not deeper than
+    that of the type of the allocator. If the [designated subtype]
+    {subtype determined by the subtype_indication or qualified_
+    expression} of the allocator has one or more [unconstrained] access
+    discriminants, then a check is made that the accessibility level of
+    the anonymous access type of each access discriminant is not deeper
+    than that of the type of the allocator. Program_Error is raised if
+    either such check fails.
+
+In 6.5(5.6/2) replace
+
+   - If the result subtype of the function is class-wide, the
+     accessibility level of the type of the expression of the return
+     statement shall not be statically deeper than that of the master
+     that elaborated the function body. If the result subtype has one or
+     more unconstrained access discriminants, the accessibility level of
+     the anonymous access type of each access discriminant, as determined
+     by the expression of the simple_return_statement or the
+     return_subtype_indication, shall not be statically deeper than that of
+     the master that elaborated the function body.
+     
+with two separate bulleted items
+
+   - If the result subtype of the function is class-wide, the
+     accessibility level of the type of the expression of the return
+     statement (if any) shall not be statically deeper than that of the
+     master that elaborated the function body.
+     
+   - If the subtype determined by the expression of the simple_return_statement
+     or by the return_subtype_indication has one or more
+     access discriminants, the accessibility level of the anonymous access
+     type of each access discriminant shall not be statically deeper than that
+     of the master that elaborated the function body.
+
 Modify 6.5(21/2) as follows:
 
     If the [result subtype]{return object} of a function has one or more
@@ -117,7 +191,7 @@
     of the master that elaborated the function body] {the level of the
     return object as determined by the point of call (see 3.10.2)}. 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
@@ -148,6 +222,151 @@
         
 !discussion
 
+Discussion relating to class-wide result types or designated types:
+
+A wording change in 6.5(21/2) seems to be needed; in the case of
+a class-wide result type, the specified check may need to be performed
+even if the result type of the function has no access discriminants.
+
+Consider the following example:
+
+  declare
+    type Root is tagged null record;
+    type Ext (D : access Integer) is new Root with null record;
+
+    function F return Root'Class is
+      Local_Var : aliased Integer;
+
+      function Local_Func return Ext is
+      begin
+        return (D => Local_Var'Access);
+      end Local_Func;
+    begin
+      return Local_Func;
+    end F;
+    
+    procedure Do_Something (X : access Integer) is ... end;
+  begin
+    Do_Something (Ext (F).D);
+  end;
+
+If this test executes without raising any exception, then a
+dangling reference will be passed to Do_Something. It seems
+that the check described in 6.5(21/2) needs to be performed
+as part of returning from F, but the result subtype of F
+lacks unconstrained access discriminants.
+   
+This will introduce distributed overhead in the sense that
+a function which returns a classwide result may have
+to check for the possibility that its result has a "bad"
+access discriminant values even if there are no access
+discriminants anywhere in the program. For some implementations,
+this might involve querying a "has anonymous access discriminants"
+flag in the descriptor associated with a specific tagged type.
+
+There is an analogous problem for allocators. Consider the
+following variation on the preceding example:
+
+  declare
+    type Root is tagged null record;
+    type Ext (D : access Integer) is new Root with null record;
+
+    type Ref is access Root'Class;
+
+    function F return Ref is
+      Local_Var : aliased Integer;
+
+      function Local_Func return Ext is
+      begin
+        return (D => Local_Var'access);
+      end Local_Func;
+    begin
+      return new Ext'(Local_Func);
+    end F;
+    
+    procedure Do_Something (X : access Integer) is ... end;
+  begin
+    Do_Something (Ext (F.all).D);
+  end;
+
+At a minimum, additional runtime checks are needed to cover these
+cases (see 4.8(10.1/2), 6.5(21/2)). Just adding runtime checks would be sloppy.
+Additional static checks are also needed (see 4.8(5.2/2) and 6.5(5.6/2)).
+So that's what's been done.
+
+The preceding two examples illustrate the need for runtime checks in
+the cases of function results and allocators. The following variations
+on those examples illustrate the need for static checking for function
+results and for allocators:
+
+ declare
+    type Root is tagged null record;
+    type Ext (D : access Integer) is new Root with null record;
+
+    function F return Root'Class is
+      Local_Var : aliased Integer;
+      
+      Result : Ext (Local_Var'Access);
+    begin
+      return Result; -- should be rejected
+    end F;
+    
+    procedure Do_Something (X : access Integer) is ... end;
+  begin
+    Do_Something (Ext (F).D);
+  end;
+  
+  declare
+    type Root is tagged null record;
+    type Ext (D : access Integer) is new Root with null record;
+
+    type Ref is access Root'Class;
+
+    function F return Ref is
+      Local_Var : aliased Integer;
+      subtype Designated is Ext (D => Local_Var'Access);
+    begin
+      return new Designated; -- should be rejected
+    end F;
+    
+    procedure Do_Something (X : access Integer) is ... end;
+  begin
+    Do_Something (Ext (F.all).D);
+  end;
+  
+Note that AI05-0032, not this AI, contains the wording changes needed
+to ensure the static rejection of cases like
+
+  declare
+    type Root is tagged null record;
+    function F return Root'Class is
+      type Local_Extension is new Root with null record;
+    begin
+      return X : Local_Extension; -- should be rejected
+    end F;
+  begin null; end;
+  
+Does the proposed wording correctly handle the case where no static check
+is possible because no information is known about the discriminant values?
+Consider the first two examples (which are intended to illustrate the need
+for runtime checks; they are not intended to be rejected at compile-time).
+Does the proposed wording for static checks correctly let these examples
+through without any definitional problems? In particular, is the
+test that "the accessibility level of the anonymous access
+type of each access discriminant shall not be statically deeper than that
+of the master that elaborated the function body" well-defined in these cases?
+
+When we refer to the subtype "determined by the expression of the
+simple_return_statement", is this well-defined?
+Suppose, for example, that the expression is an aggregate.
+Do we need to generalize the definition of "nominal subtype" so that it
+is defined for all expressions, not just names?
+
+------
+
+Discussion related to dispatching calls reaching primitive functions
+of a nested type extension:
+
 In many cases, the original formulation of the semantics rules
 for access result types followed from an informal equivalence 
 rule. The declaration
@@ -357,9 +576,9 @@
 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
+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
+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
@@ -370,43 +589,43 @@
 To find an implementation model for the dynamic accessibility check for
 a return statement as proposed by this AI, the best analogy is the
 approach used for access parameters, where the caller identifies the
-level of the actual parameter with a static accessibility level. Inside
+level of the actual parameter with a static accessibility level.  Inside
 the "callee" subprogram, the level is only of interest when converting
-the access parameter to a type declared outside the callee. Levels that
+the access parameter to a type declared outside the callee.  Levels that
 are the same or deeper than the locals of the callee are all equivalent
 for this purpose, and could be represented by any value greater than or
 equal to the level of the callee.
 
 When we carry this analogy over to the cases covered by this AI, the
 caller must pass in some kind of static accessibility level to be used
-for any accessibility check at function return. It is needed any time
+for any accessibility check at function return.  It is needed any time
 the function has an access result, or has a result subtype where return
 objects might have access discriminants that are not constrained by the
-result subtype. This includes all functions whose result type is
+result subtype.  This includes all functions whose result type is
 class-wide, since access discriminants can be added in a type extension.
-At the return statement, the accessibility level of the object to be
+ At the return statement, the accessibility level of the object to be
 designated by an access discriminant of the return object would be
-checked against this level. Similarly, if the function has an access
+checked against this level.  Similarly, if the function has an access
 result, the level of the object to be designated by the access result
-would be checked against this level. In both cases, for the dynamic
+would be checked against this level.  In both cases, for the dynamic
 accessibility check to succeed, the object to be designated by the
 access discriminant or access result must be no deeper than the level
-passed in by the caller. We presume that we would not even be
+passed in by the caller.  We presume that we would not even be
 performing this check if the static accessibility check failed, because
 such a return statement is already illegal.
 
 If we want to be sure the dynamic check will succeed, we can pass in a
-very large value (e.g. Integer'Last). We could use such a level if the
+very large value (e.g. Integer'Last).  We could use such a level if the
 result of the function call is used to initialize a local object, or is
 to be allocated out of a local storage pool, since we know that these
 cases are always safe (presuming the static accessibility legality check
-has already passed). On the other hand, if the result of the function
+has already passed).  On the other hand, if the result of the function
 is used in an initialized allocator for an access type declared outside
 the caller, or in the case of an access result, is converted to such an
 access type, the caller would pass in the static level of that non-local
-access type. If the callee function is declared at that level or
+access type.  If the callee function is declared at that level or
 below, then this passed-in level is a meaningful level for it to use in its
-dynamic check in its return statement. On the other hand, if the callee
+dynamic check in its return statement.  On the other hand, if the callee
 function is not as deeply nested as the target access type, then the
 dynamic check will always succeed, which is as it should be.
 
@@ -414,10 +633,10 @@
 
 We had earlier considered a rule where the accessibility level of the
 controlling tag used in the call would be used at the call site to
-determine the actual level of the returned object. However, after
-trying to work out the details for that, we gave up. Furthermore, it
+determine the actual level of the returned object.  However, after
+trying to work out the details for that, we gave up.  Furthermore, it
 implied a check both in the return statement and then another check
-after return on use. That seemed inefficient. Finally, we realized
+after return on use.  That seemed inefficient.  Finally, we realized
 that in essentially all of these cases, we already needed to pass in
 some kind of caller context because the return object might not allow
 copying or might require finalization, and the caller is determining
@@ -429,25 +648,25 @@
 accessibility level passed in from the caller, rather than basing it on
 the level of the master that elaborated the function body. Using the
 level of the master is too optimistic for nested overrides, and is too
-pessimistic in many other cases. We chose to leave the static legality
+pessimistic in many other cases.  We chose to leave the static legality
 checks the same.
 
 It turns out no additional rules are needed for the "class-wide"
 tag-accessibility checks, because the caller necessarily has access to
 the type that is being returned if it is at the same level as the
-function, since they are able to call the function. And presuming the
+function, since they are able to call the function.  And presuming the
 caller makes no assumptions about the tag of an object returned from a
 function with a class-wide result, then they will check it again on any
 further function return or class-wide allocator.
 
 After solving this problem for returning objects with access
 discriminants, we go on to propose essentially a similar solution for
-functions with access results. Namely, the "dynamic" accessibility
+functions with access results.  Namely, the "dynamic" accessibility
 level for access results would be determined by the caller rather than
 being determined by the master that elaborated the function body. This
 solves the problem with nested overrides, makes access results work more
 consistently with access discriminants and functions that return limited
-types, and it minimizes storage leaks. It effectively means that
+types, and it minimizes storage leaks.  It effectively means that
 whether an initialized allocator is at the call site using the result of
 the function as the initial value, or the initialized allocator is at
 the return statement of a function with an access result, and the caller
@@ -455,7 +674,7 @@
 
 EXAMPLES
 
-Here is an example. In the following, the 
+Here is an example.  In the following, the 
 initialization of X and the initialization of Y 
 produce essentially the same thing, namely a pointer
 to a heap object allocated from the storage pool 
@@ -502,7 +721,8 @@
 
 !ACATS test
 
-C-Tests need to be constructed to check this semantics.
+B-Tests and C-Tests need to be constructed to check all of these new legality
+rules and run-time checks.
 
 !appendix
 
@@ -763,6 +983,73 @@
 ****************************************************************
 
 From: Tucker Taft
+Sent: Tuesday, October 30, 2007  9:02 PM
+
+You use the phrase "This condition shall also hold ...".
+That's a new one, as far as I can remember, for the RM.
+I would suggest spelling it out, perhaps introduced by:
+
+   Similarly, if the designated subtype of the type of
+   the allocator is class-wide ... then the
+   accessibility level ... shall not be statically
+   deeper ...
+
+Alternatively, in this case, couldn't we combine the rules into:
+
+    If the type determined by the subtype_indication
+    or the qualified_expression of the allocator
+    has one or more access discriminants, then
+    the accessibility level of the anonymous access type of
+    each access discriminant, as determined by the
+    subtype_indication or qualified_expression of
+    the allocator, shall not be statically deeper
+    than that of the type of the allocator (see 3.10.2).
+
+****************************************************************
+
+Summary of a private thread about this AI:
+
+The AI has:
+
+A couple of other changes that really should have gone into AI05-0032
+are also included to handle static rejection of cases like
+
+  function Foo return T'Class is
+    type Local_Extension is new T with null record;
+  begin
+    return X : Local_Extension;
+  end Foo;
+
+---
+
+But this case is statically illegal, because "Local_Extension" does not
+have the same type as "T'Class" -- and 6.5(5.2/2) requires that for extended
+return statements (for functions with ordinary subtype returns -- there are
+different rules for access results).
+
+---
+
+But Steve is talking about AI05-0032, which allows
+the return_subtype_indication to determine any
+type that is *covered* by the result type of the
+function.
+
+---
+
+Why? That AI has never been approved. (And thus isn't in *my* AARM.) If it needs
+additional rules in order to work, then those rules need to be in that AI,
+not in some unrelated AI that happens to modify that paragraph. That's
+especially true as AI-32 is an Amendment AI, and may not be implemented for
+years if we don't vote to change the status.
+
+---
+
+Good point, Randy.  AI05-0032 should be amended
+instead of adding it to this AI.
+
+****************************************************************
+
+From: Tucker Taft
 Sent: Wednesday, October 31, 2007  12:34 AM
 
 Here is an AI [version /03 - ED.] that Steve started, and
@@ -2561,5 +2848,30 @@
 which this AI also touches.  So this version [/05 - ED] is based
 on the latest 6.5(8/2), but is otherwise identical
 to version 4 sent earlier.
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Monday, July 21, 2008  3:07 PM
+
+Here is an update to AI-51, incorporating the wording changes from AI-75.
+[This is version /07 of the AI - ED.]
+These AI's address accessibility checks on function return and on
+allocators when the designated type is classwide, and/or the function
+is a primitive of a nested extension.
+
+*****************************************************************
+
+From: Robert Dewar
+Sent: Monday, July 21, 2008  3:14 PM
+
+Re: AI05-51 + AI05-75 -- fun with accessibility
+
+AARGH
+
+fun + accessibility in the same sentence
+
+does not compute! does not compute!
+smoke starts coming out of head :-)
 
 *****************************************************************

Questions? Ask the ACAA Technical Agent