Version 1.1.1.1 of ais/ai-00109.txt

Unformatted version of ais/ai-00109.txt version 1.1.1.1
Other versions for file ais/ai-00109.txt

!standard 13.03 (55)          98-03-27 AI95-00109/05
!class binding interpretation 96-04-04
!status work item 98-04-01
!status ARG Approved (subject to letter ballot) 7-0-3 97-11-14
!status work item (letter ballot was 4-4-3) 96-10-03
!status ARG approved 5-0-3 (subject to letter ballot) 96-06-17
!status work item 96-05-07
!status received 96-04-04
!reference AI95-00051
!priority High
!difficulty Hard
!subject Size and Alignment Attributes for Subtypes
!summary 98-03-27
???Bob will update this to address the issues in the minutes of the April 1998 meeting.
This AI addresses issues related to Size and Alignment attributes for subtypes. For Size and Alignment of objects, see AI95-00051.
A non-first subtype inherits each subtype-related aspect (namely, Size and Alignment) from the first subtype, if the two subtypes are statically matching.
Recommended Level of Support:
For a packed record or array type, the Size of the first subtype should reflect the requirements of RM-13.2(7-9), except that if the record or array does not fit in a single word, the Size may be rounded up, but not past the next word boundary.
Implementation Advice:
If a type obeys the rules for well-defined unchecked conversion given in 13.9(17), then the implementation should support a Size clause that is the same as what the implementation would have chosen by default.
!question 96-09-15
The wording of 13.2(7-9) seems vague. For example, it refers to "packed as tightly as possible". What does this imply about the Size of a packed array or record?
Suppose a subtype S statically matches a first subtype T, and that the Size of T has been specified ("for T'Size use...;"). 13.1(14) seems to imply that S'Size = T'Size, whereas 13.3(55) seems to imply that S'Size is the minimum needed, based on the range. Which is correct? (The former.)
!recommendation 96-04-11
(See summary.)
!wording 96-04-11
!discussion 98-03-27
In the following examples, assume that the word size is 32 bits.
13.2(7-9) says:
7 The recommended level of support for pragma Pack is:
8 For a packed record type, the components should be packed as
tightly as possible subject to the Sizes of the component subtypes, and subject to any record_representation_clause that applies to the type; the implementation may, but need not, reorder components or cross aligned word boundaries to improve the packing. A component whose Size is greater than the word size may be allocated an integral number of words.
9 For a packed array type, if the component subtype's Size is less
than or equal to the word size, and Component_Size is not specified for the type, Component_Size should be less than or equal to the Size of the component subtype, rounded up to the nearest factor of the word size.
Consider:
type Three_Bits is record A, B, C: Boolean; end record; pragma Pack(Three_Bits); type Sixty_Two_Bits is array(1..62) of Boolean; pragma Pack(Sixty_Two_Bits);
Boolean'Size is 1, so clearly Three_Bits can fit in 3 bits, so Three_Bits'Size must be 3. Sixty_Two_Bits can fit in 62 bits, so Sixty_Two_Bits'Size must be 62, 63, or 64.
13.9(16-17) says:
16 The recommended level of support for unchecked conversions is:
17 Unchecked conversions should be supported and should be
reversible in the cases where this clause defines the result. To enable meaningful use of unchecked conversion, a contiguous representation should be used for elementary subtypes, for statically constrained array subtypes whose component subtype is one of the subtypes described in this paragraph, and for record subtypes without discriminants whose component subtypes are described in this paragraph.
This implies that the following Size clauses are legal:
type Three_Bits is record A, B, C: Boolean; end record; pragma Pack(Three_Bits); for Three_Bits'Size use 3; type Sixty_Two_Bits is array(1..62) of Boolean; pragma Pack(Sixty_Two_Bits); for Sixty_Two_Bits'Size use 64; -- This is either the Size the implementation would choose by -- default, or that value rounded up to a multiple of the word -- size.
Now, consider the case without pragma Pack:
type Three_Bytes is record A, B, C: Boolean; end record; type Sixty_Two_Bytes is array(1..62) of Boolean;
And assume that the implementation allocates 8 bits for each Boolean component, so Three_Bytes'Size = 38 and Sixty_Two_Bytes'Size = 628, by default. This is not required, but is allowed. If the implementation chooses those values by default, then it must support this as well:
type Three_Bytes is record A, B, C: Boolean; end record; for Three_Bytes'Size use 3*8; type Sixty_Two_Bytes is array(1..62) of Boolean; for Sixty_Two_Bytes'Size use 62*8; -- Note that this is a multiple of the word size.
A different implementation might allocate 32 bits for each Boolean component, and would have to support the corresponding Size clauses.
13.1(23) supports the idea that at least some Size clauses ought to be required for composite types:
23 An implementation need not support a specification for the Size
for a given composite subtype, nor the size or storage place for an object (including a component) of a given composite subtype, unless the constraints on the subtype and its composite subcomponents (if any) are all static constraints.
13.1(15) says:
15 A derived type inherits each type-related aspect of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype.
To resolve the contradiction between 13.1(14) and 13.3(55), we add the rule:
A non-first subtype inherits each subtype-related aspect (namely, Size and Alignment) from the first subtype, if the two subtype are statically matching.
This preserves 13.1(14), which says:
14 If two subtypes statically match, then their subtype-specific aspects (Size and Alignment) are the same.
13.3(54-55) says:
54 The recommended level of support for the Size attribute of subtypes is:
55 The Size (if not specified) of a static discrete or fixed point
subtype should be the number of bits needed to represent each value belonging to the subtype using an unbiased representation, leaving space for a sign bit only if the subtype contains negative values. If such a subtype is a first subtype, then an implementation should support a specified Size for it that reflects this representation.
Now, consider:
type T is range 1..10; for T'Size use 16; -- T'Size is 16. subtype S1 is T range 1..10; -- S1'Size is 16. subtype S2 is T range 1..5; -- S2'Size is 3.
The first sentence of 13.3(55) does not apply to T, since its Size is specified, so its Size is as specified -- 16. According to this AI, the Size of S1 is also specified, since S1 statically matches T, and therefore inherits the Size of T. For S2, however, the Size is not specified, so 13.3(55) applies, so S2'Size is 3.
Note that for an integer type T, T'Base and T are never statically matching. For example:
type T is range -2**31..2**31-1; for T'Size use 32;
If the implementation happens to choose a base range for T'Base that is the same as the range of T, that does not mean that T'Base statically matches T, because T'Base is unconstrained, whereas T is constrained. Therefore, we do not specify that T'Base is 32 here. The base range is not a constraint.
!appendix

!section 13.3(55)
!subject Missing AI: When is the Size "specified" for a subtype?
!reference RM95-13.3(55)
!from Tucker Taft 95-10-30
!reference 95-5373.b Tucker Taft 95-10-30>>
!discussion

In 13.3(55), it defines a recommended meaning for Size, when it is 
not "specified" for a subtype.  Throughout the language, two 
statically matching subtypes are considered completely equivalent. Hence,
if a subtype statically matches the first subtype, and the size 
has been specified for the first subtype, then Size should be 
considered "specified" for the statically matching subtype.
Or to put it another way, all statically matching subtypes should
have the same value for 'Size.

Any other interpretation of the phrase "if not specified" in
13.3(55) would create numerous problems.  In particular, if
one said that specifying a size for a first subtype "broke"
static matching between the first subtype and other subtypes whose
constraints statically match those of the first subtype, then putting 
on a "confirming" rep-clause could seriously alter the correctness 
of a program.  Alternatively, if one said that only specifying a 
non-confirming rep-clause would "break" static matching, then compilers 
that differed over what was the default Size for a subtype could have 
dramatically different effects with respect to static subtype matching.
(Remember that compilers that do not support the S.P. Annex need
not obey 13.3(55).)

Note that the "Recommended Level of Support" part of the summary becomes
mandatory in the Systems Programming Annex, whereas the "Implementation
Advice" does not.

ASIDE:

    Note that there has been some interest in reviving the ability
    to specify sizes on "secondary" subtypes.  The above suggested
    interpretation for "specified" should not be interpreted to
    affect this possibility either way.  If a secondary subtype 
    were to have a Size specified, then we would have to determine
    how such rep-clauses would interact with static matching.  
    However, even if such rep-clauses were allowed, we believe that
    when they are *not* present, any subtypes which statically
    match the first subtype must have the same 'Size as the first
    subtype.

END OF ASIDE.

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

!section 13.1(14)
!subject Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!from Gary Dismukes 95-11-01
!reference 95-5379.a Gary Dismukes 95-11-2>>
!discussion

(This comment is being submitted on behalf of Robert Dewar.)

Some comments on the SIZE problem and Issue
-------------------------------------------

First of all, let's look at the current rules in the absence of size
clauses:

   type Count is Integer range 1 .. 65;

   subtype Number_Of_Companies is Count range 1 .. 64;
   subtype Number_Of_Hotels    is Count range 1 .. 65;

   type Count_Ptr     is access all Count;
   type Companies_Ptr is access all Number_Of_Companies;
   type Hotels_Ptr    is access all Number_Of_Hotels

We have, according to paragraph 13.3(55):

   Count'Size = 7
   Number_Of_Companies'Size = 6;
   Number_Of_Hotels'Size = 7;

This is required. In Ada 83, many (most? nearly all?) compilers would
have given Integer'Size to all three types, but Ada 95 requires that
the sizes be minimal. This causes a number of subtle incompatibilities
but we already (unwisely in my view, I will not hide this) decided to
introduce this behavior.

Moreover, type Count_Ptr is convertible to type Hotels_Ptr, but
not to type Companies_Ptr.

This again seems very strange, but that's the way the language is,
and for this to work, we need to worry about:

   X : aliased Count_Ptr;
   Y : aliased Hotels_Ptr;

where X'Access and Y'Access must be interconvertible. This means that
X and Y must be stored using the same representation.

In the absence of Size clauses, Ada 95 achieves this requirement by
the default size rules in 13.3(55), and in this case 13.1(14) clearly
is correct:

  "If two subtypes statically match, then their subtype-specific
   aspects (Size and Alignment) are the same"

Together with the assumption (perhaps it is a requirement, but I
can't see the reference right now and anyway it is not really
relevant to this argument which it is) that the two objects will
be stored the same way if the sizes are the same.

What Happens When we Add Size Clauses
-------------------------------------

13.3(55) allows a size to be specified for the first subtype. If this
is a confirming size, then all is well, but consider in the above
example what happens when we write:

   type Count is Integer range 1 .. 65;

   subtype Number_Of_Companies is Count range 1 .. 64;
   subtype Number_Of_Hotels    is Count range 1 .. 65;

   for Count'Size use 16;

   type Count_Ptr     is access all Count;
   type Companies_Ptr is access all Number_Of_Companies;
   type Hotels_Ptr    is access all Number_Of_Hotels

A straightforward reading of 13.3(55) would clearly suggest that the
size clause affects only the size of Count, and that we would have:

   Count'Size = 16;
   Number_Of_Companies'Size = 6;
   Number_Of_Hotels'Size = 7;

But now we are in trouble, the subtypes Count and Number_Of_Hotels
still appear to staticaly match, but 13.1(14) is violated. So
something is wrong.

There are two basic approaches one can take to solving this problem:

  Tuck's Approach

    Hereinafter referred to as TA

    TA reads 13.1(14) as a requirement rather than an observation,
    even though it does not have a shall in it. So the effect of 13.1(14)
    in TA is that if the other rules on static subtypes are met, then
    the Size and Alignment SHALL be the same.

    TA reads into the last sentence of 13.3(55) the fact that if you
    specify the size for the first named subtype, then you also are
    implicitly specifying the size for any statically matching
    subtypes (because of the requirement of 13.1(14), and that
    therefore the default ("if not specified") size rule does not
    apply. 

    Using TA, in the above example, with the size clause, the
    value of Number_Of_Hotels'Size would become 16.

  Dewar's approach

    Hereinafter referred to as DA

    Does not treat 13.1(14) as a requirement, but rather a statement
    about what is true about static subtypes. In other words, if this
    is not true, then the subtypes do not statically match. Roughly
    the view is that if you state a rule such as:

      "Identical twins always have the same sex"

    and then you look at a boy and a girl, you know they are not identical
    twins, no matter what rules have been stated elsewhere.

    DA then takes the more natural reading of 13.3(55), and assumes that
    the size clause applies only to the first named subtype.

  Tuck mentions a third approach as a strawman in his comments on this
  subject, but (a) I don't understand it, and (b) as far as I can tell
  no one is arguing for it, so I won't bother with it.

Now, some comments on the two approaches:

1. Both TA and DA allow confirming rep clauses to be added for the first
   subtype without modifying the behavior in any way. This is important,
   since apparently one of Tuck's main concerns is that confirming rep
   clauses not have any semantic effect.
 
   (I agree that confirming rep clauses should not have any effect, but in
   the case of Size, this principle is so badly compromised by the inability
   to give any rep clauses for subtypes at all, not even confirming rep
   clauses, that I can't get too excited about it, but in any case, DA
   allows confirming rep clauses that are neutral).

2. DA means that a non-confirming size clause can affect the convertability
   of pointers to different subtypes. This is presumably the overwhelming
   concern that leads to the preference of TA.

   However, I must say I am underwhelmed. First of all it is a bit bizarre
   that the legality of these conversions depends on the equality of values
   that are likely to be logically related in the program (for example in
   the above case, if you open a new company, you suddenly get added
   convertability from Count_Ptr to Companies_Ptr. That's unlikely of
   course to cause trouble in an existing program. If you remove a hotel,
   then you lose convertability. This could cause trouble, but in fact is
   very unlikely to do so, since the conversion from Count_Ptr to
   Hotels_Ptr is a bizarre one (and the conversion from Hotels_Ptr to
   Companies_Ptr, which is now allowed is even more bizarre).

   Furthermore, it seems quite natural to me that if you have two types:

      access X
      access Y

   that they are convertible only if the representations of X and Y are
   the same, and if you specifically modify the representation of X and
   do not modify the representation of Y, then they are no longer
   convertible.

3. TA means that a size clause affects the size of a previously declared
   subtype. This seems peculiar, and I can see it causing implementation
   problems. For non subtype specific attributes, there is no problem,
   since the representation is an attribute of the base type.

   DA does not at all like this retrospective effect.

   TA does not care much, since one pass semantics aren't considered too
   important, and anyway that's not quite fair, because you can think of
   sizes as only being established at the freeze point.

4. DA thinks that it is strange that if you specify the size of the first
   subtype, then it has an effect on a certain subset of subtypes, those
   which happen to statically match, and that saying that this is the case
   will complicate 13.3(55). For example, TA could be made clear by adding
   to this paragraph the following sentence:

     Such a specification affects the first named subtype, and any other
     subtypes of the same base type that statically match.

   Probably a note needs to be added:

     This affects both subtypes declared previously to the size clause,
     and any subsequent subtypes declared in either the same declarative
     region or elsewhere.

   because this is quite surprising (that the size of a subtype in another
   unit would be affected). The actual processing for subtypes in other
   units is now something like:

     If the subtype statically matches the first named subtype, then take
     the size of the first named subtype, otherwise take the default size
     from paragraph 13.3(55).

   By contrast, the effect of DA on the RM would be as follows:

     Remove 13.1(14) completely

     Add to the first sentence of 4.9.1(2), giving

     "A subtype statically matches another subtype of the same type if they
      have statically matching constraints, and if they have the same
      subtype specific aspects (Size and Alignment)".

What we have here is two conflicting requirements in the RM. I think in such
cases it is a waste of time to make arguments saying essentially that you
can conclude that one is wrong by intent because it must be wrong, given
the other requirement. This argument can be applied either way round and
is unhelpful. I mention this, because TA uses this argument, arguing that
13.1(14) implies the desired constructive reading of 13.3(55). DA could
make the same argument the other way round, but it is besides the point.

What we need is a resolution that is least suprising, and simplest.

Ulterior Motive Disclosed
-------------------------

DA will now disclose an ulterior motive.

Up until the last moment, Ada 95 allowed 'Size to be specified for subtypes.
GNAT implemented this capability, and it was definitely useful. It was
removed from the RM late on without WG9 discussion.

Why?

Because of these static matching rules. The attempt was to ensure that
13.1(14) is in fact true, and that specifying sizes for subtypes could
not disrupt it. 

But that did not get done cleanly as we see.

To me, the removal of a really useful feature, just so that the very
marginal feature of being able to convert pointers to logically unrelated
subtypes would work, is a very poor trade off.

It is particularly important to be able to specify the size of subtypes
given the (in my view injudicious) introduction of the rules in Ada 95
that require separate sizes for subtypes (Ada 83 allowed it but did not
require it, few compilers took advantage of it, the only one I know of
that did systematically what is now required is the old Intermetrics
compiler).

This means that if we have

   type X is range 0 .. 65535;
   for X'Size use 16;

   subtype Y is X range 1 .. N;
   -- N is a constant that happens today to be 255

   then Y'Size is 8, and that in the record:

      type Rec is record
         XV : X;
         YV : Y;
      end record;

   XV is likely to occupy 16 bits, and YV to occupy 8 bits. This could well
   be incompatible with existing programs, and note that it would require
   most vendors to change their size rules, and behavior of their systems
   (with the sole exception of the Intermetrics compiler, which is indeed
   compatible with the old Intermetrics compiler).

This was not *too* worrisome before the last minute change, since at least
you could use a size clause (in this case "for Y'size use X'Size) that
would override the default, and duplicate old behavior.

Furthermore, the introduction of the restriction means that it is not
possible to specify confirming size clauses. So you have a situation in
which compared to Ada 83, the sizes of subtypes are required to vary in
an unexpected manner, and there is no way to either confirm or change
this behavior.

DA has the very interesting property that if it is adopted, then there is
no reason not to allow compilers to specify the size of subtypes, undoing
the ill effects of the last minute, incompletely executed, change.

A comment here is that MANY readers of Ada 95 assume that subtype specific
attributes can be specified for subtypes. That seems a reasonable assumption
and used to be a correct one, but is now surprisingly false. We have got a
number of bug reports from people complaining that GNAT does not allow such
specifications. We can of course explain that GNAT is right, but the
principle of least suprise is definitely violated!

Incidentally, a major use for specifying subtype sizes is in building
packed records. You just specify the size of each subtype, and then say
pragma Pack, and everything packs together nicely without needing to
write a (possibly non-portable) representation clause. Furthermore
the representation clause here is clearly undesirable over-specification.
You don't want to specify the exact layout, but you do want to control
the nature of the packing. Yes there are other ways to do this, e.g.
by using derived types, but they are messy by comparison.

The other major reason for specifying subtype sizes is in porting legacy
code, where you want to confirm size choices made by a previous Ada 83
compiler.

These requirements are strong enough that in GNAT we definitely intend to
implement a feature for this purpose.

If TA is adopted, GNAT will introduce an attribute Subtype_Size that can
be applied to arbitrary subtypes, and which will compromise static matching
in some cases. This attribute is probably technically an extension because
of this compromising effect, so we will put it under the non-pedantic (GNU'ese
for extensions allowed) mode.

If DA is adopted, GNAT will simply allow 'Size for subtypes.

A note for Bob Duff
-------------------

Yes, yes, all this applies to Alignment too. I can't get excited about
alignments for subtypes. At least there is no analog to 13.3(55) requiring
an injudicious choice of default alignments.

To be Honest
------------

There are a couple more glitches here

First, with respect to dynamic subtypes. We have to worry about dynamic
subtypes, since they can statically match. For dynamic subtypes, if you
want to be sure that access types to them are inter-convertible, then
you have to read 13.1(14) as a requirement that the sizes of statically
matching dynamic subtypes match. Note that there are no rules on the
default sizes for dynamic subtypes. TA of course handles this fine, by
changing the "are" in 13.1(14) to "shall".

DA can't get very excited about this problem, and doesn't really care
if convertability of such access types is impl dependent, but, if pressed,
would be inclined to require that all dynamic subtypes have the size
of the base type. This avoids differences between implementations, and
is perfectly acceptable in practice.

Second, with respect to alignments, there is no clear statement that requires
choice of alignments. TA would say that 13.1(14) places the requirement that
if two subtypes statically match then the alignments should match. Again
DA can't get excited, but if pressed would be inclined to say that the
alignments of two subtypes of the same size should be identical.

Original Intent
---------------

Arguments from original intent are somewhat bogus, since the RM does not
contain its history.

One could say that the longer term intent was that Size should be able
to be specified for subtypes, and that the language "subtype specific"
still implies this -- a bogus argument for DA.

One could also say that the removal of this capability obviously means
that 13.1(14) was considered sacrosanct -- a bogus argument for TA.

Conclusion
----------

There is a real disagreement here. Needs discussion!



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

!section 13.1(14)
!subject 'SIZE problem violates Ada95 "no surprises" issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 95-5379.a Gary Dismukes 95-11-2
!from David Emery 95-11-02
!reference 95-5382.a David_Emery_at_1-BCCDFA@CCGATE.HAC.COM 95-11-3>>
!discussion

RBKD's example:

   type X is range 0 .. 65535;
   for X'Size use 16;

   subtype Y is X range 1 .. N;
   -- N is a constant that happens today to be 255

   then Y'Size is 8, and that in the record:

      type Rec is record
         XV : X;
         YV : Y;
      end record;
led me to observe that the following:
    package Rec_IO is new Direct_IO (Rec);
would cause real problems when a database is maintained using
Rec_IO bt different invocations of the program, with different 
values of N.    The expectation (guaranteed by Ada83 because Y
is a subtype and not a type, I beleive), is that objects of
type Rec are the same size.  This is a particular issue for
Direct_IO, where the data layouts can depend very strongly on 
the size of the object.  

Ada95 clearly violates its "no surprises" guideline by having
the size of a subtype change in this way.  I find it basically
counterintuitive (and unacceptable) to have to do a lot of 
representation clauses for an 'invariant' that should be machine
independent, i.e. that objects of the type Rec are the same
size, regardless of the value of the constraint N.  In particular,
if this causes Direct_IO to fail because of varying values of N,
then we lose type 'equivalence', exchanging it for subtype
equivalence.  (What I mean here is that 2 values of the same type 
can be used, subject only to subtype constraint checks.)

                dave


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

!section 13.1(14)
!subject Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 95-5379.a Gary Dismukes 95-11-2
!from Bob Duff
!reference 96-5462.a Robert A Duff 96-4-11>>
!discussion

Robert, you sent in this comment just before the last ARG meeting.
It was discussed at the meeting, with no resolution of the issues.
There are some confusing things.  Could you please send a
clarification?

> (This comment is being submitted on behalf of Robert Dewar.)
> 
> Some comments on the SIZE problem and Issue
> -------------------------------------------
> 
> First of all, let's look at the current rules in the absence of size
> clauses:
> 
>    type Count is Integer range 1 .. 65;

That's not legal syntax.  You must mean one of these:

    type Count is range 1 .. 65;
    subtype Count is Integer range 1 .. 65;
    type Count is new Integer range 1 .. 65;

The ARG discussion got confused about this.

>    subtype Number_Of_Companies is Count range 1 .. 64;
>    subtype Number_Of_Hotels    is Count range 1 .. 65;

There was some feeling at the ARG meeting that this is not a compelling
example, because you're using the same type (two different subtypes) for
two totally unrelated things.  If this causes surprises, tough luck --
you should have used two different types in the first place.

Now, I realize there are (at least) two schools of thought -- some
people like to use lots of different types, whereas some people like to
make everything a subtype of the same type.  Anyway, you weren't there
to defend yourself, so you might want to do so now.

>    type Count_Ptr     is access all Count;
>    type Companies_Ptr is access all Number_Of_Companies;
>    type Hotels_Ptr    is access all Number_Of_Hotels
> 
> We have, according to paragraph 13.3(55):
> 
>    Count'Size = 7
>    Number_Of_Companies'Size = 6;
>    Number_Of_Hotels'Size = 7;
> 
> This is required. In Ada 83, many (most? nearly all?) compilers would
> have given Integer'Size to all three types, but Ada 95 requires that
> the sizes be minimal. This causes a number of subtle incompatibilities
> but we already (unwisely in my view, I will not hide this) decided to
> introduce this behavior.
> 
> Moreover, type Count_Ptr is convertible to type Hotels_Ptr, but
> not to type Companies_Ptr.
> 
> This again seems very strange, but that's the way the language is,
> and for this to work, we need to worry about:
> 
>    X : aliased Count_Ptr;
>    Y : aliased Hotels_Ptr;
> 
> where X'Access and Y'Access must be interconvertible. This means that
> X and Y must be stored using the same representation.
> 
> In the absence of Size clauses, Ada 95 achieves this requirement by
> the default size rules in 13.3(55), and in this case 13.1(14) clearly
> is correct:
> 
>   "If two subtypes statically match, then their subtype-specific
>    aspects (Size and Alignment) are the same"
> 
> Together with the assumption (perhaps it is a requirement, but I
> can't see the reference right now and anyway it is not really
> relevant to this argument which it is) that the two objects will
> be stored the same way if the sizes are the same.

I don't think there's an explicit requirement, but it seems that this is
the only viable run-time model -- aliased objects have to be stored the
same way if their type is the same, and their subtypes statically match.
The compiler can play all kinds of games with non-aliased objects.

> What Happens When we Add Size Clauses
> -------------------------------------
> 
> 13.3(55) allows a size to be specified for the first subtype. If this
> is a confirming size, then all is well, but consider in the above
> example what happens when we write:
> 
>    type Count is Integer range 1 .. 65;

Same bug as above.

>    subtype Number_Of_Companies is Count range 1 .. 64;
>    subtype Number_Of_Hotels    is Count range 1 .. 65;
> 
>    for Count'Size use 16;
> 
>    type Count_Ptr     is access all Count;
>    type Companies_Ptr is access all Number_Of_Companies;
>    type Hotels_Ptr    is access all Number_Of_Hotels
> 
> A straightforward reading of 13.3(55) would clearly suggest that the
> size clause affects only the size of Count, and that we would have:
> 
>    Count'Size = 16;
>    Number_Of_Companies'Size = 6;
>    Number_Of_Hotels'Size = 7;
> 
> But now we are in trouble, the subtypes Count and Number_Of_Hotels
> still appear to staticaly match, but 13.1(14) is violated. So
> something is wrong.
> 
> There are two basic approaches one can take to solving this problem:
> 
>   Tuck's Approach
> 
>     Hereinafter referred to as TA
> 
>     TA reads 13.1(14) as a requirement rather than an observation,
>     even though it does not have a shall in it. So the effect of 13.1(14)
>     in TA is that if the other rules on static subtypes are met, then
>     the Size and Alignment SHALL be the same.

There are lots of requirements that have no "shall".  Legality Rules use
"shall", but Static Semantics just state "facts" about the language --
in this case, the sizes "are" the same.  The facts are of course
requirements on the implementation -- if they're not true in a given
implementation, then that's not a correct implementation of Ada.
My point is: Don't base your argument on whether "shall" was used.

I do admit we have a problem, here.

>     TA reads into the last sentence of 13.3(55) the fact that if you
>     specify the size for the first named subtype, then you also are
>     implicitly specifying the size for any statically matching
>     subtypes (because of the requirement of 13.1(14), and that
>     therefore the default ("if not specified") size rule does not
>     apply. 
> 
>     Using TA, in the above example, with the size clause, the
>     value of Number_Of_Hotels'Size would become 16.
> 
>   Dewar's approach
> 
>     Hereinafter referred to as DA
> 
>     Does not treat 13.1(14) as a requirement, but rather a statement
>     about what is true about static subtypes. In other words, if this
>     is not true, then the subtypes do not statically match. Roughly
>     the view is that if you state a rule such as:
> 
>       "Identical twins always have the same sex"
> 
>     and then you look at a boy and a girl, you know they are not identical
>     twins, no matter what rules have been stated elsewhere.

No, that's not right.  If the RM said that, we would have written "An
identical twins is a pair of siblings that have the same sex [...and a
bunch of other stuff]".  Or, "NOTE: Note that identical twins always
have the same sex." (presuming it follows from the definition).

I wrote 13.1(14), and it's written in the same style as all the other
Static Semantics, and it means that we are *requiring* this to be true
in all implementations.

>     DA then takes the more natural reading of 13.3(55), and assumes that
>     the size clause applies only to the first named subtype.
> 
>   Tuck mentions a third approach as a strawman in his comments on this
>   subject, but (a) I don't understand it, and (b) as far as I can tell
>   no one is arguing for it, so I won't bother with it.
> 
> Now, some comments on the two approaches:
> 
> 1. Both TA and DA allow confirming rep clauses to be added for the first
>    subtype without modifying the behavior in any way. This is important,
>    since apparently one of Tuck's main concerns is that confirming rep
>    clauses not have any semantic effect.
>  
>    (I agree that confirming rep clauses should not have any effect, but in
>    the case of Size, this principle is so badly compromised by the inability
>    to give any rep clauses for subtypes at all, not even confirming rep
>    clauses, that I can't get too excited about it, but in any case, DA
>    allows confirming rep clauses that are neutral).
> 
> 2. DA means that a non-confirming size clause can affect the convertability
>    of pointers to different subtypes. This is presumably the overwhelming
>    concern that leads to the preference of TA.
> 
>    However, I must say I am underwhelmed. First of all it is a bit bizarre
>    that the legality of these conversions depends on the equality of values
>    that are likely to be logically related in the program (for example in
>    the above case, if you open a new company, you suddenly get added
>    convertability from Count_Ptr to Companies_Ptr. That's unlikely of
>    course to cause trouble in an existing program. If you remove a hotel,
>    then you lose convertability. This could cause trouble, but in fact is
>    very unlikely to do so, since the conversion from Count_Ptr to
>    Hotels_Ptr is a bizarre one (and the conversion from Hotels_Ptr to
>    Companies_Ptr, which is now allowed is even more bizarre).

This is where the two schools of thought I mentioned make a difference
-- many folks think that you would make Number_Of_Hotels and
Number_Of_Companies two different types, so convertibility changes would
not happen.

>    Furthermore, it seems quite natural to me that if you have two types:
> 
>       access X
>       access Y
> 
>    that they are convertible only if the representations of X and Y are
>    the same, and if you specifically modify the representation of X and
>    do not modify the representation of Y, then they are no longer
>    convertible.
> 
> 3. TA means that a size clause affects the size of a previously declared
>    subtype. This seems peculiar, and I can see it causing implementation
>    problems. For non subtype specific attributes, there is no problem,
>    since the representation is an attribute of the base type.
> 
>    DA does not at all like this retrospective effect.
> 
>    TA does not care much, since one pass semantics aren't considered too
>    important, and anyway that's not quite fair, because you can think of
>    sizes as only being established at the freeze point.

Note that this "retrospective" effect happens only within a single
package spec or declarative part.

Now wait a minute, is this really right?  Don't freezing rules require
you to give the size clause before any other *constrained* subtypes?

> 4. DA thinks that it is strange that if you specify the size of the first
>    subtype, then it has an effect on a certain subset of subtypes, those
>    which happen to statically match, and that saying that this is the case
>    will complicate 13.3(55). For example, TA could be made clear by adding
>    to this paragraph the following sentence:
> 
>      Such a specification affects the first named subtype, and any other
>      subtypes of the same base type that statically match.
> 
>    Probably a note needs to be added:
> 
>      This affects both subtypes declared previously to the size clause,
>      and any subsequent subtypes declared in either the same declarative
>      region or elsewhere.
> 
>    because this is quite surprising (that the size of a subtype in another
>    unit would be affected). The actual processing for subtypes in other
>    units is now something like:
> 
>      If the subtype statically matches the first named subtype, then take
>      the size of the first named subtype, otherwise take the default size
>      from paragraph 13.3(55).
> 
>    By contrast, the effect of DA on the RM would be as follows:
> 
>      Remove 13.1(14) completely
> 
>      Add to the first sentence of 4.9.1(2), giving
> 
>      "A subtype statically matches another subtype of the same type if they
>       have statically matching constraints, and if they have the same
>       subtype specific aspects (Size and Alignment)".
> 
> What we have here is two conflicting requirements in the RM. I think in such
> cases it is a waste of time to make arguments saying essentially that you
> can conclude that one is wrong by intent because it must be wrong, given
> the other requirement. This argument can be applied either way round and
> is unhelpful. I mention this, because TA uses this argument, arguing that
> 13.1(14) implies the desired constructive reading of 13.3(55). DA could
> make the same argument the other way round, but it is besides the point.
> 
> What we need is a resolution that is least suprising, and simplest.
> 
> Ulterior Motive Disclosed
> -------------------------
> 
> DA will now disclose an ulterior motive.
> 
> Up until the last moment, Ada 95 allowed 'Size to be specified for subtypes.
> GNAT implemented this capability, and it was definitely useful. It was
> removed from the RM late on without WG9 discussion.
> 
> Why?
> 
> Because of these static matching rules. The attempt was to ensure that
> 13.1(14) is in fact true, and that specifying sizes for subtypes could
> not disrupt it. 
> 
> But that did not get done cleanly as we see.

This history is correct.

> To me, the removal of a really useful feature, just so that the very
> marginal feature of being able to convert pointers to logically unrelated
> subtypes would work, is a very poor trade off.
> 
> It is particularly important to be able to specify the size of subtypes
> given the (in my view injudicious) introduction of the rules in Ada 95
> that require separate sizes for subtypes (Ada 83 allowed it but did not
> require it, few compilers took advantage of it, the only one I know of
> that did systematically what is now required is the old Intermetrics
> compiler).
> 
> This means that if we have
> 
>    type X is range 0 .. 65535;
>    for X'Size use 16;
> 
>    subtype Y is X range 1 .. N;
>    -- N is a constant that happens today to be 255

I presume that N is a *static* constant.  Dave Emery sent a note that
assumed N is non-static, which I think confuses the issue.

>    then Y'Size is 8, and that in the record:
> 
>       type Rec is record
>          XV : X;
>          YV : Y;
>       end record;
> 
>    XV is likely to occupy 16 bits, and YV to occupy 8 bits. This could well
>    be incompatible with existing programs, and note that it would require
>    most vendors to change their size rules, and behavior of their systems
>    (with the sole exception of the Intermetrics compiler, which is indeed
>    compatible with the old Intermetrics compiler).
> 
> This was not *too* worrisome before the last minute change, since at least
> you could use a size clause (in this case "for Y'size use X'Size) that
> would override the default, and duplicate old behavior.
> 
> Furthermore, the introduction of the restriction means that it is not
> possible to specify confirming size clauses. So you have a situation in
> which compared to Ada 83, the sizes of subtypes are required to vary in
> an unexpected manner, and there is no way to either confirm or change
> this behavior.

However, note that Ada 95 allows Size clauses on *objects* and
Component_Size clauses for array components, which somewhat alleviates
the problem.  Also, if you really want a Size clause on a subtype, you
can make it a derived type instead.  Not ideal, since extra type
conversion will be needed, but it does work OK.

> DA has the very interesting property that if it is adopted, then there is
> no reason not to allow compilers to specify the size of subtypes, undoing
> the ill effects of the last minute, incompletely executed, change.
> 
> A comment here is that MANY readers of Ada 95 assume that subtype specific
> attributes can be specified for subtypes. That seems a reasonable assumption
> and used to be a correct one, but is now surprisingly false. We have got a
> number of bug reports from people complaining that GNAT does not allow such
> specifications. We can of course explain that GNAT is right, but the
> principle of least suprise is definitely violated!
> 
> Incidentally, a major use for specifying subtype sizes is in building
> packed records. You just specify the size of each subtype, and then say
> pragma Pack, and everything packs together nicely without needing to
> write a (possibly non-portable) representation clause. Furthermore
> the representation clause here is clearly undesirable over-specification.
> You don't want to specify the exact layout, but you do want to control
> the nature of the packing. Yes there are other ways to do this, e.g.
> by using derived types, but they are messy by comparison.
> 
> The other major reason for specifying subtype sizes is in porting legacy
> code, where you want to confirm size choices made by a previous Ada 83
> compiler.
> 
> These requirements are strong enough that in GNAT we definitely intend to
> implement a feature for this purpose.
> 
> If TA is adopted, GNAT will introduce an attribute Subtype_Size that can
> be applied to arbitrary subtypes, and which will compromise static matching
> in some cases. This attribute is probably technically an extension because
> of this compromising effect, so we will put it under the non-pedantic (GNU'ese
> for extensions allowed) mode.

No, I don't think you need to play the "-pedantic" game.
Implementation-defined attributes can do whatever you like.
The only barrier is the wisdom and good taste of the compiler
writer.  ;-)

> If DA is adopted, GNAT will simply allow 'Size for subtypes.

No, *that's* not allowed.  Unless, of course, the ARG explicitly rules
that it *is* allowed.

> A note for Bob Duff
> -------------------
> 
> Yes, yes, all this applies to Alignment too. I can't get excited about
> alignments for subtypes. At least there is no analog to 13.3(55) requiring
> an injudicious choice of default alignments.

And of course for Alignment there's no issue of compatibility with
existing Ada 83 compilers.

We can decide what the right thing for Size is, and then simply rule
that Alignment works the same way, which I think is necessary.

> To be Honest
> ------------
> 
> There are a couple more glitches here
> 
> First, with respect to dynamic subtypes. We have to worry about dynamic
> subtypes, since they can statically match. For dynamic subtypes, if you
> want to be sure that access types to them are inter-convertible, then
> you have to read 13.1(14) as a requirement that the sizes of statically
> matching dynamic subtypes match. Note that there are no rules on the
> default sizes for dynamic subtypes. TA of course handles this fine, by
> changing the "are" in 13.1(14) to "shall".

No, that's not the correct wording for TA.  As I said before, the Static
Semantics *never* say "shall", they always say "are", and there's no
reason for this case to be any different.  But that's a wording issue.

> DA can't get very excited about this problem, and doesn't really care
> if convertability of such access types is impl dependent, but, if pressed,
> would be inclined to require that all dynamic subtypes have the size
> of the base type. This avoids differences between implementations, and
> is perfectly acceptable in practice.

Well, dynamic subtypes are probably fairly rare.  Nonetheless, I think
it is desirable to *allow* a compiler to deduce a smaller size than the
base SUBtype, for dynamic subtypes.

> Second, with respect to alignments, there is no clear statement that requires
> choice of alignments. TA would say that 13.1(14) places the requirement that
> if two subtypes statically match then the alignments should match. Again
> DA can't get excited, but if pressed would be inclined to say that the
> alignments of two subtypes of the same size should be identical.

I'm not sure what you mean by not getting excited, but clearly, if your
compiler doesn't obey this, then type conversions of access types simply
won't work.

> Original Intent
> ---------------
> 
> Arguments from original intent are somewhat bogus, since the RM does not
> contain its history.
> 
> One could say that the longer term intent was that Size should be able
> to be specified for subtypes, and that the language "subtype specific"
> still implies this -- a bogus argument for DA.
> 
> One could also say that the removal of this capability obviously means
> that 13.1(14) was considered sacrosanct -- a bogus argument for TA.

I agree that arguments about "intent" are often bogus.  The language
designer doesn't always have an accurate memory of intent.  Of course,
in many cases, there is evidence in the AARM about the intent.  In
*this* case, the intent was self contradictory -- the language designers
intended to support Size clauses on non-first subtypes, and also
intended that static matching for static subtypes work as it does, and
also intended that low-level mucking with rep clauses should not affect
the high-level pristine semantics of static matching.  Clearly, one
cannot achieve all of that "intent", so something's got to give.  At the
last minute, we chose to ditch size clauses on non-first subtypes.

> Conclusion
> ----------
> 
> There is a real disagreement here. Needs discussion!

Indeed.

- Bob

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

!section 13.1(14)
!subject Size attribute
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!from Bob Duff
!reference 96-5463.a Robert A Duff 96-4-11>>
!discussion

Here are some general comments on the Size issue.

First of all, in all these discussions, PLEASE make sure it's very clear
whether you're talking about a query of the Size attribute, or a Size
clause.  Numerous times, discussions on this issue have become mired in
confusion, because I said something about the query, when Robert thought
I was talking about the clause, or vice versa.

Also, please be sure to distinguish the Size of a subtype from the Size
of an object, and the corresponding clauses from each other.  The
semantics are rather different -- the Size of a subtypes is rather
flaky, whereas the Size of an object is pretty well defined.

One principle that most people seem to like is that a "confirming rep
clause" should not change things.  That is, if you have a program where
T'Size = 32 by default, and you add a rep clause, "for T'Size use 32;",
then the semantics of the new program should be identical.

For most rep clauses, in most situations, we have achieved this
principle.  However, there are some cases where the principle is
compromised.  In particular 13.3(50-52) says:

  50   If the Size of a subtype is specified, and allows for efficient
  independent addressability (see 9.10) on the target architecture, then the
  Size of the following objects of the subtype should equal the Size of the
  subtype:

     51  Aliased objects (including components).

     52  Unaliased components, unless the Size of the component is
         determined by a component_clause or Component_Size clause.

The phrase "If the Size of a subtype is specified" clearly violates the
principle that confirming rep clauses shouldn't change things.  The
principle is still a good principle -- we probably ought to at least try
to minimize the cases where it is compromised.

Note well para 51.  The Size of a stand-alone object matters to a
programmer if the programmer takes the Address of that object, and
passes that address off to some other language.  The address ought to be
pointing at a sequence of bytes of the expected size.  The reason para
51 says "aliased" is that 'Address is only well-defined in the case of
aliased objects, by 13.3(16):

   16  X'Address should produce a useful result if X is an object that
       is aliased or of a by-reference type, or is an entity whose
       Address has been specified.

Thus, if you say:

    X: Integer; -- not aliased
    ...X'Address ...

the compiler might put X in a register, and return a null address for
X'Address (or even raise an exception).

In thinking about Size, note that there can be subtypes whose range is
wider than the first subtype:

    type T is range 0..15; -- T'Size = 4
    subtype S is T'Base range -15..15; -- S'Size = 5

The above subtype S is guaranteed to be supported on all
implementations.  My point is that a rule requiring the size of all
subtypes to be the same as the first subtype just won't work.  For
example, even if you don't agree that T'Size should be 4 by default, one
could legally add "for T'Size use 4;" to the above -- certainly that was
legal in Ada 83, and it had better still be legal.  But that Size clause
clearly cannot mean T'Base'Size = 4, nor that S'Size = 4.

Robert and I seem to disagree on the desired semantics of packed
records.  This makes a difference to the Size clause issue, so I think
the ARG should explicitly consider what is desirable for packed records.
(I should note that one Ada 83 compiler doesn't support packed records
at all.  Robert is correct that it would be nice to be compatible with
that compiler, but if it conflicts with the way packed records have to
work, it's not suprising to me that this compatibility is impossible to
achieve).

Here's my view of packed records.  Assume a 32-bit machine with 8-bit
bytes.

    type My_Boolean is new Boolean; -- My_Boolean'Size = 1.
    type My_Other_Boolean is (No, Yes); -- My_Other_Boolean'Size = 1.
    subtype One_Bit_Int is Integer range 0..1; -- One_Bit_Int'Size = 1.

    type Inner_Record is
        record
            X: My_Boolean;
            Y: My_Other_Boolean;
            Z: One_Bit_Int;
        end record;
    pragma Pack(Inner_Record);
    
    type Twenty_Nine_Bits is range 0..2**29-1; -- Twenty_Nine_Bits'Size = 29.
    
    type Outer_Record is
        record
            Inner: Inner_Record;
            W: Twenty_Nine_Bits;
        end record;
    pragma Pack(Outer_Record);

To me, it seems highly desirable that the Size values shown above should
be chosen by default, and that Outer_Record should fit in a single
32-bit word, and that Outer_Record'Size should be 32.

My understanding is that 13.2(8) requires this:

    8  For a packed record type, the components should be packed as
       tightly as possible subject to the Sizes of the component
       subtypes, and subject to any record_representation_clause that
       applies to the type; the implementation may, but need not,
       reorder components or cross aligned word boundaries to improve
       the packing.  A component whose Size is greater than the word
       size may be allocated an integral number of words.

I believe Robert's view (please correct me if I'm wrong) is that the
programmer should have to write some Size clauses, in order to achieve
the above tight packing.  For example, the user would have to write:

    for One_Bit_Int'Size use 1;
    for Twenty_Nine_Bits'Size use 29;

I'm not sure if Robert's view also requires:

    for My_Boolean'Size use 1;
    for My_Other_Boolean'Size use 1;

in addition.  If so, that's pretty strange, because Boolean'Size = 1
(even though Boolean has no representation clause in Standard).  If not,
that's even stranger, since I would expect integers and enumerations to
behave the same way in this regard.

In any case, I don't see why the user should have to write Size clauses
to get reasonable packing.  That defeats the purpose of pragma Pack.  I
don't care to specify all kinds of details -- I just want the compiler
to choose a reasonably-packed representation.  (If I *did* care about
details, I would use a record_rep_clause instead.)

Certainly, in the Pascal compilers I've used, packed records are packed
according to the sub-ranges declared, without any need for Size clauses
(which is lucky, since Pascal doesn't have Size clauses).

Now, one could imagine that the record is packed like I want it, but the
'Size values are not as I indicated above.  I don't see how this can
work.  The very meaning of 'Size is that there are no objects smaller
than that (barring other overriding rep clauses).  Also, we don't want
to say that packing is different depending on whether the Size was
specified or chosen by default.

I think Robert's view is that requiring the Size clauses is desirable,
because then the desired packing won't silently change if you change the
bounds of Twenty_Nine_Bits, for example -- you'll either get the same
package, or you'll get an error message on the Size clause.  Obviously,
I don't agree that this is desirable.

- Bob

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

!section 13.1(14)
!subject Size attribute
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5463.a Robert A Duff 96-4-11
!from Keith Thompson 96-04-12
!reference 96-5466.a Keith Thompson 96-4-12>>
!discussion

Bob Duff writes:
> One principle that most people seem to like is that a "confirming rep
> clause" should not change things.  That is, if you have a program where
> T'Size = 32 by default, and you add a rep clause, "for T'Size use 32;",
> then the semantics of the new program should be identical.
> 
> For most rep clauses, in most situations, we have achieved this
> principle.  However, there are some cases where the principle is
> compromised.  In particular 13.3(50-52) says:
> 
>   50   If the Size of a subtype is specified, and allows for efficient
>   independent addressability (see 9.10) on the target architecture, then the
>   Size of the following objects of the subtype should equal the Size of the
>   subtype:
> 
>      51  Aliased objects (including components).
> 
>      52  Unaliased components, unless the Size of the component is
>          determined by a component_clause or Component_Size clause.
> 
> The phrase "If the Size of a subtype is specified" clearly violates the
> principle that confirming rep clauses shouldn't change things.  The
> principle is still a good principle -- we probably ought to at least try
> to minimize the cases where it is compromised.

In most cases, this doesn't necessarily violate the principle; at
worst, it's an incomplete statement.  Surely if the Size of a subtype,
*whether explicitly specified or not*, allows for efficient independent
addressability, aliased objects and unaliased components should have
the same Size as the subtype.

For example, if T'Size is 32 by default, aliased objects and unaliased
components should have a 'Size of 32 whether or not there's a confirming
size clause "for T'Size use 32".

The only case I can think of where there might be a conflict is for
a subtype that isn't a first subtype, like this:

    subtype Byte_Integer is Integer range -128 .. 127;
    -- Integer'Size = (say) 32, Byte_Integer'Size = 8
    Obj: aliased Byte_Integer;
    -- Obj'Size = 32?

In this case, it's reasonable for Obj'Size to be 32.  This doesn't
conflict with 13.3(50-52), but it does conflict with the interpretation
that it should apply whether or not the size is specified.

I hope I've at least narrowed down the conflicting cases.

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

!section 13.1(14)
!subject Size attribute
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5463.a Robert A Duff 96-4-11
!from Bob Duff
!reference 96-5467.a Robert A Duff 96-4-12>>
!discussion

Keith Thompson says:

> In most cases, this [13.3(50-52)] doesn't necessarily violate the
> principle; at worst, it's an incomplete statement.

Technically true.  However, consider the 80386.  You can load 8-bit and
32-bit quantities most efficiently, 16-bit quantities slightly less
efficiently.  3-bit quantities are out of the question, since they would
require extra locking code, but 16-bit quantities are efficient enough
to be called "efficient" -- at least that was *my* intent.

So, if you write:

    type T1 is range 0..2**16-1; -- T1'Size = 16
    X1: T1; -- X1'Size = 32

    type T2 is range 0..2**16-1; -- T2'Size = 16
    for T2'Size use 16;
    X2: T2; -- X2'Size = 16

This is certainly an allowed implementation, and it seems to me a
desirable implementation.  It violates the principle, since T1'Size and
T2'Size are both 16, but the meaning of their Size is different, since
one is "16 by default" and the other is "specified as 16".

Here's another "principle", which I'm not sure anybody else agrees with,
but it makes sense to me: If you don't give any rep clauses, then the
compiler ought to do what's most efficient.  If you care about
representation more than (the compiler's notion of) efficiency, then
give a rep clause.  "Predictable representations" is not a goal, if
there are no rep clauses.

- Bob

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

!section 13.1(14)
!subject Size attribute
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5463.a Robert A Duff 96-4-11
!from Bob Duff
!reference 96-5468.a Robert A Duff 96-4-12>>
!discussion

Oops.  In the message I just sent, I forgot to put "aliased".  Sorry.
Here's a correction:

Keith Thompson says:

> In most cases, this [13.3(50-52)] doesn't necessarily violate the
> principle; at worst, it's an incomplete statement.

Technically true.  However, consider the 80386.  You can load 8-bit and
32-bit quantities most efficiently, 16-bit quantities slightly less
efficiently.  3-bit quantities are out of the question, since they would
require extra locking code, but 16-bit quantities are efficient enough
to be called "efficient" -- at least that was *my* intent.

So, if you write:

    type T1 is range 0..2**16-1; -- T1'Size = 16
    X1: aliased T1; -- X1'Size = 32

    type T2 is range 0..2**16-1; -- T2'Size = 16
    for T2'Size use 16;
    X2: aliased T2; -- X2'Size = 16

This is certainly an allowed implementation, and it seems to me a
desirable implementation.  It violates the principle, since T1'Size and
T2'Size are both 16, but the meaning of their Size is different, since
one is "16 by default" and the other is "specified as 16".

Here's another "principle", which I'm not sure anybody else agrees with,
but it makes sense to me: If you don't give any rep clauses, then the
compiler ought to do what's most efficient.  If you care about
representation more than (the compiler's notion of) efficiency, then
give a rep clause.  "Predictable representations" is not a goal, if
there are no rep clauses.

- Bob

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!from Robert Dewar
!reference 96-5486.a Robert A Duff 96-4-13>>
!discussion

(Apparently, Robert has less patience than I do, with the silly headers
required by the mail server.  And I have very little patience indeed --
I had to submit some of my recent comments 3 times.  Anyway, I'll be a
nice guy, and re-submit this for Robert. -- Bob Duff)

Here's Robert's comment:

let me narrow down my size comments to a set of requirements


(which are possibly conflicting)

o  it should be possible to write confirming rep clauses for all 
        representation choices made by the compiler

o  the sizes chosen by an Ada 95 compiler should match those of an Ada 83
        compiler

o  (most important). If the second rule is not met, it should be possible
        to write rep clauses that cuase the choice to match that of the
        Ada 83 compiler.

I never liked what was going on with size in RM 95 as you now, but did not
mind too much as long as 'size could be specified for a subtype as was
the case till very late on.

It is taking that away that has left RM 95 completely broken with respect
to the critical third requirement above.

It is merely annoying that the size rules are peculiar, and reflect not
the best approximation of industry pratice in Ada 83, but rathr the
behavior of one particular vendors compiler that was in fact not a
significant presence in the market.

It is much MORE than annoying that there is no easy way to override this
choice.

At the Paris meeting, we considered it essential that a size clause for
a first subtype be imposed on all subsequent subtypes, because otherwise
confirming rep clauses would be impossible.

Ada 95 broke that (why I don't know), but I could live with it because
I could specify size for a subtype.

At this stage I would like to see:

  o  THat compilers be allowed to specify 'size for other than first
     subtypes, but not required to do so.

  o  That we simply add to the rules for statically matching subtypes
     a rule that says that if the sizes are explicitly set and different
     then the subtypes do not statically match.

I don't care too much if you keep the bizarre rule about sizes happening
to be different if the subtype happens to statically match the first subtype,
as long as I can override it.

In fact I don't too much care WHAT is done, since it is only a matter of
aesthetics, not functionality. If the ARG does not solve this question,
e.g. in the manner suggested above, then GNAT will simply implement
'Subtype_Size and solve the problem itself.

This is not a theoretical issue, we are currently not following the RM
rules, because we know they will break customer code in a manner that
is not easy to provide work arounds for (note in particular that there
is no way to easily specify the size of a record component).

P.S. I would in fact be inclined to keep the current RM rules about
minimum size, consider the following:

  type x is (a,b,c);

in Verdix x'size is 8 or somesuch, BUT Verdix allowed pragma Pack to 
go ahead and pack to 2 bits anyway. This is inconsistent with the Paris
meeting AI's and with the RM, but in practice, the packing is more
important than the size, so the RM rules are most practical. 


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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!from Bob Duff
!reference 96-5487.a Robert A Duff 96-4-13>>
!discussion

> let me narrow down my size comments to a set of requirements
> 
> 
> (which are possibly conflicting)
> 
> o  it should be possible to write confirming rep clauses for all 
>       representation choices made by the compiler

Good principle, usually, but we know we've violated it in *some* cases.
There are two issues:

    1. There are a few (minor) cases in which specifying a certain aspect
       of representation to a certain value means something different than
       having an implementation choose that same value by default.  This
       is bad, and we've minimized it to just a few cases.

    2. There are many cases in which no rep clause is legal, and therefore
       no confirming rep clause is legal.  For example, rep clauses
       usually require static-ish things, even though dynamic things
       can be queried.

There are really two possible priniciples -- confirming rep clauses,
when legal, should not change semantics, and confirming rep clauses
should always be legal, and should not change semantics.  The second of
these was never even close to true for Ada 83, so perhaps it should be
modified: confirming rep clauses should be legal for the cases that come
up in practise when interfacing, and should not change semantics.

> o  the sizes chosen by an Ada 95 compiler should match those of an Ada 83
>       compiler
> 
> o  (most important). If the second rule is not met, it should be possible
>       to write rep clauses that cuase the choice to match that of the
>       Ada 83 compiler.
> 
> I never liked what was going on with size in RM 95 as you now, but did not
> mind too much as long as 'size could be specified for a subtype as was
> the case till very late on.
> 
> It is taking that away that has left RM 95 completely broken with respect
> to the critical third requirement above.
> 
> It is merely annoying that the size rules are peculiar, and reflect not
> the best approximation of industry pratice in Ada 83, but rathr the
> behavior of one particular vendors compiler that was in fact not a
> significant presence in the market.

It was the goal of the Ada 95 rules to nail some things down that were
vague in Ada 83, so that rep clauses could be more portable across (Ada
95) implementations.  In doing that, it may well be that we've broken
compatibility with existing Ada 83 implementations.  We could solve this
problem by going back to the Ada 83 rule, which I paraphrase here: "The
Size attribute means whatever the implementation wants it to, and it's
relationship with Unchecked_Conversion, 'Address, and pragma Pack is up
to the implementation."  I'm being somewhat facetious here -- Robert's
point is that most implementations agreed with each other, and RM95
chooses an interpretation that was only chosen by some obscure Ada 83
implementation.  I'd like to hear some input from compiler vendors here
-- what did your Ada 83 implementations do, and what do think your Ada
95 implementations ought to do?

> It is much MORE than annoying that there is no easy way to override this
> choice.

You can override the choice on a per-object and per-component basis, and
that has a pretty well-defined meaning.  I admit that it's annoying that
you can't do so on a subtype basis.  The MRT removed that feature for
technical reasons.  We could decide to add it back in, I suppose, but
(1) it's a pretty big extension to be adding under the heading
"interpretations", and (2) we need to find a technically correct way to
do it.  If we choose to do so, I think we *can* find a technically
correct way, independent of how the contradiction between 13.1(14) and
13.3(55) is broken.

> At the Paris meeting, we considered it essential that a size clause for
> a first subtype be imposed on all subsequent subtypes, because otherwise
> confirming rep clauses would be impossible.

Unfortunately, Ada 95 allows:

    type T is range 0..1;
    for T'Size use 1;
    subtype S is range -1..1;

Clearly, we cannot require that S'Size be 1.

I suppose we could require it for subtypes whose range happens to be
small enough.

No, that won't work, either, because the range might not be known at
compile time.  I guess the rule would have to say something about
staticness.  Or, we could make it all implementation-defined, and let
implementations worry about how to be compatible with (various) Ada 83
compilers.

> Ada 95 broke that (why I don't know), but I could live with it because
> I could specify size for a subtype.
> 
> At this stage I would like to see:
> 
>   o  THat compilers be allowed to specify 'size for other than first
>      subtypes, but not required to do so.

Sounds like an extension to me, and not important enough for the ARG to
bless.  But I could live with it.  If we do it, should we not make some
sense of the rules?  Or do you expect implementations to deal with it?
I fear that compilers will simply generate incorrect code for
conversions of access types (see 13.1(14.a-14.i).  I would prefer to
either require it or disallow it, rather than allow it.  If we require
it, of course, we have to make some sense of it.

>   o  That we simply add to the rules for statically matching subtypes
>      a rule that says that if the sizes are explicitly set and different
>      then the subtypes do not statically match.

This can work.  But note that it violates the first principle above,
that confirming rep clauses should work.

> I don't care too much if you keep the bizarre rule about sizes happening
> to be different if the subtype happens to statically match the first subtype,
> as long as I can override it.
> 
> In fact I don't too much care WHAT is done, since it is only a matter of
> aesthetics, not functionality. If the ARG does not solve this question,
> e.g. in the manner suggested above, then GNAT will simply implement
> 'Subtype_Size and solve the problem itself.
> 
> This is not a theoretical issue, we are currently not following the RM
> rules, because we know they will break customer code in a manner that
> is not easy to provide work arounds for (note in particular that there
> is no way to easily specify the size of a record component).

Unfortunate, indeed.

> P.S. I would in fact be inclined to keep the current RM rules about
> minimum size, consider the following:
> 
>   type x is (a,b,c);
> 
> in Verdix x'size is 8 or somesuch, BUT Verdix allowed pragma Pack to 
> go ahead and pack to 2 bits anyway. This is inconsistent with the Paris
> meeting AI's and with the RM, but in practice, the packing is more
> important than the size, so the RM rules are most practical. 

OK, good, we agree on *some* things.  ;-)

Now, don't you think "type X is range 0..2;" is equivalent to the above,
at the machine level, and should work the same way with respect to
'Size?

- Bob

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Robert A Duff 96-4-13
!from Bob Duff
!reference 96-5494.a Robert A Duff 96-4-16>>
!discussion

Another correction.  Robert Dewar wrote:

> > At the Paris meeting, we considered it essential that a size clause for
> > a first subtype be imposed on all subsequent subtypes, because otherwise
> > confirming rep clauses would be impossible.

And I replied:

> Unfortunately, Ada 95 allows:
> 
>     type T is range 0..1;
>     for T'Size use 1;
>     subtype S is range -1..1;

I meant "subtype S is T'Base range -1..1;".  My point was that S has a
                      ^^^^^^
wider range than the first subtype, so:

> Clearly, we cannot require that S'Size be 1.
> 
> I suppose we could require it for subtypes whose range happens to be
> small enough.
> 
> No, that won't work, either, because the range might not be known at
> compile time.  I guess the rule would have to say something about
> staticness.  Or, we could make it all implementation-defined, and let
> implementations worry about how to be compatible with (various) Ada 83
> compilers.

Sorry for the confusion.

- Bob

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Robert A Duff 96-4-13
!from Bob Duff
!reference 96-5495.a Robert A Duff 96-4-16>>
!discussion

Robert and I have discussed the Size issue in private e-mail lately.
(It's a hobby we have, which has taken up most of our spare time in the
last few years.  ;-) )

Anyway, Robert recommends the following (I'm paraphrasing what he wrote):

  Keep the RM rules (13.3(55)) as they are with respect to default
  sizes.  Add a rule that the minimum size default rule does not apply
  to subtypes that happen to statically match the first subtype.

  Implementation Permission: *Allow* implementations to support Size
  clauses for secondary subtypes.

  Say that two subtypes do not statically match if their Sizes differ
  (this can be interesting only if one or other of them is a subtype whose
  Size has been set using the above permission).

I can live with Robert's recommendations.  I won't go *quite* so far as
to say I *agree* with them -- I don't strongly disagree.  ;-)  How's that
for wishy-washy?

Robert notes that if the above Implementation Permission is not granted
by the ARG, then GNAT will implement essentially the same thing, but
call it by a different name ('Subtype_Size).  This is important, because
when porting real Ada 83 code to GNAT, such a feature has been needed.

Robert says: P.S. I do not care two hoots about Alignment, I think
having Alignment as a subtype specific attribute is silly, and GNAT
ignores the possibility of different subtypes having different
alignments as much as it can!

Bob says: I agree -- it's not important.  For uniformity, we could
extend the Impl Permission to Alignment, too.  No big deal.  The only
important thing, is that if Alignments of subtypes can be different, we
can't have static matching of those subtypes.  Alignments are largely
implementation dependent anyway, so this is, I suppose, the
implementer's problem.

- Bob

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Robert A Duff 96-4-13
!reference 96-5495.a Robert A Duff 96-4-16
!from Bob Duff 96-4-17
!reference 96-5498.a Pascal Leroy 96-4-17>>
!discussion

I suppose we'll have an interesting discussion at the next ARG meeting,
assuming RBKD is there.  I, for one, strongly disagree with the suggestions
below, and agree with (the current wording of) AI95-00109

> Anyway, Robert recommends the following (I'm paraphrasing what he wrote):
>
>   Keep the RM rules (13.3(55)) as they are with respect to default
>   sizes.  Add a rule that the minimum size default rule does not apply
>   to subtypes that happen to statically match the first subtype.
>
>   Implementation Permission: *Allow* implementations to support Size
>   clauses for secondary subtypes.

I don't see what is gained by this.  Certainly not portability, since we don't
_require_ support for such clauses.  The only reason for this permission is
that it makes it more likely that, if vendors want to support this capability,
they'll use the same mechanism.  But then we have to assume that vendors are
not completely stupid: if GNAT for instance supports a 'Subtype_Size
attribute, and there appears to be good reasons for other vendors to support
the same capability then it would be sensible for them to use the attribute
'Subtype_Size.  There are many uniformity issues like that, and we don't have
to incorporate them in the language: we can just assume that reasonable
choices will be made.

I suspect that if we put this permission in the language, we'll spend the next
five years explaining how all the rest of the RM works in the presence of a
size clause for subtypes.

>   Say that two subtypes do not statically match if their Sizes differ
>   (this can be interesting only if one or other of them is a subtype whose
>   Size has been set using the above permission).

Now that violates the separation principle (grab your Ada 83 Rationale and
read section 15.1 to refresh your memory) and I think it's BAD, and that the
language is insufficiently broken here to abandon the separation between the
logical properties and the representation.

> Robert notes that if the above Implementation Permission is not granted
> by the ARG, then GNAT will implement essentially the same thing, but
> call it by a different name ('Subtype_Size).  This is important, because
> when porting real Ada 83 code to GNAT, such a feature has been needed.

I would be curious to see an example of such real Ada 83 code that absolutely
requires 'Size clauses for subtype.  So far, no convincing example has been
shown: Robert's Number_Of_Hotels and Number_Of_Companies stuff looked more
like an example of how to misuse subtypes.

_____________________________________________________________________
Pascal Leroy                                    +33.1.30.12.09.68
pleroy@rational.com                             +33.1.30.12.09.66 FAX

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

!section 13.3(55)
!subject Size program
!reference RM95-13.3(55)
!reference 96-5497.a Robert A Duff 96-4-17
!from Bob Duff
!reference 96-5499.a Robert A Duff 96-4-19>>
!discussion

Robert Dewar and Pascal Leroy noted some bugs in the program.  Plus I
noticed a couple myself.  Here's another version, with some bugs fixed.

Sorry.  :-(

Send the results directly to me, and once we've gotten things settled,
I'll post to ada-comment.

- Bob

with System; use System;
package Size_Test_Utils is

   procedure Put_Line(S: String);
   -- Print a line with line number.

   procedure Heading(S: String);
   -- Print a heading with blank lines around it.

   type Size_In_Bits is range 0..Max_Int;
   function Img(X: Size_In_Bits) return String;
   -- Shorthand for Size_In_Bits'Image.

   procedure Check(Subtype_Name: String;
                   Subtype_Size: Size_In_Bits;
                   Expected_Size: Size_In_Bits);
   -- Prints out the subtype's Size.  If Subtype_Size /= Expected_Size,
   -- notes that fact.

   procedure Check(Subtype_Name: String;
                   Subtype_Size: Size_In_Bits);
   -- Same as previous, but used when there's no particular expected size.

   -- The following functions are the same as the corresponding
   -- procedures.  They return an irrelevant value.  The purpose
   -- is to be able to call those procedures in a declaration
   -- context.
   function Heading(S: String) return Boolean;
   function Check(Subtype_Name: String;
                  Subtype_Size: Size_In_Bits;
                  Expected_Size: Size_In_Bits) return Boolean;
   function Check(Subtype_Name: String;
                  Subtype_Size: Size_In_Bits) return Boolean;

   type Longest_Signed_Integer is range Min_Int..Max_Int;

end Size_Test_Utils;
with Text_IO; use Text_IO;
package body Size_Test_Utils is

   procedure Put_Line_Number is
   begin
      if Col /= 1 then
         raise Program_Error;
      end if;
      Put(Positive_Count'Image(Line));
      Set_Col(8);
   end Put_Line_Number;

   procedure Put_Line(S: String) is
   begin
      Put_Line_Number;
      Text_Io.Put_Line(S);
   end Put_Line;

   procedure Heading(S: String) is
   begin
      New_Line;
      Set_Col(8);
      Text_Io.Put_Line(S);
      New_Line;
   end Heading;

   function Heading(S: String) return Boolean is
   begin
      Heading(S);
      return True;
   end Heading;

   function Img(X: Size_In_Bits) return String is
   begin
      return Size_In_Bits'Image(X);
   end Img;

   procedure Check(Subtype_Name: String;
                   Subtype_Size: Size_In_Bits;
                   Expected_Size: Size_In_Bits) is
   begin
      Put_Line_Number;
      Put(Subtype_Name & "'Size =" & Img(Subtype_Size));
      if Subtype_Size = Expected_Size then
         Put(" (ok)");
      else
         Put(" (expected" & Img(Expected_Size) & ")");
      end if;
      Text_IO.Put_Line(".");
   end Check;

   procedure Check(Subtype_Name: String;
                   Subtype_Size: Size_In_Bits) is
   begin
      Put_Line_Number;
      Put(Subtype_Name & "'Size =" & Img(Subtype_Size));
      Text_IO.Put_Line(".");
   end Check;

   function Check(Subtype_Name: String;
                  Subtype_Size: Size_In_Bits;
                  Expected_Size: Size_In_Bits) return Boolean is
   begin
      Check(Subtype_Name, Subtype_Size, Expected_Size);
      return True;
   end Check;

   function Check(Subtype_Name: String;
                  Subtype_Size: Size_In_Bits) return Boolean is
   begin
      Check(Subtype_Name, Subtype_Size);
      return True;
   end Check;

end Size_Test_Utils;
with Size_Test_Utils; use Size_Test_Utils;
pragma Elaborate(Size_Test_Utils);
package Size_Test_83_Pkg is

   -- This package prints out the 'Size of various subtypes.
   -- Ada-95-specific code is avoided here.
   -- The "..._Test" variables are ignored -- they're just there so we
   -- can call Check in a declaration context.

   package Signed_Integers is

      H1: Boolean := Heading("Signed Integers:");

      type Positive_0 is range 0..0;
      Positive_0_Test: Boolean :=
        Check("Positive_0", Positive_0'Size, 0);

      Positive_0_Base_Test: Boolean :=
        Check("Positive_0'Base", Positive_0'Base'Size);

      type Positive_1 is range 0..1;
      Positive_1_Test: Boolean :=
        Check("Positive_1", Positive_1'Size, 1);

      Positive_1_Base_Test: Boolean :=
        Check("Positive_1'Base", Positive_1'Base'Size);

      type Positive_2 is range 0..2;
      Positive_2_Test: Boolean :=
        Check("Positive_2", Positive_2'Size, 2);

      Positive_2_Base_Test: Boolean :=
        Check("Positive_2'Base", Positive_2'Base'Size);

      type Integer_3 is range -2..2;
      Integer_3_Test: Boolean :=
        Check("Integer_3", Integer_3'Size, 3);

      Integer_3_Base_Test: Boolean :=
        Check("Integer_3'Base", Integer_3'Base'Size);

      type Billion is range -1_000_000_000 .. 1_000_000_000;

      subtype Sub_Pos_0 is Billion range 0..0;
      Sub_Pos_0_Test: Boolean :=
        Check("Sub_Pos_0", Sub_Pos_0'Size, 0);
      subtype Sub_Pos_1 is Billion range 0..1;
      Sub_Pos_1_Test: Boolean :=
        Check("Sub_Pos_1", Sub_Pos_1'Size, 1);
      subtype Sub_Pos_4 is Billion range 0..15;
      Sub_Pos_4_Test: Boolean :=
        Check("Sub_Pos_4", Sub_Pos_4'Size, 4);
      subtype Sub_Int_7 is Billion range -63..63;
      Sub_Int_7_Test: Boolean :=
        Check("Sub_Int_7", Sub_Int_7'Size, 7);

   end Signed_Integers;
   use Signed_Integers;

   package Enums is

      H1: Boolean := Heading("Enums:");

      type Enum_0 is (Red);
      Enum_0_Test: Boolean :=
        Check("Enum_0", Enum_0'Size, 0);

      Enum_0_Base_Test: Boolean :=
        Check("Enum_0'Base", Enum_0'Base'Size, 0);

      type Enum_1 is (Red, Orange);
      Enum_1_Test: Boolean :=
        Check("Enum_1", Enum_1'Size, 1);

      Enum_1_Base_Test: Boolean :=
        Check("Enum_1'Base", Enum_1'Base'Size, 1);

      type Enum_2 is (Red, Orange, Yellow);
      Enum_2_Test: Boolean :=
        Check("Enum_2", Enum_2'Size, 2);

      Enum_2_Base_Test: Boolean :=
        Check("Enum_2'Base", Enum_2'Base'Size, 2);

      type Enum_4 is ('0', '1', '2', '3', '4', '5', '6', '7', '8',
                      '9', Ten, Eleven, Twelve);
      Enum_4_Test: Boolean :=
        Check("Enum_4", Enum_4'Size, 4);

      Enum_4_Base_Test: Boolean :=
        Check("Enum_4'Base", Enum_4'Base'Size, 4);

      subtype Sub_Enum_0 is Enum_4 range '0'..'0';
      Sub_Enum_0_Test: Boolean :=
        Check("Sub_Enum_0", Sub_Enum_0'Size, 0);
      subtype Sub_Enum_1 is Enum_4 range '0'..'1';
      Sub_Enum_1_Test: Boolean :=
        Check("Sub_Enum_1", Sub_Enum_1'Size, 1);

   end Enums;
   use Enums;

   package Records is

      H1: Boolean := Heading("Records:");

      type Unpacked_Rec is
         record
            A: Positive_2;
            B: Sub_Enum_1;
         end record;
      Unpacked_Rec_Test: Boolean :=
        Check("Unpacked_Rec", Unpacked_Rec'Size);

      type Rec_3 is new Unpacked_Rec;
      pragma Pack(Rec_3);
      Rec_3_Test: Boolean :=
        Check("Rec_3", Rec_3'Size, 3);

      Rec_3_Obj: Rec_3;
      A_Test: Boolean :=
        Check("Rec_3_Obj.A", Rec_3_Obj.A'Size, 2);
      B_Test: Boolean :=
        Check("Rec_3_Obj.B", Rec_3_Obj.B'Size, 1);

      type Rec_10 is
         record
            B1, B2, B3, B4, B5, B6, B7, B8, B9, B10: Boolean;
         end record;
      pragma Pack(Rec_10);
      Rec_10_Test: Boolean :=
        Check("Rec_10", Rec_10'Size, 10);

      Rec_10_Obj: Rec_10;
      B1_Test: Boolean :=
        Check("Rec_10_Obj.B1", Rec_10_Obj.B1'Size, 1);

      type Rec_32 is
         record
            X1, X2, X3: Rec_3;
            X4, X5: Integer_3;
            Two_Bits: Enum_2;
            Ten_Bits: Rec_10;
         end record;
      pragma Pack(Rec_32);
      Rec_32_Test: Boolean :=
        Check("Rec_32", Rec_32'Size, 32);

      Rec_32_Obj: Rec_32;
      X2_Test: Boolean :=
        Check("Rec_32_Obj.X2", Rec_32_Obj.X2'Size, 3);
      X5_Test: Boolean :=
        Check("Rec_32_Obj.X5", Rec_32_Obj.X5'Size, 3);

   end Records;

private

   procedure Require_Body;

end Size_Test_83_Pkg;
with System; use System;

package body Size_Test_83_Pkg is

   package Predefined_Stuff is end;
   package body Predefined_Stuff is
   begin

      Heading("Predefined Stuff:");

      Put_Line("Min_Int = " & Longest_Signed_Integer'Image(Min_Int));
      Put_Line("Max_Int = " & Longest_Signed_Integer'Image(Max_Int));
      Check("Longest_Signed_Integer", Longest_Signed_Integer'Size);

      Put_Line("Storage_Unit = " & Longest_Signed_Integer'Image(Storage_Unit));
      Check("Address", Address'Size);

      Put_Line("Boolean'First = " & Boolean'Image(Boolean'First) & ".");
      Put_Line("Boolean'Last = " & Boolean'Image(Boolean'Last) & ".");
      Check("Boolean", Boolean'Size, 1);

      Put_Line("Integer'First = " & Integer'Image(Integer'First) & ".");
      Put_Line("Integer'Last = " & Integer'Image(Integer'Last) & ".");
      Check("Integer", Integer'Size);

      Put_Line("Natural'First = " & Natural'Image(Natural'First) & ".");
      Put_Line("Natural'Last = " & Natural'Image(Natural'Last) & ".");
      Check("Natural", Natural'Size);

      Put_Line("Positive'First = " & Positive'Image(Positive'First) & ".");
      Put_Line("Positive'Last = " & Positive'Image(Positive'Last) & ".");
      Check("Positive", Positive'Size);

      Put_Line("Character'First = " & Character'Image(Character'First) & ".");
      Put_Line("Character'Last = " & Character'Image(Character'Last) & ".");
      Check("Character", Character'Size, 8);
   end Predefined_Stuff;

   procedure Require_Body is
   begin
      null;
   end Require_Body;

end Size_Test_83_Pkg;
with Size_Test_Utils; use Size_Test_Utils;
with Size_Test_83_Pkg; use Size_Test_83_Pkg;

pragma Elaborate(Size_Test_Utils);
pragma Elaborate(Size_Test_83_Pkg);

package Size_Clause_83_Pkg is

   -- Same as Size_Test_83_Pkg, except this package concentrates on cases
   -- where the Size is specified in an attribute_definition_clause.
   -- Each subtype Foo_Spec corresponds to subtype Foo from
   -- Size_Test_83_Pkg.  The declaration of Foo_Spec and Foo are
   -- the same, except that Foo_Spec has a Size clause.

   use Size_Test_83_Pkg.Signed_Integers;
   use Size_Test_83_Pkg.Enums;
   use Size_Test_83_Pkg.Records;

   package Signed_Integers is

      H1: Boolean := Heading("Signed Integers with Size Clauses:");

      type Positive_0_Spec is range 0..0;
      for Positive_0_Spec'Size use 0;
      Positive_0_Spec_Test: Boolean :=
        Check("Positive_0_Spec", Positive_0_Spec'Size, 0);

      Positive_0_Spec_Base_Test: Boolean :=
        Check("Positive_0_Spec'Base", Positive_0_Spec'Base'Size);

      type Positive_1_Spec is range 0..1;
      for Positive_1_Spec'Size use 1;
      Positive_1_Spec_Test: Boolean :=
        Check("Positive_1_Spec", Positive_1_Spec'Size, 1);

      Positive_1_Spec_Base_Test: Boolean :=
        Check("Positive_1_Spec'Base", Positive_1_Spec'Base'Size);

      type Positive_2_Spec is range 0..2;
      for Positive_2_Spec'Size use 2;
      Positive_2_Spec_Test: Boolean :=
        Check("Positive_2_Spec", Positive_2_Spec'Size, 2);

      Positive_2_Spec_Base_Test: Boolean :=
        Check("Positive_2_Spec'Base", Positive_2_Spec'Base'Size);

      type Integer_3_Spec is range -2..2;
      for Integer_3_Spec'Size use 3;
      Integer_3_Spec_Test: Boolean :=
        Check("Integer_3_Spec", Integer_3_Spec'Size, 3);

      Integer_3_Spec_Base_Test: Boolean :=
        Check("Integer_3_Spec'Base", Integer_3_Spec'Base'Size);

      type Billion_Spec is range -1_000_000_000 .. 1_000_000_000;
      for Billion_Spec'Size use 31;
      Billion_Spec_Test: Boolean :=
        Check("Billion_Spec", Billion_Spec'Size, 31);

      subtype Sub_Pos_0_Spec is Billion_Spec range 0..0;
      Sub_Pos_0_Spec_Test: Boolean :=
        Check("Sub_Pos_0_Spec", Sub_Pos_0_Spec'Size, 0);
      subtype Sub_Pos_1_Spec is Billion_Spec range 0..1;
      Sub_Pos_1_Spec_Test: Boolean :=
        Check("Sub_Pos_1_Spec", Sub_Pos_1_Spec'Size, 1);
      subtype Sub_Pos_4_Spec is Billion_Spec range 0..15;
      Sub_Pos_4_Spec_Test: Boolean :=
        Check("Sub_Pos_4_Spec", Sub_Pos_4_Spec'Size, 4);
      subtype Sub_Int_7_Spec is Billion_Spec range -63..63;
      Sub_Int_7_Spec_Test: Boolean :=
        Check("Sub_Int_7_Spec", Sub_Int_7_Spec'Size, 7);

   end Signed_Integers;
   use Signed_Integers;

   package Enums is

      H1: Boolean := Heading("Enums with Size Clauses:");

      type Enum_0_Spec is (Red);
      for Enum_0_Spec'Size use 0;
      Enum_0_Spec_Test: Boolean :=
        Check("Enum_0_Spec", Enum_0_Spec'Size, 0);

      Enum_0_Spec_Base_Test: Boolean :=
        Check("Enum_0_Spec'Base", Enum_0_Spec'Base'Size, 0);

      type Enum_1_Spec is (Red, Orange);
      for Enum_1_Spec'Size use 1;
      Enum_1_Spec_Test: Boolean :=
        Check("Enum_1_Spec", Enum_1_Spec'Size, 1);

      Enum_1_Spec_Base_Test: Boolean :=
        Check("Enum_1_Spec'Base", Enum_1_Spec'Base'Size, 1);

      type Enum_2_Spec is (Red, Orange, Yellow);
      for Enum_2_Spec'Size use 2;
      Enum_2_Spec_Test: Boolean :=
        Check("Enum_2_Spec", Enum_2_Spec'Size, 2);

      Enum_2_Spec_Base_Test: Boolean :=
        Check("Enum_2_Spec'Base", Enum_2_Spec'Base'Size, 2);

      type Enum_4_Spec is ('0', '1', '2', '3', '4', '5', '6', '7', '8',
                      '9', Ten, Eleven, Twelve);
         for Enum_4_Spec'Size use 4;
      Enum_4_Spec_Test: Boolean :=
        Check("Enum_4_Spec", Enum_4_Spec'Size, 4);

      Enum_4_Spec_Base_Test: Boolean :=
        Check("Enum_4_Spec'Base", Enum_4_Spec'Base'Size, 4);

      subtype Sub_Enum_0_Spec is Enum_4_Spec range '0'..'0';
      Sub_Enum_0_Spec_Test: Boolean :=
        Check("Sub_Enum_0_Spec", Sub_Enum_0_Spec'Size, 0);
      subtype Sub_Enum_1_Spec is Enum_4_Spec range '0'..'1';
      Sub_Enum_1_Spec_Test: Boolean :=
        Check("Sub_Enum_1_Spec", Sub_Enum_1_Spec'Size, 1);

      type Six_Bit_Enum_4_Spec is ('0', '1', '2', '3', '4', '5', '6', '7', '8',
                                '9', Ten, Eleven, Twelve);
         for Six_Bit_Enum_4_Spec'Size use 6; -- Non-default Size
      Six_Bit_Enum_4_Spec_Test: Boolean :=
        Check("Six_Bit_Enum_4_Spec", Six_Bit_Enum_4_Spec'Size, 6);

      Six_Bit_Enum_4_Spec_Base_Test: Boolean :=
        Check("Six_Bit_Enum_4_Spec'Base", Six_Bit_Enum_4_Spec'Base'Size, 6);

      subtype Sub_Six_Bit_Enum_0_Spec is Six_Bit_Enum_4_Spec range '0'..'0';
      Sub_Six_Bit_Enum_0_Spec_Test: Boolean :=
        Check("Sub_Six_Bit_Enum_0_Spec", Sub_Six_Bit_Enum_0_Spec'Size, 0);
      subtype Sub_Six_Bit_Enum_1_Spec is Six_Bit_Enum_4_Spec range '0'..'1';
      Sub_Six_Bit_Enum_1_Spec_Test: Boolean :=
        Check("Sub_Six_Bit_Enum_1_Spec", Sub_Six_Bit_Enum_1_Spec'Size, 1);

      subtype Sub_Six_Bit_Enum_6_Spec is Six_Bit_Enum_4_Spec range '0'..Twelve;
      Sub_Six_Bit_Enum_6_Spec_Test: Boolean :=
        Check("Sub_Six_Bit_Enum_6_Spec", Sub_Six_Bit_Enum_6_Spec'Size, 6);

   end Enums;
   use Enums;

   package Records is

      H1: Boolean := Heading("Records with Size Clauses:");

      type Unpacked_Rec_Spec is
         record
            A: Positive_2_Spec;
            B: Sub_Enum_1_Spec;
         end record;
      Unpacked_Rec_Spec_Test: Boolean :=
        Check("Unpacked_Rec_Spec", Unpacked_Rec'Size);

      type Rec_3_Spec is new Unpacked_Rec_Spec;
      pragma Pack(Rec_3_Spec);
      for Rec_3_Spec'Size use 3;
      Rec_3_Spec_Test: Boolean :=
        Check("Rec_3_Spec", Rec_3_Spec'Size, 3);

      Rec_3_Spec_Obj: Rec_3_Spec;
      A_Test: Boolean :=
        Check("Rec_3_Spec_Obj.A", Rec_3_Spec_Obj.A'Size, 2);
      B_Test: Boolean :=
        Check("Rec_3_Spec_Obj.B", Rec_3_Spec_Obj.B'Size, 1);

      type Rec_10_Spec is
         record
            B1, B2, B3, B4, B5, B6, B7, B8, B9, B10: Boolean;
         end record;
      pragma Pack(Rec_10_Spec);
      for Rec_10_Spec'Size use 10;
      Rec_10_Spec_Test: Boolean :=
        Check("Rec_10_Spec", Rec_10_Spec'Size, 10);

      Rec_10_Spec_Obj: Rec_10_Spec;
      B1_Test: Boolean :=
        Check("Rec_10_Spec_Obj.B1", Rec_10_Spec_Obj.B1'Size, 1);

      type Rec_32_Spec is
         record
            X1, X2, X3: Rec_3_Spec;
            X4, X5: Integer_3_Spec;
            Two_Bits: Enum_2_Spec;
            Ten_Bits: Rec_10_Spec;
         end record;
      pragma Pack(Rec_32_Spec);
      for Rec_32_Spec'Size use 32;
      Rec_32_Spec_Test: Boolean :=
        Check("Rec_32_Spec", Rec_32_Spec'Size, 32);

      Rec_32_Spec_Obj: Rec_32_Spec;
      X2_Test: Boolean :=
        Check("Rec_32_Spec_Obj.X2", Rec_32_Spec_Obj.X2'Size, 3);
      X5_Test: Boolean :=
        Check("Rec_32_Spec_Obj.X5", Rec_32_Spec_Obj.X5'Size, 3);

   end Records;

end Size_Clause_83_Pkg;
with Size_Test_Utils; use Size_Test_Utils;
with Size_Test_83_Pkg; use Size_Test_83_Pkg;
with Size_Clause_83_Pkg; use Size_Clause_83_Pkg;

pragma Elaborate(Size_Test_Utils);
pragma Elaborate(Size_Test_83_Pkg);
pragma Elaborate(Size_Clause_83_Pkg);

package Size_Test_95_Pkg is

   -- Same purpose as Size_Test_83_Pkg and Size_Clause_83_Pkg,
   -- but we put all the Ada-95-only declarations here.

   package Signed_Integers is

      H1: Boolean := Heading("Ada 95 Signed Integers:");

      use Size_Test_83_Pkg.Signed_Integers;
      use Size_Clause_83_Pkg.Signed_Integers;

      subtype Positive_0_B is
        Positive_0'Base range -Positive_0'Last..Positive_0'Last;
      Positive_0_B_Test: Boolean :=
        Check("Positive_0_B", Positive_0_B'Size, 0);

      subtype Positive_0_BB is Positive_0'Base range 0..Positive_0'Last;
      Positive_0_BB_Test: Boolean :=
        Check("Positive_0_BB", Positive_0_BB'Size, 0);

      subtype Positive_0_Spec_B is
        Positive_0_Spec'Base range -Positive_0_Spec'Last..Positive_0_Spec'Last;
      Positive_0_Spec_B_Test: Boolean :=
        Check("Positive_0_Spec_B", Positive_0_Spec_B'Size, 0);

      subtype Positive_0_Spec_BB is
        Positive_0_Spec'Base range 0..Positive_0_Spec'Last;
      Positive_0_Spec_BB_Test: Boolean :=
        Check("Positive_0_Spec_BB", Positive_0_Spec_BB'Size, 0);

      subtype Positive_1_B is
        Positive_1'Base range -Positive_1'Last..Positive_1'Last;
      Positive_1_B_Test: Boolean :=
        Check("Positive_1_B", Positive_1_B'Size, 2);

      subtype Positive_1_BB is Positive_1'Base range 0..Positive_1'Last;
      Positive_1_BB_Test: Boolean :=
        Check("Positive_1_BB", Positive_1_BB'Size, 1);

      subtype Positive_1_Spec_B is
        Positive_1_Spec'Base range -Positive_1_Spec'Last..Positive_1_Spec'Last;
      Positive_1_Spec_B_Test: Boolean :=
        Check("Positive_1_Spec_B", Positive_1_Spec_B'Size, 2);

      subtype Positive_1_Spec_BB is
        Positive_1_Spec'Base range 0..Positive_1_Spec'Last;
      Positive_1_Spec_BB_Test: Boolean :=
        Check("Positive_1_Spec_BB", Positive_1_Spec_BB'Size, 1);

      subtype Positive_2_B is
        Positive_2'Base range -Positive_2'Last..Positive_2'Last;
      Positive_2_B_Test: Boolean :=
        Check("Positive_2_B", Positive_2_B'Size, 3);

      subtype Positive_2_BB is Positive_2'Base range 0..Positive_2'Last;
      Positive_2_BB_Test: Boolean :=
        Check("Positive_2_BB", Positive_2_BB'Size, 2);

      subtype Positive_2_Spec_B is
        Positive_2_Spec'Base range -Positive_2_Spec'Last..Positive_2_Spec'Last;
      Positive_2_Spec_B_Test: Boolean :=
        Check("Positive_2_Spec_B", Positive_2_Spec_B'Size, 3);

      subtype Positive_2_Spec_BB is
        Positive_2_Spec'Base range 0..Positive_2_Spec'Last;
      Positive_2_Spec_BB_Test: Boolean :=
        Check("Positive_2_Spec_BB", Positive_2_Spec_BB'Size, 2);

      subtype Integer_3_B is
        Integer_3'Base range -Integer_3'Last..Integer_3'Last;
      Integer_3_B_Test: Boolean :=
        Check("Integer_3_B", Integer_3_B'Size, 3);

      subtype Integer_3_BB is Integer_3'Base range 0..Integer_3'Last;
      Integer_3_BB_Test: Boolean :=
        Check("Integer_3_BB", Integer_3_BB'Size, 2);

      subtype Integer_3_Spec_B is
        Integer_3'Base range -Integer_3'Last..Integer_3'Last;
      Integer_3_Spec_B_Test: Boolean :=
        Check("Integer_3_Spec_B", Integer_3_Spec_B'Size, 3);

      subtype Integer_3_Spec_BB is Integer_3'Base range 0..Integer_3'Last;
      Integer_3_Spec_BB_Test: Boolean :=
        Check("Integer_3_Spec_BB", Integer_3_Spec_BB'Size, 2);

   end Signed_Integers;

   package Modular_Integers is

      H1: Boolean := Heading("Ada 95 Modular Integers:");

      type Mod_0 is mod 2**0;
      Mod_0_Test: Boolean :=
        Check("Mod_0", Mod_0'Size, 0);

      Mod_0_Base_Test: Boolean :=
        Check("Mod_0'Base", Mod_0'Base'Size);

      type Mod_1 is mod 2**1;
      Mod_1_Test: Boolean :=
        Check("Mod_1", Mod_1'Size, 1);

      Mod_1_Base_Test: Boolean :=
        Check("Mod_1'Base", Mod_1'Base'Size);

      type Mod_2 is mod 2**2;
      Mod_2_Test: Boolean :=
        Check("Mod_2", Mod_2'Size, 2);

      Mod_2_Base_Test: Boolean :=
        Check("Mod_2'Base", Mod_2'Base'Size);

      type Mod_32 is mod 2**32;
      Mod_32_Test: Boolean :=
        Check("Mod_32", Mod_32'Size, 32);

      Mod_32_Base_Test: Boolean :=
        Check("Mod_32'Base", Mod_32'Base'Size);

      type Million is mod 1_000_000;

      subtype Sub_Mod_0 is Million range 0..0;
      Sub_Mod_0_Test: Boolean :=
        Check("Sub_Mod_0", Sub_Mod_0'Size, 0);
      subtype Sub_Mod_1 is Million range 0..1;
      Sub_Mod_1_Test: Boolean :=
        Check("Sub_Mod_1", Sub_Mod_1'Size, 1);
      subtype Sub_Mod_4 is Million range 0..15;
      Sub_Mod_4_Test: Boolean :=
        Check("Sub_Mod_4", Sub_Mod_4'Size, 4);
      subtype Sub_Int_7 is Million range 0..100;
      Sub_Int_7_Test: Boolean :=
        Check("Sub_Int_7", Sub_Int_7'Size, 7);

   end Modular_Integers;

private

   procedure Require_Body;

end Size_Test_95_Pkg;
with System; use System;
with System.Storage_Elements; use System.Storage_Elements;

package body Size_Test_95_Pkg is

   package Predefined_Stuff is end;
   package body Predefined_Stuff is

      H1: Boolean := Heading("Ada 95 Predefined Stuff:");

      type Longest_Binary_Modular is mod Max_Binary_Modulus;
      type Longest_Nonbinary_Modular is mod Max_Nonbinary_Modulus;
      Max_Binary_Modulus_Minus_One: constant := Max_Binary_Modulus - 1;
      Max_Nonbinary_Modulus_Minus_One: constant := Max_Nonbinary_Modulus - 1;
   begin

      Put_Line("Max_Binary_Modulus = " &
        Longest_Binary_Modular'Image(Max_Binary_Modulus_Minus_One) & " + 1");
      Check("Longest_Binary_Modular", Longest_Binary_Modular'Size);

      Put_Line("Max_Nonbinary_Modulus = " &
        Longest_Nonbinary_Modular'Image(Max_Nonbinary_Modulus_Minus_One) &
               " + 1");
      Check("Longest_Nonbinary_Modular", Longest_Nonbinary_Modular'Size);

      Put_Line("Word_Size = " & Longest_Signed_Integer'Image(Word_Size));

      Check("Storage_Element", Storage_Element'Size, Storage_Unit);

      Put_Line("Wide_Character'First = " &
        Wide_Character'Image(Wide_Character'First) & ".");
      Put_Line("Wide_Character'Last = " &
               Wide_Character'Image(Wide_Character'Last) & ".");
      Check("Wide_Character", Wide_Character'Size, 16);
   end Predefined_Stuff;

   procedure Require_Body is
   begin
      null;
   end Require_Body;

end Size_Test_95_Pkg;
-- This is a main program that calls the Ada 83 parts of the Size test.
-- See also Size_Test_95.

-- All the work is done during elaboration of the Size_..._Pkg packages.

with Text_IO; use Text_IO;
with Size_Test_83_Pkg;
with Size_Clause_83_Pkg;
procedure Size_Test_83 is
begin
   New_Line;
   Put_Line("[Size_Test_83 done.]");
end Size_Test_83;
-- This is a main program that calls the Ada 83 *and* Ada 95 parts
-- of the Size test.
-- See also Size_Test_83.

-- All the work is done during elaboration of the Size_..._Pkg packages.

with Text_IO; use Text_IO;
with Size_Test_83_Pkg;
with Size_Clause_83_Pkg;
with Size_Test_95_Pkg;
procedure Size_Test_95 is
begin
   New_Line;
   Put_Line("[Size_Test_95 done.]");
end Size_Test_95;

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Bob Duff
!from Randy Brukardt (RR Software)
!reference 96-5500.a rbrukardt@BIX.com 96-4-20>>

>It was the goal of the Ada 95 rules to nail some things down that were
>vague in Ada 83, so that rep clauses could be more portable across (Ada
>95) implementations.  In doing that, it may well be that we've broken
>compatibility with existing Ada 83 implementations.  We could solve this
>problem by going back to the Ada 83 rule, which I paraphrase here: "The
>Size attribute means whatever the implementation wants it to, and it's
>relationship with Unchecked_Conversion, 'Address, and pragma Pack is up
>to the implementation."  I'm being somewhat facetious here -- Robert's
>point is that most implementations agreed with each other, and RM95
>chooses an interpretation that was only chosen by some obscure Ada 83
>implementation.  I'd like to hear some input from compiler vendors here
>-- what did your Ada 83 implementations do, and what do think your Ada
>95 implementations ought to do?

Well, I've been intending to get into this discussion since it started last
Fall, but never could figure out where to begin.  Bob has given me an
appropriate starting place.

Ada 83 'Size was very vague.  At the time we were implementing it, there
were no ACVC tests, so we could not tell what the ACVC thought the intent
was.  Nor had the ARG said anything on the matter.  We concluded that 'Size
was determined on a type (not subtype) basis, and that it reflected the
size of a stand-alone object.  (Note that this conclusion is exactly opposite
what Ada 95 chose!)  We made a one exception to this conclusion: 'Size for
a subtype with a radically different representation (such as a constrained
array vs. an unconstrained array) would be different -- and that was largely
a result of ACVC tests expecting that String(1..10)'Size = 10 * Character'Size
(a requirement we found out about only after we had finished implementing
'Size, and one later removed from the tests, I think).

It was clear to use that declarations like the following all had the same
'Size, since 'Size was determined on a type basis:
        Type A Is Range -20000 .. 50000; -- 'Size = 32 = 'Base'Size.
        Subtype B Is Range 0 .. 20000; -- 'Size is still 32.
        Subtype C Is Range 0 .. 200; -- 'Size is still 32.

However, ACVC tests required that components of subtype C (for example) could
be stored in 8 bits.  That led us to two more conclusions: 'Size has no
effect on what rep. clauses can be used, and the components need to be handled
differently than stand-alone objects.  (Up to this point, they both were
handled the same way).

We also thought that 'Size on objects was intended to use discriminant/bounds
values to return the actual size.  That made some complex code, but of course
it was never tested (and probably isn't useful, either).

Eventually, we concluded that 'Size had effect on anything, and was just
another useless Ada 83 construct.

Our final implementation of 'Size looks like:
        1) 'Size can be confirmed on all types.
        2) 'Size can be set on discrete types only.  The 'Size chosen will be
           used to select a base type representation, and in (unsigned) cases,
           a possibly different in memory representation.
           We considered allowing 'Size to be set for some other types.
           In particular, we considered using a specified size to select the
           representation of a pointer (similarly to what the Ada 95 compiler
           for the U2200 does with Convention).  We also considered using
           specified sizes for record types.  The latter was not considered
           important, and the former (long pointers directly supported by
           the compiler) never was implemented.
        3) 'Size is stored in the symbol table to be returned on a user
           query.
        4) 'Size is passed at runtime to generic units (remember we use
           universal sharing as our generic model), mainly so it can be
           returned on a query.  [This was done because of ACVC tests.
           We tried to get the ARG and AVO not require this stupidity in this
           case, but were unsuccessful.]
        5) The compiler stores a stand-alone object size (unfortunately called
           'Length', that is a length of storage units), which is used for
           virutally all important purposes.
        6) 'Size for objects starts with the stand-alone size, then adds
           the size of any indirect components, based on their actual sizes.
           'Size for composite types uses the maximum size of any indirect
           components added to the stand-alone size (when it is not specified;
           note that it cannot be specified for any composite type containing
           indirect components, since such components are not statically
           constrained).
        7) Pack and rep. clauses use a minimum size calculated on the fly for
           a subtype (for discrete types).  This is essentially the same as
           the Ada 95 definition of 'Size.  Composite types always use 'Size =
           stand-alone size, and smaller components are not supported.
        8) Unchecked_Conversion uses the stand-alone object size for size
           matching.  Components are always converted to the stand-alone
           size when read, so that is the most appropriate.  This probably
           is why I always was discussing the difference between register and
           memory-based models for Unchecked_Conversion, which no one else
           ever seemed to understand.

Because of this model, I was always adamantly opposed to 'Size being specifiable
on subtypes.  With the current thinking about these models, I don't think there
is any problem with 'Size specification on discrete subtypes (because 'Size
does not affect stand-alone objects).  But I still don't anything to do
with subtypes having different sizes for composite types.

I do agree with Robert that it should be possible for an Ada 95 compiler to
layout memory the same as the Ada 83 compiler did.  Certainly we want this
to be the case for the vast majority of types in the absence of representation
clauses.  I include Pack in representation clauses; I cannot imagine a situation
where our Ada 95 compiler would get the same results for Pack that it did for
our Ada 83 compiler -- simply because our Ada 83 compiler never implemented
Pack!

I guess I never really understood the root issue here.  "Obviously", a compiler
would store subtypes with the underlying stand-alone object "length"; 'Size
has no effect on the representation of a pointed-at-object.  "Obviously",
most such conversions would work.  (As usual, the conversions themselves are
uninteresting, but 'Access is defined in terms of conversion, so that the
rule does matter.)  The problem, of course, from a language definition point
of view is that we do want to allow compilers to use different representations
for stand-alone objects of different subtypes.  Thus, I suppose we get the
mess.

In any case, I can live with Robert's recommendations.  (See the following
messages for other issues).

BTW, when perusing the ARM, I cannot find any mention of the recommended
level of support for specifying 'Size.  It says a lot about the meaning of
'Size, but not about what (sub)types allow specification.  Have I missed
something, or are we all discussing the wrong issue???

                                Randy Brukardt

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

!section 13.2(08)
!subject By-reference types and packing
!reference RM95-13.2(8)
!reference RM95-13.2(9)
!reference RM95-13.3(72)
!reference RM95-13.3(73)
!reference 96-5463.a Bob Duff
!from Randy Brukardt (RR Software)
!reference 96-5501.a rbrukardt@BIX.com 96-4-20>>

The referenced message contains examples of packing.  This brings up a question
in my mind.

    type Device_Info is
        record
            In_Ready: Boolean;
            Out_Ready: Boolean;
        end record;
    pragma Pack(Device_Info); -- Device_Info'Size = 2.

    type Device_Array is Array (1..4) of Device_Info;
    for Device_Array'Component_Size use 2;

    Dev : Device_Array;

    procedure Operate (A : In Out Device_Info);

This example appears to be legal.

Consider the call:
        Operate (Dev(2));

Since the second component of Dev is packed, it will start at bit 2; certainly
it will not start at a storage unit boundary, and will not be directly
addressible.

That means that the item almost certainly will be passed by copy.  Either it
will be directly passed by copy, or it will be passed by reference via a
copy made at the call site.  It can be passed by reference only if all
parameters of that type are passed using a bit pointer of some sort.

Now, consider that a record such as Device_Info can be made into a by-reference
type in at least three ways:
        1) By explicitly declaring it limited.  (This is probably pathological).
        2) By applying pragma Atomic to it.
        3) By applying pragma Volatile to it.
The last two are certainly possible in real programs (which I hopefully
illustrated by my choice of names).

A by-reference type does not allow pass by copy.  Therefore, a bit pointer
must be used to pass the type.  This is quite expensive, and I believe was
not intended.  Worse, a side effect of requiring that in even a single
unlikely case, is that an implementation using universal generic code sharing
will be forced to pass ALL generic private and many generic derived and array
types with bit pointers.

Have I missed a rule somewhere which states that by reference components are
treated similarly to aliased components?  Come to think of it, I can't
find any rule which says that

    type Device_Array is Array (1..8) of Aliased Boolean;
    for Device_Array'Component_Size use 1;

is not required, either.

(Of course, we can avoid the problem by not supporting the system programming
annex, but I doubt that is a good long-term plan...)

                        Randy Brukardt

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Bob Duff
!reference 96-5500.a rbrukardt@BIX.com 96-4-20
!reference 96-5503.a Robert A Duff 96-4-21>>

> BTW, when perusing the ARM, I cannot find any mention of the recommended
> level of support for specifying 'Size.  It says a lot about the meaning of
> 'Size, but not about what (sub)types allow specification.  Have I missed
> something, or are we all discussing the wrong issue???

For subtypes, look at the last sentence of 13.3(55), "If such a subtype
is a first subtype, then an implementation should support a specified
Size for it that reflects this representation."  13.3(53) is also
relevant.

For objects, there's 13.3(43):

   43  A Size clause should be supported for an object if the specified
       Size is at least as large as its subtype's Size, and corresponds
       to a size in storage elements that is a multiple of the object's
       Alignment (if the Alignment is nonzero).

- Bob

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

!section 13.2(08)
!subject By-reference types and packing
!reference RM95-13.2(8)
!reference RM95-13.2(9)
!reference RM95-13.3(72)
!reference RM95-13.3(73)
!reference 96-5463.a Bob Duff
!reference 96-5501.a rbrukardt@BIX.com 96-4-20
!from Bob Duff
!reference 96-5504.a Robert A Duff 96-4-21>>

> Now, consider that a record such as Device_Info can be made into a by-reference
> type in at least three ways:
>       1) By explicitly declaring it limited.  (This is probably pathological).
>       2) By applying pragma Atomic to it.
>       3) By applying pragma Volatile to it.
> The last two are certainly possible in real programs (which I hopefully
> illustrated by my choice of names).

It is certainly true that there is no intention of requiring
pass-by-reference to be implemented using some sort of bit-field
pointers.  Clearly, if any of the above are true, then the
implementation should allocate things on a storage unit boundary,
despite pragma Pack.  In fact, some implementations might require 4-byte
boundaries, or something, which should be allowed.

The same goes for "aliased" things.

- Bob

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Bob Duff
!reference 96-5500.a rbrukardt@BIX.com 96-4-20
!reference 96-5503.a Robert A Duff 96-4-21
!from Randy Brukardt 96-4-23
!reference 96-5507.a Ian Goldberg  96-4-23>>
!discussion

>> BTW, when perusing the ARM, I cannot find any mention of the =
recommended
>> level of support for specifying 'Size.  It says a lot about the =
meaning of
>> 'Size, but not about what (sub)types allow specification.  Have I =
missed
>> something, or are we all discussing the wrong issue???

>For subtypes, look at the last sentence of 13.3(55), "If such a subtype
>is a first subtype, then an implementation should support a specified
>Size for it that reflects this representation."  13.3(53) is also
>relevant.

Therefore, the only required support for specification of 'Size is for =
discrete and fixed point types, and only a single size is required.  =
That means any specification of 'Size on a composite, access, or float =
type is at the whim of the implementor, as is specification to =
(multiples of) the storage unit size.

Thus, most of the examples we have been discussing are relavant only in =
terms of permitted support, as opposed to required support.

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

!section 13.1(14)
!subject Re: Dewar's comments on the SIZE problem and Issue
!reference RM95-13.1(14)
!reference RM95-13.3(55)
!reference 96-5486.a Robert Dewar
!reference 96-5487.a Bob Duff
!reference 96-5500.a rbrukardt@BIX.com 96-4-20
!reference 96-5503.a Robert A Duff 96-4-21
!reference 96-5507.a Ian Goldberg  96-4-23
!from Bob Duff
!reference 96-5526.a Robert A Duff 96-4-29>>
!discussion

> Thus, most of the examples we have been discussing are relavant only in =
> terms of permitted support, as opposed to required support.

Yes.  The question is: should more support be required and/or
recommended?

Note that 13.2(7-9) could, depending on how you read it, be considered
to place further requirements on implementations, in addition to
13.3(55).

- Bob

P.S. Your mail software seems garble things, e.g. it puts strange "="
signs all over, which is kind of annoying.  Especially in the output of
the example program, where it changes "=" to "=3D".

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

!section 13.03(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!from Ken Garlington 96-05-13
!keywords Size
!reference 96-5552.a Ken Garlington  96-5-13>>
!discussion

AI95-00051: It seems to me that the restriction on 'Size for fixed and
floating point values is excessive, and that the justification could
easily apply to any value (e.g., a compiler/architecture could choose a
"special" representation for integers, and stay within the language).

Suggest replacing the current proposal for fixed/floating point with the
following:

  - For fixed point, up to the Size of the largest fixed point
    type supported by the implementation.
 
  - For floating point, up to the Size of the largest floating point
    type supported by the implementation.

For example, if an architecture had two "special" representations for
floating point (e.g., normal and extended floating point on a
MIL-STD-1750), a sufficiently large Size for a normal floating point
would cause the compiler to generate an extended floating point
representation. If there was only one representation for floating point,
then Size would have no effect. This also seems consistent with the
"minimal size" rule, in that a special representation for a number would
force the allocation of a certain number of bits regardless of Size.

The suggested alternative seems more consistent with the other rules,
while preserving what I think was the intent of the current proposal.

(By the way, I assume that someone has made sure these interpretations
regarding objects have also been carried forward to types where
applicable...)

AI95-00109/01:  I am strongly in favor of the Robert Dewar position
described in the commentary, including his "Ulterior Motive".


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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!from Robert Dewar 96-05-18
!keywords Size
!reference 96-5564.a Robert Dewar 96-5-18>>
!discussion

Ken Garlington suggests

  "For example, if an architecture had two "special" representations for
   floating point (e.g., normal and extended floating point on a
   MIL-STD-1750), a sufficiently large Size for a normal floating point
   would cause the compiler to generate an extended floating point
   representation. If there was only one representation for floating point,
   then Size would have no effect. This also seems consistent with the
   "minimal size" rule, in that a special representation for a number would
   force the allocation of a certain number of bits regardless of Size."

This seems very wrong. Remember that Size is a subtype specific attribute
which means that you can get implicit conversions. Consider:

    type x is float digits 5; -- 32 bits by default

    function Sqrt (m : x) return x;

    type y is new x;
    for y'size use 64;

according to Ken's suggestion, y would be represented in double precision,
but when you called Sqrt you would get implicit narrowing to 32 bits. This
seems very undesirable.

The whole point is that Size should not make any significant changes to
the internal representation. The idea of having Size affect the precision
is not at all in the spirit of the RM requirements, and would be actively
undesirable (though not non-conformant, just undesirable). I think it would
be helpful if the AI makes clear that this is undesirable and explains why.

Similarly Size on a fixed-point type can affect the padding, but should
NOT affect the Small value.


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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!keywords Size
!reference 96-5564.a Robert Dewar 96-5-18
!from Randy Brukardt
!reference 96-5569.a Ian Goldberg  96-5-22>>
!discussion

(From Randy Brukardt, although the header my say something different.)

>Ken Garlington suggests
>
>  "For example, if an architecture had two "special" representations for
>   floating point (e.g., normal and extended floating point on a
>   MIL-STD-1750), a sufficiently large Size for a normal floating point
>   would cause the compiler to generate an extended floating point
>   representation. If there was only one representation for floating point,
>   then Size would have no effect. This also seems consistent with the
>   "minimal size" rule, in that a special representation for a number would
>   force the allocation of a certain number of bits regardless of Size."
>
>This seems very wrong. Remember that Size is a subtype specific attribute
>which means that you can get implicit conversions. Consider:
>
>    type x is float digits 5; -- 32 bits by default
>
>    function Sqrt (m : x) return x;
>
>    type y is new x;
>    for y'size use 64;
>
>according to Ken's suggestion, y would be represented in double precision,
>but when you called Sqrt you would get implicit narrowing to 32 bits. This
>seems very undesirable.
>
>The whole point is that Size should not make any significant changes to
>the internal representation. The idea of having Size affect the precision
>is not at all in the spirit of the RM requirements, and would be actively
>undesirable (though not non-conformant, just undesirable). I think it would
>be helpful if the AI makes clear that this is undesirable and explains why. 

Well, I completely disagree about the 'undesirable' part.

Our (read my) intent for our compiler was always that it would do this.
I don't think we ever did it for floating point types, but we do allow it for
all other types.  (Yes, our compiler [used to] allow explicitly changing
the 'Small value for fixed point types; I think we took it out when some
ACVC test pointed out it was illegal.  I know our compiler has code to
do the needed conversions when parameter passing.)

While changing representations on derived floating types might be
unnecessary, it is very useful to allow this capability on first named
subtypes.  Otherwise, there is no (semi) portable way to select a
particular representation (for interfacing, for example):

        Type My_Flt is Digits 5;
        For My_Flt'Size Use 64;

The only alternative ways is to select more precision than the program
needs, or to add some sort of junk range which may not have anything
to do with the program requirements.

As with any programming, there is a certain amount of user-beware
needed.  If someone specifies something unlikely that loses precision,
that's their problem and just too bad.  (I don't find derived subprograms
on a floating point type particularly likely, and the combination is even
less likely.)

We had to do something similar to be able to convert between the two
representations of pointers on the Unisys 2200.

        Type My_Ada_Ptr Is Access <something>;
        Pragma Convention (My_Ada_Ptr, Ada);

        Type My_C_Ptr Is New My_Ada_Ptr;
        Pragma Convention (My_C_Ptr, C);

An alternative way to specify that would have been:

        Type My_Ada_Ptr Is Access <something>;
        For My_Ada_Ptr'Size Use 36;

        Type My_C_Ptr Is New My_Ada_Ptr;
        For My_C_Ptr'Size Use 72;

(I didn't do that because it was a lot more work to implement properly.)









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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!keywords Size
!reference 96-5564.a Robert Dewar 96-5-18
!from Robert Dewar
!reference 96-5570.a Robert Dewar 96-5-22>>
!discussion

Randy said, replying to me

>>The whole point is that Size should not make any significant changes to
>>the internal representation. The idea of having Size affect the precision
>>is not at all in the spirit of the RM requirements, and would be actively
>>undesirable (though not non-conformant, just undesirable). I think it would
>>be helpful if the AI makes clear that this is undesirable and explains why.

>Well, I completely disagree about the 'undesirable' part.
>
>Our (read my) intent for our compiler was always that it would do this.
>I don't think we ever did it for floating point types, but we do allow it for
 all other types.  (Yes, our compiler [used to] allow explicitly changing
>the 'Small value for fixed point types; I think we took it out when some
>ACVC test pointed out it was illegal.  I know our compiler has code to
>do the needed conversions when parameter passing.)

As best I understand it, this is a comment from Randy on how he would like
the language to be, but it seems clear that this is not what is intended.
The advice that Size not alter the internal representation of an item is
clearly applicable in this case. Also the strong difference in rules between
Size and Small indicates that the notion that Size could affect Small is
not at all what is intended.

Consider the following

     type x is digits 5;

     procedure Noop (a : in out x) is
     begin
        null;
     end;

     type y is new x;
     for y'size use 64;

It seems quite wrong that a call to Noop with an argument of type y would
modify the value of the argument (by stripping extra precision). This is
precisely why a 'Small attribute clause would not have been allowed for y
in the corresponding fixed-point case, and it seems clear that Size is
only expected to affect padding etc where the conversions do not have
significant change-of-representation semantics. The whole idea of change
of representation in Ada is that it should be explicit, never implicit.

Randy, are you simply saying you don't think the language should have been
designed with this restriction, or are you seriously suggesting that it is
appopriate that 'Size clauses cause a change of representation resulting
in implicit (non-trivial) change of representation conversions.


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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!keywords Size 
!reference 96-5564.a Robert Dewar 96-5-18
!reference 96-5570.a Robert Dewar 96-5-22
!from Randy Brukardt
!reference 96-5571.a Ian Goldberg  96-5-23>>
!discussion

Robert gives the following example in replying to me (Randy Brukardt):

>Consider the following
>
>     type x is digits 5;
>
>     procedure Noop (a : in out x) is
>     begin
>        null;
>     end;
>
>     type y is new x;
>     for y'size use 64;
>
>It seems quite wrong that a call to Noop with an argument of type y would
>modify the value of the argument (by stripping extra precision). This is
>precisely why a 'Small attribute clause would not have been allowed for y
>in the corresponding fixed-point case, and it seems clear that Size is
>only expected to affect padding etc where the conversions do not have
>significant change-of-representation semantics. The whole idea of change
>of representation in Ada is that it should be explicit, never implicit.

I of course agree that change of representation should be explicit,
never implicit.  But the problem here is (taking some license) that
programmer here is planning on using the EXPLICIT conversion to
or from Y(...) to handle the conversion.  They just forgot that the
Noop routine would be derived.

Normal Ada programmers probably ought to avoid derived routines (for
untagged types) altogether, because the rules are just too complex
for the average programmer to understand.  It took us months to
get this stuff right in our Ada 83 compiler, and I doubt we still have
it right in our Ada 95 compiler.

Anyway, explicit representation change via derived types has a long
history in Ada, including an entire section devoted to the idea.  It seems
very odd to deny a programmer (and implementors) the capability to
specify a representation for floating point and fixed point types, but to
allow it for all other types.  (It is true that the numeric conversion rules
are liberal enough that it is not necessary to do this, which is probably
why it was omitted in the first place.  But it is very natural, given that
it must be done for access, array, and record types.)

In any case, the most useful usage of 'Size to force a representation
is on the first-named subtype of an original type declaration.  That
is a capability which is not present anywhere else in the language,
and one that is needed from time to time.  I think the original
commentor had that case in mind, and that is mainly what I care
about here.  The problem is that it is difficult to separate the
cases.

Some other way to specify a hardware floating-point representation
would also fill the need, of course.  Pragma Float_Rep does not
seem too satisfying, however, since such a usage could not be
portable to another compiler.

Ada 83 generally restricted clauses on derived types to those
without primitive operations.  Such a restriction on representation
changing clauses of any kind could be recommended, and
eliminate Robert's concern, without throwing the baby out with
the bathwater.

(Of course, the fact that 'Size is a "subtype" attribute makes
reasoning about it much more complex.  Once the capability
to specify 'Size for subtypes was removed, there was no
reason to retain "subtype" attributes [other than that they
slightly simplify the description of 'Component_Size and
record component clauses].  Unfortunately, such a change
is too much for the ARG to undertake.)


 






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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!keywords Size
!reference 96-5564.a Robert Dewar 96-5-18
!reference 96-5570.a Robert Dewar 96-5-22
!from Robert Dewar
!reference 96-5572.a Robert Dewar 96-5-23>>
!discussion

Randy said

 (Of course, the fact that 'Size is a "subtype" attribute makes
 reasoning about it much more complex.  Once the capability
 to specify 'Size for subtypes was removed, there was no
 reason to retain "subtype" attributes [other than that they
 slightly simplify the description of 'Component_Size and
 record component clauses].  Unfortunately, such a change
 is too much for the ARG to undertake.)

I don't find the reasoning complex. It is an invention of Ada 83, not
Ada 95 that draws a strong distinction between size and other rep clauses
such as record and enumeration representation clauses. The reason is the
same in Ada 83 and Ada 95, namely that it is assumed that different sizes
do NOT correspond to a significant change in repressenation.

To make Size a type specific attribute in Ada 95 would introduce terrible
upwards incompatibilities (the program I gave with Noop is legal Ada 83,
and legal Ada 95, but would of course be illegal Ada 95 if we followed
Randy's suggestion and made Size a type-related attribute).

The fact of the matter is that Randy is complaining about a design decision
made in Ada 83, which is unchanged in Ada 95. His recommendation of not using
derived types for non-tagged types strikes me as absurd, since this is a much
used feature in both Ada 83 and Ada 95 programs, in particular to effect
change of representation. It sounds like the RR compiler at first missed
the very important distinction between Size and other rep clauses, but this
is a crucial distinction in Ada 83 as well as in Ada 95.

It is quite in order to complain about this design decision, but that does
not translate into action at this stage. I happen to think that the Ada 83
decision (and the corresponding identical Ada 95 semantics) is quite
reasonable, but in any case it is clearly the rule of the language as it
stands, and I do not see any cogent argument for suggesting a change at
this stage.


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

!section 13.3(42)
!subject Comments to AIs regarding 'Size
!reference AI95-00051
!reference AI95-00109
!reference 96-5552.a Ken Garlington  96-5-13
!keywords Size 
!reference 96-5564.a Robert Dewar 96-5-18
!reference 96-5570.a Robert Dewar 96-5-22
!reference 96-5571.a Ian Goldberg  96-5-23
!from Erhard Ploedereder
!reference 96-5573.a Erhard Ploedereder  96-5-24>>

> Anyway, explicit representation change via derived types has a long
> history in Ada, including an entire section devoted to the idea.  It seems
> very odd to deny a programmer (and implementors) the capability to specify a
> representation for floating point and fixed point types, but to allow it for
> all other types.  (It is true that the numeric conversion rules are liberal
> enough that it is not necessary to do this, which is probably why it was
> omitted in the first place.  But it is very natural, given that it must be
> done for access, array, and record types.)

This argument conveniently ignores that this RM Section (13.6) in Ada9X
talks only about records (and arrays) and requires the absence of inherited
subprograms for derived records with rep.clauses. On might infer from the
omission that such representation change for real types was considered
undesirable.

Note also RM 13.1(10) which imposes the "no-inherited subprograms" rule for
all type-related rep.clauses (anything other than Size and Alignment) on
derived types. It would be most curious if
  for T'Small use ...   were illegal, while
  for T'Size use        were legal with an effect that changes 'Small.







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

Questions? Ask the ACAA Technical Agent