!standard 13.1(23) 10-08-12 AI05-0155-1/04 !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; -- 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? (It is probably 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 specifying 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 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 substansively 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; -- Legal? 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; -- Legal? Rechecked? 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); -- Legal? (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 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). ****************************************************************