!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) @drepl 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. @dby 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." ****************************************************************