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

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

!standard G.3.1          07-05-15 AI05-0053-1/01
!class binding interpretation 07-05-15
!status work item 07-05-15
!status received 07-05-07
!priority Medium
!difficulty Hard
!qualifier Omission
!subject Aliased views of unaliased objects
!summary
TBD
!question
An extended return statement can be used to obtain an aliased view of an unaliased object.
This introduces a number of problems.
How are these problems to be resolved?
!recommendation
Not clear. Ban aliased return objects? See discussion for ideas.
!wording
TBD
!discussion
Consider the case where an extended return statement includes the reserved word "aliased" and the function is called to initialize an unaliased object in place, either as required by 7.5(8.1/2) or as allowed by 7.6(21/2).
If an implementation wants to treat aliased objects differently than unaliased objects in some way, then an aliased view of an unaliased object can be problematic.
An optimizer might wish to assume that an assignment through an access value does not "kill" any information that is known about the value of an unaliased object.
If this were the only problem, then this might be resolved via a "clarification" stating that if an aliased view of an unaliased object is used as the prefix of an Unchecked_Access attribute, then the resulting access value is valid only for the lifetime of the aliased view (which will typically be shorter than the lifetime of the designated object).
This "clarification" seems like a good idea, but unfortunately it does not solve all of the problems in this area.
For example, the IBM/Rational Ada compiler implements an aliased object X whose nominal subtype is an unconstrained array subtype by storing a contiguous dope vector. This is needed in order to support the evaluation of X'Access in the case where the designated type of the access type is unconstrained.
In the case of an unaliased object, no storage is allocated for a contiguous dope vector.
This implementation model worked for Ada95 and it was not the intention of the Ada05 designers to invalidate this approach.
If it is possible to construct an aliased view of an object which lacks a contiguous dope vector, then things can go downhill rapidly.
The following example illustrates the situation:
procedure Aliased_Return_Object is type Outer; type Inner (Ref : access Outer) is limited null record; type Outer is limited record Self : Inner (Outer'access); Data : Integer := 0; end record;
type Vector is array (Positive range <>) of Outer; subtype S is Vector (1 .. 10);
function F return Vector is begin return X : aliased Vector := S'(others => <>) do declare type Vector_Ref is access all Vector; for Vector_Ref'Storage_Size use 0; Ptr : Vector_Ref := X'access; -- requires contiguous dope Xx : Vector renames Ptr.all; begin for I in Xx'range loop Xx (I).Data := I; end loop; end; end return; end F;
Y : S := F; -- no contiguous dope for Y begin null; end Aliased_Return_Object;
There is also a considerably more obscure problem involving object identity. In this example,
subtype Zero_Sized is String (1 .. Report.Ident_Int (0)); X1, Y1 : Zero_Sized := Some_Function; X2, Y2 : aliased Zero_Sized;
, it is ok if X1'Address = Y1'Address but it is not ok if X2'Access = Y2'Access. If we can somehow construct X1'Access and Y1'Access, and if they must be distinct, then some implementations might have a problem.
This particular problem is not very important (and it would be solved by the Unchecked_Access "clarification" described above), but it does suggest that there may be other issues that have not been discovered yet.
How should these problems be addressed?
One could simply change the syntax to disallow aliased extended return objects, but that's a fairly major incompatibility.
It would probably be better to explicitly state the Unchecked_Access "clarification" described above and then add a runtime check which raises Program_Error when X'Access is evaluated during the execution of the preceding example.
How precise should the condition of that runtime check be?
Perhaps the check fails during the evaluation of Some_Object'Access (or Some_Object'Unchecked_Access) if Some_Object is an aliased extended return object whose nominal subtype is an unconstrained array subtype and the designated subtype of the access type is unconstrained.
Or perhaps for the check to fail it must also be the case that the function is called to initialize an object other than an aliased array object with an unconstrained nominal subtype (in implementation terms, an object which lacks a contiguous dope vector).
Or perhaps (if portability is not a concern) it must also be the case that the initialization of this dopeless object must be in place.
The first predicate, although the least precise, seems to be the best. The more precise alternatives would probably incur distributed overhead because a caller would have to pass in additional information (albeit only a boolean) on the off chance that a function's body might contain this problematic construct.
!ACATS test
!appendix

From: Randy Brukardt
Sent: Never, authored May 15, 2007  8:30 PM

>If this were the only problem, then this might be resolved via a
>"clarification" stating that if an aliased view of an unaliased
>object is used as the prefix of an Unchecked_Access attribute,
>then the resulting access value is valid only for the lifetime of
>the aliased view (which will typically be shorter than the lifetime
>of the designated object).

This "clarification" makes no sense. Are you saying that a program
that has such a 'Access and saves it somewhere is erroneous? That's
completely unacceptable to me - the error should be detected somehow;
it would make more sense to ban the 'Access or (better) define the
accessibility of such a 'Access to be limited to the extended return statement.

Is there any actual value to aliased return objects in the first place?

The best solution I can think of would be to have "aliased" as part of the function
spec. We actually talked about that at one time but eventually dropped that.

> For example, the IBM/Rational Ada compiler implements an aliased
> object X whose nominal subtype is an unconstrained array subtype
> by storing a contiguous dope vector. This is needed in order to 
> support the evaluation of X'Access in the case where the designated
> type of the access type is unconstrained.

I have little sympathy for trying to support a contiguous dope vector; this is
an idea that I concluded wouldn't work (in all cases) back in 1983. It was the
original reason that we support/use non-contiguous objects. The struggle to
allow contiguous dope vectors reminds me of the struggle to support generic code
sharing. Arguably, implementers should get over it. ;-) In both cases, we add
rules to allow it, but those rules are both harmful to users and also don't
help that much. For instance, 3.10.2(27.1/2) requires static matching, while there
is no problem supporting *any* 'Access for an access-to-unconstrained array as long
as you don't require continguous array descriptors. Even slices would work fine.
(I vaguely recall that this rules helped in some generic code sharing case, so I'm
not being that serious about trying to repeal it...)

So, while I agree with

> This implementation model worked for Ada95 and it was not
> the intention of the Ada05 designers to invalidate this approach.

there are lots of other unintended consequences (like the incomparability of accessibility
in some cases) that are a lot harder to implement and have a lot more impact.

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

Questions? Ask the ACAA Technical Agent