Version 1.1 of ais/ai-10291.txt
!standard 13.01 (7) 04-12-07 AI95-00291-02/02
!standard 13.01 (18.1/1)
!standard 13.01 (21)
!standard 13.01 (24)
!standard 13.02 (06)
!standard 13.03 (18)
!standard 13.03 (22/1)
!standard 13.03 (23)
!standard 13.03 (24)
!standard 13.03 (25)
!standard 13.03 (26)
!standard 13.03 (28)
!standard 13.03 (43)
!standard 13.03 (56)
!class binding interpretation 04-10-05
!status work item 04-11-20
!status received 04-10-05
!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 (ignoring extra space at the end of a composite
object).
!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 (ignoring extra space at the end of a composite
object).
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
Replace 13.1(7) with the following:
The representation of an objects consists of a certain number of bits
(the size of the object). For an object of an elementary type, these
are the bits that are normally read or updated by the machine code
when loading, storing, or operating-on the value of the object. For an
object of a composite type, these are the bits reserved for this object,
and include bits occupied by subcomponents of the object. If the
size of an object is greater than that of its subtype, the additional
bits are padding bits. For an elementary object, these padding
bits are normally read and updated along with the others. For a composite
object, composite operations are generally defined in terms of
operations on components, so padding bits might not be read or updated
in any given composite operation, depending on the implementation.
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
4 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, when the alignment
attribute of the subtype of such an object is nonzero, at an address
that is not an integral multiple of that alignment.
* An implementation need not support a nonconfirming representation item
if it could cause an aliased object of an elementary type to have a
size other than that which would have been chosen by default.
* An implementation need not support a nonconfirming representation item
if it could cause an aliased object of a composite type, or an object
whose type is by-reference, to have a size smaller than that which would
have been chosen by default.
* 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
is based solely on the properties of the type itself, not on any
available information about how the type is used. in particular, it
presumes that minimally aligned objects of this type might be 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 such a component need not be be aligned according
to the Alignment of the component's subtype; in particular
it need not be allocated on a storage element boundary.
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.
!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.
Note that we distinguish between elementary types and composite
types. Allowing for extra space at the end of a composite object is not
considered to impose a burden on implementations, even for
aliased or by-reference types. This is particularly important for
record types because there are no standard rules for choosing the
size of a record subtype. For example, some implementations round
up to a multiple of the alignment of the record subtype when determining
the subtype size, while others do not, deferring the padding
to the allocation of particular objects or arrays of such objects.
We want to allow users to pad out the size of an external record
object so as to match the expectations of a different compiler or
a different language, or some hardware device or coprocessor, even if
other objects of the type are not always given this padded size.
We don't reiterate the allowed restriction on alignment and size
for aliased and by-reference objects in each RM paragraph where it
might apply. Implementations can refer to the new overarching
permission to justify the restriction in any given compiler error
message.
!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.
****************************************************************
Questions? Ask the ACAA Technical Agent