!standard 7.6.1( 9) 01-09-20 AC95-00013/00 !standard 7.6.1(15) !class confirmation 01-09-20 !status received no action 01-09-19 !subject Finalization raises exception during assignment !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" ;-). ****************************************************************