[Home] [Prev] [Next] [Index]

13.1 Representation Items

13.1 Representation Items

1
There are three kinds of representation items: representation_clauses, component_clauses, and representation pragmas. [Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). Representation items also specify other specifiable properties of entities. A representation item applies to an entity identified by a local_name, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a compilation.]

Syntax

2
representation_clause ::= attribute_definition_clause
      | enumeration_representation_clause
      | record_representation_clause
      | at_clause

3
local_name ::= direct_name
      | direct_name'attribute_designator
      | library_unit_name

4
A representation pragma is allowed only at places where a representation_clause or compilation_unit is allowed.

Name Resolution Rules

5
In a representation item, if the local_name is a direct_name, then it shall resolve to denote a declaration (or, in the case of a pragma, one or more declarations) that occurs immediately within the same declarative_region as the representation item. If the local_name has an attribute_designator, then it shall resolve to denote an implementation-defined component (see 13.5.1) or a class-wide type implicitly declared immediately within the same declarative_region as the representation item. A local_name that is a library_unit_name (only permitted in a representation pragma) shall resolve to denote the library_item that immediately precedes (except for other pragmas) the representation pragma.

5.a
Reason: This is a Name Resolution Rule, because we don't want a representation item for X to be ambiguous just because there's another X declared in an outer declarative region. It doesn't make much difference, since most representation items are for types or subtypes, and type and subtype names can't be overloaded.

5.b
Ramification: The visibility rules imply that the declaration has to occur before the representation item.

5.c
For objects, this implies that representation items can be applied only to stand-alone objects.

Legality Rules

6
The local_name of a representation_clause or representation pragma shall statically denote an entity (or, in the case of a pragma, one or more entities) declared immediately preceding it in a compilation, or within the same declarative_part, package_specification, task_definition, protected_definition, or record_definition as the representation item. If a local_name denotes a [local] callable entity, it may do so through a [local] subprogram_renaming_declaration [(as a way to resolve ambiguity in the presence of overloading)]; otherwise, the local_name shall not denote a renaming_declaration.

6.a
Ramification: The "statically denote" part implies that it is impossible to specify the representation of an object that is not a stand-alone object, except in the case of a representation item like pragma Atomic that is allowed inside a component_list (in which case the representation item specifies the representation of components of all objects of the type). It also prevents the problem of renamings of things like "P.all" (where P is an access-to-subprogram value) or "E(I)" (where E is an entry family).

6.b
The part about where the denoted entity has to have been declared appears twice - once as a Name Resolution Rule, and once as a Legality Rule. Suppose P renames Q, and we have a representation item in a declarative_part whose local_name is P. The fact that the representation item has to appear in the same declarative_part as P is a Name Resolution Rule, whereas the fact that the representation item has to appear in the same declarative_part as Q is a Legality Rule. This is subtle, but it seems like the least confusing set of rules.

6.c
Discussion:  A separate Legality Rule applies for component_clauses. See 13.5.1, "Record Representation Clauses".

7
The representation of an object consists of a certain number of bits (the size of the object). 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. This includes some padding bits, when the size of the object is greater than the size of its subtype. Such padding bits are considered to be part of the representation of the object, rather than being gaps between objects, if these bits are normally read and updated.

7.a
To be honest: Discontiguous representations are allowed, but the ones we're interested in here are generally contiguous sequences of bits.

7.b
Ramification: Two objects with the same value do not necessarily have the same representation. For example, an implementation might represent False as zero and True as any odd value. Similarly, two objects (of the same type) with the same sequence of bits do not necessarily have the same value. For example, an implementation might use a biased representation in some cases but not others:

7.c
subtype S is Integer range 1..256;
type A is array(Natural range 1..4) of S;
pragma Pack(A);
X : S := 3;
Y : A := (1, 2, 3, 4);

7.d
The implementation might use a biased-by-1 representation for the array elements, but not for X. X and Y(3) have the same value, but different representation: the representation of X is a sequence of (say) 32 bits: 0...011, whereas the representation of Y(3) is a sequence of 8 bits: 00000010 (assuming a two's complement representation).

7.e
Such tricks are not required, but are allowed.

7.f
Discussion:  The value of any padding bits is not specified by the language, though for a numeric type, it will be much harder to properly implement the predefined operations if the padding bits are not either all zero, or a sign extension.

7.g
Ramification: For example, suppose S'Size = 2, and an object X is of subtype S. If the machine code typically uses a 32-bit load instruction to load the value of X, then X'Size should be 32, even though 30 bits of the value are just zeros or sign-extension bits. On the other hand, if the machine code typically masks out those 30 bits, then X'Size should be 2. Usually, such masking only happens for components of a composite type for which packing, Component_Size, or record layout is specified.

7.h
Note, however, that the formal parameter of an instance of Unchecked_Conversion is a special case. Its Size is required to be the same as that of its subtype.

7.i
Note that we don't generally talk about the representation of a value. A value is considered to be an amorphous blob without any particular representation. An object is considered to be more concrete.

8
A representation item directly specifies an aspect of representation of the entity denoted by the local_name, except in the case of a type-related representation item, whose local_name shall denote a first subtype, and which directly specifies an aspect of the subtype's type. A representation item that names a subtype is either subtype-specific (Size and Alignment clauses) or type-related (all others). [Subtype-specific aspects may differ for different subtypes of the same type.]

8.a
To be honest: Type-related and subtype-specific are defined likewise for the corresponding aspects of representation.

8.b
To be honest: Some representation items directly specify more than one aspect.

8.c
Discussion:  For example, a pragma Export specifies the convention of an entity, and also specifies that it is exported.

8.d
Ramification: Each specifiable attribute constitutes a separate aspect. An enumeration_representation_clause specifies the coding aspect. A record_representation_clause (without the mod_clause) specifies the record layout aspect. Each representation pragma specifies a separate aspect.

8.e
Reason: We don't need to say that an at_clause or a mod_clause specify separate aspects, because these are equivalent to attribute_definition_clauses. See J.7, "At Clauses", and J.8, "Mod Clauses".

8.f
Ramification: The following representation items are type-related:

8.g ·   
enumeration_representation_clause
8.h ·   
record_representation_clause
8.i ·   
Component_Size clause
8.j ·   
External_Tag clause
8.k ·   
Small clause
8.l ·   
Bit_Order clause
8.m ·   
Storage_Pool clause
8.n ·   
Storage_Size clause
8.o ·   
Read clause
8.p ·   
Write clause
8.q ·   
Input clause
8.r ·   
Output clause
8.s ·   
Machine_Radix clause
8.t ·   
pragma Pack
8.u ·   
pragmas Import, Export, and Convention (when applied to a type)
8.v ·   
pragmas Atomic and Volatile (when applied to a type)
8.w ·   
pragmas Atomic_Components and Volatile_Components (when applied to an array type)
8.x ·   
pragma Discard_Names (when applied to an enumeration or tagged type)

8.y
The following representation items are subtype-specific:

8.z ·   
Alignment clause (when applied to a first subtype)
8.aa ·   
Size clause (when applied to a first subtype)

8.bb
The following representation items do not apply to subtypes, so they are neither type-related nor subtype-specific:

8.cc ·   
Address clause (applies to objects and program units)
8.dd ·   
Alignment clause (when applied to an object)
8.ee ·   
Size clause (when applied to an object)
8.ff ·   
pragmas Import, Export, and Convention (when applied to anything other than a type)
8.gg ·   
pragmas Atomic and Volatile (when applied to an object or a component)
8.hh ·   
pragmas Atomic_Components and Volatile_Components (when applied to an array object)
8.ii ·   
pragma Discard_Names (when applied to an exception)
8.jj ·   
pragma Asynchronous (applies to procedures)

9
A representation item that directly specifies an aspect of a subtype or type shall appear after the type is completely defined (see 3.11.1), and before the subtype or type is frozen (see 13.14). If a representation item is given that directly specifies an aspect of an entity, then it is illegal to give another representation item that directly specifies the same aspect of the entity.

9.a
Ramification: The fact that a representation item that directly specifies an aspect of an entity is required to appear before the entity is frozen prevents changing the representation of an entity after using the entity in ways that require the representation to be known.

10
For an untagged derived type, no type-related representation items are allowed if the parent type is a by-reference type, or has any user-defined primitive subprograms.

10.a
Ramification: On the other hand, subtype-specific representation items may be given for the first subtype of such a type.

10.b
Reason: The reason for forbidding type-related representation items on untagged by-reference types is because a change of representation is impossible when passing by reference (to an inherited subprogram). The reason for forbidding type-related representation items on untagged types with user-defined primitive subprograms was to prevent implicit change of representation for type-related aspects of representation upon calling inherited subprograms, because such changes of representation are likely to be expensive at run time. Changes of subtype-specific representation attributes, however, are likely to be cheap. This rule is not needed for tagged types, because other rules prevent a type-related representation item from changing the representation of the parent part; we want to allow a type-related representation item on a type extension to specify aspects of the extension part. For example, a pragma Pack will cause packing of the extension part, but not of the parent part.

11
Representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type.

11.a
Ramification: Representation items are allowed for types whose subcomponent types or index subtypes are generic formal types.

11.b
Reason: Since it is not known whether a formal type has user-defined primitive subprograms, specifying type-related representation items for them is not allowed, unless they are tagged (in which case only the extension part is affected in any case).

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.

13
A representation item that is not supported by the implementation is illegal, or raises an exception at run time.

Static Semantics

14
If two subtypes statically match, then their subtype-specific aspects (Size and Alignment) are the same.

14.a
Reason: This is necessary because we allow (for example) conversion between access types whose designated subtypes statically match. Note that it is illegal to specify an aspect (including a subtype-specific one) for a nonfirst subtype.

14.b
Consider, for example:

14.c
package P1 is
    subtype S1 is Integer range 0..2**16-1;
    for S1'Size use 16; --Illegal!
        --S1'Size would be 16 by default.
    type A1 is access S1;
    X1: A1;
end P1;

14.d
package P2 is
    subtype S2 is Integer range 0..2**16-1;
    for S2'Size use 32; --Illegal!
    type A2 is access S2;
    X2: A2;
end P2;

14.e
procedure Q is
    use P1, P2;
    type Array1 is array(Integer range <>) of aliased S1;
    pragma Pack(Array1);
    Obj1: Array1(1..100);
    type Array2 is array(Integer range <>) of aliased S2;
    pragma Pack(Array2);
    Obj2: Array2(1..100);
begin
    X1 := Obj2(17)'Access;
    X2 := Obj1(17)'Access;
end Q;

14.f
Loads and stores through X1 would read and write 16 bits, but X1 points to a 32-bit location. Depending on the endianness of the machine, loads might load the wrong 16 bits. Stores would fail to zero the other half in any case.

14.g
Loads and stores through X2 would read and write 32 bits, but X2 points to a 16-bit location. Thus, adjacent memory locations would be trashed.

14.h
Hence, the above is illegal. Furthermore, the compiler is forbidden from choosing different Sizes by default, for the same reason.

14.i
The same issues apply to Alignment.

15
A derived type inherits each type-related aspect of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype.

15.a
To be honest: 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.

15.b
Ramification: If a representation item for the parent appears after the derived_type_declaration, then inheritance does not happen for that representation item.

16
Each aspect of representation of an entity is as follows:

17 ·
If the aspect is specified for the entity, meaning that it is either directly specified or inherited, then that aspect of the entity is as specified, except in the case of Storage_Size, which specifies a minimum.

17.a
Ramification: This rule implies that queries of the aspect return the specified value.  For example, if the user writes "for X'Size use 32;", then a query of X'Size will return 32.

18 ·
If an aspect of representation of an entity is not specified, it is chosen by default in an unspecified manner.

18.a
Ramification: Note that representation_clauses can affect the semantics of the entity.

18.b
The rules forbid things like "for S'Base'Alignment use ..." and "for S'Base use record ...".

18.c
Discussion:  The intent is that implementations will represent the components of a composite value in the same way for all subtypes of a given composite type. Hence, Component_Size and record layout are type-related aspects.

Dynamic Semantics

19
For the elaboration of a representation_clause, any evaluable constructs within it are evaluated.

19.a
Ramification: Elaboration of representation pragmas is covered by the general rules for pragmas in Section 2.

Implementation Permissions

20
An implementation may interpret aspects of representation in an implementation-defined manner. An implementation may place implementation-defined restrictions on representation items. A recommended level of support is specified for representation items and related features in each subclause. These recommendations are changed to requirements for implementations that support the Systems Programming Annex (see C.2, "Required Representation Support").

20.a
Implementation defined:  The interpretation of each aspect of representation.

20.b
Implementation defined:  Any restrictions placed upon representation items.

20.c
Ramification: Implementation-defined restrictions may be enforced either at compile time or at run time. There is no requirement that an implementation justify any such restrictions. They can be based on avoiding implementation complexity, or on avoiding excessive inefficiency, for example.

Implementation Advice

21
The recommended level of support for all representation items is qualified as follows:

22 ·
An implementation need not support representation items containing nonstatic expressions, except that an implementation should support a representation item for a given entity if each nonstatic expression in the representation item is a name that statically denotes a constant declared before the entity.

22.a
Reason: This is to avoid the following sort of thing:

22.b
X : Integer := F(...);
Y : Address := G(...);
for X'Address use Y;

22.c
In the above, we have to evaluate the initialization expression for X before we know where to put the result. This seems like an unreasonable implementation burden.

22.d
The above code should instead be written like this:

22.e
Y : constant Address := G(...);
X : Integer := F(...);
for X'Address use Y;

22.f
This allows the expression "Y" to be safely evaluated before X is created.

22.g
The constant could be a formal parameter of mode in.

22.h
An implementation can support other nonstatic expressions if it wants to.  Expressions of type Address are hardly ever static, but their value might be known at compile time anyway in many cases.

23 ·
An implementation need not support a specification for the Size for a given composite subtype, nor the size or storage place for an object (including a component) of a given composite subtype, unless the constraints on the subtype and its composite subcomponents (if any) are all static constraints.

24 ·
An aliased component, or a component whose type is by-reference, should always be allocated at an addressable location.

24.a
Reason: The intent is that access types, type System.Address, and the pointer used for a by-reference parameter should be implementable as a single machine address - bit-field pointers should not be required. (There is no requirement that this implementation be used - we just want to make sure its feasible.)

24.b
Implementation Note: Note that the above rule does not apply to types that merely allow by-reference parameter passing; for such types, a copy typically needs to be made at the call site when a bit-aligned component is passed as a parameter.

24.c
Ramification: A pragma Pack will typically not pack so tightly as to disobey the above rule. A Component_Size clause or record_representation_clause will typically by illegal if it disobeys the above rule. Atomic components have similar restrictions (see C.6, "Shared Variable Control").

Incompatibilities With Ada 83

24.d
It is now illegal for a representation item to cause a derived by-reference type to have a different record layout from its parent. This is necessary for by-reference parameter passing to be feasible. This only affects programs that specify the representation of types derived from types containing tasks; most by-reference types are new to Ada 9X. For example, if A1 is an array of tasks, and A2 is derived from A1, it is illegal to apply a pragma Pack to A2.

Extensions to Ada 83

24.e
Ada 9X allows additional representation_clauses for objects.

Wording Changes From Ada 83

24.f
The syntax rule for type_representation_clause is removed; the right-hand side of that rule is moved up to where it was used, in representation_clause. There are two references to "type representation clause" in RM83, both in Section 13; these have been reworded.

24.g
We have defined a new term "representation item," which includes both representation_clauses and representation pragmas, as well as component_clauses. This is convenient because the rules are almost identical for all three.

24.h
All of the forcing occurrence stuff has been moved into its own subclause (see 13.14), and rewritten to use the term "freezing".

24.i
RM83-13.1(10) requires implementation-defined restrictions on representation items to be enforced at compile time. However, that is impossible in some cases. If the user specifies a junk (nonstatic) address in an address clause, and the implementation chooses to detect the error (for example, using hardware memory management with protected pages), then it's clearly going to be a run-time error. It seems silly to call that "semantics" rather than "a restriction."

24.j
RM83-13.1(10) tries to pretend that representation_clauses don't affect the semantics of the program. One counter-example is the Small clause. Ada 9X has more counter-examples. We have noted the opposite above.

24.k
Some of the more stringent requirements are moved to C.2, "Required Representation Support".



[Home] [Prev] [Next] [Index]

documentation@rational.com
Copyright © 1993-1998, Rational Software Corporation.   All rights reserved.