Version 1.3 of ai05s/ai05-0282-1.txt
!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)
Replace the paragraph:
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.
by:
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.
!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.
****************************************************************
Questions? Ask the ACAA Technical Agent