!standard 4.3.2(8) 11-12-30 AI05-0282-1/03 !class binding interpretation 11-11-08 !status Amendment 2012 11-12-30 !status ARG Approved 6-0-2 11-11-13 !status work item 11-11-08 !status received 11-09-26 !priority Low !difficulty Easy !qualifier Omission !subject Bad ancestor constraints for extension aggregates !summary 4.3.2(8) applies when the ancestor of an extension aggreate is constraint. !question 4.3.2(8) does not seem to apply if the ancestor is constrained. Consider: procedure Foo is type Root (D : natural) is tagged record F1 : String (1 .. D) := (others => 'x'); end record; subtype S1 is Root (1); subtype S2 is Root (2); type Ext is new S1 with record F2 : Integer; end record; Var : Ext := (S2 with F2 => 123); begin null; end Foo; One would hope that this would raise Constraint_Error, but nothing seems to have that effect. !recommendation (See summary.) !wording Replace 4.3.2(8): If the type of the ancestor_part has discriminants that are not inherited by the type of the extension_aggregate, then, unless the ancestor_part is a subtype_mark that denotes an unconstrained subtype, a check is made that each discriminant of the ancestor has the value specified for a corresponding discriminant, either in the record_component_association_list, or in the derived_type_definition for some ancestor of the type of the extension_aggregate. Constraint_Error is raised if this check fails. With: If the type of the ancestor_part has discriminants and the ancestor_part is not a subtype_mark that denotes an unconstrained subtype, then a check is made that each discriminant determined by the ancestor part has the value specified for a corresponding discriminant, if any, either in the record_component_association_list, or in the derived_type_definition for some ancestor of the type of the extension_aggregate. Constraint_Error is raised if this check fails. !discussion If the ancestor type of an extension aggregate has discriminants, then there are 6 cases to consider: the cross-product of whether the discriminants of the ancestor type are inherited by the type of the extension aggregate (yes or no) and the three possible forms of the ancestor part: an expression a subtype mark denoting a constrained subtype a subtype mark denoting an unconstrained subtype. Keep in mind that an inherited discriminant might correspond to itself. This change is technically inconsistent with Ada 2005. An extension_aggregate with an ancestor_part whose discriminants are constrained and inherited might now raise Constraint_Error if the aggregate's type is constrained, while it was OK in Ada 2005. In almost all cases, this will make no difference as the constraint will be checked by the immediately following use of the aggregate, but it is possible to compare such an aggregate for equality; in this case, no exception would be raised by Ada 2005, while Ada 2012 will raise Constraint_Error. This should be very rare, and having the possibility means that the representation of the aggregate type has to be able to support unconstrained values of the type, even if the first subtype is constrained and no such objects can be created any other way. This is too costly to allow for such an unlikely case. !corrigendum 4.3.2(8) @drepl If the type of the @fa has discriminants that are not inherited by the type of the @fa, then, unless the @fa is a @fa that denotes an unconstrained subtype, a check is made that each discriminant of the ancestor has the value specified for a corresponding discriminant, either in the @fa, or in the @fa for some ancestor of the type of the @fa. Constraint_Error is raised if this check fails. @dby If the type of the @fa has discriminants and the @fa is not a @fa that denotes an unconstrained subtype, then a check is made that each discriminant determined by the @fa has the value specified for a corresponding discriminant, if any, either in the @fa, or in the @fa for some ancestor of the type of the @fa. Constraint_Error is raised if this check fails. !ACATS Test Create an ACATS C-Test similar to the example in the question. !ASIS No ASIS impact. !appendix From: Steve Baird Sent: Monday, September 26, 2011 5:28 PM The following example obviously should raise Constraint_Error (assuming that it is not rejected at compile time - one could imagine adding some sort of "statically matching subtype" legality rule, but that seems outside the scope of this discussion): procedure Foo is type Root (D : natural) is tagged record F1 : String (1 .. D) := (others => 'x'); end record; subtype S1 is Root (1); subtype S2 is Root (2); type Ext is new S1 with record F2 : Integer; end record; Var : Ext := (S2 with F2 => 123); begin null; end Foo; It seems that the present RM wording fails to capture this intent. Note that 4.3.2(8) does not apply because it begins with "If the type of the ancestor_part has discriminants that are not inherited by the type of the extension_aggregate, ..." Perhaps this condition needs to be expanded to include the case of inherited discriminants and a constrained ancestor subtype_mark. **************************************************************** From: Steve Baird Sent: Sunday, November 13, 2011 1:02 AM Wording to discuss on Sunday. ==== In 4.3.2(7), replace: are initialized by default as for an object of the ancestor type. with are initialized by default as for an object of the subtype denoted by the subtype_mark. and append a new paragraph: If the type of the ancestor_part has discriminants and the ancestor_part is a subtype_mark that denotes an unconstrained subtype, each discriminant of the ancestor type has the value specified for a corresponding discriminant, either in the record_component_association_list, or in the derived_type_definition or some ancestor of the type of the extension_aggregate. Replace 4.3.2(8): If the type of the ancestor_part has discriminants that are not inherited by the type of the extension_aggregate, then, unless the ancestor_part is a subtype_mark that denotes an unconstrained subtype, a check is made that each discriminant of the ancestor has the value specified for a corresponding discriminant, either in the record_component_association_list, or in the derived_type_definition for some ancestor of the type of the extension_aggregate. Constraint_Error is raised if this check fails. With: If the type of the ancestor_part has discriminants and the ancestor_part is not a subtype_mark that denotes an unconstrained subtype, then a check is made that each discriminant of the ancestor has the value specified for a corresponding discriminant, either in the record_component_association_list, or in the derived_type_definition for some ancestor of the type of the extension_aggregate. Constraint_Error is raised if this check fails. ==== In order to help understand this wording, I think it helps to realize that if the ancestor type of an extension aggregate has discriminants, then there are 6 cases to consider: the cross-product of whether the discriminants of the ancestor type are inherited by the type of the extension aggregate (yes or no) and the three possible forms of the ancestor part: an expression a subtype mark denoting a constrained subtype a subtype mark denoting an unconstrained subtype. ****************************************************************