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

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

!standard 13.1(10/4)          20-04-17 AI12-0376-1/01
!class Amendment 20-04-17
!status work item 20-04-17
!status received 20-03-31
!priority Low
!difficulty Easy
!subject Representation changes finally allowed for untagged derived types
!summary
An untagged derived type can have a different representation from its parent type even if it has primitive operations, but not if it has by-reference parts.
!problem
Default_Value is a representation aspect. Therefore, it is not allowed to have different defaults for a derived type and the parent type. This sometimes is a useful capability and it has been used in practice (using a compiler that failed to enforce the requirement).
!proposal
(See Summary.)
!wording
Replace 13.1(10/4):
For an untagged derived type, it is illegal to specify a type-related representation aspect if the parent type is a by-reference type, or has any user-defined primitive subprograms. Similarly, it is illegal to specify a nonconfirming type-related representation aspect for an untagged by-reference type after one or more types have been derived from it.
with:
It is illegal to specify a nonconfirming type-related representation aspect for an untagged by-reference type if it is derived from a by-reference type, or if one or more types have been derived from it prior to the specification of the aspect.
!discussion
For by-reference types, it is clear that the rule is necessary; it's not practical to change the representation as noted in AI95-0246-1. Thus, the by-reference part of the rule is needed.
However, the part about primitive subprogram is essentially a methodological restriction. If the conversion is between two types with the same value set but different representations, there is no semantic problem. The main purpose here is to prevent expensive implementation conversions.
Methodological restrictions are always questionable, as they merely prevent a programmer from doing something that they may actually need to do. After all, there are plenty of operations that can be quite expensive in practice (controlled types, equality of composites, and so on). Generally, it's better to let knowledgable users write the code that they need (especially given that 13.6 recommends this approach for representation conversions), and give warnings if that leads to overly expensive code.
13.1(10/3) is intended to require explicitly converting between two different representations. That seems admirable, until one realizes that the effect is to require the elimination of all primitive operations of a (record) type in order to use Ada-language conversions. That means that the standard organization of putting a type and its operations together in a package cannot be followed - the operations have to placed somewhere else in order to take advantage of compiler-generated representation change. For many types (especially ones in packages already in use for which moving operations would require changes to many clients), the net effect is that derivation is infeasible and the representation changes end up getting written manually by the user, with all of the potential for mistakes and higher execution costs that entails.
The question of AI12-0109-1 shows that users have been clever in finding ways around this restriction. Moreover, the technique of AI12-0109-1 provides a way to end-run 13.1(10/4), much like generics provided a way to end-run the ban on redefinition of "=" in Ada 83.
When we considered AI12-0109-1, we didn't have the backbone to eliminate this methodological restriction; but now we have another example of it causing problems. So we finally eliminate this nuisance (about 30 years late in the author's opinion).
Note that there can be a minor semantic issue with in out parameters, in that there can be precision loss if a derived type has more precision than its parent type. For instance, in:
type Dollars is delta 0.01 with Small => 1.0; procedure Munge (Val : in out Dollars) is null;
type Cents is new Dollars with Small => 0.01; --(A) -- Inherits Munge.
declare Obj : Cents := 0.55; begin Munge (Obj); -- Obj = 1.0 here! end;
The implicit conversion of Obj to Dollars causes the value to be rounded to 1.0, and it will stay 1.0 on the reverse conversion, even though Munge itself never touches the parameter.
Luckily (??), this case [specifically, the declaration of (A)] is illegal by 3.5.10(2/5), which only allows specifying Small for "nonderived ordinary fixed point types". So we don't have to worry about this.
This could still happen for floating point types, but only if the implementation allows a derived type to use a different representation. There's no requirement to support nonconfirming size clauses for floating point types.
As such, we can ignore this concern. If an implementation wants to make trouble for itself, it can, but we don't want to prevent useful things simply because someone could cause a problem with a badly thought out type declaration and a permissive implementation.
The rules of AI12-0074-1 also may need some adjustment, but as several issues with those rules have been brought up, we'll handle that AI separately with the knowledge that 13.1(10/4) will no longer apply to types with Default_Value and Default_Component_Value.
---
There is a minor change to the rules for by-reference types, in that we now allow confirming representation clauses for such types. This is consistent with our Language Design Principle that confirming aspects are always allowed and do not affect the semantics (a principle that wasn't always followed in Ada 95 rules such as this one). This expansion only allows more specifications of aspects, so there isn't a compatibility concern. Since it depends on confirming values, which are almost always implementation-defined, it does potentially raise a portability concern, but certainly no more than any other specification of a representation aspect.
!corrigendum 13.1(10/4)
Replace the paragraph:
For an untagged derived type, it is illegal to specify a type-related representation aspect if the parent type is a by-reference type, or has any user-defined primitive subprograms. Similarly, it is illegal to specify a nonconfirming type-related representation aspect for an untagged by-reference type after one or more types have been derived from it.
by:
It is illegal to specify a nonconfirming type-related representation aspect for an untagged by-reference type if it is derived from a by-reference type, or if one or more types have been derived from it prior to the specification of the aspect.
!ASIS
No ASIS effect.
!ACATS test
Various existing B-Tests need modification. An ACATS C-Test is needed to check that a derived type with a different representation than its parent and with primitive operations works as expected.
!appendix

Editor's note: Here is a listing of AIs (including e-mail threads) that 
mention 13.1(10) - in any of its various forms. The first matching text 
snippet is shown, followed by a summary and sometimes commentary. (Note: I've
skipped No Action AIs, and for Ada 202x AIs, any that aren't finished or on
hold.)

[Note: If an AI mentions 13.1(10) with some non-standard syntax, I may have
missed it. There are enough hits here as it is.]

All of the important conclusions are including in the !discussion of this AI.
One only needs to read this if they want to convince themselves that every
known problem has been considered.

---------- AI-00031.TXT
It is forbidden by 13.1(10): "For an untagged derived type, no

[This AI asks if 13.6 only works if there are no derived subprograms, which of
course follows from 13.1(10).] 

---------- AI-00051-2.TXT
Note also RM 13.1(10) which imposes the "no-inherited subprograms" rule for

[This seems tangential to the actual discussion (about 'Size). Not relevant.]

---------- AI-00108.TXT
"tagged" occurs: in 13.1(10) and 13.1(11). And it is those rules that

[Just an off-hand reference that has nothing to do with the AI.]

---------- AI-00137.TXT
13.1(10) says:
13.1(10) seems to forbid the following example:
The intent of 13.1(10) is to forbid two types from having different
...

[Here, 13.1(10) was one of the motivating reasons for introducing "operational 
aspects". Since it no longer applies to such aspects, that's not interesting
going forward.]

---------- AI-00195.TXT
says that 13.1(10) does not apply to stream attributes. This would just be
> says that 13.1(10) does not apply to stream attributes. This would just be
Yes, I agree, since 13.1(10) does not apply to stream attributes, we

[This AI is about stream attributes, and these references are referring to 
AI-00137.TXT.]

---------- AI-00246.TXT
However, 13.1(10) prevents these sorts of problems for type-related aspects of
13.1(10.b) explains that this rule exists precisely to prevent this sort of
...

[This one is important. This AI notes that we don't have to worry about type
conversions between related types as 13.1(10) prevents trouble by preventing
change of representation for untagged by-reference types. This demonstrates
that the by-reference part of the rule has to be retained. (I think we already
knew that, but here is the confirmation.)

------ AI-00291-2.TXT
   not a multiple of the parent type's alignment (13.1(10) allows this;

[This notes that 13.1(10) doesn't prevent a derived type from having a 
different alignment.]


---------- AI05-0083-1.TXT
similar to 13.1(10): "For a composite derived type, no subtype-related

[This AI discusses Alignment again, and this just notes that 13.1(10) doesn't
apply.]

---------- AI05-0106-1.TXT
This appears to be legal, as 13.1(10) does not apply, and T is considered to be

[This is about generic formal derived types, not relevant to the need for 13.1(10).]

---------- AI05-0229-1.TXT
means we cannot run afoul of 13.1(10).]
The inabilility to derive also means we cannot run afoul of 13.1(10).]
derive also means we cannot run afoul of 13.1(10).]
also means we cannot run afoul of 13.1(10).]

[This notes that task and private aspects don't run into 13.1(10) since such
types can't be derived. Not relevant here.]

---------- AI05-0295-1.TXT
!standard  13.1(10)
Modify 13.1(10):
Update the AARM notes 13.1(10.a/1) and 13.1(10.b/3).

[This updates the wording of 13.1(10), so it's already captured. The AI is the
presentation rewrite of 13.1.]

---------- AI12-0027-1.TXT
I read 13.1(10/3) as supporting this change - it suggests that it was intended
        13.1(10/3) doesn't do this. It just says
> I read 13.1(10/3) as supporting this change - it suggests that it was
the problem is that in the current case, 13.1(10/3) provides no protection,
>         13.1(10/3) doesn't do this. It just says
illegal (see 13.1(11/3), so I don't think we ever get to 13.1(10/3) in that
is no possibility of something like 13.1(10/3) to save us).
>>         13.1(10/3) doesn't do this. It just says
> to 13.1(10/3) in that case. How else could this happen?
BTW, note that changing 13.1(10/3) as you suggest would be wildly incompatible,
a by-reference type was supposed to be prevented by 13.1(10/3):
       13.1(10/3), quoted above, gets this point wrong -
> 13.1(10/3):
ban this (I'd rather repeal 13.1(10/3), which is a pain in the neck as it
That would be the case if 13.1(10/3) did not exist, but since it does, it's
> That would be the case if 13.1(10/3) did not exist, but since it does,

[This AI makes the copying implicit in a value conversion explicit in order to
avoid the creation of dangling access values. 13.1(10) is used here to justify
not allowing copies in many cases, but it also was used to justify likelyhood
of incompatibilities. In the end, 13.1(10) doesn't figure into the result.
There's also some discussion that gets covered in a later AI.]

---------- AI12-0074-1.TXT
as 13.1(10) ensures that the Default_Value aspect is the same for the derived type
because of the infamous 13.1(10/3). Any case where the programmer wrote this

[This is the infamous view conversion is illegal for many unrelated types AI.
We already have a request to abandon most of this AI. 13.1(10) is important in
allowing the rule for Default_Value to not include related types. Repealing
13.1(10) would invalidate some the assumptions used in this AI, and thus we 
would have to revisit this AI if we do that (regardless of any other requests).]

---------- AI12-0109-1.TXT
!standard 13.1(10/3)                                15-01-20  AI12-0109-1/03
(1) There appears to be a hole related to 13.1(10/3).
situation that 13.1(10/3) is intended to prevent.
Add at the end of 13.1(10/3):
...

[This AI adds the second sentence to 13.1(10/4), which prevents problems with
by-reference types. This clearly will have to stay in any repeal. We looked at
repealing 13.1(10), but got no traction, in particular because of FUD that I'm
trying to combat by doing this document.]

---------- AI12-0352-1.TXT
of the useful cases are banned by 13.1(10). And almost all of the rest of them 

[Just a note that untagged derivation isn't as useful as it should be, not
really relevant to the need for 13.1(10).]

****************************************************************

From: Tucker Taft
Sent: Tuesday, March 31, 2020  8:47 AM

As AdaCore has been tightening some of the restrictions associated with 
Default_Value and Default_Component_Value, we have run into a number of places 
where customer code is affected by these restrictions.  Below I mentioned the 
issue with access-type-related problems in AI12-0074-1.   Another comes from 
Default_Value and Default_Component_Value being considered representation 
aspects.  There seems some justification for Default_Value, in that it affects
the size of OUT parameters, but I could not find any justification for making 
Default_Component_Value a representation aspect.  So I think we should re-open
the discussion on that, so that Default_Component_Value can be specified on 
derived types, even when they have user-defined primitives, as specified in 
13.1(10).

It also may be time to consider eliminating the user-defined-primitive-related 
restriction part of 13.1(10).  Clearly if something must be passed by 
reference, expecting a representation change is not practical.  On the other 
hand, the rule disallowing a change of representation when there are inherited
subprograms seems like it might be a fix that is worse than the disease.  Yes,
there is some overhead in changing representation, but so what?  If the 
inherited subprogram does something useful, why disallow the representation 
change and the associated implicit conversion.  Generally there was a desire 
to make expensive operations visible, but one wonders whether this particular 
rule is really worth the added user complexity.

Finally, the freezing associated with specifying a Default_Value has come up 
for the case of enumeration literals.  One wonders whether we need a more 
general exception for Default_Value so it can be specified without freezing
the type being defined.  Using T'First or T'Last in the specification of 
Default_Value seems like a common thing to want to do, and so probably should 
be allowed.

****************************************************************

From: Arnaud Charlet
Sent: Tuesday, March 31, 2020  1:21 PM

For the record, this was found in the context of ACATS test B360001 and
testing the changes in our customer testsuite. So when we make Tuck's 
suggested changes, B360001 will also need to be revised.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, March 31, 2020  3:10 PM

> As AdaCore has been tightening some of the restrictions associated 
> with Default_Value and Default_Component_Value, we have run into a 
> number of places where customer code is affected by these 
> restrictions.  Below I mentioned the issue
> with access-type-related problems in AI12-0074-1.   Another 
> comes from Default_Value and Default_Component_Value being considered 
> representation aspects.  There seems some justification for 
> Default_Value, in that it affects the size of OUT parameters, but I 
> could not find any justification for making Default_Component_Value a 
> representation aspect.  So I think we should re-open the discussion on 
> that, so that Default_Component_Value can be specified on derived 
> types, even when they have user-defined primitives, as specified in 
> 13.1(10).

You've said that you believe that there are only two kinds of type-related aspects, and I don't think that Default_Component_Value makes much sense as an operational aspect. (Do we want to allow Default_Component_Value on a partial view?? I think not.) Bes
ides...
 
> It also may be time to consider eliminating the 
> user-defined-primitive-related restriction part of 13.1(10).

That time was 1992. :-)

> Clearly if something must be passed by reference, expecting a 
> representation change is not practical.  On the other hand, the rule 
> disallowing a change of representation when there are inherited 
> subprograms seems like it might be a fix that is worse than the 
> disease.  Yes, there is some overhead in changing representation, but 
> so what?  If the inherited subprogram does something useful, why 
> disallow the representation change and the associated implicit 
> conversion.

Exactly. If there's too much overhead, then don't do that. Why should the
compiler prevent something useful because someone might abuse it?

We do need to be careful, however, since there have been several rules over 
the years where 13.1(10) avoided pestilence. We'd need to find those and put
in the needed rules to avoid trouble (still a better choice than preventing 
useful untagged derived types).

There also was a concern about precision loss in fixed point types if the 
smalls vary. Not sure if we need to worry about that or not (I don't use 
fixed point enough to have an opinion).

>  Generally there was a desire to make expensive operations visible, 
> but one wonders whether this particular rule is really worth the added 
> user complexity.

It appears to me that if we did this, then it isn't a problem to keep 
Default_Component_Size as a representation aspect. Explain if wrong.

> Finally, the freezing associated with specifying a Default_Value has 
> come up for the case of enumeration literals.  One wonders whether we 
> need a more general exception for Default_Value so it can be specified 
> without freezing the type being defined.  Using T'First or T'Last in 
> the specification of Default_Value seems like a common thing to want 
> to do, and so probably should be allowed.

We just discussed this on this list, and I included the case 'First in my 
write-up, yet no one wanted to make a change. Not quite sure what changed 
here.

Anyway, completely removing freezing would not work. The freezing rule 
prevents nonsense like:

     type Fooey is range 1 .. 10 with Default_Value => Fooey'Size;

or worse

     type Fooey is range 1 .. 10 with Default_Value => Sub'Alignment;
     subtype Sub is Fooey;

I could see punching some additional holes into the freezing specifically for 
Default_Value, but removing it in a blanket way would open the door to lots 
of problems that would be hard to fix without inventing something new that's 
much like freezing. (Let's not do that!)

****************************************************************

From: Tucker Taft
Sent: Tuesday, March 31, 2020  3:34 PM

>> ...
> 
> You've said that you believe that there are only two kinds of 
> type-related aspects, and I don't think that Default_Component_Value 
> makes much sense as an operational aspect. (Do we want to allow 
> Default_Component_Value on a partial view?? I think not.) Besides...

I don't see a problem, since it is only permitted on array types.  But perhaps
if we get rid of 13.1(10) it doesn't matter.

>> It also may be time to consider eliminating the 
>> user-defined-primitive-related restriction part of 13.1(10).
> 
> ...
> 
> We do need to be careful, however, since there have been several rules 
> over the years where 13.1(10) avoided pestilence. We'd need to find 
> those and put in the needed rules to avoid trouble (still a better 
> choice than preventing useful untagged derived types).

Interesting.  I don't remember such rules, but alas, that doesn't prove much...
 
...
>> Generally there was a desire to make expensive operations visible, 
>> but one wonders whether this particular rule is really worth the 
>> added user complexity.
> 
> It appears to me that if we did this, then it isn't a problem to keep 
> Default_Component_Size as a representation aspect. Explain if wrong.

I think you are right.  I don't think it will matter either way at that point.
 
 
>> Finally, the freezing associated with specifying a Default_Value has 
>> come up for the case of enumeration literals.  One wonders whether we 
>> need a more general exception for Default_Value so it can be 
>> specified without freezing the type being defined.  Using T'First or 
>> T'Last in the specification of Default_Value seems like a common 
>> thing to want to do, and so probably should be allowed.
> 
> We just discussed this on this list, and I included the case 'First in 
> my write-up, yet no one wanted to make a change. Not quite sure what 
> changed here.

I don't think I understood all of the implications.

> Anyway, completely removing freezing would not work. The freezing rule 
> prevents nonsense like:
> 
>     type Fooey is range 1 .. 10 with Default_Value => Fooey'Size;
> 
> or worse
> 
>     type Fooey is range 1 .. 10 with Default_Value => Sub'Alignment;
>     subtype Sub is Fooey;

I agree we don't want to allow use of representation attributes in defining 
Default_Value.  But many other attributes seem fair game.  We could perhaps 
specifically allow 'First and 'Last when static.  That would probably cover 
most interesting cases.

> I could see punching some additional holes into the freezing 
> specifically for Default_Value, but removing it in a blanket way would 
> open the door to lots of problems that would be hard to fix without 
> inventing something new that's much like freezing. (Let's not do 
> that!)

Agreed.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, March 31, 2020  4:04 PM

...
> > ...
> > 
> > We do need to be careful, however, since there have been several 
> > rules over the years where 13.1(10) avoided pestilence. We'd need to 
> > find those and put in the needed rules to avoid trouble (still a 
> > better choice than preventing useful untagged derived types).
> 
> Interesting.  I don't remember such rules, but alas, that doesn't 
> prove much...

I was just reading an old AI that mentioned that last week. Now, if you were 
to ask to me to remember what I was reading last week, that I wouldn't know.
:-) I'm not sure of the best way to search for that, but I'll think about it.

****************************************************************

From: Tucker Taft
Sent: Tuesday, March 31, 2020  4:19 PM

It is sort of hard to imagine what could be the problem, because clearly you 
can simulate what an inherited subprogram does by inserting explicit 
conversions at the call site.  Perhaps we claimed that 'Access would work on 
an inherited subprogram without having to create a wrapper.  Now that wrappers
are needed in a number of cases, this problem might no longer be considered 
that big of a deal.

****************************************************************

From: Arnaud Charlet
Sent: Wednesday, April 1, 2020  3:40 AM

> > There also was a concern about precision loss in fixed point types 
> > if the smalls vary. Not sure if we need to worry about that or not 
> > (I don't use fixed point enough to have an opinion).
> > 
> >> Generally there was a desire to make expensive operations visible, 
> >> but one wonders whether this particular rule is really worth the 
> >> added user complexity.
> > 
> > It appears to me that if we did this, then it isn't a problem to 
> > keep Default_Component_Size as a representation aspect. Explain if wrong.
> 
> I think you are right.  I don't think it will matter either way at that point.

Agreed as well, assuming we get rid of 13.1(10) then we can keep 
Default_Component_Value as a representation aspect.

> > Anyway, completely removing freezing would not work. The freezing 
> > rule prevents nonsense like:
> > 
> >     type Fooey is range 1 .. 10 with Default_Value => Fooey'Size;
> > 
> > or worse
> > 
> >     type Fooey is range 1 .. 10 with Default_Value => Sub'Alignment;
> >     subtype Sub is Fooey;
> 
> I agree we don't want to allow use of representation attributes in defining 
> Default_Value.  But many other attributes seem fair game.  We could perhaps 
> specifically allow 'First and 'Last when static.  That would probably cover 
> most interesting cases.

I'm curious, why would it be a problem to allow the use of 'Size or 
'Alignment? FWIW GNAT has no troubles with the above code.

I don't think we want to add a special case here, so to me it should be all 
or nothing.

****************************************************************

From: Tucker Taft
Sent: Wednesday, April 1, 2020  7:11 AM

>>> ...
>> 
>> I agree we don't want to allow use of representation attributes in defining 
>> Default_Value.  But many other attributes seem fair game.  We could perhaps 
>> specifically allow 'First and 'Last when static.  That would probably cover 
>> most interesting cases.
> 
> I'm curious, why would it be a problem to allow the use of 'Size or 
> 'Alignment? FWIW GNAT has no troubles with the above code.

The concern is that the presence of a Default_Value might affect some aspect 
of the representation, such as 'Size or 'Alignment of the type.  Because it is
considered a representation aspect, its presence or absence, or its particular
value, might have such an effect.
 
> I don't think we want to add a special case here, so to me it should 
> be all or nothing.

There are already some special cases for Default_Value, for enumeration types.
So this would not be without precedent.  But agreed that special cases do add 
complexity.  It would be useful to know whether the current regressions would 
be solved by allowing 'First and 'Last, or if it is a more general problem.

****************************************************************

From: Arnaud Charlet
Sent: Wednesday, April 1, 2020  7:24 AM

> > I'm curious, why would it be a problem to allow the use of 'Size or 
> > 'Alignment? FWIW GNAT has no troubles with the above code.
> 
> The concern is that the presence of a Default_Value might affect some aspect
> of the representation, such as 'Size or 'Alignment of the type.  Because it 
> is considered a representation aspect, its presence or absence, or its 
> particular value, might have such an effect.

Still, I don't see the issue, a compiler should be able to handle that these 
days (as shown by GNAT), it's not like we care anymore about e.g. one pass 
compilers at this stage, or is that the concern? Because Ada 2020 is not 
implementable with a one pass compiler in any case.

> > I don't think we want to add a special case here, so to me it should 
> > be all or nothing.
> 
> There are already some special cases for Default_Value, for enumeration 
> types.  So this would not be without precedent.  But agreed that special
> cases do add complexity.  It would be useful to know whether the current
> regressions would be solved by allowing 'First and 'Last, or if it is a 
> more general problem.

No, the regressions wouldn't improve with allowing 'First/'Last at all.

The regressions are all related to the rule we now all agree we want to get 
rid of (13.1(10), the part about parent types with primitive operations), 
so we should be fine on this front.

****************************************************************

From: Tucker Taft
Sent: Wednesday, April 1, 2020  7:36 AM

> Still, I don't see the issue, a compiler should be able to handle that 
> these days (as shown by GNAT), it's not like we care anymore about 
> e.g. one pass compilers at this stage, or is that the concern? Because 
> Ada 2020 is not implementable with a one pass compiler in any case.

Freezing issues are not related to one pass or two.  It is more circularity,
where the value of the new aspect affects the value of the aspect used to 
define it.  E.g.:

   type T is range 0 .. 31 with Default_Value => T'Object_Size;

where a choice between 16 and 32 for Object_Size would clearly affect the 
legality, and conceivably the presence of the Default_Value might affect this 
choice.

>>> I don't think we want to add a special case here, so to me it should 
>>> be all or nothing.
>> 
>> There are already some special cases for Default_Value, for enumeration 
>> types.  So this would not be without precedent.  But agreed that special
>> cases do add complexity.  It would be useful to know whether the current
>> regressions would be solved by allowing 'First and 'Last, or if it is a 
>> more general problem.
> 
> No, the regressions wouldn't improve with allowing 'First/'Last at all.

Ah, OK.  I thought you had some examples of uses of 'First or 'Last in 
customer code.

> The regressions are all related to the rule we now all agree we want 
> to get rid of (13.1(10), the part about parent types with primitive 
> operations), so we should be fine on this front.

OK, so let's focus on this derived-type issue and separate out the concern about 
Default_Value using 'First or 'Last.

****************************************************************

From: Arnaud Charlet
Sent: Wednesday, April 1, 2020  9:58 AM

> Freezing issues are not related to one pass or two.  It is more circularity,
> where the value of the new aspect affects the value of the aspect used to 
> define it.  E.g.:
> 
>    type T is range 0 .. 31 with Default_Value => T'Object_Size;
> 
> where a choice between 16 and 32 for Object_Size would clearly affect the 
> legality, and conceivably the presence of the Default_Value might affect 
> this choice.

OK. I still don't see the issue FWIW, but I guess we can keep the status quo 
for now.

> > No, the regressions wouldn't improve with allowing 'First/'Last at all.
> 
> Ah, OK.  I thought you had some examples of uses of 'First or 'Last in 
> customer code.

No, the issues were only part of the ACATS test b360001, so completely 
artificial.

> > The regressions are all related to the rule we now all agree we want 
> > to get rid of (13.1(10), the part about parent types with primitive 
> > operations), so we should be fine on this front.
> 
> OK, so let's focus on this derived-type issue and separate out the concern 
> about Default_Value using 'First or 'Last.

Seems fine for the time being.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, April 1, 2020  4:59 PM

> OK. I still don't see the issue FWIW, but I guess we can keep the status
> quo for now.

For Janus/Ada at least, all of the aspects and attribute definition clauses 
for a type being frozen are evaluated before any determination of 
representation is done. So, while specified aspects could presumably be 
handled (although finding an order would be difficult), the default values
aren't determined until all of the specified aspects are known (since 
those specifications can change the default - for instance, specifying 
Size can change the default Object_Size). Additionally, when subtypes are 
involved, those won't have been frozen yet when the base type is determined.

Consider something like:

    type T is range 0 .. 31 with Default_Value => S'Object_Size;
    subtype S is T'Base range 0 .. 2**12-1;

One has to freeze T before one can freeze S, and freezing T will determine the 
Default_Value.

You could create a separate set of rules just for Default_Value (say allowing 
T'Object_Size but not S'Object_Size), but that seems like a way guaranteed to 
cause never ending work for the ARG and for implementers to plug new holes as 
they are found.

****************************************************************

From: Arnaud Charlet
Sent: Thursday, April 2, 2020  2:41 AM

...
> Consider something like:
> 
>     type T is range 0 .. 31 with Default_Value => S'Object_Size;
>     subtype S is T'Base range 0 .. 2**12-1;
> 
> One has to freeze T before one can freeze S, and freezing T will 
> determine the Default_Value.

Isn't the above already illegal in any case? GNAT certainly rejects it
with:

     2.     type T is range 0 .. 31 with Default_Value => S'Object_Size;
                                                          |
        >>> type "S" cannot be used before end of its declaration

even without involving any freezing rule.

****************************************************************

From: Arnaud Charlet
Sent: Thursday, April 2, 2020  3:53 AM

> > The regressions are all related to the rule we now all agree we want 
> > to get rid of (13.1(10), the part about parent types with primitive 
> > operations), so we should be fine on this front.
> 
> OK, so let's focus on this derived-type issue and separate out the concern 
> about Default_Value using 'First or 'Last.

FWIW, only one acats test is impacted in the version of ACATS we're running, 
bxb3004:

--- expected
 +++ output
 @@ -126,4 +126,2 @@
  114.    type Bad_Der is new Not_UU with Unchecked_Union;              -- ERROR: (D)
 ->>> type-related representation item not permitted                <<<
 ->>> parent type "Not_UU" has primitive operations                 <<<
  115.
 @@ -175,3 +173,3 @@
  157.
 -158 lines: 11 errors
 +158 lines: 9 errors
  ###>> DONE

which is as expected.

Also interestingly, GNAT already has a warning to inform the customer when a 
change of representation (potentially costly) is involved. This warning is now
triggering in cases where previously code was rejected before we try to relax 
13.1(10), e.g:

-convert_record.adb:20:03: type-related representation item not permitted
-convert_record.adb:20:03: parent type "R" has primitive operations
+convert_record.adb:23:10: warning: change of representation required

with Ada.Text_IO;
procedure convert_record is
  package P is
    type R is record
       c: Character;
       a, b: Integer;
       end record;

    function foo(x: R) return Integer;
  end P;

  package body P is
    function foo(x: R) return Integer is
    begin
      return x.a + x.b;
    end foo;
  end P;

  type R2 is new P.R;
  pragma pack(R2);
  x: R2 := (a => 1, b => 2, c =>'c');
begin
  if foo(x) = 3 then
    Ada.Text_IO.Put_Line("Passed");
  else
    Ada.Text_IO.Put_Line("Failed");
  end if;
end convert_record;

in other words, relaxing the rule allows the above code to now compile and run 
successfully, and inform the user of what's happening behind the scene, 
letting him choose what he wants (the runtime hit, or rewrite his code for 
more efficiency). This seems to be the best option at this stage and remember
that this change of representation is in any case already required in other 
cases, so it's not like this requires a new mechanism for the compiler.

****************************************************************

From: Randy Brukardt
Sent: Thursday, April 2, 2020  2:17 PM

The only reason that you couldn't "use S before the end of its declaration" 
would be because T was getting frozen during the declaration of S. Otherwise, 
you would have evaluated the aspect later at some other freezing point.

That probably happened because I used a range. If I had simply said:

       subtype S is T'Base;

then the declaration of S should not involve any freezing. Sorry about 
botching the example.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, April 21, 2020  7:27 PM

> OK, so let's focus on this derived-type issue and separate 
> out the concern about Default_Value using 'First or 'Last.

Attached find the AI I created to repeal the annoying part of 13.1(10/3).
It has been reviewed by Steve and Tucker. Tucker suggested making the
remaining part of the rule only apply to nonconfirming specifications of
aspects, so that's why the wording was totally reorganized.

I researched every occurrence of 13.1(10) in every existing AI in order 
to see if there were any other AIs to change. The only AI with a 
substantial relevance is AI95-0246-1, in which it is discovered that one 
needs to ban changing representations of by-reference types. (We're 
keeping that part of the rule.) AI12-0074-1 also seems to depend on the rule, 
but we had already been asked to revisit that AI.) I also noticed that the 
concern about precision loss does not happen even with this repeal, unless 
an implementation wants to make trouble for itself. (In particular, Small 
cannot be specified on a derived type, so the portable way to cause issues 
is illegal.)

As always, comments welcome.

****************************************************************

Questions? Ask the ACAA Technical Agent