Version 1.4 of ai05s/ai05-0234-1.txt

Unformatted version of ai05s/ai05-0234-1.txt version 1.4
Other versions for file ai05s/ai05-0234-1.txt

!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
!priority Low
!difficulty Hard
!qualifier Omission
!subject Hole in AI05-0051-1
!summary
Plug access discriminant accessibility checking holes for functions and allocators.
!question
There remains a problem not covered by AI05-0051-1. Consider the following:
with Text_IO; 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); -- allocator should fail, but RM 4.8(10) doesn't capture this -- correctly (with or without the changes of AI05-0051) end Bad_News;
Ptr : Ref := Bad_News;
procedure Do_Nothing is begin null; end Do_Nothing; begin Text_IO.Put_Line ("*** Test failed - an exception should have been raised");
Text_IO.Put_Line (" Ptr.Discrim.all =" & Integer'Image (Extension (Ptr.all).Discrim.all));
Do_Nothing;
Text_IO.Put_Line (" Ptr.Discrim.all =" & 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
At the recent ARG meeting in Fairfax, we approved AI05-0051 with the understanding that there remained a known dangling-reference problem involving allocators which still needs to be addressed.
The following example illustrates the problem:
with Text_IO; 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); -- allocator should fail, but RM 4.8(10) doesn't capture this -- correctly (with or without the changes of AI05-0051) end Bad_News;
Ptr : Ref := Bad_News;
procedure Do_Nothing is begin null; end Do_Nothing; begin Text_IO.Put_Line ("*** Test failed - an exception should have been raised");
Text_IO.Put_Line (" Ptr.Discrim.all =" & Integer'Image (Extension (Ptr.all).Discrim.all));
Do_Nothing;
Text_IO.Put_Line (" Ptr.Discrim.all =" & Integer'Image (Extension (Ptr.all).Discrim.all)); end Cw_Alloc;
Using the Gnat compiler (version 6.3.2) on x86_64 Linux, the following command
gnatmake cw_alloc.adb -gnat05
produces an executable whose output is
*** Test failed - an exception should have been raised
Ptr.Discrim.all = 123 Ptr.Discrim.all = 0
Note that the call to Do_Nothing caused the value of Ptr.Discrim.all to change from 123 to 0.
This is not a compiler bug - the Gnat compiler is, as far as I know, correctly implementing all of the checks that the language definition requires for this example.
The language definition is missing a check in this case.
****************************************************************
From: Tucker Taft Sent: Tuesday, November 2, 2010 9:36 PM
Do we know whether the same problem might exist for the return statement? I think there is some possibility of that.
****************************************************************
From: Steve Baird Sent: Tuesday, November 2, 2010 9:50 PM
I think you are right; good point. I'll try to flesh this one out tomorrow, but I see no reason that we won't run into the same problem.
****************************************************************
From: Steve Baird Sent: Friday, November 5, 2010 12:33 PM
You are right. Consider the following variation on the original example:
with Text_IO; 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; -- return should fail, but RM 6.5(21) doesn't capture this -- correctly (with or without the changes of AI05-0051) end Bad_News;
Obj : Root'Class := Bad_News;
begin Text_IO.Put_Line ("*** Test failed - an exception should have been raised");
Text_IO.Put_Line (" Obj.Discrim.all =" & Integer'Image (Extension (Obj).Discrim.all)); end Cw_Return;
Compiled and executed as described previously, resulting output is
*** Test failed - an exception should have been raised
Obj.Discrim.all = 32767
As before, this is not a compiler bug; this is a language definition problem.
****************************************************************
From: Steve Baird Sent: Monday, November 15, 2010 3:39 PM
How do we want to proceed on the "son of AI05-0051" problem?
If we can agree on a general approach, I can try to come up with wording to throw rocks at on Friday.
To recap, we want to prevent (probably via some kind of runtime check, but that is to be decided) two bad things:
- a function with a classwide result returning a value which has
an access discriminant which designates an object which is too short-lived
- an allocator of an access-to-classwide type which allocates a
an object which has an access discriminant which designates an object which is too short-lived
Randy and I have discussed an approach. It involves a tiny amount of distributed overhead (an extra bit in the descriptor associated with a tagged type; the value of the bit is known statically when the type is declared). Tuck may have also mentioned this approach at the Fairfax meeting when we discussed this problem for about 20 seconds - I'm not sure.
The bit indicates whether the given type has unconstrained access discriminants (inherited or not).
To provide motivation, consider a very straightforward (albeit draconian) solution. We add a runtime accessibility check at the point of the return/allocator based on the accessibility level of the returned/allocated "expression" (the term "expression" isn't quite general enough in the case of an uninitialized allocator, but you get the idea).
This means that the following would raise P_E:
function F return T'Class is Result : Some_Specific_Undiscriminated_Type := ''' ; begin ... return Result; end F;
That seems like an unacceptable incompatibility.
So we add the rule that the check is only performed if the specific type in question (which, in genreal, is not known until runtime) has one or more unconstrained access discriminants.
Most implementations would need something like the aforementioned descriptor bit in order to implement this.
This check is still conservative in the sense that it fails in come cases which would be safe to allow, but handling types with no access discriminants is a substantial improvement.
There are other (statically known) cases where we could safely omit the check. Notably, we can be a lot more precise in the case of an immutably limited type, although we still have to worry about, for example,
declare Local : aliased T; subtype S is My_Limited_Type (Discrim => Local'access); begin Global_Ptr := new S; end;
and we have to do the right thing in the usual build-in-place cases (an aggregate, a function call, an extended-return-statement object).
In some cases, the accessibility level of the object designated by the discriminant may be known (as opposed to conservatively using the accessibility level of the discriminated object). For example, consider an aggregate where the discriminant value is given explicitly as part of the aggregate.
It might seem odd to reject
return Some_Specific_Type
(Discrim => Some_Safe_Global'Access; ,,,,);
on the grounds that the the discriminant might refer to a local.
Or what about
return Some_Safe_Global_Constrained_Subtype (Acc_to_Cw.all);
So one question about this approach has to do with which, if any, special cases we want to identify in order to make the test less conservative.
I think that we don't care about ancestor types (except to the extent that they contribute inherited discriminants which noone has chosen to constrain),
If a more-distant ancestor type, T1, introduces an access discriminant, and a less-distant ancestor type, T2, constrains it, then there are two cases:
The acceessibility level of T2 is such that it will or will not fail the accessibility check on the specific type of an allocated or returned value in the classwide case.
If it is going to fail the check, then we don't need another check. Raising P_E once is good enough. If it is going to pass the check, then the discriminant value that was supplied must be ok too, as it must designate something that already existed when T2 was declared.
Thoughts?
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 3:57 PM
This message seems to adequetely sum up what Steve and I talked about, with one minor (but important) exception:
The proposed check is purely a runtime check (since we cannot know in general what the specific type returned is), but it would have to include both the static and dynamic accessibility checks. That is necessary to avoid introducing distributed overhead for parameters passed by reference. That happens since the language is very clear that the dynamic accessibility of such a parameter is that of the actual object, and we definitely don't want to have to pass that accessibility with all reference parameters. The reason we don't have to do that now is that the static accessibility check rejects any cases where it could matter -- they're already illegal. We cannot change that without adding major runtime overhead (this was the same problem that made handling conditional expressions such a mess).
This clearly is a wording challenge, but I don't think it can be helped. (And hardly anyone will ever run into this in practice.)
****************************************************************
From: Tucker Taft Sent: Monday, November 15, 2010 5:07 PM
I was thinking about this a bit and came to the conclusion that paragraphs 12-12.4 in 3.10.2 might already answer most of your questions. Basically it says what is the accessibility level of the discriminants, and I believe it handles some of the special cases you mention.
The most recent wording for 4.8(10.1) for AI05-51/09 says:
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.
That says that the tag is checked if class-wide, which implies that the "has-access-discriminants" bit you mention needs to exist.
The most recent AI05-51 wording for 6.5(21) says:
If any part of the return object (or coextension thereof) of a function 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, as determined by the expression or the return_ subtype_indication of the function, 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.
Although it doesn't explicitly say that the tag is checked, it sort of implies it in saying that the level of the access discriminants is "determined by the expression," and 3.10.2(12-12.4) indicates what that means. We could be more explicit about checking the tag, as the wording is in 4.8(10.1).
Hence, I don't see that we need anything more than a "tweak" of the AI05-51 wording.
As far as the "static" check, I'll need Randy to give an example of what he has in mind there. I don't see how the value of the tag can possibly affect the static check.
****************************************************************
From: Steve Baird Sent: Monday, November 15, 2010 5:47 PM
> I was thinking about this a bit and came to the conclusion that > paragraphs 12-12.4 in 3.10.2 might already answer most of your > questions. > Basically it says what is the accessibility level of the > discriminants, and I believe it handles some of the special cases you > mention.
I agree. I had forgotten about those rules.
> The most recent wording for 4.8(10.1) for AI05-51/09 says: > > 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. > > That says that the tag is checked if class-wide, which implies that > the "has-access-discriminants" bit you mention needs to exist. > > ...
> Hence, I don't see that we need anything more than a "tweak" of the > AI05-51 wording.
I believe that we did not approve AI05-51/09 at the last meeting; we backed out of my proposed changes and approved, in effect, AI05-51/08, You expressed concern at the time that the wording proposed in version 09 would require storing an accessibility level for each access discriminant at runtime, so we decided to close up AI05-0051 and deal with the problems we are discussing today in a separate AI.
If we decide that it makes sense after all, we can obviously still adopt the wording of AI05-51/09 or some variation thereon.
I'm just pointing out that the baseline that we are working from today does not include those version 09 changes (if I am remembering what happened in Fairfax correctly).
****************************************************************
From: Tucker Taft Sent: Monday, November 15, 2010 5:51 PM
> I'm just pointing out that the baseline that we are working from today > does not include those version 09 changes (if I am remembering what > happened in Fairfax correctly).
Thanks for clarifying that. I guess I need to go back and look at version 08. But having accepted the fact that we need the "has-access-discriminants" bit, coupled with a re-reading of 3.10.2(12-12.4) I now think your proposed wording in version 09 looks pretty good.
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 5:57 PM
... > I believe that we did not approve AI05-51/09 at the last meeting; we > backed out of my proposed changes and approved, in effect, AI05-51/08, > You expressed concern at the time that the wording proposed in version > 09 would require storing an accessibility level for each access > discriminant at runtime, so we decided to close up > AI05-0051 and deal with the problems we are discussing today in a > separate AI.
My notes end with:
We decide to revert to the previous version of this wording, and create a new AI to address this specific problem. (Especially as AI-142-4 also modified this paragraph.)
So Steve's memory is correct. Forget the /09 version of the AI.
(Note that /09 wording doesn't make a lot of sense to me, as it seems to mix statically determined and dynamically known types in the same sentence without explaining which is which.)
****************************************************************
From: Steve Baird Sent: Monday, November 15, 2010 4:53 PM
>... the language is very clear that the dynamic accessibility of such >a parameter is that of the actual object, and we definitely don't want >to have to pass that accessibility with all reference parameters.
I'm not disagreeing with you because I see the argument: A dynamic accessibility level is a property of an object (as opposed to a view of an object) and a by-reference parameter doesn't introduce a new object - just a view of an existing object.
But how do you reconcile this with 3.10.2(7/2):
A parameter of a master has the same accessibility level as the master.
?
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 5:12 PM
> But how do you reconcile this with 3.10.2(7/2): > A parameter of a master has the same accessibility level > as the master. > ?
I can't, because out of context this doesn't make any sense at all. Masters don't have parameters; a master is a execution or evaluation of something (typically a statement), so I'm not quite sure what this is referring to. In context, it appears to be talking about parameters of declarations, but that doesn't make much sense either with this particular wording.
I presume this is intended to do two things: define the static accessibility of parameters, and define the dynamic accessibility of by-copy parameters, but it is badly botched. Besides the by-reference case, it also is confused with access parameters that have some other accessibility defined (either that of the passed-in entity or "deeper than anything else"). This wording makes no sense for dynamic accessibility (with which it is associated), period.
I would prefer to invoke the Duff rule on this one (the ARG is not in the business of answering questions that no one - other than ARG members musing around - has asked). But perhaps there is really something wrong here (not surprising, almost everything about accessibility is screwy in one way or another).
****************************************************************
From: Tucker Taft Sent: Monday, November 15, 2010 5:37 PM
Dynamic accessibility level can vary depending on the "view." Parameters in general are treated like local variables, even when of a type that requires pass by reference. The one exception is explicitly aliased parameters, where they are guaranteed to live at least as long as the return object.
Similarly, even if an access discriminant is initialized to designate a global variable, the dynamic accessibility level of a dereference of the access discriminant is (generally) determined by the dynamic accessibility level of the enclosing object.
So dynamic accessibility levels do vary according to the view.
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 5:25 PM
... > As far as the "static" check, I'll need Randy to give an example of > what he has in mind there. > I don't see how the value of the tag can possibly affect the static > check.
Maybe I'm confused, but in the examples that Steve showed, the accessibility check was against the level of the expression, not the level of the type. That's a check that you cannot make normally at compile-time, as you would fail an accessibility check in normal cases.
For example, assuming T is a tagged non-limited type, and TT is an extension of it at the same level:
function Fooey (P : in TT; ...) return T'Class is begin if ... then return T'Class(P); -- OK in Ada 95 and Ada 2005 else ... end if; end Fooey;
This return statement is legal in Ada 2005. There would be an accessibility check on the tag of TT, but it would staticly be OK.
Now further presume that TT has an access discriminant. If we had directly returned the object TT, we would have needed an accessibility check on the object. In that case, the static accessibility check would have failed (we assume that P is local for this purpose). However, if we didn't have that static accessibility check, then we would have to use the accessibility of the actual object, which would have to be passed it (adding overhead). The only reason we don't need that overhead is because we have the static check that fails.
Now, in the classwide case, we have only a runtime check, because in general we know nothing about the tag until runtime. That means that unless we add some sort of wording about the static check to the dynamic case, we have a distributed overhead in that every reference parameter would have to pass a dynamic accessibility level (in particular, that would be needed for all tagged parameters).
Note that the check you described would always pass if Fooey was called with a library-level actual parameter, but should fail if called with a local actual parameter. That's what we have to avoid.
****************************************************************
From: Tucker Taft Sent: Monday, November 15, 2010 5:48 PM
> Now further presume that TT has an access discriminant. If we had > directly returned the object TT, we would have needed an accessibility > check on the object. In that case, the static accessibility check > would have failed (we assume that P is local for this purpose). > However, if we didn't have that static accessibility check, then we > would have to use the accessibility of the actual object, which would > have to be passed it (adding overhead). The only reason we don't need > that overhead is because we have the static check that fails.
The dynamic accessibility level of a parameter, even if passed by reference, is like that of a local variable. Just think what happens when you take 'Access of a tagged parameter in Ada 95 and pass it as an access parameter. It gets a run-time accessibility level that makes it look like a local variable.
The new "aliased" parameters are a bit different, in that they promise to live at least as long as the return object, so this example should be fine, even in Ada 2012.
> Now, in the classwide case, we have only a runtime check, because in > general we know nothing about the tag until runtime. That means that > unless we add some sort of wording about the static check to the > dynamic case, we have a distributed overhead in that every reference > parameter would have to pass a dynamic accessibility level (in > particular, that would be needed for all tagged parameters).
Again, the "dynamic" accessibility level of a parameter is "local" even if the actual parameter is a global object.
> Note that the check you described would always pass if Fooey was > called with a library-level actual parameter, but should fail if > called with a local actual parameter. That's what we have to avoid.
In cases like this, the accessibility level of an access discriminant is the same as the enclosing object, and that is "local" since it is a parameter. That means you don't need to pass anything in, and it will fail the run-time check if the actual object has access discriminants, even if the actual object is a global object.
I think the net effect is that the "static" check you were mentioning is already a part of the "dynamic" check, since parameters lose their "real" accessibility level and take on the accessibility of a local variable.
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 5:52 PM
> Dynamic accessibility level can vary depending on the "view." > Parameters in general are treated like local variables, even when of a > type that requires pass by reference.
This is an oxymoron. Views are static properties that do not have any effect on dynamic properties. It doesn't make any sense.
Beyond that, the one place in the standard that gives some credence to this view is clearly wrong, in that it is contradicted later in the same clause when access parameters are discussed.
We never actually decided the question of whether by-reference parameters are objects in their own right, or whether they are just views of the actuals. It appears that we will need to do something on this line (either that, or fix up the wording to make sense).
> The one exception is > explicitly aliased parameters, where they are guaranteed to live at > least as long as the return object. > > Similarly, even if an access discriminant is initialized to designate > a global variable, the dynamic accessibility level of a dereference of > the access discriminant is (generally) determined by the dynamic > accessibility level of the enclosing object.
The accessibility is that of the access discriminant (which is that of the enclosing object). So what? I don't see your point here.
> So dynamic accessibility levels do vary according to the view.
Well, that simply doesn't make sense in the Ada model. Of course, nothing else about accessibility makes sense, either, so perhaps we can get away with it. But if that is what we want, it needs to be clearly explained in the AARM, and it is not.
Remember that "view of" can automatically be appended to static semantic rules, but not to dynamic rules. If you mean that, you had better say so. Yes, I see these rules are defined in "Static semantics", but that makes no sense for a dynamic value.
Accessibility is still badly defined. What else is new.
****************************************************************
From: Bob Duff Sent: Monday, November 15, 2010 6:11 PM
> > But how do you reconcile this with 3.10.2(7/2): > > A parameter of a master has the same accessibility level > > as the master. > > ?
I didn't see the above-quoted message from Steve.
Tucker said in another message that dynamic accessibility is a view property. I agree -- it has to be that way, because by-ref and by-copy are (sometimes) impl-def, and we don't want the semantics to differ (other than the essential difference in aliasing). I realize we're talking about tagged types in this conversation, but I'm just saying in general, passing something by ref shouldn't cause differences in accessibility level and so forth.
> I can't, because out of context this doesn't make any sense at all. > Masters don't have parameters; a master is a execution or evaluation > of something (typically a statement), so I'm not quite sure what this is > referring to.
It's talking about a master that is the execution of a procedure body, and the (formal) parameters of that. These are the plain old run-of-the-mill masters we got from Ada 83 -- all these "little" masters like statements were added since then.
****************************************************************
From: Steve Baird Sent: Monday, November 15, 2010 6:31 PM
Thanks to Tuck and Bob for straightening that one out. Ignoring new-fangled explicitly aliased parameters, a parameter pretty much behaves like a local with respect to accessibility.
In most cases, one is more likely to arrive at the right answer if you go back to the RM and read the relevant wording instead of relying on internalized "I'm sure I remember it works this way" knowledge. In the case of accessibility rules, however, every rereading is an opportunity to get confused all over again.
****************************************************************
From: Randy Brukardt Sent: Monday, November 15, 2010 6:35 PM
... > > > But how do you reconcile this with 3.10.2(7/2): > > > A parameter of a master has the same accessibility level > > > as the master. > > > ? > > I didn't see the above-quoted message from Steve.
Steve sent it just to me, not sure if that was by accident or on purpose, but since I wanted to get the Tucker and Bob take on it, I replied to the list of names.
> Tucker said in another message that dynamic accessibility is a view > property. I agree -- it has to be that way, because by-ref and > by-copy are (sometimes) impl-def, and we don't want the semantics to > differ (other than the essential difference in aliasing). I realize > we're talking about tagged types in this conversation, but I'm just > saying in general, passing something by ref shouldn't cause > differences in accessibility level and so forth. > > > I can't, because out of context this doesn't make any sense at all. > > Masters don't have parameters; a master is a execution or evaluation > > of something (typically a statement), so I'm not quite sure what > > this is referring to. > > It's talking about a master that is the execution of a procedure body, > and the (formal) parameters of that. These are the plain old > run-of-the-mill masters we got from Ada 83 > -- all these "little" masters like statements were added since then.
It would be nice if this wording said that. Especially the word "formal", in which case it makes at least some sense.
"A {formal} parameter of {the entity that} a master {is executing} has the same accessibility level as the master."
Or something like that. Plus we need an exception for access parameters (because this rule surely doesn't not apply to them), and for explicitly aliased parameters. So
"{Unless otherwise defined, } a {formal} parameter of {the entity that} a master {is executing} has the same accessibility level as the master."
And we also need an AARM note to explain that.
"AARM Ramification: Note that accessibility can differ depending on the view of an object (for both static and dynamic accessibility). In addition to the formal parameter case above, similar effects occur for the entities designated by access discriminants."
"AARM Reason: We define the (dynamic) accessibility of formal parameters in order that it not depend on the parameter passing model (by-reference or by-copy) as that is implementation defined. Otherwise, there would be a portability issue."
Or something like that (not sure we really want to list out examples, there may be more). Since we never actually say "dynamic accessibility in the standard, I put that in parens in the notes.
P.S. Note that my original concern probably still exists for explicitly aliased parameters used in an allocator, although I doubt anyone will ever write a test to check that case. ;-)
****************************************************************
From: Bob Duff Sent: Monday, November 15, 2010 6:43 PM
> Or something like that. Plus we need an exception for access > parameters (because this rule surely doesn't not apply to them), and > for explicitly aliased parameters. So
I mostly agree with your message, but I don't see the problem for access parameters. Are you talking about the parameter itself, or what it designates? "X: access T", the accessibility level of X is not relevant, since it's not aliased, so X'[Unchecked_]Access is illegal. The accessibility level of X.all is dynamic, but X.all is not a parameter so the rule we're talking about doesn't apply.
The new aliased parameters may well need more thought.
****************************************************************
From: Randy Brukardt Sent: Tuesday, November 16, 2010 12:23 AM
> > Or something like that. Plus we need an exception for access > > parameters (because this rule surely doesn't not apply to them), and > > for explicitly aliased parameters. So > > I mostly agree with your message, but I don't see the problem for > access parameters. Are you talking about the parameter itself, or > what it designates? "X: access T", the accessibility level of X is > not relevant, since it's not aliased, so X'[Unchecked_]Access is > illegal. The accessibility level of X.all is dynamic, but X.all is > not a parameter so the rule we're talking about doesn't apply.
I suppose you are right.
> The new aliased parameters may well need more thought.
They don't need "more thought", they have their own accessibility rule (3.10.2(13.3/3)). I wasn't aware of this older blanket rule, or I would have added wording to repeal it in that case.
They probably need "more thought" for AI05-0234-1, because I'd expect that the static/dynamic case would come up for allocators (as Tucker points out, they have to pass a return statement).
BTW, it seems that we really want formal by-reference parameters to be a new object that happens to share memory with the old object. Besides this accessibility rule (where claiming that dynamic accessibility is a view property is unappealing), we also had similar issues with the values of representation aspects like 'Size and 'Alignment. We surely don't want to have to pass those along with parameters just so we can report them accurately. (I recall we decided that wasn't necessary with some phony hand-waving.) I wouldn't be surprised if this keeps coming up until we finally give in and change the definition...
****************************************************************
From: Steve Baird Sent: Tuesday, November 16, 2010 2:21 PM
> Hence, I don't see that we need anything more than a "tweak" of the > AI05-51 wording. > .... > Although it doesn't explicitly say that the tag is checked, it sort of > implies it in saying that the level of the access discriminants is > "determined by the expression," and 3.10.2(12-12.4) indicates what > that means. We could be more explicit about checking the tag, as the > wording is in 4.8(10.1).
I think that perhaps the version 09 RM wording is fine as is.
When we say
"any part of the return object (or coextension thereof)", I don't see any need to add "Oh and, by the way, you might need to look at the object's
tag in order to identify the set of parts we are talking about here".
, at least in the RM. An AARM note along those lines would be a good idea.
Do you see other changes/tweaks to the version 09 wording that are needed?
I'm trying to determine what, if any, work remains to be done for this AI. Perhaps just adding an AARM note as mentioned above to the existing version 09 wording?
I am assuming that any changes that may result from Randy's discussion of whether the definition of the accessibility level of a formal needs revision will go in another AI.
****************************************************************
From: Tucker Taft Sent: Tuesday, November 16, 2010 2:44 PM
> When we say > "any part of the return object (or coextension thereof)", I don't see > any need to add "Oh and, by the way, you might need to look at the > object's tag in order to identify the set of parts we are talking > about here". > , at least in the RM. An AARM note along those lines would be a good > idea.
I find it a bit uncomfortable that we mention the tag when talking about the check on allocators but don't mention it when talking about the check on a return statement, but I guess I can get over it. I definitely think an AARM note is in order to emphasize that the need for the check may depend on the value of the run-time tag when the type is classwide.
> Do you see other changes/tweaks to the version 09 wording that are > needed? > > I'm trying to determine what, if any, work remains to be done for this > AI. Perhaps just adding an AARM note as mentioned above to the > existing version 09 wording?
Yes, that seem to be all that is necessary.
****************************************************************
From: Randy Brukardt Sent: Tuesday, November 16, 2010 3:16 PM
... > I find it a bit uncomfortable that we mention the tag when talking > about the check on allocators but don't mention it when talking about > the check on a return statement, but I guess I can get over it. > I definitely think an AARM note is in order to emphasize that the need > for the check may depend on the value of the run-time tag when the > type is classwide.
I agree with Tucker here, except that I disagree on the "can get over it". Moreover, I'm concerned that the intent is that the checks depends on some runtime effect when nothing actually says that.
The /09 wording for return statements appears to be
If the subtype determined by the expression of the simple_return_statement or by the return_subtype_indication...
This seems to be talking about the nominal subtype of the expression, simply because there is no such thing as a runtime subtype. That means for a class-wide type, you are asking whether the class-wide type has access discriminants, which is not what we want. If you want to talk about the type determined by the tag, I think you need to say that explicitly:
If the subtype determined by the expression of the simple_return_statement or by the return_subtype_indication (or the type indicated by the tag if the determined subtype is class-wide) has one or more access discriminants...
or something like this. If not, Adam will complain. I think this is way too much for a to-be-honest note.
... > > I am assuming that any changes that may result from Randy's > > discussion of whether the definition of the accessibility level of a > > formal needs revision will go in another AI.
My head hurts just thinking about thinking about it. (That is, this is a meta-pain.)
****************************************************************
From: Bob Duff Sent: Tuesday, November 16, 2010 3:22 PM
> I'm trying to determine what, if any, work remains to be done for this > AI. Perhaps just adding an AARM note as mentioned above to the > existing version 09 wording?
Plus the intended implementation model (the bit in the type descriptor).
****************************************************************
From: Steve Baird Sent: Tuesday, November 16, 2010 3:30 PM
> Plus the intended implementation model (the bit in the type > descriptor).
Good point.
****************************************************************
From: Tucker Taft Sent: Tuesday, November 16, 2010 3:41 PM
> This seems to be talking about the nominal subtype of the expression, > simply because there is no such thing as a runtime subtype. That means > for a class-wide type, you are asking whether the class-wide type has > access discriminants, which is not what we want. If you want to talk > about the type determined by the tag, I think you need to say that explicitly: > > If the subtype determined by the expression of the > simple_return_statement or by the return_subtype_indication (or the > type indicated by the tag if the determined subtype is class-wide) has > one or more access discriminants...
This isn't the part where the tag comes into play. It is in:
Modify 6.5(21/2) as follows:
If [the result subtype]{any part of the return object (or coextension thereof)} of a function has one or more [unconstrained] 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, as determined by the expression or the return_subtype_indication of the function, is not deeper than [that 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.
That mammoth first sentence will need to be broken up a bit if we want to make it clear that whether the return object or its coextensions have discriminants may involve checking some run-time tags. Something like the following might accomplish this:
A check is made whether any part of the return object (or any coextension thereof) of a function has one or more access discriminants whose value is not constrained by the result of the function; when the return object or any coextension is of a class-wide type, this depends on the tag of the object. If any such access discriminants exist, then a check is made that the accessibility level of ...
Pretty groddy, but perhaps clearer (and Adam proof?).
****************************************************************
From: Steve Baird Sent: Wednesday, November 17, 2010 7:04 PM
> A check is made whether any part of the return object (or any > coextension thereof) of > a function has one or more access discriminants whose value is not > constrained by the result of the function; when the return object > or any > coextension is of a class-wide type, this depends on the tag of the > object. If any such access discriminants exist, then a check is made > that the accessibility level of ... > > Pretty groddy, but perhaps clearer (and Adam proof?).
A "check" which does not raise an exception or have any other similar consequence seems peculiar to me.
Generally, we have wording of the form
A check is made that blah blah. Mumble_Error is raised if this check fails.
It seems odd to see
A check is made whether this object has any discriminants. If it does, then a check is made that .... Program_Error is raised if this second check fails.
So here are my suggested changes, relative to the recently posted version 13 of AI05-0051.
====
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 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.
The only change is the parenthesized "(or by the tag ...)" wording.
In 6.5(21/2) (as modified by AI05-0051), we've currently got
If any part of the return object (or coextension thereof) of a function 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, as determined by the expression or the return_subtype_indication of the function, 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.
Are we missing an article inside the parens? Should that be "(or a coextension thereof)" or perhaps "(or any coextension thereof)"? Flip a coin, but either seems like an improvement. Splitting the phrase "return object of a function" by adding parens in the middle also seems confusing when I read it.
In the phrase "the expression or the return_subtype_indication of the function", should "of the function" be replaced by "of the executed return statement"? Does it make sense to talk about, for example, the return_subtype_indication of a function?
Or should that whole ", as determined by ... of the function," clause just be deleted? Otherwise, how does the current wording apply in a case like
return X : T'Class := ... do ... end return;
, where there is no expression and T'Class does not determine whether ther return object has access discriminants. So delete the clause.
This all leaves us with
If any part 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 an AARM note after 6.5(21/2):
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, an implementation may need to maintain data structures at runtime to keep track of whether a given specific tagged type (as identified by its tag) has unconstrained access discriminants (explicit or inherited) or has any subcomponents with such discriminants. If an implementation is already maintaining a runtime descriptor of some kind for each tagged type, then an additional Boolean could be added to this descriptor. In the cases where this flag needs to be queried, the accessibility level of the access dicriminant(s) (if any) is that of the return object.
Do we need an AARM note to make it clear that this wording handles the following example?
X : aliased Integer;
type Component_Type (Discrim : access Integer := X'access) is limited null record;
type Undiscriminated is record F : Component_Type; end record;
function F return Undiscriminated is Local : aliaed Integer; begin return X : Untagged := (F => (Discrim => Local'access)) do Foo; end return; -- raises P_E after calling Foo. end F;
I think no note is needed - the rule for this example follows from the "or has any subcomponents" wording above.
This means that components with defaulted discrims must participate in the computation of the aforementioned descriptor bit. On the other hand, a component subject to a propagated discriminant constraint doesn't affect the setting of the bit.
Note that we don't raise P_E before calling Foo because of 3.10.2(10.1/2):
Within a return statement, the accessibility level of the return object is that of the execution of the return statement. If the return statement completes normally by returning from the function, then prior to leaving the function, the accessibility level of the return object changes to be a level determined by the point of call, as does the level of any coextensions (see below) of the return object.
Do we need to explicitly state that we don't want to distinguish between present and inactive variant fields. Suppose that type Untagged in the preceding example had a Boolean discriminant which governed a variant part and the declaration of the F component was moved into one of the arms of the variant part. I think we want to look at tags at runtime, but not at discriminant values.
Does this need a TBH note?
****************************************************************
From: Tucker Taft Sent: Wednesday, November 17, 2010 8:20 PM
> This all leaves us with > > If any part 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.
Sounds good to me.
> > Add an AARM note after 6.5(21/2): > > 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, an implementation may > need to maintain data structures at runtime to keep track of whether a > given specific tagged type (as identified by its tag) has > unconstrained access discriminants (explicit or inherited) or has any > subcomponents with such discriminants. > If an implementation is already maintaining a runtime descriptor of > some kind for each tagged type, then an additional Boolean could be > added to this descriptor. In the cases where this flag needs to be > queried, the accessibility level of the access dicriminant(s) (if any) > is that of the return object. > > Do we need an AARM note to make it clear that this wording handles the > following example?
I wouldn't hurt to include this example in the AARM note. > > X : aliased Integer; > > type Component_Type (Discrim : access Integer := X'Access) is limited > null record; > > type Undiscriminated is record F : Component_Type; end record; > > function F return Undiscriminated is > Local : aliased Integer; > begin > return X : Untagged := (F => (Discrim => Local'Access)) do Foo; end > return; > -- raises P_E after calling Foo. > end F; > > I think no note is needed - the rule for this example follows from the > "or has any subcomponents" wording above.
I agree it isn't necessary but it wouldn't hurt. > > This means that components with defaulted discrims must participate in > the computation of the aforementioned descriptor bit. > On the other hand, a component subject to a propagated discriminant > constraint doesn't affect the setting of the bit. > > Note that we don't raise P_E before calling Foo because of > 3.10.2(10.1/2): > > Within a return statement, the accessibility level of the return > object is that of the execution of the return statement. If the return > statement completes normally by returning from the function, then > prior to leaving the function, the accessibility level of the return > object changes to be a level determined by the point of call, as does > the level of any coextensions (see below) of the return object. > > Do we need to explicitly state that we don't want to distinguish > between present and inactive variant fields. Suppose that type > Untagged in the preceding example had a Boolean discriminant which > governed a variant part and the declaration of the F component was > moved into one of the arms of the variant part. I think we want to > look at tags at runtime, but not at discriminant values.
Agreed. > > Does this need a TBH note?
Yes, probably.
****************************************************************
From: Randy Brukardt Sent: Wednesday, November 17, 2010 9:39 PM
... > This all leaves us with > > If any part 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.
I think this is OK, as it doesn't seem to say that you can figure out whether the check is needed statically.
> Add an AARM note after 6.5(21/2): > > 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, an implementation may > need to maintain data structures at runtime to keep track of > whether a given specific tagged type (as identified by its tag) > has unconstrained access discriminants (explicit or inherited) > or has any subcomponents with such discriminants. > If an implementation is already maintaining a runtime descriptor > of some kind for each tagged type, then an additional Boolean > could be added to this descriptor. In the cases where this flag > needs to be queried, the accessibility level of the > access dicriminant(s) (if any) is that of the return object.
Is it possible to implement a tag without some sort of runtime descriptor? It would seem that the model of tagged types require such a descriptor somewhere.
Note that the "runtime descriptor" is likely to be built at compile-time, and there isn't any need for this flag to be any different in that respect. So I think this note is misleading.
I would have said something like:
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, an implementation probably will need to 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. In the cases where this flag needs to be queried, the accessibility level of the access dicriminant(s) (if any) is that of the return object.
Which is simpler and doesn't confuse compile-time determined indications with the runtime check of the flag.
... > Do we need to explicitly state that we don't want to distinguish > between present and inactive variant fields. > Suppose that type Untagged in the preceding example had a Boolean > discriminant which governed a variant part and the declaration of the > F component was moved into one of the arms of the variant part. I > think we want to look at tags at runtime, but not at discriminant > values. > > Does this need a TBH note?
This is clearly true based on the wording you gave, but it wouldn't hurt to have 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 ...
****************************************************************
From: Steve Baird Sent: Tuesday, January 25, 2011 5:40 PM
Ok, I'll produce wording.
Here are the two mail messages on the subject that were sent earlier. As usual, any feedback will be appreciated.
==== Message #1 ====
When an object is built in place, the anonymous object and the object being initialized which it "mutates" into (as described in 7.6(17.5/3) and following) may have different accessibility levels.
In some cases this leads to problems when a dynamic accessibility check is performed against the object's current accessibility level rather than against the level it is eventually going to have.
AI05-0051 deals with parts of this situation by performing checks against an accessibility level "as determined by the point of call" but it appears that some cases involving coextensions are are not handled correctly (and the precise meaning of this wording is not obvious).
In the case of an aggregate, the situation is even worse.
There are no dynamic accessibility checks associated with the evaluation of an aggregate, presumably because it was believed that there was no way for the anonymous object of the aggregate to contain a reference to something more short-lived than itself.
This is certainly false if mutation occurs, as illustrated by one of the examples given in this AI.
To address this, I think we need to bite the bullet and define an "ultimate" (perhaps "post-mutation" or "eventual" would be better terms?) accessibility level for a type or object.
Roughly speaking, this is the accessibility level that an object will have after all the mutating has finished.
This is a dynamic notion and is only used in the definition of dynamic accessibility checks.
More precisely:
The ultimate accessibility level of an anonymous function_result/aggregate object which is built in place is the ultimate accessibility level of the object that the anonymous object is being used to initialize. Ditto for the ultimate accessibility level of the named function return object of an extended return statement.
The ultimate accessibility level of the access type of an allocator which creates a coextension, and of the coextension objct itself, is the ultimate accessibility level of the coextension's owner.
The ultimate accessibility level of an anonymous access type which is a result type for a dispatching function which is called via a dispatching call is the ultimate accessibility level of the result type of the function called by the caller.
[Note:
This case has nothing to do with build in place, but I think we still need to include this case in order to get the definition right.]
For all other entities, the ultimate accessibility level of the entity is the same as its accessibility level.
For example, if an allocator is initialized by calling function Foo which in turn returns the result of calling function Bar (with b-i-p at every step) then the ultimate accessibility level of Bar's function result object is that of the access type.
[Note:
We need to look at the interactions between this definition and optional (as opposed to required) build-in-place. I don't know of any problems in this area, but it is something to keep in mind.]
The checks where we currently (see AI05-0051) use "as determined at the point of call" wording would be modified to become checks against the ultimate accessibility level of the object/type in question.
I think his would address the corner case problems with coextensions that we have discussed earlier in the context of this AI.
In the [rare] case of an aggregate of a discriminated type having one or more access discriminants for which defaults are provided, a dynamic accessibility check is performed of the accessibility level of each discriminant value against the ultimate accessibility level of the anonymous object of the aggregate.
The check can be omitted in the case where the subtype of the object being initialized is constrained, or when the discriminant value is the result of evaluating the discriminant's default expression.
[Note:
Typically a dynamic accessibility check has a corresponding static legality rule to prohibit the cases where it is statically known that the dynamic check would fail. Static rules corresponding to the dynamic checks described in this proposal would need to be considered, but they might not be needed because typically these rules involve knowledge about both sides of a call. Perhaps something like an aggregate used to initialize an allocator with no calls in sight would warrant a check?]
[Note:
We need to confirm that this is straightforward to implement. I think that the "pass in an accessibility level parameter" model described in AI05-0051 suffices, but this needs confirmation.]
==== Message #2 ====
I hate to hair this proposal up with complexity that is specific to coextensions, but I think the "ultimate accessibility level" definition for a coextension (and for its access type) needs to take into account transfer of coextension ownership in the non-bip case (i.e., 3.10.2(14.4/3), as it applies in the non-bip case).
The definition I outlined earlier already handles this ownership transfer in the b-i-p case because there really isn't a transfer in that case (the old owner mutates into the new one).
The idea is that the ult-acc-lev of a coextension is the ult-acc-lev not of its current owner, but of the object which will end up being its owner.
Would an example illustrating the need for this be useful?
In some sense, this wrinkle strengthens the case for the general "ultimate accessibility level" approach.
The "ultimate accessibility level" of an object is a complicated idea, but by factoring out all this complexity into one place (i.e., the definition of the term), we can plug holes in lots of places in the RM by using this new term in defining various dynamic accessibility checks.
****************************************************************

Questions? Ask the ACAA Technical Agent