Version 1.7 of ai05s/ai05-0155-1.txt
!standard 13.1(23) 10-10-08 AI05-0155-1/05
!standard 13.3(56.2/2)
!class ramification 10-06-09
!status ARG Approved 9-0-1 10-06-19
!status work item 09-06-01
!status received 09-04-07
!priority Medium
!difficulty Medium
!qualifier Omission
!subject 'Size clause on type with nonstatic bounds
!summary
Only Size clauses with a size greater than or equal to the
Size that would be chosen by default may be safely presumed
to be supported on non-static elementary subtypes.
Implementations may choose to support smaller sizes,
but only if the Size allows any value of the subtype to be
represented, for every possible elaboration of the type
declaration.
!question
What does "any value of the subtype" mean when the bounds of the subtype
aren't known at compile time?
package Pak1 is
type Integer_32 is range -2**31 .. 2**31-1;
procedure Proc (Low, High : Integer_32);
end Pak1;
package body Pak1 is
procedure Proc (Low, High : Integer_32) is
type T is new Integer_32 range Low .. High;
for T'Size use 16; --
begin
null;
end Proc;
end Pak1;
Is the 'Size clause legal, requiring a check at runtime to make sure
there's enough space given the actual values of Low and High; or is it
illegal? (It is illegal.)
!response
(See Summary.)
!wording
Add after 13.3(56.2/2):
AARM Ramification:
Only Size clauses with a size greater than or equal to the
Size that would be chosen by default may be safely presumed
to be supported on non-static elementary subtypes.
Implementations may choose to support smaller sizes,
but only if the Size allows any value of the subtype to be
represented, for any possible value of the bounds.
!discussion
13.1(23) says that there are no requirements to support representation
items on composite types with non-static constraints. But that leaves
such items supported for all elementary types, and covered by the
recommended level of support.
That means, for instance, that supporting the specification of 'Size for
discrete and fixed point types with dynamic constraints is required
so long as the value is large enough to allow "any value of the subtype".
There seems to be five possible solutions to this problem:
(1) Allow any reasonable value for 'Size, and require a runtime check
that it fits based on the actual bounds. (similarly for record representation
component clauses.). This is clearly the most flexible solution, but it adds
runtime overhead and surely would need wording to define the needed check.
(2) Remove "composite" from 13.1(23).
This would put all subtypes on an equal footing here, and would match the
Ada 83 rules. But it seems clear that the Ada 9x team intended this as a
language change - it would be hard to rewrite this text and accidentally
insert "composite"! Unfortunately, they did not document this as either an
extension to Ada83 or wording change from Ada83, so we don't know for sure.
(3) Add wording to exclude dynamically constrained discrete and fixed
point types from the requirements of "recommended level of support" for
subtypes and record representation component clauses. This would not be
substantially different than (2), other than continuing to allow specification
of non-confirming alignments for such subtypes. And this would require
more complex wording in a number of places.
(4) Actually define what "any value of the subtype" means for dynamically
constrained subtypes. We could define it to use whatever static bound
information is known about the bounds. (Perhaps as a Ramification and "Honest"
AARM note rather than actual language text.) However, we need to be careful
to deal with cases where bounding information comes from the bound expressions
as well as from the parent subtype. For instance:
package Pak2 is
type Integer_32 is range -2**31 .. 2**31-1;
subtype Sub is Integer_32 range -100 .. 100;
procedure Proc (Low, High : Sub);
end Pak2;
package body Pak2 is
procedure Proc (Low, High : Sub) is
type T is new Integer_32 range Low .. High;
for T'Size use 16; --
begin
null;
end Proc;
end Pak2;
Requiring support for this case is surely more complex than simply looking at
the "narrowest" static bounds of an ancestor subtype. (Compilers often use
"narrowest bound" information for eliminating range checks, so that is a
common operation.)
We would also need to explain what "any value" means when there is no information
about the parent subtype, as in the case of generic formal types:
generic
type Disc is (<>);
Low, High : Disc;
package Pak3 is
type New_Disc is new Disc range Low .. High;
for New_Disc'Size use 16; --
end Pak3;
type Integer_16 is range -2**16 .. 2**16-1;
for Integer_16'Size use 16;
package New_Pak3 is new Pak3 (Integer_16, 0, 10_000); --
(5) Only rely on support for sizes >= Size chosen by default, for
non-static elementary subtypes.
Implementations may already be choosing the minimum possible value
for Size for non-static elementary subtypes (even though that is
not specifically required), so using the Size chosen by default
as an expected minimum supported Size seems reasonable. In fact,
many Size clauses for elementary subtypes are specifying sizes larger
than the minimum Size, and we would still want to allow that.
Trying to specify a smaller size would not be portable.
We chose this last option; we do not believe that any normative wording
changes are needed for this interpretation. We leave exactly what is
required to support "any value of the subtype" up to the implementation,
but clearly values larger than the size chosen by default must qualify.
!ACATS Test
This is a permission not to support something, so it is not testable.
!appendix
!topic 'Size clause on type with nonstatic bounds
!reference 13.1(12)
!from Adam Beneschan 09-04-07
!discussion
13.1(12): "A representation item that specifies the Size for a given
subtype, or the size or storage place for an object (including a
component) of a given subtype, shall allow for enough storage space
to accommodate any value of the subtype."
What does "any value of the subtype" mean when the bounds of the subtype
aren't known at compile time?
package Pak1 is
type Integer_32 is range -2**31 .. 2**31-1;
procedure Proc (Low, High : Integer_32);
end Pak1;
package body Pak1 is
procedure Proc (Low, High : Integer_32) is
type T is new Integer_32 range Low .. High;
for T'Size use 16; -- LEGAL?
begin
null;
end Proc;
end Pak1;
Is the 'Size clause legal, requiring a check at runtime to make sure
there's enough space given the actual values of Low and High; or is it
illegal?
package Pak1 is
type Integer_32 is range -2**31 .. 2**31-1;
subtype Sub is Integer_32 range -100 .. 100;
procedure Proc (Low, High : Sub);
end Pak1;
package body Pak1 is
procedure Proc (Low, High : Sub) is
type T is new Integer_32 range Low .. High;
for T'Size use 16; -- LEGAL?
begin
null;
end Proc;
end Pak1;
What about this one?
Ada 83 disallowed 'Size clauses on types with non-static constraints, but
I don't see this restriction anywhere in Ada 95 or Ada 2005.
GNAT rejects both, by the way, saying that a minimum size of 32 is required.
****************************************************************
From: Randy Brukardt
Date: Wednesday, April 8, 2009 1:24 PM
...
> What does "any value of the subtype" mean when the bounds of the
> subtype aren't known at compile time?
The rules requiring staticness were moved to "Recommended Level of Support".
Specifically, 13.1(22) and 13.1(23) say that non-static stuff doesn't need to be
supported.
But there seems to be an intentional hole for elementary types. Why that is is
totally unclear to me, as it either requires ridiculous implementation
hand-stands or is totally pointless. (The only representation clause that could
reasonably required for such a type is a confirming one, which by itself doesn't
seem useful enough to require.)
Because of that supposedly intentional hole, we definitely do need to mention
"non-static" constraints in the recommended level of support for 'Size. (Or we
need to remove the hole by deleting "composite" from 13.1(23); that would be
easier but would deal with more than the immediate problem).
Probably, there should be an extra bullet in 13.3(56.1-3):
An implementation need not support a non-confirming Size clause for a type with
non-static constraints.
That would leave examples like yours completely implementation-defined (without
banning them outright). Something similar ought to be done for elementary
components of a subtype with non-static constraints in a record representation
clause (it has the same issues since the number of bits needed is not known at
compile-time).
****************************************************************
From: Tucker Taft
Date: Wednesday, June 9, 2010 1:15 PM
Here is a "ramification" writeup of the AI relating to 'Size on non-static
scalar subtypes. I didn't find the minutes as useful as I had hoped, and wasted
an inordinate amount of time on something that will almost certainly have no
effect on any implementation. In any case, here it is. [This is version /02 of
the AI.]
The main conclusion I had was that users should be allowed to specify a
confirming or larger Size for a non-static elementary subtype, but not
necessarily a smaller Size. In some implementations, the confirming Size is
already as small as the implementation will support, even for non-static
subtypes.
I also came down on the side of making the Size clause legal only if it would be
legal in every possible elaboration of the type. Hence, if the subtype bounds
are dynamic, then an implementation may assume the "worst" when deciding whether
a specified Size is adequate, rather than expecting a run-time check during
elaboration of the type to be sure the specified Size is adequate, which
probably wouldn't be doing anyone any favors.
****************************************************************
From: Steve Baird
Date: Wednesday, June 9, 2010 2:04 PM
> ... for every possible elaboration of the type declaration.
Using the phrase "every possible elaboration" in RM wording with no further
clarification of what this means seems odd. In addition, I just generally don't
like linking legality rules to dynamic semantics.
Maybe it is ok in this case; I don't see how it can cause any problems.
For example, I suppose it would be ok if a peculiar implementation chose to
accept something like
declare
procedure Never_Called (Lo, Hi : Integer) is
type T is new Integer range Lo .. Hi;
for T'Size use 1;
begin null; end Never_Called;
Untrue : Boolean := False;
begin
if Untrue then
Never_Called (Lo => Integer'First, Hi => Integer'Last);
end if;
end;
It may be that there is no problem here, but I think it deserves review.
****************************************************************
From: Tucker Taft
Date: Wednesday, June 9, 2010 2:04 PM
I agree this is somewhat weird. We could say "any possible value of the bounds,
if non-static." That falls back on the "any possible value" which is already
used (and not well defined ;-).
****************************************************************
From: Randy Brukardt
Date: Thursday, June 10, 2010 2:04 PM
It's an AARM note, so it doesn't need to be that well-defined. :-) The use of
"may be" is iffy (but OK because it's an AARM note).
Anyway, I don't see much need for the "if non-static" here. If the bounds are
static, "any possible value of the bounds" is a single value; otherwise, they
are whatever they are. Besides the first sentence says that we are talking
mainly about non-static subtypes. Here's the revised paragraph again:
Only Size clauses with a size greater than or equal to the
Size that would be chosen by default may be safely presumed
to be supported on non-static elementary subtypes.
Implementations may choose to support smaller sizes,
but only if the Size allows any value of the subtype to be
represented, for any possible value of the bounds.
Anyway, I made this change, so hopefully we can dispose of this AI quickly when
it comes up.
****************************************************************
From: Tucker Taft
Date: Thursday, June 10, 2010 9:29 PM
Your change looks fine to me. I remembered after I responded to Steve that this
was an AARM note, so mixing static and dynamic issues is not a very big deal.
I was told to write this up as a "ramification"
so that's what I did, but it feels a bit more like an implementation requirement
and hence a binding interpretation.
****************************************************************
From: Randy Brukardt
Date: Thursday, June 10, 2010 9:42 PM
I thought you were the one that wanted a "Ramification" because we didn't want
to force any compiler changes (that would be pointless if not harmful). Maybe I
misremember, it was a long time ago. In any case, don't waste time thinking
about this one now, get those two critical AIs done (and if you have time, think
about the issues that you left open in AI-183).
****************************************************************
Questions? Ask the ACAA Technical Agent