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

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

--- ai05s/ai05-0234-1.txt	2010/11/18 07:07:36	1.2
+++ ai05s/ai05-0234-1.txt	2010/11/19 04:36:43	1.3
@@ -1,4 +1,4 @@
-!standard  7.6(17.1/3)                             10-11-15    AI05-0234-1/00
+!standard  6.5(21/3)                               10-11-18    AI05-0234-1/01
 !class binding interpretation 10-11-15
 !status work item 10-11-15
 !status received 10-10-31
@@ -8,6 +8,8 @@
 !subject Hole in AI05-0051-1
 !summary
 
+Plug access discriminant accessibility checking holes for functions and
+allocators.
 
 !question
 
@@ -55,15 +57,213 @@
           & Integer'Image (Extension (Ptr.all).Discrim.all));
    end Cw_Alloc;
 
+Are the access discriminant accessibility checks associated with allocators and
+function returns performed even in the case where the existence of those
+discriminants is not known statically at the point of the check? (Yes.)
 
+Are access discriminants of subcomponents also checked in the case where the
+subtype of the subcomponent is unconstrained? (Yes.)
+
 !wording
 
+Modify 4.8(10.1/3) as (modified by AI05-0051-1) 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 subtype determined by the subtype_indication or
+      qualified_ expression {(or by the tag of the value of the qualified
+      expression if the type of the qualified expression is class-wide)}
+      of the allocator has one or more 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.
+
+Replace 6.5(21/3) (as modified by AI05-0051-1) with:
+
+    If any part (ignoring the values of bounds and discriminants) of the return
+    object of a function (or a coextension thereof) has one or more access
+    discriminants whose value is not constrained by the result subtype of the
+    function, a check is made that the accessibility level of the anonymous
+    access type of each access discriminant is not deeper than 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.
+
+Add a (massive) AARM note after 6.5(21/3):
+
+   For a function with a classwide result type, the access values that
+   need to be checked are determined by the tag of the return object.
+   In order to implement this accessibility check in the case where
+   the tag of the result is not known statically at the point of the
+   return statement, an implementation may need to somehow
+   associate with the tag of a specific tagged
+   type an indication of whether the type has unconstrained access
+   discriminants (explicit or inherited) or has any subcomponents
+   with such discriminants. If an implementation is already maintaining
+   a statically initialized descriptor of some kind for each specific
+   tagged type, then an additional Boolean could be added to this
+   descriptor.
+
+   Note that the flag should only be queried in the case where any
+   access discriminants which the result object might have would
+   have subtypes with "bad" accessibility levels (as determined by
+   the rules of 3.10.2 for determining the accessibility level of
+   the type of an access discriminant in the expression or
+   return_subtype_indication of a return statement).
+
+   Thus, in a case like
+
+       type Global is access T'Class;
+       function F (Ptr : Global) return T'Class is
+       begin
+           return Ptr.all;
+       end F;
+
+   there is no need for a runtime accessibility check. The setting
+   of the bit doesn't matter and there is no need to query it.
+
+   On the other hand, given
+
+      function F return T'Class is
+          Local : T'Class := ... ;
+      begin
+          return Local;
+      end F;
+
+   In this case, a check would typically be required.
+
+   The need for including subcomponents in this check is illustrated by
+   the following example:
+
+      X : aliased Integer;
+
+      type Component_Type (Discrim : access Integer := X'Access)
+        is limited null record;
+
+      type Undiscriminated is record
+        Fld : Component_Type;
+      end record;
+
+      function F return Undiscriminated is
+          Local : aliaed Integer;
+      begin
+          return X : Untagged := (Fld => (Discrim => Local'Access)) do
+            Foo;
+          end return;
+          -- raises Program_Error after calling Foo.
+      end F;
+
+   Ramification:
+   In the case where the tag of the result is not known statically
+   at the point of the return statement and the runtime accessibility
+   check is needed, discriminant values and array bounds
+   play no role in performing this check. That is, array components are
+   assumed to have non-zero length and components declared
+   within variant parts are assumed to be present  Thus, the check
+   may be implemented simply by testing the aforementioned descriptor
+   bit and conditionally raising Program_Error.
 
 !discussion
 
+The language already specifies accessibility checks for access discriminants in
+the case of allocators (to ensure that discriminant values refer do not refer to
+something that is shorter-lived than the access type) and for function results
+(to ensure that discriminant values do not refer to something that is
+shorter-lived than the eventual destination of the function result, as
+determined by the point of call).
+
+In the case where the designated type of an access type is classwide, say
+T'Class, it needs to be made clear that this check is based on the tag of the
+allocated object. A check may be required even if, for example, T is
+undiscriminated.
+
+In the case where a function result type is classwide, a similar check is
+needed. The problem is illustrated by the following two examples:
+
+   procedure Cw_Alloc is
+     type Root is tagged null record;
+     type Ref is access Root'Class;
+
+     type Extension (Discrim : access Integer)
+       is new Root with null record;
+
+     function Bad_News return Ref is
+         Local_Int : aliased Integer := 123;
+         Local_Ext : aliased Extension (Discrim => Local_Int'Access);
+         type Local_Ref is access all Root'Class;
+         for Local_Ref'Storage_Size use 0;
+         Local_Ptr : Local_Ref :=  Local_Ext'Access;
+     begin
+         return new Root'Class'(Local_Ptr.all);
+         -- fails accessibility check? (yes)
+     end Bad_News;
+
+     Ptr : Ref := Bad_News;
+   begin
+     -- If we reach this point, Ptr.Discrim is a dangling reference
+     ...
+   end Cw_Alloc;
+
+   procedure Cw_Return is
+     type Root is tagged null record;
+     type Extension (Discrim : access Integer)
+       is new Root with null record;
+
+     function Bad_News return Root'Class is
+         Local_Int : aliased Integer := 123;
+         Local_Ext : aliased Extension (Discrim => Local_Int'Access);
+         type Local_Ref is access all Root'Class;
+         for Local_Ref'Storage_Size use 0;
+         Local_Ptr : Local_Ref :=  Local_Ext'Access;
+     begin
+         return Local_Ptr.all;
+         -- fails accessibility check? (yes)
+     end Bad_News;
+
+     Obj : Root'Class := Bad_News;
+
+   begin
+     -- If we reach this point, Obj.Discrim is a dangling reference
+     ...
+   end Cw_Return;
+
+In addition, these checks also need to be generalized to handle the case of a
+subcomponent which has defaulted access discriminant values, as in
+
+    X : aliased Integer;
+
+    type Subcomponent_Type (Discrim : access Integer := X'Access)
+      is limited null record;
+
+    type Component_Type is record S : Subcomponent_Type; end record;
 
+    type Undiscriminated is record
+      Fld : Component_Type;
+    end record;
+
+    function F return Undiscriminated is
+        Local : aliaed Integer;
+    begin
+        return X : Untagged
+          := (Fld => (S => (Discrim => Local'Access))) do
+
+          Foo;
+        end return;
+        -- raises Program_Error after calling Foo.
+    end F;
+
 !ACATS Test
 
+Add an ACATS C-Test to check that the exception is raised in examples like the
+ones given in this AI.
+
+!ASIS
+
+No impact.
+
 From: Steve Baird
 Sent: Tuesday, November 2, 2010  8:08 PM
 
@@ -1320,6 +1520,78 @@
 a Ramification that makes it clear that we intended that result. It's not a TBH,
 simply because the wording says precisely this ("any part" means exactly that,
 not any part that happens to be currently selected).
+
+****************************************************************
+
+From: Steve Baird
+Sent: Thursday, November 18, 2010  7:19 PM
+
+[Most of this note became version /01 of the AI - Editor.]
+
+...
+   To be honest:
+   In the case where the tag of the result is not known statically
+   at the point of the return statement and the runtime accessibility
+   check is needed, discriminant values and array bounds
+   play no role in performing this check. That is, array components are
+   assumed to have non-zero length and components declared
+   within variant parts are assumed to be present  Thus, the check
+   may be implemented simply by testing the aforementioned descriptor
+   bit and conditionally raising Program_Error.
+
+   [Randy - if I understand you correctly, you don't think this needs a
+    TBH label. My concern is in the opposite direction - it seems to
+    me that this requires explicit RM wording. We haven't talked
+    at all about the "vanilla" (i.e., specific result type) case, but
+    what about
+
+        Might_Be_Zero : Natural := ...;
+
+        type T (D : access Integer := null) is
+          limited tagged null record;
+
+        type Vector is array (1 .. Might_Be_Zero) of T;
+
+        function F return Vector is
+             Local : aliased Integer;
+             Result : Vector := (others => (D => Local'Access));
+        begin
+             return Result;
+        end F;
+
+     Clearly this fails the accessibility check if Might_Be_Zero
+     is nonzero. What happens if Might_Be_Zero equals zero?
+
+     It would be odd to allow conservative "assume all arrays
+     have non-zero length" behavior in the classwide result type
+     case described above, but not in this case. It seems that
+     this needs to be nailed down one way or the other. Bother!
+     I was hoping we were almost done with this one.]
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, November 18, 2010  10:15 PM
+
+I don't see the problem. The operative wording is "any part of the return
+object"; "any part" is something that has to be determined statically, and thus
+the values of bounds and discriminants are irrelevant (they cannot be known in
+general).
+
+If there is a problem, it occurs because this is a dynamic semantics rule, and
+thus someone could be confused by the fact that "any part" is determined
+statically. (It is *always* determined statically, so far as I know, but that
+isn't obvious.)
+
+If this was just English wording, I would probably suggest adding "possible":
+
+  If any possible part of the return object...
+
+But that isn't formal enough. Probably you are right and normative words need to
+be added:
+
+   If any part of the return object (ignoring the values of bounds and
+   discriminants) of a function ...
 
 ****************************************************************
 

Questions? Ask the ACAA Technical Agent