!standard 4.09 (38) 04-10-04 AI95-00291/04 !class binding interpretation 02-03-26 !status work item 03-09-17 !status received 02-03-26 !qualifier Error !priority Medium !difficulty Hard !subject By-reference types and the recommended level of support for representation items !summary The recommended level of support for representation items does not preclude maintaining the invariant that all objects of a given by-reference type and all aliased objects of any given type are consistently aligned and have a common representation. !question The recommended level of support for representation items should not preclude maintaining the invariant that all objects of a given by-reference type and all aliased objects of any given type are consistently aligned and have a common representation. There exist representation items which violate this rule (and which most implementations would therefore reasonably reject) but which are not excluded from the recommended level of support for representation items. Was this intended? (No.) !recommendation (See summary.) !wording Insert after 13.1(18.1/1) A representation item that specifies an aspect of representation that would have been chosen in the absence of the representation item is said to be *confirming*. Insert after 13.1(21) (that is, as the first item in the bulleted list) A confirming representation item should be supported. Replace bulleted-list item 13.1(24) with the following (formatted as 3 bulleted-list items and then a paragraph following the bulleted list): * An implementation need not support a nonconfirming representation item if it could cause an aliased object or an object of a by-reference type to be allocated at a nonaddressable location or, if the alignment attribute of the subtype of such an object is nonzero, at an address which is not an integral multiple of that alignment. * An implementation need not support a nonconfirming representation item if it could cause an aliased object or an object whose type is by-reference to have a different size than some other such object of the same definite subtype. * An implementation need not support a nonconfirming subtype-specific representation item specifying an aspect of representation of an indefinite or abstract subtype. For purposes of these rules, the determination of whether a representation item applied to a type "could cause" an object to have some property should be based solely on the properties of the type itself, not on any available information about how the type is used. In particular, it should be assumed that minimally aligned objects of this type are declared at some point. Insert after 13.2(6): If a packed type has a component which is not of a by-reference type and has no aliased part, then that component of an object need not be allocated at an addressable location whose address is an integral multiple of the Alignment of the component's subtype. Delete 13.3(18) [text was moved to 13.1(24)] Following formatting of 13.3(39/1 - 48), replace 13.3(22/1 - 26) with For a prefix X that denotes an object: X'Alignment The value of this attribute is of type *universal_integer*, and nonnegative; zero means that the object is not necessarily aligned on a storage element boundary. If X'Alignment is not zero, then X is aligned on a storage unit boundary and X'Address is an integral multiple of X'Alignment (that is, the Address modulo the Alignment is zero). Alignment may be specified for stand-alone objects via an attribute_definition clause; the expression of such a clause shall be static, and its value nonnegative. For every subtype S: S'Alignment The value of this attribute is of type *universal_integer*, and nonnegative. For an object X of subtype S, if S'Alignment is not zero, then X'Alignment is a nonzero integral multiple of S'Alignment unless specified otherwise by a representation item. Insert after 13.3(25) (note that AI247 deleted 13.3(26)) An implementation need not support an Alignment specified for a derived tagged type which is not a multiple of the Alignment of the parent type. An implementation need not support a nonconfirming Alignment specified for a derived untagged by-reference type. An implementation need not support Alignments specified for objects of a by-reference type or for objects of types containing aliased subcomponents if the specified Alignment is not a multiple of the Alignment of the object's subtype. Replace 13.3(28) with For an object X that is not allocated under control of the implementation, execution is erroneous if the object is not aligned according to its Alignment. In 13.3(43) replace "A Size clause should be supported for an object if ..." with "A nonconfirming Size clause should be supported for an object (excepting aliased elementary objects) if ..." Insert after 13.3(56) A nonconfirming size clause for the first subtype of a derived untagged by-reference type need not be supported. Insert after 13.3(72): An implementation need not support a nonconfirming Component_Size clause if the array type has an aliased part. In 13.5.1(19), replace "A storage place should be supported" with "A storage place for an unaliased component should be supported". !discussion We do not want to *require* that implementations reject problematic representation items such as type T is array (1..32) of aliased Boolean; for T'Size use 32; ; we just want to *allow* implementations to reject such beasts without running afoul of C.2(2). Note that the term "object" includes the case of a component. Thus, for example, the allowed non-support of a representation item which could result in a misaligned object would imply permission to reject something like type Rec1 is record F : aliased Integer; end record; for Rec1'Alignment use Integer'Alignment / 2; or type Rec2 is record F : aliased Integer; end record; for Rec2 use record F at Integer'Alignment / 2 range 0 .. Integer'Size - 1; end record; Given an object X of subtype S, X'Alignment must be consistent with S'Alignment "unless specified otherwise by a representation item". Note that the representation item need not be an alignment clause. It could be a Pack pragma, a Component_Size specification, a record representation clause, a size clause, etc. !ACATS test !appendix From: Steve Baird Sent: Tuesday, March 26, 2002 6:39 PM The recommended level of support for representation items should not preclude maintaining the invariant that all objects of a given by-reference type and all aliased objects of any given type are consistently aligned and have a common representation. There exist representation items which violate this rule (and which most implementations would therefore reasonably reject) but which are not excluded from the recommended level of support for representation clauses. These include: 1) Alignment clauses for derived tagged types specifying a value which is not a multiple of the parent type's alignment (13.1(10) allows this; an alignment clause is not a type-related representation item). For example: type T1 is tagged record F : Long_Float; end record; for T1'Alignment use 8; -- ok type T2 is new T1 with null record; for T2'Alignment use 4; -- bad X2 : T2; pragma Import (Ada, X2); -- Since T1 (X2) may be passed as a parameter to a subprogram, -- the subprogram may not assume that its argument is 8-byte -- aligned. This is not good. 2) Non-confirming size or alignment clauses for untagged derived by-reference types. For example: type My_Tagged_Type is tagged null record; for My_Tagged_Type'Alignment use 4; -- ok type Parent is array (1 .. 10) of My_Tagged_Type; for Parent'Alignment use 4; -- ok type Child is new Parent; for Child'Alignment use 8; -- bad -- A view conversion may result in a misaligned object of the -- more strictly aligned type. 3) Non-confirming size specifications for objects of a by-reference type. 4) Alignment specifications for objects of a by-reference type (or which have aliased subcomponents), where the specified alignment is not a non-zero multiple of the overridden alignment value. 5) Representation items (e.g. record representation clauses, component_size clauses, size clauses, and alignment clauses) which would result in misaligned components which are either aliased, contain aliased subcomponents, or are of a by-reference type. For example: type U32 is new Interfaces.Unsigned_32; for U32'Size use 32; -- ok for U32'Alignment use 4; -- ok type R1 is record F1 : aliased U32; F2 : Character; end record; for R1'Size use 40; -- ok type R1_Vec is array (1..10) of R1; for R1_Vec'Component_Size use 40; -- bad For purposes of this discussion, an object of type T may be "misaligned" in either of two ways: 1) If T'Alignment > 0, then the object is misaligned if its address is not an multiple of T'Alignment. 2) Any object which is not aligned on a storage element boundary is considered to be misaligned, regardless of the value of T'Alignment (i.e. even if T'Alignment = 0). For example: type Switch_Setting is (Off, On); for Switch_Setting'Alignment use 0; -- ok for Switch_Setting'Size use 1; -- ok type Setting_Set is array (1..32) of aliased Switch_Setting; for Setting_Set'Component_Size use 1; -- bad 6) Representation items which would result in aliased or by_reference components having different sizes than they otherwise would have had. For example: type I16 is new Interfaces.Integer_16; for I16'Size use 16; -- ok for I16'Alignment use 2; -- ok type R2 is record F : aliased I16; end record; for R2 use record F at 0 range 0 .. 31; -- bad end record; Pragma Pack is also problematic. In this example type Vec is array (1 .. 32) of aliased Boolean; pragma Pack (Vec); , the Pack pragma should be accepted, but choosing a Component_Size of 8, rather than 1, for Vec should be consistent with the recommended level of support for pragma Pack. These representation items could all be supported (e.g. by representing access-to-object values and by-reference parameter values as something other than a simple storage-unit address), but the recommended level of support for representation items should not require such contortions. **************************************************************** From: Robert Dewar Sent: Tuesday, March 26, 2002 9:36 PM I agree with all Steve's points here, and consider them obvious, in the sense that no other interpretation makes any sense. **************************************************************** From: Randy Brukardt Sent: Friday, April 19, 2002 7:58 PM I believe each example you provided. But in order to proceed, we'll need to have references to the particular recommended level of support paragraphs and some suggestion of how to fix them. I've created an empty AI (AI-291) with just a question for you to fill in. Doing this will at least cover part of the ground of the never completed AI-51/109. I'm sure Bob Duff will be happy that you have volunteered to write the AI for this albatross^h^h^h^h^h^h^h^h^h issue. **************************************************************** From: Tucker Taft Sent: Monday, September 20, 2004 9:20 PM I claimed that the Ada 9X team had a pretty clear model in their heads relating to representation, and I thought it might be useful to try to communicate it. I realize that this model was not well communicated in the RM, and that it may not be the "right" one as far as some are concerned. Nevertheless, it might be useful to try to put it into words. THE 9X MODEL In the Ada 95 RM, we tried to make a clear distinction between "type-related" representation aspects and "subtype-specific" representation aspects. The idea was that all objects of a given type would share the same type-related representation aspects, but that individual objects might differ in subtype-specific representation aspects. For example, for a fixed-point type, the "small" is type-related, whereas the range is subtype-specific (and hence can vary from object to object for a given fixed-point type). Perhaps "subtype-specific" might better have been called "object-specific." Size and Alignment are subtype-specific in Ada 95, whereas things like array component-size, record component layout, fixed small, are all type-related. Subtype-specific aspects need not be the same between objects, and in particular, need not be the same between actual and formal. For by-copy parameter passing, it is clear that it is easy for the actual and formal to have different subtype-specific aspects. For by-copy parameter passing, it would be bad for type-related aspects to differ for two reasons, one because precision might be lost (e.g. if the smalls didn't agree), and the second because the parameter passing would be too expensive (e.g. having to change the layout of the record). By by-reference parameter passing, if is even more clear that type-related aspects need to match between actual and formal. For subtype-specific aspects to differ, it must mean that the formal can reasonably provide a "view" of the actual that will not "corrupt" the actual. For example, if the actual is an unconstrained record, but the formal is constrained, there is no problem so long as the incoming discriminants satisfy the constraints of the formal. Similarly, it is fine if the size of the actual differs from the size of the formal, so long as the part that is actually touched via the formal exists in the actual. It seems clear that it should be possible to "touch" from the 'Address of the formal up through formal'Size bits thereafter. This means that the size of the actual should be greater than or equal to the size of the formal (again, we are talking only about by-reference parameter passing here). Similarly, for by-reference paramter passing, there seems no harm if the alignment of the actual is greater than the alignment of the formal, so long as it is an integral multiple of the alignment of the formal. Given the above analysis, it seems like reasonable choices were made in Ada 95 in terms of making certain aspects type-related, and others (Size and Alignment), subtype-specific (or perhaps better, "specifiable for individual objects"). Nevertheless, there are still some limitations on the specification of the subtype-specific aspects. For example, for scalar types, the object Size is clearly required to be large enough to represent all the distinct in-range values. For objects that are going to be passed by reference, the size (and alignment) must be no less than that of any formal with which they are compatible (i.e., for which there is no Constraint_Error). If it is an option to pass by copy, then the compiler could choose to allow smaller size or alignment, but if the object is required to be passed by reference, then smaller size or alignment is not an option. HOLES IN THE MODEL One part of the model which was clearly missing had to do with aliased elementary objects. These are elementary objects which are effectively accessed "by-reference." This implies they must obey rules similar to by-reference parameter passing, requiring that the Size and Alignment be no smaller than that expected by the access value through which they are referenced. It would be fine if their alignment were greater. If their size were greater, it would have to be purely padding occuring at the "end" of the object. If there were any "significant" bits in an area not referenced by the access value, that would be trouble. Because of the traditional assumption for elementary objects that the size means something about the kind of machine instructions used to manipulate it, and we don't like to build in dependence on the machine being "little-endian", it seems like the Size should match exactly between the object and the size referenced via the access value. It is conceivable that a compiler could support larger aliased discrete or fixed objects if the machine were little-endian and the range were non-negative (so it always had trailing zero bits), but that seems of dubious value, and clearly non-portable. Hence, only confirming size specifications for aliased elementary objects seem justifiable. As mentioned above, increasing the aligmnent is always safe for an aliased object. A second part of the model which was incomplete had to do with conversions. If a type is a by-reference type, and the conversion is used as an actual parameter, the conversion is required to also be "by-reference" (see 6.2(10)). Based on the discussion above, this means that an object's size must be no smaller than any subtype or type to which it can be converted, if its type is by-reference. For untagged types, where conversion can go between any two types with a common ancestor, this means that all by-reference types with a common ancestor must have the same size for (namable) subtypes with the same constraints. All objects (with the same constraints) must have a size no smaller than this size. Similarly, alignment requirements must be the same for all such subtypes, and all objects must have an alignment at least this great. For tagged types, this means that sizes (and alignments) must not decrease as you move from ancestor to descendant. Objects must have a size and alignment no smaller than that of their (nameable) subtype. Note that AI-246 already disallowed the problematic array conversions between types without a common ancestor, if the type is (or might be) by-reference or limited. SUMMARY OF THE ABOVE: The 9X model distinguishes type-related from subtype-specific representation aspects, where subtype-specific might be better thought of as aspects that can vary from one object of the type to another. Size and Alignment are the two subtype-specific representation aspects. Any object can be safely given a larger alignment than that required by its type, provided it is an integral multiple of the required alignment. (Note that we don't require supporting arbitrarily large alignments, but rather choose to allow implementations to define a maximum alignment for each class of types.) Non-aliased objects of a non-by-reference type may safely have any size and alignment (subject to representing all allowed values). (Note that we don't require support for arbitrarily large elementary objects, but rather choose to allow implementations to limit sizes of elementary objects to the "natural" sizes on the machine.) Only confirming size specifications need be supported for aliased objects of an elementary type (and anything else seems unwise). Composite aliased objects need to have a size that is no smaller than that of any (constrained) designated subtype through which they can be viewed. By-reference objects need to have a size that is no smaller than that of any (constrained) formal subtype through which they can be viewed, either directly or via a type conversion. Subtype Size (and Alignment) clauses are somewhat more limiting: For an untagged by-ref type, all its descendants must have the same size and alignment for "corresponding" subtypes. (There was already a rule that disallowed type-related rep-clauses for untagged derived by-reference types). For tagged types, sizes/alignments of subtypes should not shrink as we go from ancestors to descendants. We rely on AI-246 to disallow array conversions between unrelated by-reference types. I hope the above is of some help in understanding the model the 9X team was trying to use for representation, and also the two holes in the model relating to aliased elementary objects and by-reference conversion. Neither hole seems to imply we need to disallow Size clauses on composite objects that specify an overly generous size. There does seem to be a need to require confirming Size and Alignment clauses on derived (sub)types of an untagged by-reference type, and confirming size specifications on elementary aliased objects. **************************************************************** From: Robert Dewar Sent: Saturday, October 2, 2004 7:55 PM Tucker Taft wrote: > THE 9X MODEL > > In the Ada 95 RM, we tried to make a clear distinction > between "type-related" representation aspects and > "subtype-specific" representation aspects. The idea > was that all objects of a given type would share the > same type-related representation aspects, but that individual > objects might differ in subtype-specific representation > aspects. For example, for a fixed-point type, the "small" > is type-related, whereas the range is subtype-specific > (and hence can vary from object to object for a given > fixed-point type). Perhaps "subtype-specific" might > better have been called "object-specific." Yes indeed, especially since the Ada 95 terminology invites you to think you can change the subtype specific attributes for subtypes :-) > > Size and Alignment are subtype-specific in Ada 95, > whereas things like array component-size, record > component layout, fixed small, are all type-related. > Subtype-specific aspects need not be the same between > objects, and in particular, need not be the same between > actual and formal. It's really too bad they cannot be specified for subtypes (the GNAT extensions are useful here!) > By by-reference parameter passing, if is even more clear > that type-related aspects need to match between actual > and formal. For subtype-specific aspects to differ, > it must mean that the formal can reasonably provide a > "view" of the actual that will not "corrupt" the actual. > For example, if the actual is an unconstrained record, > but the formal is constrained, there is no problem > so long as the incoming discriminants satisfy the > constraints of the formal. Similarly, it is fine if > the size of the actual differs from the size of the > formal, so long as the part that is actually touched > via the formal exists in the actual. It seems clear > that it should be possible to "touch" from the 'Address > of the formal up through formal'Size bits thereafter. > This means that the size of the actual should be greater > than or equal to the size of the formal (again, we > are talking only about by-reference parameter passing > here). Yes, that works for size, but not for alignment ... > Given the above analysis, it seems like reasonable choices > were made in Ada 95 in terms of making certain aspects > type-related, and others (Size and Alignment), subtype-specific > (or perhaps better, "specifiable for individual objects"). Note that this distinction was already implicit in Ada 83 from the rules about derived types and primitive subprograms > HOLES IN THE MODEL > ... > A second part of the model which was incomplete had to do with > conversions. If a type is a by-reference type, and the conversion > is used as an actual parameter, the conversion is required to > also be "by-reference" (see 6.2(10)). Based on the discussion > above, this means that an object's size must be no smaller than > any subtype or type to which it can be converted, if its type > is by-reference. Should also say something about alignment here (alignment is the twin sister of size, please always include both of them for all social occasions on which either of them are mentioned). > I hope the above is of some help in understanding the model > the 9X team was trying to use for representation, and also the two > holes in the model relating to aliased elementary objects > and by-reference conversion. Neither hole seems to imply > we need to disallow Size clauses on composite objects that specify an > overly generous size. There does seem to be a need to > require confirming Size and Alignment clauses on derived (sub)types > of an untagged by-reference type, and confirming size specifications > on elementary aliased objects. Thanks Tuck, a very helpful note, since I agree this confuses many people. I think this part of the model is in fact fine (though a bit incomplete in not allowing specification of sizes of subtypes) By the way, the mention I made of difficulties in Ada 95 from the handling of size relates to e.g. the decision to make Natural'Size be 31. This is a different decision than nearly all Ada 83 compilers and is in effect a fairly severe incompatibility, and because of the incompleteness mentioned above, it cannot easily be fixed. ****************************************************************