Version 1.2 of ai05s/ai05-0082-1.txt

Unformatted version of ai05s/ai05-0082-1.txt version 1.2
Other versions for file ai05s/ai05-0082-1.txt

!standard 3.10.2(19/2)          08-02-22 AI05-0082-1/02
!standard 3.10.2(20)
!class binding interpretation 08-01-16
!status ARG Approved 6-0-3 08-02-10
!status work item 08-01-16
!status received 08-01-11
!priority Medium
!difficulty Medium
!qualifier Omission
!subject Accessibility level of generic formal types
!summary
Static accessibility checks are not made on type derived from generic formal types.
!question
It appears the following is illegal:
package Pak1 is type Root is tagged null record; type Root_Acc is access all Root'Class; end Pak1;
package Pak2 is procedure Proc; end Pak2;
with Pak1; package body Pak2 is
procedure Proc is
generic type T is new Pak1.Root with private; procedure Gen_Proc;
procedure Gen_Proc is Ptr : Pak1.Root_Acc; begin Ptr := new T; -- Error? (No.) end Gen_Proc;
begin null; end Proc;
end Pak2;
The accesibility level of the formal type is determined by the point of its declaration, and that is statically deeper than Pak1.Root. Therefore, this is illegal by 4.8(5.1/2).
However, this is incompatible with Ada 95, which didn't have such accessibility checks (and thus this code was legal).
Should this be legal? (Yes.)
!recommendation
(See summary.)
!wording
Modify 3.10.2(19/2) as follows:
The statically deeper relationship does not apply to the accessibility level of the anonymous type of an access parameter specifying an access-to-object type{ nor does it apply to a descendant of a generic formal type}; that is, such an accessibility level is not considered to be statically deeper, nor statically shallower, than any other.
Mark 3.10.2(20) as redundant in the AARM. Add an AARM Proof:
A generic package does not introduce a new master, so it has the static level of its declaration; the rest follows from the other "statically deeper" rules.
AARM Note: This means that the static accessibility check of a type descended from a generic formal type always succeeds when compiling the generic. But this rule only applies to the generic, not to the instance.
While there is no static accessibility level for a generic formal type, it still has a dynamic accessibility level which can fail the runtime accessibility check. It also can fail the recheck in the instance specification. End AARM Note.
!discussion
The rules currently say that the static accessibility level of a generic formal type is that of the generic. But the effect of that is to prevent doing things in the generic which will work perfectly well in instances (presuming that they are instantiated with an actual type that have the right level). Moreover, this is an incompatibility with Ada 95, and one that would be hard to work around - the only fix is to eliminate the nesting of the generic. (One has to presume that the user has a reason, such as accessing up-level entities, for nesting the generic.)
So we simply assume-the-best everywhere (essentially meaning that there is no check in the generic).
Of course, the checks are still made in the specification of the generic instance, and any checks skipped in the body will be checked at runtime.
!corrigendum 3.10.2(19)
Replace the paragraph:
The statically deeper relationship does not apply to the accessibility level of the anonymous type of an access parameter specifying an access-to-object type; that is, such an accessibility level is not considered to be statically deeper, nor statically shallower, than any other.
by:
The statically deeper relationship does not apply to the accessibility level of the anonymous type of an access parameter specifying an access-to-object type nor does it apply to a descendant of a generic formal type; that is, such an accessibility level is not considered to be statically deeper, nor statically shallower, than any other.
!ACATS Test
Check that examples like the ones given here are legal, and that the checks are made on runtime (or in the instance) when necessary.
!appendix

!topic Accessibility level of generic formal type extension
!reference RM05 3.10.2, 4.8(5.1), 4.8(10.1)
!from Adam Beneschan 08-01-11
!discussion

I'm having problems determining whether this is legal in Ada 2005:

    package Pak1 is
        type Root is tagged null record;
        type Root_Acc is access all Root'Class;
    end Pak1;

    package Pak2 is
        procedure Proc;
    end Pak2;    

    with Pak1;
    package body Pak2 is

        procedure Proc is

            generic
                type T is new Pak1.Root with private;
            procedure Gen_Proc;

            procedure Gen_Proc is
                Ptr : Pak1.Root_Acc;
            begin
                Ptr := new T;      -- statically deeper?
            end Gen_Proc;

        begin
            null;
        end Proc;

    end Pak2;    

The version of GNAT I'm using accepts this in Ada 95 mode, but rejects
it in Ada 2005 mode, saying "type in allocator has deeper level than
designated class-wide type".  I'd like to believe GNAT is wrong, since
I don't think it was intended to introduce this sort of
incompatibility with AI95-344.  

Of course, in Ada 95, it's impossible for the statement with the
allocator to cause a problem, since nested type extensions aren't
allowed and therefore T must be at the same accessibility level as
Root no matter what the actual for T is.  (And, of course, 4.8(5.1)
didn't need to exist, for that reason.)  Here, it's possible to
instantiate Gen_Proc with a type that would make the allocator violate
4.8(10.1).  But, of course, it's possible to instantiate Gen_Proc with
a library-level type extension for T, which would make the allocator
perfectly fine.  And it's possible to envision a case where no nested
type extensions of Root are declared, but it's still desirable to nest
the generic inside the procedure (so that the rest of the code can
access a procedure parameter or local variable, e.g.).  So it would
seem that the check on this allocator should be a run-time check
(4.8(10.1)), not a compile-time check (4.8(5.1)).

But the static accessibility rules don't seem to say anything about
generic formal types.  One could, perhaps, read the rules to say that
since they don't say anything about generic formal types, that
therefore generic formal types aren't statically deeper than anything,
and the allocator is therefore legal.  But the rules do say that Proc
is statically deeper than Root, and any (non-generic) type extension
declared inside Proc would certainly be statically deeper than Root,
and T is (in some sense) declared inside Proc, so T is therefore
statically deeper than Root...  I'm not sure how to interpret the
rules for this case.

3.10.2(20) doesn't really help.  It says to presume that, in a generic
package body, that the generic is instantiated at the same level at
which it's declared---but it doesn't say anything about what to
presume about the actuals for the generic formals.  (And anyway, this
is a generic procedure, not a generic package.)

Is this just a matter of interpretation or clarification, or is there
a rule missing?  It seems that for static accessibility level checking
purposes, a generic formal type extension should be presumed to be at
the same level as the parent type, to avoid introducing this sort of
incompatibility.  (And, of course, a runtime check would be
necessary.)

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

From: Tucker Taft
Sent: Saturday, January 12, 2008  8:23 AM

> I'm having problems determining whether this is legal in Ada 2005:

It certainly should be legal, though finding the
wording in the RM that makes that clear is a challenge.

>     package Pak1 is
>         type Root is tagged null record;
>         type Root_Acc is access all Root'Class;
>     end Pak1;
> 
>     package Pak2 is
>         procedure Proc;
>     end Pak2;    
> 
>     with Pak1;
>     package body Pak2 is
> 
>         procedure Proc is
> 
>             generic
>                 type T is new Pak1.Root with private;
>             procedure Gen_Proc;
> 
>             procedure Gen_Proc is
>                 Ptr : Pak1.Root_Acc;
>             begin
>                 Ptr := new T;      -- statically deeper?

The RM does not make clear what is the accessibility
level of a formal tagged type.  Clearly in an instance it
is the same as the actual, and in the absence of other
information, we probably want to assume the "best" in the generic
since that is how accessibility is handled in generic
bodies normally.  I think we need at least a clarification
in the RM to pull formal tagged types into this
"assume the best" model.

>             end Gen_Proc;
> 
>         begin
>             null;
>         end Proc;
> 
>     end Pak2;    
> 
> The version of GNAT I'm using accepts this in Ada 95 mode, but rejects
> it in Ada 2005 mode, saying "type in allocator has deeper level than
> designated class-wide type".  I'd like to believe GNAT is wrong, since
> I don't think it was intended to introduce this sort of
> incompatibility with AI95-344.  

You are correct.  No incompatibility was intended to
be associated with nested type extensions.

...

> Is this just a matter of interpretation or clarification, or is there
> a rule missing?  It seems that for static accessibility level checking
> purposes, a generic formal type extension should be presumed to be at
> the same level as the parent type, to avoid introducing this sort of
> incompatibility.  (And, of course, a runtime check would be
> necessary.)

I think you are right that we need to clarify the static
accessibility level of formal types.  A similar problem
would occur on trying to convert from a formal access type
to a library-level access type.  In general, I think for the
purposes of accessibility level of formal types, we always
want to assume the "best" inside a generic and rely on the
run-time checks to pick up the slack.

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

From: Randy Brukardt
Sent: Monday, January 14, 2008  10:01 PM

...
> > 3.10.2(20) doesn't really help.  It says to presume that, in a generic
> > package body, that the generic is instantiated at the same level at
> > which it's declared---but it doesn't say anything about what to
> > presume about the actuals for the generic formals.  (And anyway, this
> > is a generic procedure, not a generic package.)

I'm not sure it is necessary to assume anything about the actuals. Remember
how Legality Rules are checked in a generic unit: "based on the properties
of the formals" (12.3(11)). The accessibility level of the formal is all
that matters, and that the level of the declaration by 3.10.2(7) unless
otherwise stated [and it is not!].

Anyway, in the original example:

        procedure Proc is

            generic
                type T is new Pak1.Root with private;
            procedure Gen_Proc;

            procedure Gen_Proc is
                Ptr : Pak1.Root_Acc;
            begin
                Ptr := new T;      -- statically deeper?
            end Gen_Proc;
        ...

T is more nested than the designated type of Root_Acc, so this is statically
illegal. (That is, I agree with GNAT.) OTOH, if you had declared this
generic at library-level, it would be legal.

I agree that this is an incompatibility, but I have a hard time getting
excited about an incompatibility that only shows up if you nest a generic
unit inside of a subprogram -- that's already a rather unusual thing to do.
When it comes to accessibility, the attempt to fix things often makes things
worse! So I'd lean toward not trying to fix this (presuming that we agree on
how formal types have their own accessibility - which may be a bad
presumption).

On an unrelated subject, it appears that 3.10.2(20) is intended to handle
cases of 'Access directly at the outer level of generic packages. That means
it doesn't have anything to do with subprograms. But the that rule doesn't
cover anything for generic specifications. I'm not sure why (and the AARM is
no help): rechecking needs to occur in instance specifications, but
"assume-the-best" for accessibility checks has to happen everywhere in a
generic package, not just the body. Otherwise, things would illegal in the
specification that would be legal in the body (which would be backwards of
the normal case). Maybe it doesn't matter (it doesn't matter in this case),
but I doubt that...

> > Is this just a matter of interpretation or clarification, or is there
> > a rule missing?  It seems that for static accessibility level checking
> > purposes, a generic formal type extension should be presumed to be at
> > the same level as the parent type, to avoid introducing this sort of
> > incompatibility.  (And, of course, a runtime check would be
> > necessary.)
>
> I think you are right that we need to clarify the static
> accessibility level of formal types.  A similar problem
> would occur on trying to convert from a formal access type
> to a library-level access type.  In general, I think for the
> purposes of accessibility level of formal types, we always
> want to assume the "best" inside a generic and rely on the
> run-time checks to pick up the slack.

I'm very dubious that there is a problem for formal access types; we would
have seen that long ago as it surely is present in all Ada 95 compilers.
There must be some way to figure out how these work (the way I explained
above seems likely, although it is a bit weird). And if we can agree on
that, then formal tagged types work the same way - and that probably is good
enough.

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

From: Tucker Taft
Sent: Monday, January 14, 2008  10:35 PM

This seems like an undesirable incompatibility to me,
especially since there seems no reason to presume that the
accessibility level of the formal is the same
as that of the generic.  Clearly in Ada 95 it could
*not* be the same.  I think we should presume
the "best" and recheck the spec on instantiation,
and recheck the body with the usual run-time
check.

To say that an incompatibility like this is "no big deal"
is pretty dangerous.  If someone has a big Ada 95 system
that happens to bump into this, it may be practically
impossible to fix without major surgery, since presumably
the generic is declared inside the subprogram for a good
reason (e.g. needs up-level visibility, etc.).  It isn't
an incompatibility you can always work around with a
minor "tweak."

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


Questions? Ask the ACAA Technical Agent