13.1 Operational and Representation Aspects
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
{8652/0009} [Two kinds of aspects of entities can be specified: representation aspects and operational aspects. Representation aspects affect how the types and other entities of the language are to be mapped onto the underlying machine. Operational aspects determine other properties of entities.]
Term entry: operational aspect — aspect that indicates a logical property of an entity, such as the precondition of a subprogram, or the procedure used to write a given type of object to a stream
Term entry: representation aspect — aspect that indicates how an entity is mapped onto the underlying hardware, for example the size or alignment of an object
[Either kind of aspect of an entity may be specified by means of an aspect_specification
(see 13.1.1), which is an optional element of most kinds of declarations and applies to the entity or entities being declared. Aspects may also be specified by certain other constructs occurring subsequent to the declaration of the affected entity: a representation aspect value may be specified by means of a representation item and an operational aspect value may be specified by means of an operational item.]
{8652/0009} There are six kinds of representation items: attribute_definition_clause
s for representation attributes, enumeration_representation_clause
s, record_representation_clause
s, at_clause
s, component_clause
s, and representation pragmas. [ 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). ]
{8652/0009} An operational item is an attribute_definition_clause
for an operational attribute.
{8652/0009} [An operational item or 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
.]
Language Design Principles
{8652/0009} Representation aspects are intended to refer to properties that need to be known before the compiler can generate code to create or access an entity. For instance, the size of an object needs to be known before the object can be created. Conversely, operational aspects are those that only need to be known before they can be used. For instance, how an object is read from a stream only needs to be known when a stream read is executed. Thus, representation aspects have stricter rules as to when they can be specified.
Confirming the value of an aspect should never change the semantics of the aspect. Thus Size = 8 (for example) means the same thing whether it was specified with a representation item or whether the compiler chose this value by default.
Term entry: aspect — specifiable property of an entityaspect_specification
on the declaration of the entity. Some aspects can be queried via attributes.
Syntax
2/1{8652/0009} aspect_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/1
{8652/0009} A representation pragma is allowed only at places where an aspect_clause
or compilation_unit
is allowed.
Name Resolution Rules
5/1{8652/0009} In an operational item or 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 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 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.
{8652/0009} This is a Name Resolution Rule, because we don't want an operational or 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 operational or representation items are for types or subtypes, and type and subtype names can't be overloaded.
{8652/0009} The visibility rules imply that the declaration has to occur before the operational or representation item.
{8652/0009} For objects, this implies that operational or representation items can be applied only to stand-alone objects.
Legality Rules
6/1{8652/0009} The local_name
of an aspect_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 or operational 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
.
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).
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.
A separate Legality Rule applies for component_clause
s. See 13.5.1, “Record Representation Clauses”.
The representation of an object 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, it is unspecified whether padding bits are read or updated in any given composite operation.
To be honest: Discontiguous representations are allowed, but the ones we're interested in here are generally contiguous sequences of bits. For a discontiguous representation, the size doesn't necessarily describe the “footprint” of the object in memory (that is, the amount of space taken in the address space for the object).
In the case of composite objects, we want the implementation to have the flexibility to either do operations component-by-component, or with a block operation covering all of the bits. We carefully avoid giving a preference in the wording. There is no requirement for the choice to be documented, either, as the implementation can make that choice based on many factors, and could make a different choice for different operations on the same object.
In the case of a properly aligned, contiguous object whose size is a multiple of the storage unit size, no other bits should be read or updated as part of operating on the object. We don't say this normatively because it would be difficult to normatively define “properly aligned” or “contiguous”.
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:
subtype S is Integer range 1..256;
type A is array(Natural range 1..4) of S
with Pack;
X : S := 3;
Y : A := (1, 2, 3, 4);
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).
Such tricks are not required, but are allowed.
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.
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 Pack, Component_Size, or record layout is specified.
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.
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.
A representation item directly specifies a representation aspect 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, Object_Size, and Alignment clauses) or type-related (all others).
To be honest: Some representation items directly specify more than one aspect.
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.
We don't need to say that an at_clause
or a mod_clause
specify separate aspects, because these are equivalent to attribute_definition_clause
s. See J.7, “At Clauses”, and J.8, “Mod Clauses”.
We give a default naming for representation aspects of representation pragmas so we don't have to do that for every pragma. Operational and representation attributes are given a default naming in 13.3. We don't want any anonymous aspects; that would make other rules more difficult to write and understand.
The following representation items are type-related:
enumeration_representation_clause
8.hrecord_representation_clause
8.i- Component_Size clause
- This paragraph was deleted.{8652/0009}
- Small clause
- Bit_Order clause
- Storage_Pool clause
- Storage_Size clause
- {8652/0009} Stream_Size clause
- {8652/0009} pragma Unchecked_Union
- This paragraph was deleted.{8652/0009}
- This paragraph was deleted.{8652/0009}
- Machine_Radix clause
- pragma Pack
- pragmas Import, Export, and Convention (when applied to a type)
- pragmas Atomic, Independent, and Volatile (when applied to a type)
- pragmas Atomic_Components, Independent_Components, and Volatile_Components (when applied to a type)
- pragma Discard_Names (when applied to an enumeration or tagged type)
- pragmas Priority and Interrupt_Priority (when applied to a task or protected type)
- pragma CPU (when applied to a task or protected type)
- pragma Dispatching_Domain
- pragma Relative_Deadline (when applied to a task or protected type)
The following representation items are subtype-specific:
The following representation items do not apply to subtypes, so they are neither type-related nor subtype-specific:
- Address clause (applies to objects and program units)
- Alignment clause (when applied to an object)
- Size clause (when applied to an object)
- pragma Inline (applies to subprograms)
- pragmas Import, Export, and Convention (when applied to anything other than a type)
- pragmas Atomic and Volatile (when applied to an object or a component)
- pragmas Atomic_Components, Independent_Components, and Volatile_Components (when applied to an array object)
- pragma Discard_Names (when applied to an exception)
- pragma Asynchronous (applies to procedures)
- pragma No_Return (applies to subprograms)
- pragmas Attach_Handler and Interrupt_Handler (apply to protected units)
- pragmas Priority and Interrupt_Priority (when applied to a subprogram)
- pragma CPU (when applied to a subprogram)
- pragma Relative_Deadline (when applied to a subprogram)
While an aspect_specification
is not a representation item, a similar categorization applies to the aspect that corresponds to each of these representation items. In addition, there are representation aspects that do not have associated representation items.
The following representation aspects that do not have associated representation items are type-related:
There are no subtype-specific representation aspects that do not have associated representation items.
The following representation aspects that do not have associated representation items also do not apply to subtypes, so they are neither type-related nor subtype-specific:
{8652/0009} An operational item directly specifies an operational aspect of the entity denoted by the local_name
, except in the case of a type-related operational item, whose local_name
shall denote a first subtype, and which directly specifies an aspect of the type of the subtype.
Aspects that can be specified for types and subtypes are also classified into type-related or subtype-specific aspects. Representation aspects that can be specified for types and subtypes are considered type-related unless specified otherwise. In contrast, the classification of operational aspects are given with the definition of the aspect. Type-related aspects have the same value for all subtypes of (a view of) a type[, while subtype-specific aspects may differ for different subtypes of the same type].
We talk about “type-related aspects”, which of course include both type-related representation aspects and type-related operational aspects. Aspects Size, Object_Size, and Alignment are subtype-specific, as that is specified above. All other representation aspects are either type-related or not specifiable for a type or subtype. Unlike representation aspects, there is no default for operational aspects; whether they are type-related or subtype-specific should be part of the definition of the aspect.
A representation item or operational item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.14).
{8652/0009} The fact that a representation item (or operational 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.
{8652/0009} A representation aspect of a subtype or type shall not be specified (whether by a representation item or an aspect_specification
) before the type is completely defined (see 3.11.1).
Unlike representation items, operational items can be specified on partial views. Since they don't affect the representation, the full declaration need not be known to determine their legality.
If a representation item, operational item, library unit pragma (see J.15), or aspect_specification
is given that directly specifies an aspect of an entity, then it is illegal to give another representation item, operational item, library unit pragma, or aspect_specification
that directly specifies the same aspect of the entity.
This rule applies to all aspects, not just those that have operational items or representation items. For instance, it applies to subtype predicates and type invariants.
To be honest: This rule is also intended to cover other ways to specify representation aspects, such as obsolescent pragma
Priority. Priority is not a representation pragma, and as such is neither a representation item nor an aspect_specification
. Regardless, giving both a pragma
Priority and an aspect_specification
for Priority is illegal. We didn't want to complicate the wording solely to support obsolescent features.
Unless otherwise specified, it is illegal to specify an operational or representation aspect of a generic formal parameter.
Specifying an aspect on a generic formal parameter implies an added contract for a generic unit. That contract needs to be defined via generic parameter matching rules, and, as aspects vary widely, that has to be done for each such aspect. Since most aspects do not need this complexity, we avoid the complexity by saying that such contract-forming aspect specifications are banned unless the rules defining them explicitly exist. Note that the method of specification does not matter: aspect_specification
s, representation items, and operational items are all covered by this rule.
A by-reference primitive is a user-defined primitive subprogram for a type T that has an access result designating type T, or that has a formal parameter that is an access parameter designating type T or is aliased and of type T. It is illegal to specify a nonconfirming type-related representation aspect for an untagged type T if it is derived from a by-reference type or inherits one or more by-reference primitives, or if one or more types have been derived from T prior to the specification of the aspect and type T is a by-reference type or defines one or more by-reference primitives that are inherited by these descendants.
{8652/0009} On the other hand, subtype-specific representation aspects may be specified for the first subtype of such a type, as can operational aspects.
The reason for forbidding specification of type-related representation aspects on untagged by-reference types is because a change of representation is impossible when passing by reference (to an inherited subprogram). (A by-reference object cannot be copied to change its representation.) The reason for forbidding specification of type-related representation aspects on untagged types with by-reference primitives is that access parameters, access results, and aliased parameters cannot be converted as part of invoking an inherited subprogram if the representation of the designated types might be different. This rule is not needed for tagged types, because other rules prevent a type-related representation aspect from changing the representation of the parent part; we want to allow specifying a type-related representation aspect on a type extension to specify aspects of the extension part. For example, specifying aspect Pack will cause packing of the extension part, but not of the parent part.
“By-reference type” usually cannot be used in Legality Rules, as it is privacy breaking. Our use here is privacy breaking, but we're stuck with it for compatibility reasons. Since representation aspects cannot be specified on partial views, privacy violations only can happen when a type includes a component of a private type. In that case, whether these rules are triggered depends on the full type of the private type — which is clearly privacy breaking.
{8652/0009} {8652/0011} If a type-related aspect is defined for the partial view of a type, then it has the same definition for the full view of the type, except for certain Boolean-valued operational aspects where the language specifies that the partial view can have the value False even when the full view has the value True. Type-related aspects [cannot be specified, and] are not defined for an incomplete view of a type. Representation aspects of a generic formal parameter are the same as those of the actual. Specification of a type-related representation aspect is not allowed for a descendant of a generic formal untagged type.
{8652/0009} Specifying representation aspects is allowed for types whose subcomponent types or index subtypes are generic formal types. Specifying operational aspects and subtype-related representation aspects is allowed on descendants of generic formal types.
Since it is not known whether a formal type has user-defined primitive subprograms, specifying type-related representation aspects for them is not allowed, unless they are tagged (in which case only the extension part is affected in any case).
Different views of an entity can have different representation and operational aspects. Most type-related aspects are the same for all views of a type; but specific aspects may have different rules. Similarly, different views of an object can have different representation aspects. For instance, an actual object passed by reference and the associated formal parameter may have different values for Alignment even though the formal parameter is merely a view of the actual object. This is necessary to maintain the language design principle that Alignments are always known at compile time.
For type-related aspects, the aspect of the partial view (if any) and full view have to be the same, with an exception for certain Boolean-valued aspects. The exception is intended for aspect Preelaborable_Initialization, where it would be wildly incompatible (as well as unfriendly) to require the (possibly implicit) state of the full view to be repeated explicitly on the partial view. Aspect Nonblocking has a similar rule for similar reasons, though it is a subtype-specific aspect.
The syntax of incomplete_type_declaration
s and formal_incomplete_type_declaration
s do not allow for an aspect_specification
. The prefix
of an attribute_reference
cannot name an incomplete type (see 3.10.1), so no attribute_definition_clause
can be used with an incomplete type. Similarly, the local_name
of a representation pragma cannot name an incomplete type, so no such pragmas can be used with an incomplete type.
The specification of the Size aspect 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.
{8652/0009} The specification of certain language-defined aspects is not required to be supported by all implementations; in such an implementation, the specification for such an aspect is illegal or raises an exception at run time.
There is an Implementation Permission below that allows an implementation to put restrictions on any representation aspect; this rule applies if that permission is used for an aspect. This rule only applies to an operational aspect if the aspect explicitly allows the aspect to not be supported.
A type_declaration
is illegal if it has one or more progenitors, and a nonconfirming value was specified for a representation aspect of an ancestor, and this conflicts with the representation of some other ancestor. The cases that cause conflicts are implementation defined.
The cases that cause conflicts between the representation of the ancestors of a type_declaration
.
This rule is needed because it may be the case that only the combination of types in a type declaration causes a conflict. Thus it is not possible, in general, to reject the original representation item or aspect_specification
. For instance:
package Pkg1 is
type Ifc is interface;
type T is tagged record
Fld : Integer;
end record;
for T use record
Fld at 0 range 0 .. Integer'Size - 1;
end record;
end Pkg1;
Assume the implementation uses a single tag with a default offset of zero, and that it allows the use of nondefault locations for the tag (and thus accepts representation items like the one above). The representation item will force a nondefault location for the tag (by putting a component other than the tag into the default location). Clearly, this package will be accepted by the implementation. However, other declarations could cause trouble. For instance, the implementation could reject:
with Pkg1;
package Pkg2 is
type NewT is new Pkg1.T and Pkg1.Ifc with null record;
end Pkg2;
because the declarations of T and Ifc have a conflict in their representation items. This is clearly necessary (it's hard to imagine how Ifc'Class could work with the tag at a location other than the one it is expecting without introducing distributed overhead).
Conflicts will usually involve implementation-defined attributes (for specifying the location of the tag, for instance), although the example above shows that doesn't have to be the case. For this reason, we didn't try to specify exactly what causes a conflict; it will depend on the implementation's implementation model and what representation aspects it allows to be changed.
An implementation can only use this rule to reject type_declaration
s where one of its ancestors had a nonconfirming representation value specified. An implementation must ensure that the default representations of ancestors cannot conflict.
When specifying an aspect that denotes a subprogram, the profile of the subprogram shall be mode conformant with the one required for the aspect, and the convention shall be Ada. Additional requirements are defined for particular aspects.
As well as applying to aspect_specification
s, this rule applies to attribute_definition_clause
s for those aspects that have associated attributes.
This rule implies, for example, that if one writes:
type T is ...
with Read => R;
R has to be a procedure with two parameters with the appropriate subtypes and modes as shown in 13.13.2.
Static Semantics
14/5If two subtypes statically match, then their subtype-specific aspects (for example, Size and Alignment) are the same.
This is necessary because we allow (for example) conversion between access types whose designated subtypes statically match. Note that most aspects (including the subtype-specific aspects Size and Alignment) may not be specified for a nonfirst subtype. The only language-defined exceptions to this rule are the Object_Size, Static_Predicate, and Dynamic_Predicate aspects.
Consider, for example:
package P1 is
subtype S1 is Integer range 0..2**16-1
with Size => 16; -- Illegal!
-- S1'Size would be 16 by default.
type A1 is access all S1;
X1: A1;
end P1;
14.d/5
package P2 is
subtype S2 is Integer range 0..2**16-1
with Size => 32; -- Illegal!
type A2 is access all S2;
X2: A2;
end P2;
14.e/3
procedure Q is
use P1, P2;
type Array1 is array(Integer range <>) of aliased S1
with Pack;
Obj1: Array1(1..100);
type Array2 is array(Integer range <>) of aliased S2
with Pack;
Obj2: Array2(1..100);
begin
X1 := Obj2(17)'Unchecked_Access;
X2 := Obj1(17)'Unchecked_Access;
end Q;
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.
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.
Hence, the above is illegal. Furthermore, the compiler is forbidden from choosing different Sizes by default, for the same reason.
The same issues apply to Alignment. Similar issues apply to Object_Size, Static_Predicate, and Dynamic_Predicate, but the chosen solution is different: explicit rules in 4.9.1 that ensure that the aspects are the same if specified.
The above static matching rule combined with the definition of static matching in 4.9.1 (after updating to add Object_Size) does not cause incompatibilities in existing Ada 2012 code that does not mention Object_Size. But it does constrain the implementation-defined value of Object_Size when it is not specified for a subtype; the above rule applies even in that case. (The effects noted in the example above would occur otherwise.)
We need this rule even though static matching explicitly excludes confirming values of Object_Size. That's because a general access type can designate any aliased object whose subtype statically matches the designated subtype. Since the Object_Size of a subtype determines the number of bits allocated for an aliased object of the subtype, if we allowed different Object_Sizes for statically matching subtypes, we'd be allowing the access type to designate objects with differing numbers of bits. That isn't going to work.
{8652/0040} A derived type inherits each type-related representation 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 representation 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 representation aspect is overridden by a subsequent aspect_specification
or representation item that specifies a different value for the same aspect of the type or subtype.
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.
If a representation item for the parent appears after the derived_type_definition
, then inheritance does not happen for that representation item.
If an inherited aspect is confirmed by an aspect_specification
or a later representation item for a derived type, the confirming specification does not override the inherited one. Thus the derived type has both a specified confirming value and an inherited nonconfirming representation value — this means that rules that apply only to nonconfirming representation values still apply to this type.
If an aspect was specified by an aspect_specification
and the parent type has not yet been frozen, then the inherited aspect might not yet have been resolved and evaluated. The implementation will need to have a mechanism to handle such an aspect.
{8652/0040} In contrast, whether type-related operational aspects are inherited by a derived type depends on each specific aspect; unless specified, an operational aspect is not inherited. When type-related operational aspects are inherited by a derived type, aspects that were directly specified by aspect_specification
s or operational items that are visible at any point within the immediate scope of the derived type declaration, or (in the case where the parent is derived) that were inherited by the parent type from the grandparent type, are inherited. An inherited operational aspect is overridden by an aspect_specification
or operational item that specifies the same aspect of the type.
As with representation items, if an operational item for the parent appears after the derived_type_definition
, then inheritance does not happen for that operational item.
Unlike representation aspects, operational aspects can be inherited at any point in the immediate scope, and can be overridden by aspect_specifications or operational items that occur at a point before or after the inheritance takes place.
When a type-related operational aspect is inherited, the rules for inheritance depend on the nature of the aspect (see 13.1.1). Unless otherwise specified for a given aspect, these rules are as follows:
- For an operational aspect that is a value, the inherited aspect has the same value;
- For an operational aspect that is a
name
: 15.5/5 - if the
name
denotes one or more primitive subprograms of the type, the inherited aspect is aname
that denotes the corresponding primitive subprogram(s) of the derived type;
A primitive subprogram that is declared after the end of the enclosing declaration list of a derived type (in particular, in the private part of a package if the derived type is declared in the package's visible part) is not the “corresponding primitive subprogram” in the sense of this rule. In a case like this, the corresponding primitive subprogram is actually the inherited subprogram. This doesn't make a difference for tagged types, because of the “dispatching” semantics used, which means a call on the inherited subprogram actually “reaches” the body of the overriding. But for untagged types, overriding an inherited subprogram of an untagged derived type in the private part is “too late” to have an effect on external uses of the primitive, since non-visible overridings are not generally reachable, and a call that only “sees” the inherited subprogram goes to the body of the parent's operation, effectively ignoring the private overriding. This same rule applies to aspects that denote an inherited subprogram of an untagged derived type — the private overriding is effectively ignored.
- otherwise, the inherited aspect is a
name
that denotes the same entity or entities as the original aspect; 15.7/5 - For an operational aspect that is an identifier specific to the aspect, the inherited aspect is the same identifier;
- For an operational aspect that is an
expression
or anaggregate
, the inherited aspect is a correspondingexpression
oraggregate
where eachname
, value, and identifier follows these same rules for inheritance.
Each aspect of representation of an entity is as follows:
- 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.
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.
- If an aspect of representation of an entity is not specified, it is chosen by default in an unspecified manner.
{8652/0009} Note that specifying a representation aspect can affect the semantics of the entity.
The rules forbid things like “for S'Base'Alignment use ...” and “for S'Base use record ...”.
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.
As noted previously, in the case of an object, the entity mentioned in this text is a specific view of an object. That means that only references to the same view of an object that has a specified value for a representation aspect R necessarily have that value for the aspect R. The value of the aspect R for a different view of that object is unspecified. In particular, this means that the representation values for by-reference parameters is unspecified; they do not have to be the same as those of the underlying object.
{8652/0040} If an operational aspect is specified for an entity (meaning that it is either directly specified or, if type-related or subtype-specific, inherited), then that aspect of the entity is as specified. Otherwise, the aspect of the entity has the default value for that aspect.[ For aspects that are neither type-related nor subtype-specific, the terms “specified” and “directly specified” are equivalent.]
An aspect_specification
or representation item that specifies a representation aspect that would have been chosen in the absence of the aspect_specification
or representation item is said to be confirming. The aspect value specified in this case is said to be a confirming representation aspect value. Other values of the aspect are said to be nonconfirming, as are the aspect_specification
s and representation items that specified them. Similarly, an aspect_specification
or operational item that specifies an operational aspect to be the same as the definition it would have by default is said to be confirming; otherwise it is nonconfirming.
As noted at the beginning of this subclause, we have a Language Design Principle that confirming aspects do not change the semantics. However, it is not a Language Design Principle principle that one can always specify a confirming aspect. Some aspects can never be confirmed. For instance, the default implementation of a stream-oriented attribute cannot be confirmed, as any subprogram that can be specified is not the same as the default subprogram, and thus is nonconfirming. Whether the effect is the same is not relevant for this purpose; it would be very difficult to formally define what it means to have the same effect. (Note that one can name any implementation for a stream-oriented attribute by using the associated attribute but specifying that by name would violate the circular aspect definition rule.) This is true for any implicitly composed aspect. Similarly, aspect Default_Value cannot be confirmed as the default is that there is no default value; any value that can be specified is not that.
Dynamic Semantics
19/1{8652/0009} For the elaboration of an aspect_clause
, any evaluable constructs within it are evaluated.
Elaboration of representation pragmas is covered by the general rules for pragmas in 2.8.
Implementation Permissions
20/3An implementation may interpret representation aspects in an implementation-defined manner. An implementation may place implementation-defined restrictions on the specification of representation aspects. A recommended level of support is defined for the specification of representation aspects 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”).
The interpretation of each representation aspect.
Any restrictions placed upon the specification of representation aspects.
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/3The recommended level of support for the specification of all representation aspects is qualified as follows:
- A confirming specification for a representation aspect should be supported.
To be honest: A confirming representation aspect value might not be possible for some entities. For instance, consider an unconstrained array. The size of such a type is implementation-defined, and might not actually be a representable value, or might not be static.
- An implementation is not required to support the specification for a representation aspect that contains nonstatic expressions, unless each nonstatic expression is a
name
that statically denotes a constant declared before the entity.
This is to avoid the following sort of thing:
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.
The above code should instead be written like this:
This allows the expression “Y” to be safely evaluated before X is created.
The constant could be a formal parameter of mode in.
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.
- An implementation is not required to support a specification for the Object_Size or 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.
We don't want to require that Object_Size or Size be supported on types that might have a representation not completely specified at compile time, or are represented discontiguously, or are represented differently for different constraints.
- An implementation is not required to support specifying a nonconfirming representation aspect value if it can 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.
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 it's feasible.)
We want subprograms to be able to assume the properties of the types of their parameters inside of subprograms. While many objects can be copied to allow this (and thus do not need limitations), aliased or by-reference objects cannot be copied (their memory location is part of their identity). Thus, 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.
- An implementation is not required to support specifying a nonconfirming representation aspect value if it can cause an aliased object of an elementary type to have a size other than that which would have been chosen by default.
Since all bits of elementary objects participate in operations, aliased objects must not have a different size than that assumed by users of the access type.
- An implementation is not required to support specifying a nonconfirming representation aspect value if it can 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.
Unlike elementary objects, there is no requirement that all bits of a composite object participate in operations. Thus, as long as the object is the same or larger in size than that expected by the access type, all is well.
This rule presumes that the implementation allocates an object of a size specified to be larger than the default size in such a way that access of the default size suffices to correctly read and write the value of the object.
- An implementation is not required to support specifying a nonconfirming subtype-specific representation aspect value for an indefinite or abstract subtype.
A type with the Pack aspect specified will typically not be packed so tightly as to disobey the above rules. A Component_Size clause or record_representation_clause
will typically be illegal if it disobeys the above rules. Atomic components have similar restrictions (see C.6, “Shared Variable Control”).
For purposes of these rules, the determination of whether specifying a representation aspect value for a type can 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 can be declared at some point.
The recommended level of support for all representation items should be followed.
NOTE Aspects that can be specified are defined throughout this document, and are summarized in K.1.
Incompatibilities With Ada 83
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 95. 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
Wording Changes from Ada 83
{8652/0009} 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 aspect_clause
. There are two references to “type representation clause” in RM83, both in Section 13; these have been reworded. Also, the representation_clause
has been renamed the aspect_clause
to reflect that it can be used to control more than just representation aspects.
{8652/0009} We have defined a new term “representation item”, which includes all representation clauses and representation pragmas, as well as component_clause
s. This is convenient because the rules are almost identical for all of them. We have also defined the new terms “operational item” and “operational aspects” in order to conveniently handle new types of specifiable entities.
All of the forcing occurrence stuff has been moved into its own subclause (see 13.14), and rewritten to use the term “freezing”.
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”.
RM83-13.1(10) tries to pretend that representation_clause
s don't affect the semantics of the program. One counter-example is the Small clause. Ada 95 has more counter-examples. We have noted the opposite above.
Some of the more stringent requirements are moved to C.2, “Required Representation Support”.
Extensions to Ada 95
Amendment Confirming representation items are defined, and the recommended level of support is now that they always be supported.
Wording Changes from Ada 95
{8652/0009} Corrigendum: Added operational items in order to eliminate unnecessary restrictions and permissions on stream attributes. As part of this, representation_clause
was renamed to aspect_clause
.
{8652/0009} Corrigendum: Added wording to say that the partial and full views have the same operational and representation aspects. Ada 2005 extends this to cover all views, including the incomplete view.
{8652/0040} Corrigendum: Changed operational items to have inheritance specified for each such aspect.
Added wording to allow the rejection of types with progenitors that have conflicting representation items.
The description of the representation of an object was clarified (with great difficulty reaching agreement). Added wording to say that representation items on aliased and by-reference objects never need be supported if they would not be implementable without distributed overhead even if other recommended level of support says otherwise. This wording matches the rules with reality.
Added wording so that inheritance depends on whether operational items are visible rather than whether they occur before the declaration (we don't want to look into private parts). Also limited operational inheritance to untagged types to avoid anomalies with private extensions (this is not incompatible, no existing operational attribute used this capability). Also added wording to clearly define that subprogram inheritance works like derivation of subprograms.
Incompatibilities With Ada 2005
Specifying a language-defined aspect for a generic formal parameter is no longer allowed. Most aspects could not be specified on these anyway; moreover, this was not allowed in Ada 83, so it is unlikely that compilers are supporting this as a capability (and it is not likely that they have a consistent definition of what it means if it is allowed). Thus, we expect this to occur rarely in existing programs. Note: This correction is repealed in Ada 2022, as a number of aspects are allowed on formals in that later language version.
Wording Changes from Ada 2005
Defined that overriding of a representation aspect only happens for a nonconfirming representation item. This prevents a derived type from being considered to have only a confirming representation item when the value would be nonconfirming if given on a type that does not inherit any aspects of representation. This change just eliminates a wording confusion and ought not change any behavior.
Defined a default naming for representation aspects that are representation pragmas.
Added text ensuring that the rules for representational and operational items also apply appropriately to aspect_specification
s; generalized operational aspects so that they can be defined for entities other than types. Any extensions are documented elsewhere.
Rewrote many rules to be in terms of "specifying a representation aspect" rather than use of a "representation item". This better separates how an aspect is specified from what rules apply to the value of the aspect.
Incompatibilities With Ada 2012
Corrigendum: Added a rule that makes it illegal to specify a representation value after a type is derived from an untagged by-reference type. This restriction is incompatible, but since the implementation would have had to copy an object that does not allow copying in order to change the representation for any implicit or explicit conversion between the original and the derived type, it is unlikely that any program could exist without running into internal compiler errors or bogus results.
Added a rule preventing self-referencing representation or operational aspects. This is technically incompatible, but since the similar representation or operational item has been illegal since they've existed, and they don't make any sense, it's unlikely that any implementation accepted them or that they appear in any program.
Added a rule preventing giving a representation aspect on a partial view. Since this has always been prohibited for other kinds of representation items, it's unlikely that any implementation accepted them or that they appear in any program.
Extensions to Ada 2012
It is now allowed to specify type-related representation aspects for an untagged derived type that has primitive operations, so long as the type is not a by-reference type.
Wording Changes from Ada 2012
Corrigendum: Clarified that an aspect (any aspect) can be specified only once for an entity, no matter what means of specifying it are used.
13.1.1 Aspect Specifications
1/3[Certain representation or operational aspects of an entity may be specified as part of its declaration using an aspect_specification
, rather than using a separate representation or operational item.] The declaration with the aspect_specification
is termed the associated declaration.
Syntax
2/3aspect_specification
::=
with aspect_mark
[=> aspect_definition
] {,
aspect_mark
[=> aspect_definition
] }
3/3
aspect_mark
::=
aspect_identifier
['Class]
4/5
aspect_definition
::=
name
| expression
| identifier
| aggregate
| global_aspect_definition
Language Design Principles
The aspect_specification
is an optional element in most kinds of declarations. Here is a list of all kinds of declarations and an indication of whether or not they allow aspect clauses, and in some cases a short discussion of why (* = allowed, NO = not allowed). Kinds of declarations with no indication are followed by their subdivisions (which have indications).
basic_declaration
type_declaration
full_type_declaration
type declaration syntax*
task_type_declaration
*
protected_type_declaration
*
incomplete_type_declaration
-- NO
-- Incomplete types do not have aspects by definition,
-- , so it would not make sense to allow specifying them.
private_type_declaration
*
private_extension_declaration
*
subtype_declaration
*
object_declaration
object declaration syntax*
single_task_declaration
*
single_protected_declaration
*
number_declaration
-- NO
iterated_component_association
-- NO
subprogram_declaration
*
abstract_subprogram_declaration
*
null_procedure_declaration
*
expression_function_declaration
*
package_declaration
* -- via package_specification
renaming_declaration
*
-- There are no language-defined aspects that may be specified
-- on renames, but implementations might support some.
exception_declaration
*
generic_declaration
generic_subprogram_declaration
*
generic_package_declaration
* -- via package_specification
generic_instantiation
*enumeration_literal_specification
-- NO
-- The syntax would be ambiguous if this was supported directly.discriminant_specification
*
-- There are no language-defined aspects that may be specified
-- on discriminants, but implementations might support some.component_declaration
*loop_parameter_specification
-- NOchunk_specification
-- NO - the enclosing construct has an aspect_specification
iterator_specification
-- NOiterator_parameter_specification
-- NOparameter_specification
*
-- There are no language-defined aspects that may be specified
-- on parameters, but implementations might support some.subprogram_body
* -- - but language-defined aspects only if there is no explicit specificationentry_declaration
*entry_index_specification
*
-- There are no language-defined aspects that may be specified
-- on an entry index, but implementations might support some.subprogram_body_stub
* -- - but language-defined aspects only if there is no explicit specificationchoice_parameter_specification
-- NOgeneric_formal_parameter_declaration
*
formal_object_declaration
*
formal_type_declaration
formal_complete_type_declaration
*
formal_incomplete_type_declaration
-- NO - see incomplete_type_declaration
above
formal_subprogram_declaration
formal_concrete_subprogram_declaration
*
formal_abstract_subprogram_declaration
*
formal_package_declaration
*extended_return_object_declaration
*
-- There are no language-defined aspects that may be specified
-- on return objects, but implementations might support some.
-- We also allow aspect_specification
s on all kinds of bodies, but there are no language-defined aspects
-- that may be specified on a body. These are allowed for implementation-defined aspects.
-- See above for subprogram bodies and stubs (as these can be declarations).package_body
*task_body
*protected_body
*entry_body
*package_body_stub
*task_body_stub
*protected_body_stub
*
Syntactically, aspect_specification
s generally are located at the end of declarations. When a declaration is all in one piece such as a null_procedure_declaration
, object_declaration
, or generic_instantiation
the aspect_specification
goes at the end of the declaration; it is then more visible and less likely to interfere with the layout of the rest of the structure. However, we make an exception for program units (other than subprogram specifications) and bodies, in which the aspect_specification
goes before the is. In these cases, the entity could be large and could contain other declarations that also have aspect_specification
s, so it is better to put the aspect_specification
toward the top of the declaration. (Some aspects – such as Pure – also affect the legality of the contents of a unit, so it would be annoying to only see those after reading the entire unit.)
Name Resolution Rules
5/5An aspect_mark
identifies an aspect of the entity defined by the associated declaration (the associated entity); the aspect denotes an object, a value, an expression, an aggregate
, a subprogram, or some other kind of entity. If the aspect_mark
identifies:
- an aspect that denotes an object, the
aspect_definition
shall be aname
. The expected type for thename
is the type of the identified aspect of the associated entity; 7/3 - an aspect that is a value or an expression, the
aspect_definition
shall be anexpression
. The expected type for theexpression
is the type of the identified aspect of the associated entity; 7.1/5 - an aspect that is an
aggregate
, the aspect definition shall be anexpression
that is anaggregate
, with the form of theaggregate
determined by the identified aspect;
The only requirement here is that the expression
is syntactically an aggregate
; there is no requirement that it resolve to some particular type or even that it should resolve like an aggregate
. Each aspect that uses an aggregate
is responsible for specifying how the choice(s), component(s), and other contents of the aggregate
are resolved and interpreted.
- an aspect that denotes a subprogram, the
aspect_definition
shall be aname
; the expected profile for thename
is the profile required for the aspect of the associated entity; 9/3 - an aspect that denotes some other kind of entity, the
aspect_definition
shall be aname
, and the name shall resolve to denote an entity of the appropriate kind; 10/3 - an aspect that is given by an identifier specific to the aspect, the
aspect_definition
shall be anidentifier
, and theidentifier
shall be one of the identifiers specific to the identified aspect.
The usage names in an aspect_definition
associated with a declaration [ are not resolved at the point of the associated declaration, but rather] are resolved at the end of the immediately enclosing declaration list, or in the case of the declaration of a library unit, at the end of the visible part of the entity.
If an aspect_specification
is not associated with a declaration (instead being part of a statement
or expression
), then it is resolved when the associated construct is resolved.
If the associated declaration is for a subprogram, entry, or access-to-subprogram type, the names of the formal parameters are directly visible within the aspect_definition
, as are certain attributes, as specified elsewhere in this document for the identified aspect. If the associated declaration is a type_declaration
, within the aspect_definition
the names of any visible components, protected subprograms, and entries are directly visible, and the name of the first subtype denotes the current instance of the type (see 8.6). If the associated declaration is a subtype_declaration
, within the aspect_definition
the name of the new subtype denotes the current instance of the subtype.
Legality Rules
13/3If the first freezing point of the associated entity comes before the end of the immediately enclosing declaration list, then each usage name in the aspect_definition
shall resolve to the same entity at the first freezing point as it does at the end of the immediately enclosing declaration list.
An expression
or name
that causes freezing of an entity shall not occur within an aspect_specification
that specifies a representation or operational aspect of that entity.
The rule prevents an aspect of an entity from depending (directly or indirectly) on properties of the entity itself.
This check needs to be deferred at least to the freezing of the entity (as the aspect_definition
is not resolved until then), and might be accomplished during the freezing of the aspect_definition
(since it is closely related). Keep in mind that multiple other entities could be involved.
At most one occurrence of each aspect_mark
is allowed within a single aspect_specification
. The aspect identified by the aspect_mark
shall be an aspect that can be specified for the associated entity (or view of the entity defined by the associated declaration).
This rule prevents multiple specifications in the same aspect_specification
. Rules in 13.1 prevent multiple specifications in different aspect_specification
s (on different views of the same type, for instance), or between operational or representation items and an aspect_specification
.
The aspect_definition
associated with a given aspect_mark
may be omitted only when the aspect_mark
identifies an aspect of a boolean type, in which case it is equivalent to the aspect_definition
being specified as True.
If the aspect_mark
includes 'Class, then the associated entity shall be a tagged type or a primitive subprogram of a tagged type.
Unless otherwise specified for a specific aspect, a language-defined aspect cannot be specified on a renaming_declaration
or a generic_formal_parameter_declaration
.
Implementation-defined aspects can be allowed on these, of course; the implementation will need to define the semantics. In addition, the language does not define default aspect matching rules for generic formals; only the handful of aspects allowed on formals have such rules. Therefore, the implementation will need to define actual type matching rules for any aspects allowed on formal types.
Unless specified otherwise, a language-defined aspect shall not be specified in an aspect_specification
given on a completion of a program unit.
Most language-defined aspects (for example, preconditions) are intended to be available to callers, and specifying them on a body that has a separate declaration hides them from callers. Specific language-defined aspects may allow this, but they have to do so explicitly (by defining an alternative Legality Rule), and provide any needed rules about visibility. Note that this rule does not apply to implementation-defined aspects, so implementers need to carefully define whether such aspects can be applied to bodies and stubs, and what happens if they are specified on both the declaration and body of a unit.
If an aspect of a derived type is inherited from an ancestor type and has the boolean value True, the inherited value shall not be overridden to have the value False for the derived type, unless otherwise specified in this document.
Most boolean-valued language-defined aspects are associated with a representation pragma. The existing rules for such pragmas assume that the aspect cannot be removed. For instance, if a type T is declared to be Atomic, then all descendants of T are also Atomic. This rule ensures that remains the case when using the aspect notation instead of pragmas.
This definition leaves holes for Boolean aspects that can be specified on non-first subtypes. Such aspects (for instance, Nonblocking) must have their own rules (that is, "otherwise specify" rules) that define the effects of inheriting from subtypes (both first subtypes and nonfirst subtypes).
If a given aspect is type-related and inherited, then within an aspect_definition
for the aspect, if a name
resolves to denote multiple visible subprograms, all or none of the denoted subprograms shall be primitives of the associated type.
Certain type-related aspects are defined to be nonoverridable; all such aspects are inherited by derived types according to the rules given in 13.1. Any legality rule associated with a nonoverridable aspect is re-checked for the derived type, if the derived type is not abstract. Certain type-related and subtype-specific aspects are defined to be additive; such aspects are not inherited, but they can apply to the types derived from, or the subtypes based on, the original type or subtype, as defined for each such aspect. Finally, certain type-related aspects are implicitly composed; such aspects are not inherited, but rather a default implementation for a derived type is provided, as defined for each such aspect, based on that of its parent type, presuming the aspect for the parent type is available where the derived type is declared, plus those of any new components added as part of a type extension.
If a nonoverridable aspect is directly specified for a type T, then any explicit specification of that aspect for any descendant of T (other than T itself) shall be confirming. In the case of an aspect that is a name
, this means that the specified name
shall match the inherited aspect in the sense that it shall denote the same declarations as would the inherited name
. Similarly, for an aspect that is an expression
or an aggregate
, confirming means the defining expression
is fully conformant (see 6.3.1) with the defining expression
for the inherited aspect, with the added rule that an identifier that is specific to the aspect is the same as the corresponding identifier in the inherited aspect.
If a full type has a partial view, and a given nonoverridable aspect is allowed for both the full view and the partial view, then the given aspect for the partial view and the full view shall be the same: the aspect shall be directly specified only on the partial view; if the full type inherits the aspect, then a matching definition shall be specified (directly or by inheritance) for the partial view.
In order to enforce these rules without breaking privacy, we cannot allow a private type that could have a particular overridable aspect to have a hidden definition of that aspect. There is no problem if the private type does not allow the aspect (as the aspect could not be specified on descendants in that case).
If a type inherits a nonoverridable aspect from multiple ancestors, the value of the aspect inherited from any given ancestor shall be confirming of the values inherited from all other ancestors.
If more than one progenitor of a type T specifies a nonoverridable aspect, they all have to specify the same or matching values for that aspect. Otherwise, we'd have two different values for the aspect that depend on which progenitor we inherit from.
In addition to the places where Legality Rules normally apply (see 12.3), these rules about nonoverridable aspects also apply in the private part of an instance of a generic unit.
We don't need an assume-the-worst rule for most nonoverridable aspects as they only work on tagged types and deriving from formal tagged types is not allowed in generic bodies. In the case of Implicit_Dereference, a derivation in a generic body does not cause problems (the ancestor necessarily cannot have the aspect, else specifying the aspect would be illegal), as there could be no place with visibility on both aspects. In the case of Max_Entry_Queue_Length, it is only allowed on task and protected types, and on entries, and there are not formal versions of any of those things. In the case of No_Controlled_Parts, we defined an assume-the-worst rule with the aspect.
A list of all nonoverridable aspects can be found in the index, under “nonoverridable aspect”.
Static Semantics
19/3Depending on which aspect is identified by the aspect_mark
, an aspect_definition
specifies:
- a
name
that denotes a subprogram, object, or other kind of entity; 21/5 - an
expression
(other than anaggregate
), which is either evaluated to produce a single value, or which (as in a precondition) is to be evaluated at particular points during later execution; 22/5 - an
identifier
specific to the aspect; or 22.1/5 - an
aggregate
, which is positional or named, and is composed of elements of any of these four kinds of constructs.
The identified aspect of the associated entity, or in some cases, the view of the entity defined by the declaration, is as specified by the aspect_definition
(or by the default of True when boolean). Whether an aspect_specification
applies to an entity or only to the particular view of the entity defined by the declaration is determined by the aspect_mark
and the kind of entity. The following aspects are view specific:
- An aspect specified on an
object_declaration
; 25/3 - An aspect specified on a
subprogram_declaration
; 26/3 - An aspect specified on a
renaming_declaration
.
All other aspect_specification
s are associated with the entity, and apply to all views of the entity, unless otherwise specified in this document.
If the aspect_mark
includes 'Class (a class-wide aspect), then, unless specified otherwise for a particular class-wide aspect:
- if the associated entity is a tagged type, the specification applies to all descendants of the type;
- if the associated entity is a primitive subprogram of a tagged type T, the specification applies to the corresponding primitive subprogram of all descendants of T.
All specifiable operational and representation attributes may be specified with an aspect_specification
instead of an attribute_definition_clause
(see 13.3).
The name of the aspect is the same as that of the attribute (see 13.3), so the aspect_mark
is the attribute_designator
of the attribute.
Unless specified otherwise, all of the requirements for specifying a particular aspect with an attribute_definition_clause
also apply to an aspect_specification
for the aspect. These are enforced at the freezing point of the entity. For example, when specifying the Size aspect of a subtype, the expression has to be a static expression with an integer type and a nonnegative value, all of the recommended level of support requirements apply if Annex C is supported (see C.2), and so on.
Some aspects are defined to be library unit aspects. Library unit aspects are of type Boolean. The expression specifying a library unit aspect shall be static. Library unit aspects are defined for all program units, but shall be specified only for library units. Notwithstanding what this document says elsewhere, the expression of a library unit aspect is resolved and evaluated at the point where it occurs in the aspect_specification
[, rather than the first freezing point of the associated unit].
The name of the aspect is the same as that of the pragma (see 13.1), so the aspect_mark
is the name of the pragma.
In addition, other operational and representation aspects not associated with specifiable attributes or representation pragmas may be specified, as specified elsewhere in this document.
This paragraph was deleted.
If a Legality Rule or Static Semantics rule only applies when a particular aspect has been specified, the aspect is considered to have been specified only when the aspect_specification
or attribute_definition_clause
is visible (see 8.3) at the point of the application of the rule.
Some rules only apply when an aspect has been specified (for instance, an indexable type is one that has aspect Variable_Indexing specified). In order to prevent privacy breaking, this can only be true when the specification of the aspect is visible. In particular, if the Variable_Indexing aspect is specified on the full view of a private type, the private type is not considered an indexable type.
Alternative legality and semantics rules may apply for particular aspects, as specified elsewhere in this document.
Dynamic Semantics
37/5At the freezing point of the associated entity, the aspect_specification
is elaborated. When appearing in a construct other than a declaration, an aspect_specification
is elaborated as part of the execution of the construct. The elaboration of the aspect_specification
consists of the elaboration of each aspect_definition
in an arbitrary order. The elaboration of an aspect_definition
includes the evaluation of any name
or expression
that is part of the aspect_definition
unless the part is itself an expression. If the corresponding aspect (or part thereof) represents an expression (as in a precondition), the elaboration of that part has no effect; the expression is evaluated later at points within the execution as specified elsewhere in this document for the particular aspect.
Implementation Permissions
38/3Implementations may support implementation-defined aspects. The aspect_specification
for an implementation-defined aspect may use an implementation-defined syntax for the aspect_definition
, and may follow implementation-defined legality and semantics rules.
The intent is to allow implementations to support aspects that are defined, for example, by a subtype_indication
rather than an expression
or a name
. We chose not to try to enumerate all possible aspect_definition
syntaxes, but to give implementations maximum freedom.
Implementation-defined aspects, including the syntax for specifying such aspects and the legality rules for such aspects.
An implementation may ignore the specification of an unrecognized aspect; if an implementation chooses to ignore such an aspect specification (as opposed to rejecting it), then it has no effect on the semantics of the program except for possibly (and this is not required) the rejection of syntax errors within the aspect_definition
.
Identifying the textual end of an aspect_definition
for an unrecognized aspect may be challenging, particularly if the syntax for the unrecognized aspect's aspect_definition
is implementation-defined. It is not specified how an implementation might accomplish this. Note that an implementation is never required to be able to do this; if an aspect_definition
for an unrecognized aspect is problematic in any way, then it can always be rejected (as opposed to being ignored).
Extensions to Ada 2005
Inconsistencies With Ada 2012
Names of protected subprograms and entries are now directly visible in an aspect of a type declaration. This was always intended to be the case, but it was omitted from the Reference Manual by an editing error. In the unlikely case that a parameterless protected function has the same name and type as an entity used in a type invariant expression, the meaning would change from the outside entity which would now be hidden by the protected function. It is much more likely that a conflict (itself rather unlikely) would cause a resolution failure.
Incompatibilities With Ada 2012
Corrigendum: Added a clarification that aspects that correspond to library unit pragmas are resolved and evaluated immediately. This is incompatible, as a reference to an entity defined after the aspect will now be illegal. However, this would have required retroactive enforcement of such aspects, which is a new capability not available from the associated pragma, and moreover no known Ada 2012 implementation has ever allowed late evaluation of such aspects. As such, there should be no practical incompatibility.
Parameters of access-to-subprogram types are now visible in aspect specifications. This can be incompatible if some entity with the same name as a parameter is used in an existing aspect specification. We believe that all such aspects require either static expressions or a subprogram that is statically denoted; since a parameter can be neither of these and hides everything else, all such cases will be caught at compile-time. In addition, we expect such cases to be very rare.
Extensions to Ada 2012
An aspect can be an unresolved aggregate
, these can be used to specify a list of entities, or to set a group of different but related properties with a single aspect.
Wording Changes from Ada 2012
Corrigendum: Clarified the wording so that the restriction against language-defined aspects on subprogram completions includes completions that are expressions functions and null procedures.
Corrigendum: Added a definition of nonoverridable aspects. This is necessary to prevent generic contract problems with formal derived types.
Added entry_body
to the list of entities that don't allow any language-defined aspects. This was an oversight in which allowed aspect_specification
s on an entry_body
in the first place.
Added a rule so that the a nonoverridable aspect has to be the same for every ancestor of a type.
Clarified when elaboration and resolution of aspect_specification
s not associated with a declaration occur.
Revised the rules about entities that cannot have specified language-defined aspects. The body portion of the rule was changed to a general prohibition on specifying language-defined aspects on completions (this allows specifying aspects on bodies that act as a declaration, and eliminates the list of entities, which was a maintenance nightmare). Then the remaining entities (renamings and generic formal parameters) were revised to allow specific aspects, since Nonblocking (see 9.5), as well as Pre and Post, are now allowed on generic formal parameters.
Added a description of additive and implicitly composed aspects in order to explain the different inheritance mechanisms used by existing aspects.