Version 1.1 of ais/ai-00162.txt

Unformatted version of ais/ai-00162.txt version 1.1
Other versions for file ais/ai-00162.txt

!standard 03.10.02 (13)          96-09-15 AI95-00162/01
!class binding interpretation 96-09-10
!status received 96-09-10
!priority Medium
!difficulty Hard
!subject Anonymous allocators and tasks/finalization
!summary 96-09-10
!question 96-09-10
!recommendation 96-09-10
!wording 96-09-10
!discussion 96-09-10
!appendix

!section 3.10(2)
!subject Anonymous access types and finalization
!reference RM95 3.10(2)
!reference RM95 3.7(27)
!reference RM95 7.6.1(11)
!from Pascal Leroy 96-08-20
!reference 96-5633.a Pascal Leroy 96-8-21>>
!discussion

The finalization of an object created by an allocator occurs when the master
of the ultimate ancestor of the access type is left, as stated in 7.6.1(11).
 In the case of access discriminants, 3.10(2) tells us that "an
access_definition defines an anonymous access type"; I take this to imply that
an anonymous access type is an "ultimate ancestor" in the sense of 7.6.1(11).
 In addition, 3.7(27) tells us that "an access_definition is elaborated when
the value of a corresponding access discriminant is defined"; I take this to
imply that the master of the anonymous access type is the master that
elaborated the discriminant constraint.

The interaction of these rules has the unfortunate consequence that it makes
it possible to reference an object after it has been finalized, as shown in
the following example:

    procedure P1 is
        type T (D : access Some_Controlled_Type) is ... ;

        procedure P2 is
            type T_Ref is access T;

            X : T_Ref;

            procedure P3 is
            begin
                X := new T (D => new Some_Controlled_Type);
                -- (1)
            end P3;
        begin
            P3;
            -- (2)
        end P2;
    begin
        P2;
    end P1;

The discriminant constraint for the allocated object X.all is elaborated by
P3.  The elaboration of this constraint also elaborates the access_definition,
therefore, the master of the anonymous access type is P3.  So when leaving P3,
at the point marked (1), the allocated object X.all.D.all is finalized, as per
7.6.1(11).  But of course, after leaving P3 we can still use the name
X.all.D.all to reference this object (at the point marked (2)), and this is
bad...

It seems to me that we need a rule that says that the master of an anonymous
access type A used in the specification of an access discriminant in type T,
the master of A is the master of T, not the master that caused A to be
elaborated.  Or, alternatively, that when an allocator is used as a
discriminant value for an anonymous access type, the master of the allocated
object is defined to be the master of the discriminated object. (These two
proposals are different, but they both seem to cure the problem, although the
first one is probably easier to implement.)

_____________________________________________________________________
Pascal Leroy                                    +33.1.30.12.09.68
pleroy@rational.com                             +33.1.30.12.09.66 FAX

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

!section 3.10(2)
!subject Anonymous access types and finalization
!reference RM95 3.10(2)
!reference RM95 3.7(27)
!reference RM95 7.6.1(11)
!reference RM95 3.10.2(12)
!reference 96-5633.a Pascal Leroy 96-08-20
!from Tucker Taft 96-08-22
!reference 96-5637.a Tucker Taft 96-8-22>>
!discussion

> The finalization of an object created by an allocator occurs when the master
> of the ultimate ancestor of the access type is left, as stated in 7.6.1(11).
>  In the case of access discriminants, 3.10(2) tells us that "an
> access_definition defines an anonymous access type"; I take this to imply that
> an anonymous access type is an "ultimate ancestor" in the sense of 7.6.1(11).
>  In addition, 3.7(27) tells us that "an access_definition is elaborated when
> the value of a corresponding access discriminant is defined"; I take this to
> imply that the master of the anonymous access type is the master that
> elaborated the discriminant constraint.

Not quite.

The accessibility level determines the lifetime for the purposes of
finalization.  For access discriminants, the accessibility level is
defined by RM95-3.10.2(12):

    The accessibility level of the anonymous access type of an access
    discriminant is the same as that of the containing object or associated
    constrained subtype.

> The interaction of these rules has the unfortunate consequence that it makes
> it possible to reference an object after it has been finalized, as shown in
> the following example:

This is not a problem, given 3.10.2(12).

>     procedure P1 is
>         type T (D : access Some_Controlled_Type) is ... ;
>
>         procedure P2 is
>             type T_Ref is access T;
>
>             X : T_Ref;
>
>             procedure P3 is
>             begin
>                 X := new T (D => new Some_Controlled_Type);
>                 -- (1)
>             end P3;
>         begin
>             P3;
>             -- (2)
>         end P2;
>     begin
>         P2;
>     end P1;
>
> The discriminant constraint for the allocated object X.all is elaborated by
> P3.  The elaboration of this constraint also elaborates the access_definition,
> therefore, the master of the anonymous access type is P3.  So when leaving P3,
> at the point marked (1), the allocated object X.all.D.all is finalized, as per
> 7.6.1(11).  But of course, after leaving P3 we can still use the name
> X.all.D.all to reference this object (at the point marked (2)), and this is
> bad...
>
> It seems to me that we need a rule that says that the master of an anonymous
> access type A used in the specification of an access discriminant in type T,
> the master of A is the master of T, not the master that caused A to be
> elaborated.  Or, alternatively, that when an allocator is used as a
> discriminant value for an anonymous access type, the master of the allocated
> object is defined to be the master of the discriminated object. (These two
> proposals are different, but they both seem to cure the problem, although the
> first one is probably easier to implement.)

As specified by 3.10.2(12), the accessibility level associated with the
nested allocator "new Some_Controlled_Type" is the same as that of
the enclosing object, X.all, which is the same as T_Ref.  The master
is hence P2, and the finalization for the nested allocator should be
performed when exiting P2.

> Pascal Leroy                                    +33.1.30.12.09.68
> pleroy@rational.com                             +33.1.30.12.09.66 FAX

-Tuck

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

!section 3.10(2)
!subject Anonymous access types and finalization
!reference RM95 3.10(2)
!reference RM95 3.7(27)
!reference RM95 7.6.1(11)
!reference RM95 3.10.2(12)
!reference 96-5633.a Pascal Leroy 96-08-20
!from Pascal Leroy 96-08-23
!reference 96-5641.a Pascal Leroy 96-8-23>>
!discussion

> The accessibility level determines the lifetime for the purposes of
> finalization.  For access discriminants, the accessibility level is
> defined by RM95-3.10.2(12):
>
>     The accessibility level of the anonymous access type of an access
>     discriminant is the same as that of the containing object or associated
>     constrained subtype.

I stand corrected.  I had failed to see the significance of accessibility
levels in this case, as explained in 7.6.1(4).  I guess I was reasoning a la
Ada 83 ;-)

Pascal

_____________________________________________________________________
Pascal Leroy                                    +33.1.30.12.09.68
pleroy@rational.com                             +33.1.30.12.09.66 FAX

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

!section 3.10.2(13)
!subject Anonymous allocators and tasks/finalization
!reference RM95 3.10.2(13)
!reference RM95 7.6.1(13)
!reference 96-5633.a Pascal Leroy 96-08-20
!reference 96-5637.a Tucker Taft 96-08-22
!reference 96-5641.a Pascal Leroy 96-08-20
!from Tucker Taft 96-09-10
!reference 96-5698.a Tucker Taft 96-9-10>>
!discussion

In 96-5633.s Pascal Leroy indicated a concern with when the object
created by an "anonymous" allocator (one whose expected type
was the anonymous access type of an access parameter) would
be finalized.  In answer, I pointed to 7.6.1(13) where it identifies
the accessibility level of such allocators as being the same as
that of the execution of the called subprogram.

That seemed to resolve the issue.  However, if you consider
anonymous allocators that create tasks as part of an object
whose size is not known at compile-time, you encounter the
first situation where the master of a task should perhaps be the
execution of a construct "smaller" than a block statement.

It seems that 7.6.1(13) should be augmented to cover the case
of anonymous allocators, which can result in the creation of
"anonymous" objects as part of any subprogram call.  Since these
anonymous objects might be of a limited type (unlike the case
for function returns and array aggregates), we need to consider
task "finalization" as well.  I believe the only consistent
approach is to consider the "master" for such anonymous objects
to be (the execution of) the construct (or construct "part") containing
the subprogram call, and ensure that both task waiting and finalization
occur as part of "leaving" the construct part.  By construct part, I mean
what 7.6.1(13) implicitly identifies as the unit of finalization for temps,
namely, the innermost declarative_item or statement, or in the case of
a compound statement, the part of the compound statement
up to the next statement nested within the compound statement.

Two (rejected0 alternatives are to associate the "anonymous" task with the
innermost enclosing (normal) master of the caller, or with the
execution of the called subprogram.  Neither of these work too well.

    Associating with the enclosing master doesn't work,
    since if the anonymous allocator is inside a loop, one clearly wants
    to recover the storage associated with the anonymous allocator
    before going on to the next loop iteration, even though a loop
    is not a master.

    Associating with the called subprogram
    doesn't work too well, since the call frame for the called
    subprogram doesn't exist at the time when the anonymous task is
    created (and may never exist if one of the later parameter
    evaluations raises an exception).

Also, other temps associated with subprogram call are finalized
immediately after the results of the call are no longer needed, so
it seems that anonymous allocators should operate the same way.

Hence, it seems we need a new notion of "master" to properly
deal with anonymous allocators, or we at least need to *permit*
implementations to wait for tasks created by anonymous allocators
before the enclosing "normal" master completes (I suppose non-real-time
implementations can wait for anything anytime they want, but we care
about real-time-conforming implementations as well).

In any case, 7.6.1(13) should acknowledge this new kind of anonymous
object, namely the anonymous object created by the evaluation
of an "anonymous" allocator.

-Tuck

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

Questions? Ask the ACAA Technical Agent