Version 1.5 of ai12s/ai12-0046-1.txt
!standard 4.3.1(16/3) 12-12-27 AI12-0046-1/02
!class binding interpretation 12-12-01
!status Corrigendum 2014 12-12-27
!status WG9 Approved 13-06-14
!status ARG Approved 8-0-2 12-12-06
!status work item 12-12-01
!status received 12-08-01
!priority Low
!difficulty Easy
!subject Enforcing legality for anonymous access components in record aggregates
!summary
The legality of an expression is enforced separately for each associated
component.
!question
4.3.1(16/3) says:
If a record_component_association with an expression has two or more
associated components, all of them shall be of the same type, or all
of them shall be of anonymous access types whose subtypes statically
match.
There are currently three known situations where this allows constructs which
would be legal for some but not all of the associated components.
1)
type Rec (D : access Integer) is
record F : access Integer; end record;
begin
declare
X : aliased Integer;
R : Rec := (D | F => X'access); --
2)
type T1 is tagged record F1 : access Integer; end record;
begin
declare
type T2 is new T1 with record F2 : access Integer; end record;
X : aliased Integer;
T2_Obj : T2 :=
(F1 | F2 => X'access); --
3) We have T1 and T2 as in example #2 except that both are declared
at library level. Exactly one of the two is declared in a unit
which has a "null" default storage pool.
Then the aggregate is
(F1 | F2 => new Integer)
which is legal only for the component with the non-null
default storage pool.
Clearly, any legality rules that are to be applied to a component expression in
a record aggregate are to be applied for each associated component. Do we need
to state this explicitly? (Yes.)
!recommendation
(See summary.)
!wording
Add to the end of 4.3.1(16/3):
In addition, Legality Rules are enforced separately for each associated
component.
Replace AARM 4.3.1(16.c):
AI83-00244 also requires that the expression shall be legal for each associated
component. Ada 95 omitted this wording, as it was thought that all cases of
difference had been eliminated. That probably was true, but Ada 2005 reintroduced
cases where the types match but the legality differs. For example:
type Rec (D : access Integer) is record
F : access Integer;
end record;
...
X : aliased Integer;
R : Rec := (D | F => X'access); --
There are additional ways for this to happen; because of cases like the above
we require that the Legality Rules are checked individually for each associated
component.
End AARM Note.
!discussion
We considered tightening up the rules so that only components with the same
legality would be allowed. For instance, consider:
If a record_component_association with an expression has two
or more associated components, all of them shall be of the same
type, or all of them shall be of anonymous access types whose
subtypes statically match and whose definitions all occur within
one known_discriminant_part or record_definition.
However, this is incompatible with Ada 2005 and Ada 2012. The above would
make the following legal Ada 2005 code illegal:
type T1 is tagged record
F1 : access Integer;
end record;
type T2 is new T1 with record
F2 : access Integer;
end record;
X : aliased Integer;
T2_Obj : T2 := (others => X'access); --
This problem isn't severe enough to introduce an incompatibility, so this
option was dropped.
!corrigendum 4.3.1(16/3)
Replace the paragraph:
Each record_component_association other than an others choice with
a <> shall have at least one associated component, and each needed component
shall be associated with exactly one record_component_association. If a
record_component_association with an expression has two or more
associated components, all of them shall be of the same type, or all of them
shall be of anonymous access types whose subtypes statically match.
by:
Each record_component_association other than an others choice with
a <> shall have at least one associated component, and each needed component
shall be associated with exactly one record_component_association. If a
record_component_association with an expression has two or more
associated components, all of them shall be of the same type, or all of them
shall be of anonymous access types whose subtypes statically match.
In addition, Legality Rules are enforced separately for each associated
component.
!ACATS test
An ACATS B-Test should be created to test that legality checks are
made as needed.
!ASIS
No ASIS impact.
!appendix
From: Steve Baird
Sent: Friday, August 10, 2012 4:59 PM
4.3.1(16/3) says:
If a record_component_association with an expression has two or more
associated components, all of them shall be of the same type, or all
of them shall be of anonymous access types whose subtypes statically
match.
There are currently three known situation where this allows constructs which
would be legal for some but not all of the associated components.
#1)
type Rec (D : access Integer) is
record F : access Integer; end record;
begin
declare
X : aliased Integer;
R : Rec := (D | F => X'Access); -- ok for D, not for F
#2)
type T1 is tagged record F1 : access Integer; end record;
begin
declare
type T2 is new T2 with record F2 : access Integer; end record;
X : aliased Integer;
T2_Obj : T2 :=
(F1 | F2 => X'Access); -- ok for F2, not for F1
3) We have T1 and T2 as in example #2 except that both are declared
at library level. Exactly one of the two is declared in a unit
which has a "null" default storage pool.
Then the aggregate is
(F1 | F2 => new Integer)
, which is legal only for the component with the non-null
default storage pool.
It seems that the existing RM wording doesn't unambiguously address these cases.
After discussions with Gary and Randy, it seems clear that we need to somehow
(wording TBD) explicitly state that any legality rules that are to be applied to
a component expression in a record aggregate are to be applied for each
associated component.
[begin rejected alternative
We looked briefly at
If a record_component_association with an expression has two
or more associated components, all of them shall be of the same
type, or all of them shall be of anonymous access types whose
subtypes statically match and whose definitions all occur within
one known_discriminant_part or record_definition.
, but this introduces an incompatibility.
We would start rejecting, for example,
type T1 is tagged record F1 : access Integer; end record;
type T2 is new T1 with record F2 : access Integer; end record;
X : aliased Integer;
T2_Obj : T2 := (others => X'Access); -- Ok by A, illegal by B
end rejected alternative]
Is there agreement that there is a (very minor) problem here that ought to be
fixed?
Incidentally, Randy has convinced me that there is no problem with the fudging
in name resolution where we say
The expected type for the expression of a
record_component_association is the type of
the associated component(s)
Referring to "the type" when the associated components don't all have the same
type is a bit odd, but it is ok if we interpret this to mean "any one of the
types of the associated components" because the anonymous access types in
question are interchangeable for purposes of name resolution (although not for
purposes of legality checking, which is the point of this AI).
****************************************************************
From: Tucker Taft
Sent: Friday, August 10, 2012 5:44 PM
I would say of course each component's legality is checked separately. Note that
the two components could be of significantly different subtypes so the
expression will need to be treated separately in much of the processing, so it
is no surprise to me that legality checks might also differ.
****************************************************************
From: Steve Baird
Sent: Monday, August 13, 2012 12:51 PM
Right. The question is whether the existing RM wording capture this intent.
****************************************************************
From: Tucker Taft
Sent: Monday, August 13, 2012 1:57 PM
16.c in the section on Record Aggregates says the following:
Discussion: AI83-00244 also requires that the expression
shall be legal for each associated component. ...
and then goes on to say that this was due to legality of array aggregates
depending on the subtype of the target, which was no longer true in Ada 95. So
we could add something back, perhaps even retrieving the old Ada 83 wording.
But it still seems unnecessary, since there seems no alternative to enforcing
legality rules from other sections of the manual, than doing it for each
component named in the choice list. How else could you possibly do it? We
don't mention legality rules from other parts of the manual in general, so why
do we need to start mentioning them just because there are multiple components
involved? Clearly in the dynamic semantic section it states in paragraph 20:
The expression of a record_component_association is evaluated
(and converted) once for each associated component.
and so the legality of that conversion, for example, seems necessarily to be
checked for each associated component (we don't even mention the conversion in
the static semantics of legality sections).
I think we could get by with a "TBH" if we really felt it was important to make
some clarification.
****************************************************************
From: Randy Brukardt
Sent: Monday, August 13, 2012 2:26 PM
> 16.c in the section on Record Aggregates says the following:
>
> Discussion: AI83-00244 also requires that the expression
> shall be legal for each associated component. ...
>
> and then goes on to say that this was due to legality of array
> aggregates depending on the subtype of the target, which was no longer
> true in Ada 95. So we could add something back, perhaps even
> retrieving the old Ada 83 wording.
Thanks for noticing this. It suggests that leaving the wording out was
intentional, but that Ada 2005 added cases where it matters (because of
anonymous access types, as noted by Steve). And Ada 2012 has added more. We
should insert some similar wording.
> But it still seems unnecessary, since there seems no alternative to
> enforcing legality rules from other sections of the manual, than doing
> it for each component named in the choice list. How else could you
> possibly do it?
You certainly could enforce the rule just once. I suspect that the vast majority
of implementers and Ada users would be surprised to learn that that is
insufficient. One can read 16.c to say that it is not necessary to enforce the
rules separately.
> We don't mention legality rules from other parts of the manual in
> general, so why do we need to start mentioning them just because there
> are multiple components involved?
Because we're doing something unusual here: enforcing different rules on the
same piece of source text. I don't know of any non-generic case where that's
necessary, and for generics we explicit define how the Legality Rules are
enforced (there's a lot of wording about that, as you well know). So I'd feel
better if the wording explained what's necessary.
At the very least, we need to redo 16.c, since it is a lie for Ada 2005 and
later. And add a TBH. But the fact that it was considered necessary to talk
about it in Ada 83 (and Ada 95 documents that the rules were changed so it
wasn't necessary), suggests to me that first-class wording would be preferable.
> Clearly in the dynamic semantic section it states in paragraph 20:
>
> The expression of a record_component_association is evaluated
> (and converted) once for each associated component.
>
> and so the legality of that conversion, for example, seems necessarily
> to be checked for each associated component (we don't even mention the
> conversion in the static semantics of legality sections).
I don't follow your implication. Lots of expressions are evaluated multiple
times in Ada, but I'm not aware of any others for which the legality checks
could get different answers (again, outside of generic instances, which have
their own legality rules anyway). And in any case, we keep Dynamic Semantics and
Legality Rules separate.
I agree that we pretty much have to check the rules separately in order to do
this evaluation successfully, but I think we need to say so explicitly.
> I think we could get by with a "TBH" if we really felt it was
> important to make some clarification.
We could, but it would be inconsistent with the way generic instances handle a
similar situation. That to me says we ought to have wording. It's only one
sentence anyway, not a big deal. Adding at the end of 4.3.1(16/3) something
like:
In addition, Legality Rules are enforced separately for each associated
component.
And then updating 4.3.1(16.c) to explain how this can fail for one component and
not another.
****************************************************************
From: Tucker Taft
Sent: Monday, August 13, 2012 2:46 PM
> ... Adding at the end of 4.3.1(16/3) something
> like:
>
> In addition, Legality Rules are enforced separately for each
> associated component.
>
> And then updating 4.3.1(16.c) to explain how this can fail for one
> component and not another.
That seems fine. I would claim it is "obvious" but so are a lot of things we
say explicitly now. And certainly 16.c is a clear "lie" now, so it should be
fixed.
****************************************************************
Questions? Ask the ACAA Technical Agent