Version 1.1 of ai12s/ai12-0046-1.txt

Unformatted version of ai12s/ai12-0046-1.txt version 1.1
Other versions for file ai12s/ai12-0046-1.txt

!standard 4.3.1(16/3)          12-12-01 AI12-0046-1/01
!class binding interpretation 12-12-01
!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); -- 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.
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 they thought they had eliminated all cases of difference. 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); -- Legal for D, illegal for F
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); -- Ok in Ada 2005, illegal by proposed rule
This problem isn't severe enough to introduce an incompatibility, so this option was dropped.
!ACATS test
An ACATS B-Test should be created to test that legality checks are made as needed.
!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