Version 1.1 of acs/ac-00013.txt

Unformatted version of acs/ac-00013.txt version 1.1
Other versions for file acs/ac-00013.txt

!standard 7.6.1( 9)          01-09-20 AC95-00013/00
!standard 7.6.1(15)
!class uninteresting 01-09-20
!status received 01-09-19
!subject Finalization called by aggregate during elaboration
!summary
!appendix

!topic Finalization raises exception during assignment
!reference RM95-7.6.1(15),7.6.1(9)
!from Adam Beneschan 09-19-01
!discussion

If a record type contains two controlled components (and no access
discriminants), and Finalize on one of those components raises an
exception when an object of that type is the target of an assignment,
is it true that Finalize may or may not be called on the other
component?

Suppose the record type is

    type T is record
        Comp1 : Controlled_Type_1;
        Comp2 : Controlled_Type_2;
    end record;

and an object X of type T is declared; then in this statement:

    X := Y;

X.Comp1 and X.Comp2 need to be finalized before the assignment.
Suppose that Finalize propagates an exception on X.Comp2.  My
understanding is that one cannot tell whether X.Comp1 will be
finalized before Program_Error is raised, since 7.6.1(9) says the
components of a record are finalized in an arbitrary order when access
discriminants are not involved, and 7.6.1(15) says that if an
exception propagated by a Finalize invoked as part of an assignment
statement, Program_Error is raised immediately (as opposed to other
situations in 7.6.1(16-20) which require that other Finalizations due
to be performed are still performed).

However, my understanding does not agree with ACATS test c761006.  One
of the tests in c761006 is:

    type Fin_Check_Root is new Ada.Finalization.Controlled with record
      Good_Component : C761006_0.Good;
      Fin_Fails      : C761006_0.Bad_Finalize;
    end record;

    type Fin_Check is  new C761006_1.Fin_Check_Root  with null record;

    procedure Finalize_15 is
      Item   : C761006_2.Fin_Check;
      Target : C761006_2.Fin_Check;
    begin

      Item := Target;
      -- finalization of Item should cause PE
      -- ARM7.6:21 allows the implementation to omit the assignment of the
      -- value into an anonymous object, which is the point at which Adjust
      -- is normally called.  However, this would result in Program_Error's
      -- being raised before the call to Adjust, with the consequence that
      -- Adjust is never called.

    exception
      when Program_Error => -- expected case
             if not Sup.Events_Occurring(Sup.Good_Finalize) then
               Report.Failed("Assignment: " & Fin_Not_Perf);
             end if;
      when others =>
             Report.Failed("Other exception in Finalize_15");

    -- finalization of Item/Target should cause PE
    end Finalize_15;

Finalize on Item.Fin_Fails propagates an exception.  The test checks
to make sure that Finalize has been called on Item.Good_Component,
which conflicts with my understanding that, at that point, the program
cannot tell whether Item.Good_Component has been finalized or not.

Is my understanding of the RM incorrect?

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

From: Randy Brukardt
Sent: Wednesday, September 19, 2001 7:37 PM

Humm. While the Technical Corrigendum rewrites nearly all of these rules, it
doesn't touch 7.6.1(15). Therefore, it appears to me that your analysis is
correct - I cannot find any RM rule that requires the Good_Component be
finalized during the assignment. (It will be finalized when the object is
destroyed, because in that case the "other finalizations yet to performed"
wording is in effect - TC 7.6.1(17.2/1).)

I'm not certain if the difference in 7.6.1(15) is intentional -- the AARM
provides no enlightenment. The test was withdrawn in ACVC 2.1, and repaired
for ACATS 2.2, so only a few implementations are known to pass it. Those
implementations could have been lucky.

It appears to me that the test ought to be corrected (presuming that others
here don't think that 7.6.1(15) is wrong).

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

From: Pascal Leroy
Sent: Thursday, September 20, 2001  3:50 AM

I agree that the difference between 7.6.1(15) and the other paragraphs is odd,
but as you point out the Good_Component will ultimately be finalized when the
object is destroyed.  It seems to me that the difference between 7.6.1(15) and
the other cases (e.g. 17, 18) is that in these other cases you won't have
another chance to do the "other finalizations yet to performed", for instance
because you are leaving the scope.

Since there doesn't seem to be any problem with 7.6.1(15), the axiom "if it
ain't broke, don't fix it" probably applies.

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

From: Tucker Taft
Sent: Thursday, September 20, 2001 10:02 AM

That is exactly correct.  The difference was intentional.

It is "safe" for an exception from any finalize to cause
the entire assignment to be abandoned, because finalize
for non-limited objects is required to be idempotent.
Adjust is different, since it must be performed to make
the assigned-to object safe for end-of-scope finalization.
Even if one of the Adjusts fails, we want to do the others
to avoid having one bad abstraction poison all the others.

> Since there doesn't seem to be any problem with 7.6.1(15), the axiom "if it
> ain't broke, don't fix it" probably applies.

This of course depends on agreeing on the definition of "broke" ;-).

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

Questions? Ask the ACAA Technical Agent