Contents Index Previous Next
13.5.1 Record Representation Clauses
1
[A
record_representation_clause
specifies the storage representation of records and record extensions,
that is, the order, position, and size of components (including discriminants,
if any).
{bit field: See record_representation_clause}
]
Language Design Principles
1.a
It should be feasible for an implementation
to use negative offsets in the representation of composite types. However,
no implementation should be forced to support negative offsets. Therefore,
negative offsets should be disallowed in record_representation_clauses.
Syntax
2
record_representation_clause
::=
for first_subtype_local_name use
record [
mod_clause]
{
component_clause}
end record;
3
component_clause
::=
component_local_name at position range first_bit ..
last_bit;
4
position
::= static_expression
5
first_bit
::= static_simple_expression
6
last_bit
::= static_simple_expression
6.a
Reason: First_bit
and last_bit need to be simple_expression
instead of expression for the same reason
as in range (see 3.5,
``Scalar Types'').
Name Resolution Rules
7
{expected type (component_clause
expressions) [partial]} {expected
type (position) [partial]} {expected
type (first_bit) [partial]} {expected
type (last_bit) [partial]} Each
position,
first_bit, and
last_bit
is expected to be of any integer type.
7.a
Ramification: These need
not have the same integer type.
Legality Rules
8
The first_subtype_local_name
of a record_representation_clause
shall denote a specific nonlimited record or record extension subtype.
8.a
Ramification: As for all
type-related representation items, the local_name
is required to denote a first subtype.
9
If the component_local_name
is a direct_name, the local_name
shall denote a component of the type. For a record extension, the component
shall not be inherited, and shall not be a discriminant that corresponds
to a discriminant of the parent type. If the component_local_name
has an attribute_designator, the
direct_name of the local_name
shall denote either the declaration of the type or a component of the
type, and the attribute_designator
shall denote an implementation-defined implicit component of the type.
10
The position,
first_bit, and last_bit
shall be static expressions. The value of position
and first_bit shall be nonnegative.
The value of last_bit shall be no
less than first_bit - 1.
10.a
Ramification: A component_clause
such as ``X at 4 range 0..-1;'' is allowed if X can fit
in zero bits.
11
At most one component_clause
is allowed for each component of the type, including for each discriminant
(component_clauses may be given
for some, all, or none of the components). Storage places within a component_list
shall not overlap, unless they are for components in distinct variants
of the same variant_part.
12
A name that denotes a component of a type is
not allowed within a record_representation_clause
for the type, except as the component_local_name
of a component_clause.
12.a
Reason:
It might seem strange to make the record_representation_clause
part of the declarative region, and then disallow mentions of the components
within almost all of the record_representation_clause.
The alternative would be to treat the component_local_name
like a formal parameter name in a subprogram call (in terms of visibility).
However, this rule would imply slightly different semantics, because
(given the actual rule) the components can hide other declarations. This
was the rule in Ada 83, and we see no reason to change it. The following,
for example, was and is illegal:
12.b
type T is
record
X : Integer;
end record;
X : constant := 31; -- Same defining name as the component.
for T use
record
X at 0 range 0..X; -- Illegal!
end record;
12.c
The component X hides the named
number X throughout the record_representation_clause.
Static Semantics
13
A
record_representation_clause
(without the
mod_clause) specifies the
layout. The storage place attributes (see
13.5.2)
are taken from the values of the
position,
first_bit, and
last_bit
expressions after normalizing those values so that
first_bit
is less than Storage_Unit.
13.a
Ramification: For example,
if Storage_Unit is 8, then ``C at 0 range 24..31;'' defines
C'Position = 3, C'First_Bit = 0, and C'Last_Bit = 7. This is true of
machines with either bit ordering.
13.b
A component_clause
also determines the value of the Size attribute of the component, since
this attribute is related to First_Bit and Last_Bit.
14
[A record_representation_clause
for a record extension does not override the layout of the parent part;]
if the layout was specified for the parent type, it is inherited by the
record extension.
Implementation Permissions
15
An implementation may generate implementation-defined
components (for example, one containing the offset of another component).
An implementation may generate names that denote such implementation-defined
components; such names shall be implementation-defined attribute_references.
An implementation may allow such implementation-defined names to be used
in record_representation_clauses.
An implementation can restrict such component_clauses
in any manner it sees fit.
15.a
Implementation defined: Implementation-defined
components.
15.b
Ramification: Of course,
since the semantics of implementation-defined attributes is implementation
defined, the implementation need not support these names in all situations.
They might be purely for the purpose of component_clauses,
for example. The visibility rules for such names are up to the implementation.
15.c
We do not allow such component
names to be normal identifiers -- that would constitute blanket permission
to do all kinds of evil things.
15.d
Discussion: {dope}
Such implementation-defined components are known
in the vernacular as ``dope.'' Their main purpose is for storing offsets
of components that depend on discriminants.
16
If a record_representation_clause
is given for an untagged derived type, the storage place attributes for
all of the components of the derived type may differ from those of the
corresponding components of the parent type, even for components whose
storage place is not specified explicitly in the record_representation_clause.
16.a
Reason: This is clearly
necessary, since the whole record may need to be laid out differently.
Implementation Advice
17
{recommended
level of support (record_representation_clause) [partial]}
The recommended level of support for
record_representation_clauses
is:
18
- An implementation should support storage places that can
be extracted with a load, mask, shift sequence of machine code, and set
with a load, shift, mask, store sequence, given the available machine
instructions and run-time model.
19
- A storage place should be supported if its size is equal
to the Size of the component subtype, and it starts and ends on a boundary
that obeys the Alignment of the component subtype.
20
- If the default bit ordering applies to the declaration
of a given type, then for a component whose subtype's Size is less than
the word size, any storage place that does not cross an aligned word
boundary should be supported.
20.a
Reason: The above recommendations
are sufficient to define interfaces to most interesting hardware. This
causes less implementation burden than the definition in ACID, which
requires arbitrary bit alignments of arbitrarily large components. Since
the ACID definition is neither enforced by the ACVC, nor supported by
all implementations, it seems OK for us to weaken it.
21
- An implementation may reserve a storage place for the tag
field of a tagged type, and disallow other components from overlapping
that place.
21.a
Ramification: Similar permission
for other dope is not granted.
22
- An implementation need not support a component_clause
for a component of an extension part if the storage place is not after
the storage places of all components of the parent type, whether or not
those storage places had been specified.
22.a
Reason: These restrictions
are probably necessary if block equality operations are to be feasible
for class-wide types. For block comparison to work, the implementation
typically has to fill in any gaps with zero (or one) bits. If a ``gap''
in the parent type is filled in with a component in a type extension,
then this won't work when a class-wide object is passed by reference,
as is required.
23
12 If no component_clause
is given for a component, then the choice of the storage place for the
component is left to the implementation. If component_clauses
are given for all components, the record_representation_clause
completely specifies the representation of the type and will be obeyed
exactly by the implementation.
23.a
Ramification: The visibility
rules prevent the name of a component of the type from appearing in a
record_representation_clause at
any place except for the component_local_name
of a component_clause. However,
since the record_representation_clause
is part of the declarative region of the type declaration, the component
names hide outer homographs throughout.
23.b/1
{8652/0009}
A record_representation_clause cannot be
given for a protected type, even though protected types, like record types,
have components. The primary reason for this rule is that there is likely to
be too much dope in a protected type -- entry queues, bit maps for barrier values,
etc. In order to control the representation of the user-defined components,
simply declare a record type, give it a record_representation_clause,
and give the protected type one component whose type is the record type. Alternatively,
if the protected object is protecting something like a device register, it makes
more sense to keep the thing being protected outside the protected object (possibly
with a pointer to it in the protected object), in order to keep implementation-defined
components out of the way.
Examples
24
Example of specifying
the layout of a record type:
25
Word : constant := 4; -- storage element is byte, 4 bytes per word
26
type State is (A,M,W,P);
type Mode is (Fix, Dec, Exp, Signif);
27
type Byte_Mask is array (0..7) of Boolean;
type State_Mask is array (State) of Boolean;
type Mode_Mask is array (Mode) of Boolean;
28
type Program_Status_Word is
record
System_Mask : Byte_Mask;
Protection_Key : Integer range 0 .. 3;
Machine_State : State_Mask;
Interrupt_Cause : Interruption_Code;
Ilc : Integer range 0 .. 3;
Cc : Integer range 0 .. 3;
Program_Mask : Mode_Mask;
Inst_Address : Address;
end record;
29
for Program_Status_Word use
record
System_Mask at 0*Word range 0 .. 7;
Protection_Key at 0*Word range 10 .. 11; -- bits 8,9 unused
Machine_State at 0*Word range 12 .. 15;
Interrupt_Cause at 0*Word range 16 .. 31;
Ilc at 1*Word range 0 .. 1; -- second word
Cc at 1*Word range 2 .. 3;
Program_Mask at 1*Word range 4 .. 7;
Inst_Address at 1*Word range 8 .. 31;
end record;
30
for Program_Status_Word'Size use 8*System.Storage_Unit;
for Program_Status_Word'Alignment use 8;
31
13 Note on the example:
The record_representation_clause
defines the record layout. The Size clause guarantees that (at least)
eight storage elements are used for objects of the type. The Alignment
clause guarantees that aliased, imported, or exported objects of the
type will have addresses divisible by eight.
Wording Changes from Ada 83
31.a
31.b
We have clarified that implementation-defined
component names have to be in the form of an attribute_reference
of a component or of the first subtype itself; surely Ada 83 did not
intend to allow arbitrary identifiers.
31.c
The RM83-13.4(7) wording incorrectly
allows components in non-variant records to overlap. We have corrected
that oversight.
Contents Index Previous Next Legal