!standard A.5.5(0) 20-09-03 AC95-00332/00 !standard A.5.6(0) !standard A.5.7(0) !class Amendment 20-09-03 !status received no action 20-09-03 !status received 20-07-10 !subject Unchecked_Union query !summary !appendix From: Jeff Cousins Sent: Friday, July 10, 2020 1:55 PM I’ve been assisting John Barnes in updating his book to get the Ada 2012 baseline correct before adding anything to do with Ada 202X. A question that has arisen goes back to Ada 2005’s Unchecked_Union. In the following we think it’s relatively clear that a Program_Error should be raised comparing X and Y when a default discriminant is used as Number is mutable, and indeed both GNAT and ObjectAda raise a Program_Error. with Ada.Text_IO; procedure Unchecked_Union_With_Default_Test is type Precision is (Single_Precision, Multiple_Precision); type Number (Kind : Precision := Single_Precision) is record case Kind is when Single_Precision => SP_Value : Long_Float; when Multiple_Precision => MP_Value_Length : Integer; MP_Value_First : access Long_Float; end case; end record; pragma Unchecked_Union (Number); X : Number := (Single_Precision, 45.6); Y : Number (Single_Precision); -- Inferable discriminant begin Y.SP_Value := 55.7; if X = Y then -- Raises Program_Error with GNAT and ObjectAda Ada.Text_IO.Put_Line ("X is Y"); else Ada.Text_IO.Put_Line ("X isn't Y"); end if; end Unchecked_Union_With_Default_Test; But what about when the discriminant doesn’t have a default? GNAT raises a Program_Error but ObjectAda doesn’t. I think ObjectAda is correct as X is explicitly set to Single_Precision and this cannot change. with Ada.Text_IO; procedure Unchecked_Union_No_Default_Test is type Precision is (Single_Precision, Multiple_Precision); type Number (Kind : Precision) is record case Kind is when Single_Precision => SP_Value : Long_Float; when Multiple_Precision => MP_Value_Length : Integer; MP_Value_First : access Long_Float; end case; end record; pragma Unchecked_Union (Number); X : Number := (Single_Precision, 45.6); Y : Number (Single_Precision); -- Inferable discriminant begin Y.SP_Value := 55.7; if X = Y then -- Raises Program_Error with GNAT but not ObjectAda Ada.Text_IO.Put_Line ("X is Y"); else Ada.Text_IO.Put_Line ("X isn't Y"); end if; end Unchecked_Union_No_Default_Test; The ACATS 4.1 tests seem to test to death the case of a default discriminant but not test at all the case of no default. Thoughts? *************************************************************** From: Steve Baird Sent: Friday, July 10, 2020 6:02 PM > But what about when the discriminant doesn’t have a default?  GNAT > raises a Program_Error but ObjectAda doesn’t.  I think ObjectAda is > correct as X is explicitly set to Single_Precision and this cannot change. I think GNAT is doing the right thing here. The RM says Program_Error is raised if Evaluation of the predefined equality operator for an unchecked union type if either of the operands lacks inferable discriminants. So the relevant question here is not "Can a human looking at this example use a minimal amount of common sense to identify the discriminant value at compile time?". The relevant question has to do with the definition of "inferable discriminants", which in turn becomes a question about the nominal subtype of the equality operand. In the example, the nominal subtype of the object Y is unconstrained. *************************************************************** From: Tucker Taft Sent: Friday, July 10, 2020 8:33 PM > In the example, the nominal subtype of the object Y is unconstrained. The "actual" subtype is "constrained by its initial value" but the "nominal" subtype is unconstrained, which is what matters for "inferable discriminants." See RM 3.3.1(9/2) and B.3.3(20/2). *************************************************************** From: Jeff Cousins Sent: Saturday, July 11, 2020 9:54 AM Thanks Steve and Tuck. Maybe time for more ACATS tests, and to do for 3.1 too as that doesn't have any Unchecked_Union tests. *************************************************************** From: Randy Brukardt Sent: Sunday, July 19, 2020 3:44 AM ... >But what about when the discriminant doesn't have a default? GNAT >raises a Program_Error but ObjectAda doesn't. I think ObjectAda is >correct as X is explicitly set to Single_Precision and this cannot change. Steve gave the correct answer. I want to note that the same sort of effect happens with aggregates. A modification of the example: with Ada.Text_IO; procedure Unchecked_Union_No_Default_Test is type Precision is (Single_Precision, Multiple_Precision); type Number (Kind : Precision) is record case Kind is when Single_Precision => SP_Value : Long_Float; when Multiple_Precision => MP_Value_Length : Integer; MP_Value_First : access Long_Float; end case; end record; pragma Unchecked_Union (Number); BTW, this is assuming that Long_Float and Integer and "access Long_Float" are C-compatible. None of those things are required by Ada. If one wants this to be portable, one must use types that have convention C (and for an anonymous type, one would need to declare the entire Number record convention C). Anyway, back to the example already in progress. Y : Number (Single_Precision); -- Inferable discriminant begin Y.SP_Value := 55.7; if Y = (Single_Precision, 45.6) then -- Should raise Program_Error Ada.Text_IO.Put_Line ("Y is single 45.6"); else Ada.Text_IO.Put_Line ("Y isn't single 45.6"); end if; end Unchecked_Union_No_Default_Test; One would have to qualify the aggregate with a constrained subtype (meaning *that* would have to be declared and given a name) to eliminate the Program_Error. Note that an aggregate doesn't even have a nominal subtype, so there's no obvious way to eliminate this case. OTOH, this is far from an intended use for an Unchecked_Union, so the oddity shouldn't matter often. Probably not worth fixing. *************************************************************** From: John Barnes Sent: Sunday, July 19, 2020 4:17 AM Thanks for helping with that. Hopefully that was the last known error in Programming in Ada 2012. So I should now have a cleanish baseline for moving forward. *************************************************************** From: Richard Wai Sent: Sunday, July 19, 2020 12:02 PM I'm super looking forward to the new edition! *************************************************************** From: Jeff Cousins Sent: Sunday, July 19, 2020 4:21 AM Thanks Randy. The ACATS tests turned out not to be terribly useful as they allow a Program_Error to be raised, by having an exception handler to consume it, but don't actually check that a Program_Error IS raised. Hopefully you've received my suggested changes. ***************************************************************