Version 1.1 of ai05s/ai05-0281-1.txt

Unformatted version of ai05s/ai05-0281-1.txt version 1.1
Other versions for file ai05s/ai05-0281-1.txt

!standard 3.10.2(12/2)          11-11-12 AI05-0281-1/01
!standard 3.10.2(12.1/2)
!standard 3.10.2(12.5/3)
!class ramification 11-11-12
!status ARG Approved 5-0-4 11-11-12
!status work item 11-11-08
!status received 11-09-26
!priority Low
!difficulty Hard
!qualifier Omission
!subject Accessibility of access discriminants of a subtype
!summary
The subtype_indication mentioned in 3.10.2(12.1/2) is not necessarily declared at the place of the check (which is an allocator or return statement); it could be declared in a separate declaration elsewhere.
!question
Consider:
procedure Condit_Expr_Accessibility is Flag : Boolean := True; Test_Failed : exception;
type Drec (Int_Ref : access Integer) is null record;
type Global_Ref is access Drec; Global_Ptr : Global_Ref;
Global_Var : aliased Integer;
procedure Nested is type Local_Ref is access Drec; Local_Ptr : Local_Ref;
Local_Var : aliased Integer;
function Checker return Drec is -- Flag is always True at this point, but the -- compiler doesn't know that.
subtype S is Drec (Int_Ref => (if Flag then Local_Var'access else Global_Var'access)); begin Flag := False;
return X : S; end Checker; begin Local_Ptr := new Drec'(Checker); -- -- for the above call, it is ok for -- Checker to return a result which --- references Local_Var
Flag := True; begin Global_Ptr := new Drec'(Checker); -- -- for the above Call, returning -- a result which references Local_Var -- should fail an accessibility check
raise Test_Failed; exception when Program_Error => null; end; end Nested; begin Nested; end Condit_Expr_Accessibility;
In order to make the return accessibility check, we need to know the accessibility of S.Int_Ref. 3.10.2(12.1/2) does not apply (because this is not in an allocator or return statement), so we use 3.10.2(12.5/3). But that says that it is the "accessibility of the enclosing object" -- and there is no enclosing object.
Is this right? (No.)
!response
The subtype_indication mentioned in 3.10.2(12.1/2) is not necessarily declared in the allocator or return statement; the check has to occur in one of those contexts, but not the declaration of the subtype. So 3.10.2(12.1/2) does apply, and there is no problem.
!wording
Add an AARM note after 3.10.2(12.d/2) to clarify this:
The subtype_indication mentioned in this bullet is not necessarily the one given in the allocator or return statement that is determining the accessibility level; the constrained subtype might have been defined in an earlier declaration (as a named subtype).
!discussion
It would be nice to make this clearer in the normative wording, but this wording is clear as mud already, so messing with it further is unlikely to help. Thus we just add an AARM note.
!ACATS Test
An ACATS C-Test should be created (but this is likely to be low priority).
!ASIS
No ASIS impact.
!appendix

From: Steve Baird
Sent: Monday, September 26, 2011  5:24 PM

The following issue came up while reviewing interactions
between conditional expressions and accessibility, but it seems 
that conditional expressions are not an essential part of the 
problem.
 
Consider:
 
   procedure Condit_Expr_Accessibility is
      Flag : Boolean := True;
      Test_Failed : exception;
 
      type Drec (Int_Ref : access Integer) is null record;
 
      type Global_Ref is access Drec;
      Global_Ptr : Global_Ref;
 
      Global_Var : aliased Integer;
 
      procedure Nested is
         type Local_Ref is access Drec;
         Local_Ptr : Local_Ref;
 
         Local_Var : aliased Integer;
 
         function Checker return Drec is
            -- Flag is always True at this point, but the
            -- compiler doesn't know that.
 
            subtype S is Drec
               (Int_Ref => (if Flag then Local_Var'Access
                                    else Global_Var'Access));
         begin
            Flag := False;
 
            return X : S;
         end Checker;
      begin
         Local_Ptr := new Drec'(Checker);
         --
         -- for the above call, it is ok for
         -- Checker to return a result which
         --- references Local_Var
 
         Flag := True;
         begin
            Global_Ptr := new Drec'(Checker);
            --
            -- for the above Call, returning
            -- a result which references Local_Var
            -- should fail an accessibility check
 
            raise Test_Failed;
         exception
            when Program_Error =>
               null;
         end;
      end Nested;
   begin
      Nested;
   end Condit_Expr_Accessibility;
 
On returning from Checker, we need to perform a check
that the discriminant of the result designates something
which is sufficiently long-lived:
 
   RM 6.5:
       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 return
       statement, is not deeper than the level of the master of
       the call (see 3.10.2)
 
So in this case, what is the "accessibility level of the anonymous 
access type of each discriminant". What is the accessibility level 
of, speaking loosely, the type of S.Int_Ref?

I don't believe that 3.10.2 handles this case correctly, Strictly 
speaking, I think it falls into the "when others" handler:
 
    The accessibility level of the anonymous access type of an access
    discriminant in any other context is that of the enclosing object.
 
This is obviously absurd (there is no enclosing object - S is a 
subtype).

One solution would be to use the rule that is currently used only 
in the special case where the subtype_indication in question is the 
subtype_indication for an extended return statement or for an 
allocator:
 
      If the value of the access discriminant is determined by a
      discriminant_association in a subtype_indication, the
      accessibility level of the object or subprogram designated
      by the associated value  (or library level if the value is null)
 
It seems clear that this rule was very explicitly intended only for 
the special cases of allocators and return statements.
Was this an oversight?

****************************************************************

!response

The rules clearly were intended to apply only to "original" declarations,
and not the declaration of a completion. No user or implementer is going
to misinterpret these rules, given that a literal interpretation would
prevent the declaration of any concrete tagged type with primitive operations
(those operations could never be completed).

Moreover, one could argue that subprogram declarations in a body are not
primitive subprograms - whether or not completions of a primitive subprogram
also is a primitive subprogram when a stand-alone subprogram would not be
primitive is not clearly addressed by 3.2.3(2-7) -- a literal reading would
say that they are not.

But that would just make the issue even more confusing.

With the unlikelyhood of misinterpretation, we simply add a To Be Honest note
to the AARM to make it crystal clear that completions are not considered.

Note the introduction of expression functions by AI05-0177-1 makes this a more
significant issue. We would not want the following to be illegal:

    package Pak2 is
       type T is tagged private;
       function F (Obj : T) return Boolean;
    private
       type T is tagged record
          Flag : Boolean;
       end record;
       Object : T; -- Freezes T.
       function F (Obj : T) return Boolean is (Obj.Flag);
    end Pak2;


!wording

Add a new AARM note after 3.9.2(13) and after 13.14(16):

AARM To Be Honest: This rule only applies to "original" declarations and
not to the completion of a primitive subprogram, even though a completion
is technically an explicit declaration, and it may declare a primitive
subprogram.

!ACATS Test

An ACATS test could be constructed for the expression function case (the
example of the question is too much of a pathology to matter).

!ASIS

This has no impact on ASIS.

!appendix

!topic Subprogram body declarations and 3.9.2(13)
!reference RM 3.9.2(13), 13.14(16), 6.3(5)
!from Adam Beneschan 10-03-25
!discussion


This is a wording nitpick that I'm not sure really needs to be fixed: 

    package Pak1 is
       type T1 is tagged record ... end record;
       procedure Op (X : in out T1);
    end Pak1;

    with Pak1;
    procedure Proc2 is

       type T2 is new Pak1.T1 with record ... end record;
       overriding
       procedure Op (X : in out T2);

       Var : T2;

       overriding
       procedure Op (X : in out T2) is       -- (A)
       begin
          ...
       end Op;

    ...

Shouldn't cause any problems, right?  Op (on T2) is declared before
Var, which is before T2 is frozen.

However, the way things are worded:

3.9.2(13): "The explicit declaration of a primitive subprogram of a
tagged type shall occur before the type is frozen."

6.3(5): "A subprogram_body is considered a declaration.  It can either
complete a previous declaration, or itself be the initial declaration
of the subprogram."

one could think that since line (A) is a declaration, and it's
occurring after the type is frozen, that 3.9.2(13) makes it illegal. 

Perhaps the intent is so obvious that no fix is needed; but if it's
considered incorrect, then changing 3.9.2(13) and 13.14(16) to
something like

   The explicit declaration (that is not the completion of a previous
   declaration) of a primitive subprogram of a tagged type shall occur
   before the type is frozen.

would work.

****************************************************************

Questions? Ask the ACAA Technical Agent