Section 13: Representation Issues 1/1 {8652/0009} {AI95-00137-01} [This section describes features for querying and controlling certain aspects of entities and for interfacing to hardware.] Wording Changes from Ada 83 1.a The clauses of this section have been reorganized. This was necessary to preserve a logical order, given the new Ada 95 semantics given in this section. 13.1 Operational and Representation Items 0.1/1 {8652/0009} {AI95-00137-01} [Representation and operational items can be used to specify aspects of entities. Two kinds of aspects of entities can be specified: aspects of representation and operational aspects. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. Operational items specify other properties of entities.] 1/1 {8652/0009} {AI95-00137-01} {representation item} {representation pragma [distributed]} {pragma, representation [distributed]} There are six kinds of representation items: attribute_definition_clauses for representation attributes, enumeration_representation_clauses, record_representation_clauses, at_clauses, component_clauses, 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). ] 1.1/1 {8652/0009} {AI95-00137-01} An {operational item} operational item is an attribute_definition_clause for an operational attribute. 1.2/1 {8652/0009} {AI95-00137-01} [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 1.a.1/1 {8652/0009} {AI95-00137-01} Aspects of representation 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, aspects of representation have stricter rules as to when they can be specified. 1.a.2/2 {AI95-00291-02} Confirming the value of an aspect with an operational or representation item 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. Syntax 2/1 {8652/0009} {AI95-00137-01} 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} {AI95-00137-01} A representation pragma is allowed only at places where an aspect_clause or compilation_unit is allowed. {representation_clause: See aspect_clause} Name Resolution Rules 5/1 {8652/0009} {AI95-00137-01} 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. 5.a/1 Reason: {8652/0009} {AI95-00137-01} 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. 5.b/1 Ramification: {8652/0009} {AI95-00137-01} The visibility rules imply that the declaration has to occur before the operational or representation item. 5.c/1 {8652/0009} {AI95-00137-01} For objects, this implies that operational or representation items can be applied only to stand-alone objects. Legality Rules 6/1 {8652/0009} {AI95-00137-01} 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. 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/2 {AI95-00291-02} {representation of an object} {size (of an object)} 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. {padding bits} For an elementary object, these padding bits are normally read and updated along with the others. For a composite object, padding bits might not be read or updated in any given composite operation, depending on the implementation. 7.a/2 To be honest: {AI95-00291-02} {contiguous representation [partial]} {discontiguous representation [partial]} 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). 7.a.1/2 Discussion: {AI95-00291-02} 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. 7.a.2/2 {AI95-00291-02} 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". 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 {aspect of representation [distributed]} {representation aspect} {directly specified (of an aspect of representation of an entity)} 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. {type-related (representation item) [distributed]} {subtype-specific (of a representation item) [distributed]} {type-related (aspect) [distributed]} {subtype-specific (of an aspect) [distributed]} 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/1 * This paragraph was deleted.{8652/0009} {AI95-00137-01} 8.k * Small clause 8.l * Bit_Order clause 8.m * Storage_Pool clause 8.n * Storage_Size clause 8.n.1/2 * {AI95-00270-01} Stream_Size clause 8.o/1 * This paragraph was deleted.{8652/0009} {AI95-00137-01} 8.p/1 * This paragraph was deleted.{8652/0009} {AI95-00137-01} 8.q/1 * This paragraph was deleted.{8652/0009} {AI95-00137-01} 8.r/1 * This paragraph was deleted.{8652/0009} {AI95-00137-01} 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) 8.kk/2 * {AI95-00414-01} pragma No_Return (applies to procedures) 8.1/1 {8652/0009} {AI95-00137-01} An operational item directly specifies an operational aspect of the type of the subtype denoted by the local_name. The local_name of an operational item shall denote a first subtype. An operational item that names a subtype is type-related. {operational aspect [distributed]} {directly specified (of an operational aspect of an entity)} {type-related (operational item) [distributed]} {type-related (aspect) [partial]} 8.ll/1 Ramification: {8652/0009} {AI95-00137-01} The following operational items are type-related: 8.mm/1 * External_Tag clause 8.nn/1 * Read clause 8.oo/1 * Write clause 8.pp/1 * Input clause 8.qq/1 * Output clause 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/1 Ramification: {8652/0009} {AI95-00137-01} The fact that a representation item (or operational item, see next paragraph) 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. 9.1/1 {8652/0009} {AI95-00137-01} An operational item that directly specifies an aspect of a type shall appear before the type is frozen (see 13.14). If an operational item is given that directly specifies an aspect of a type, then it is illegal to give another operational item that directly specifies the same aspect of the type. 9.a.1/1 Ramification: 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. 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/1 Ramification: {8652/0009} {AI95-00137-01} On the other hand, subtype-specific representation items may be given for the first subtype of such a type, as can operational items. 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/2 {8652/0009} {AI95-00137-01} {8652/0011} {AI95-00117-01} {AI95-00326-01} Operational and representation aspects of a generic formal parameter are the same as those of the actual. Operational and representation aspects are the same for all views of a type. A type-related representation item is not allowed for a descendant of a generic formal untagged type. 11.a/1 Ramification: {8652/0009} {AI95-00137-01} Representation items are allowed for types whose subcomponent types or index subtypes are generic formal types. Operational items and subtype-related representation items are allowed on descendants of 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). 11.c/2 Ramification: {AI95-00326-01} All views of a type, including the incomplete and partial views, have the same operational and representation aspects. That's important so that the properties don't change when changing views. While most aspects are not available for an incomplete view, we don't want to leave any holes by not saying that they are the same. 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/1 {8652/0009} {AI95-00137-01} A representation or operational item that is not supported by the implementation is illegal, or raises an exception at run time. 13.1/2 {AI95-00251-01} A type_declaration is illegal if it has one or more progenitors, and a representation item applies to an ancestor, and this representation item conflicts with the representation of some other ancestor. The cases that cause conflicts are implementation defined. 13.a/2 Implementation defined: The cases that cause conflicts between the representation of the ancestors of a type_declaration. 13.b/2 Reason: 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. For instance: 13.c/2 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; 13.d/2 Assume the implementation uses a single tag with a default offset of zero, and that it allows the use of non-default locations for the tag (and thus accepts representation items like the one above). The representation item will force a non-default 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: 13.e/2 with Pkg1; package Pkg2 is type NewT is new Pkg1.T and Pkg1.Ifc with null record; end Pkg2; 13.f/2 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). 13.g/2 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 items it allows. 13.h/2 Implementation Note: An implementation can only use this rule to reject type_declarations where one its ancestors has a representation item. An implementation must ensure that the default representations of ancestors cannot conflict. Static Semantics 14 If two subtypes statically match, then their subtype-specific aspects (Size and Alignment) are the same. {statically matching (effect on subtype-specific aspects) [partial]} 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/1 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 all S1; X1: A1; end P1; 14.d/1 package P2 is subtype S2 is Integer range 0..2**16-1; for S2'Size use 32; -- Illegal! type A2 is access all S2; X2: A2; end P2; 14.e/1 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)'Unchecked_Access; X2 := Obj1(17)'Unchecked_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/1 {8652/0040} {AI95-00108-01} A derived type inherits each type-related aspect of representation 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 representation 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_definition, then inheritance does not happen for that representation item. 15.1/2 {8652/0040} {AI95-00108-01} {AI95-00444-01} In contrast, whether operational aspects are inherited by an untagged derived type depends on each specific aspect. [Operational aspects are never inherited for a tagged type.] When operational aspects are inherited by an untagged derived type, aspects that were directly specified by operational items that are visible at the point 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 a subsequent operational item that specifies the same aspect of the type. 15.b.1/1 Ramification: 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. 15.b.2/2 Discussion: {AI95-00444-01} Only untagged types inherit operational aspects. Inheritance from tagged types causes problems, as the different views can have different visibility on operational items - potentially leading to operational items that depend on the view. We want aspects to be the same for all views. Untagged types don't have this problem as plain private types don't have ancestors, and thus can't inherit anything. In addition, it seems unlikely that we'll need inheritance for tagged types, as usually we'll want to incorporate the parent's operation into a new one that also handles any extension components. 15.2/2 {AI95-00444-01} When an aspect that is a subprogram is inherited, the derived type inherits the aspect in the same way that a derived type inherits a user-defined primitive subprogram from its parent (see 3.4). 15.c/2 Reason: This defines the parameter names and types, and the needed implicit conversions. 16 Each aspect of representation of an entity is as follows: 17 * {specified (of an aspect of representation of an entity)} 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 * {unspecified [partial]} If an aspect of representation of an entity is not specified, it is chosen by default in an unspecified manner. 18.a/1 Ramification: {8652/0009} {AI95-00137-01} Note that representation items 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. 18.1/1 {8652/0040} {AI95-00108-01} {specified (of an operational aspect of an entity)} If an operational aspect is specified for an entity (meaning that it is either directly specified or inherited), then that aspect of the entity is as specified. Otherwise, the aspect of the entity has the default value for that aspect. 18.2/2 {AI95-00291-02} A representation item that specifies an aspect of representation that would have been chosen in the absence of the representation item is said to be confirming.{confirming (representation item)} Dynamic Semantics 19/1 {8652/0009} {AI95-00137-01} {elaboration (aspect_clause) [partial]} For the elaboration of an aspect_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. {recommended level of support [distributed]} 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. 20.c.1/1 {8652/0009} {AI95-00137-01} There is no such permission for operational aspects. Implementation Advice 21 {recommended level of support (with respect to nonstatic expressions) [partial]} The recommended level of support for all representation items is qualified as follows: 21.1/2 * {AI95-00291-02} A confirming representation item should be supported. 21.a.1/2 To be honest: A confirming representation item 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. 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/2 * {AI95-00291-02} An implementation need not support a nonconfirming representation item if it could cause an aliased object or an object of a by-reference type to be allocated at a nonaddressable location or, when the alignment attribute of the subtype of such an object is nonzero, at an address that is not an integral multiple of that alignment. 24.a/1 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 it's feasible.) 24.b/2 Implementation Note: {AI95-00291-02} 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. 25/2 * {AI95-00291-02} An implementation need not support a nonconfirming representation item if it could cause an aliased object of an elementary type to have a size other than that which would have been chosen by default. 25.a/2 Reason: 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. 26/2 * {AI95-00291-02} An implementation need not support a nonconfirming representation item if it could cause an aliased object of a composite type, or an object whose type is by-reference, to have a size smaller than that which would have been chosen by default. 26.a/2 Reason: 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. 26.b/2 Ramification: 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. 27/2 * {AI95-00291-02} An implementation need not support a nonconfirming subtype-specific representation item specifying an aspect of representation of an indefinite or abstract subtype. 27.a/2 Reason: Aspects of representations are often not well-defined for such types. 27.b/2 Ramification: {AI95-00291-02} A pragma Pack will typically not pack 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"). 28/2 {AI95-00291-02} For purposes of these rules, the determination of whether a representation item applied to a type could cause an object to have some property is based solely on the properties of the type itself, not on any available information about how the type is used. In particular, it presumes that minimally aligned objects of this type might be declared at some point. 28.a/2 Implementation Advice: The recommended level of support for all representation items should be followed. Incompatibilities With Ada 83 28.b {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 28.c/1 {8652/0009} {AI95-00137-01} {extensions to Ada 83} Ada 95 allows additional aspect_clauses for objects. Wording Changes from Ada 83 28.d/1 {8652/0009} {AI95-00137-01} 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. 28.e/2 {8652/0009} {AI95-00137-01} {AI95-00114-01} We have defined a new term "representation item," which includes all representation clauses and representation pragmas, as well as component_clauses. 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. 28.f All of the forcing occurrence stuff has been moved into its own subclause (see 13.14), and rewritten to use the term "freezing". 28.g 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." 28.h 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 95 has more counter-examples. We have noted the opposite above. 28.i Some of the more stringent requirements are moved to C.2, " Required Representation Support". Extensions to Ada 95 28.j/2 {AI95-00291-02} {extensions to Ada 95} Amendment Correction: Confirming representation items are defined, and the recommended level of support is now that they always be supported. Wording Changes from Ada 95 28.k/2 {8652/0009} {AI95-00137-01} 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. 28.l/2 {8652/0009} {AI95-00137-01} {AI95-00326-01} 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. 28.m/2 {8652/0040} {AI95-00108-01} Corrigendum: Changed operational items to have inheritance specified for each such aspect. 28.n/2 {AI95-00251-01} Added wording to allow the rejection of types with progenitors that have conflicting representation items. 28.o/2 {AI95-00291-02} 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. 28.p/2 {AI95-00444-01} 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). Limited operational inheritance to untagged types to avoid anomolies 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. 13.2 Pragma Pack 1 [A pragma Pack specifies that storage minimization should be the main criterion when selecting the representation of a composite type.] Syntax 2 The form of a pragma Pack is as follows: 3 pragma Pack(first_subtype_local_name); Legality Rules 4 The first_subtype_local_name of a pragma Pack shall denote a composite subtype. Static Semantics 5 {representation pragma (Pack) [partial]} {pragma, representation (Pack) [partial]} {aspect of representation (packing) [partial]} {packing (aspect of representation)} {packed} A pragma Pack specifies the packing aspect of representation; the type (or the extension part) is said to be packed. For a type extension, the parent part is packed as for the parent type, and a pragma Pack causes packing only of the extension part. 5.a Ramification: The only high level semantic effect of a pragma Pack is independent addressability (see 9.10, "Shared Variables"). Implementation Advice 6 If a type is packed, then the implementation should try to minimize storage allocated to objects of the type, possibly at the expense of speed of accessing components, subject to reasonable complexity in addressing calculations. 6.a.1/2 Implementation Advice: Storage allocated to objects of a packed type should be minimized. 6.a Ramification: A pragma Pack is for gaining space efficiency, possibly at the expense of time. If more explicit control over representation is desired, then a record_representation_clause, a Component_Size clause, or a Size clause should be used instead of, or in addition to, a pragma Pack. 6.1/2 {AI95-00291-02} If a packed type has a component that is not of a by-reference type and has no aliased part, then such a component need not be aligned according to the Alignment of its subtype; in particular it need not be allocated on a storage element boundary. 7 {recommended level of support (pragma Pack) [partial]} The recommended level of support for pragma Pack is: 8 * For a packed record type, the components should be packed as tightly as possible subject to the Sizes of the component subtypes, and subject to any record_representation_clause that applies to the type; the implementation may, but need not, reorder components or cross aligned word boundaries to improve the packing. A component whose Size is greater than the word size may be allocated an integral number of words. 8.a Ramification: The implementation can always allocate an integral number of words for a component that will not fit in a word. The rule also allows small component sizes to be rounded up if such rounding does not waste space. For example, if Storage_Unit = 8, then a component of size 8 is probably more efficient than a component of size 7 plus a 1-bit gap (assuming the gap is needed anyway). 9 * For a packed array type, if the component subtype's Size is less than or equal to the word size, and Component_Size is not specified for the type, Component_Size should be less than or equal to the Size of the component subtype, rounded up to the nearest factor of the word size. 9.a Ramification: If a component subtype is aliased, its Size will generally be a multiple of Storage_Unit, so it probably won't get packed very tightly. 9.b/2 Implementation Advice: The recommended level of support for pragma Pack should be followed. Wording Changes from Ada 95 9.c/2 {AI95-00291-02} Added clarification that pragma Pack can ignore alignment requirements on types that don't have by-reference or aliased parts. This was always intended, but there was no wording to that effect. 13.3 Operational and Representation Attributes 1/1 {8652/0009} {AI95-00137-01} [{representation attribute} {attribute (representation)} The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate operational or representation attributes. {attribute (specifying) [distributed]} Some of these attributes are specifiable via an attribute_definition_clause.] Language Design Principles 1.a In general, the meaning of a given attribute should not depend on whether the attribute was specified via an attribute_definition_clause, or chosen by default by the implementation. Syntax 2 attribute_definition_clause ::= for local_name'attribute_designator use expression; | for local_name'attribute_designator use name; Name Resolution Rules 3 For an attribute_definition_clause that specifies an attribute that denotes a value, the form with an expression shall be used. Otherwise, the form with a name shall be used. 4 {expected type (attribute_definition_clause expression or name) [partial]} For an attribute_definition_clause that specifies an attribute that denotes a value or an object, the expected type for the expression or name is that of the attribute. {expected profile (attribute_definition_clause name) [partial]} For an attribute_definition_clause that specifies an attribute that denotes a subprogram, the expected profile for the name is the profile required for the attribute. For an attribute_definition_clause that specifies an attribute that denotes some other kind of entity, the name shall resolve to denote an entity of the appropriate kind. 4.a Ramification: For example, the Size attribute is of type universal_integer. Therefore, the expected type for Y in "for X'Size use Y;" is universal_integer, which means that Y can be of any integer type. 4.b Discussion: For attributes that denote subprograms, the required profile is indicated separately for the individual attributes. 4.c Ramification: For an attribute_definition_clause with a name, the name need not statically denote the entity it denotes. For example, the following kinds of things are allowed: 4.d for Some_Access_Type'Storage_Pool use Storage_Pool_Array(I); for Some_Type'Read use Subprogram_Pointer.all; Legality Rules 5/1 {8652/0009} {AI95-00137-01} {specifiable (of an attribute and for an entity) [distributed]} {attribute (specifiable) [distributed]} An attribute_designator is allowed in an attribute_definition_clause only if this International Standard explicitly allows it, or for an implementation-defined attribute if the implementation allows it. {aspect of representation (specifiable attributes) [partial]} Each specifiable attribute constitutes an {operational aspect (specifiable attributes) [partial]} operational aspect or aspect of representation. 5.a Discussion: For each specifiable attribute, we generally say something like, "The ... attribute may be specified for ... via an attribute_definition_clause." 5.b The above wording allows for T'Class'Alignment, T'Class'Size, T'Class'Input, and T'Class'Output to be specifiable. 5.c A specifiable attribute is not necessarily specifiable for all entities for which it is defined. For example, one is allowed to ask T'Component_Size for an array subtype T, but "for T'Component_Size use ..." is only allowed if T is a first subtype, because Component_Size is a type-related aspect. 6 For an attribute_definition_clause that specifies an attribute that denotes a subprogram, the profile shall be mode conformant with the one required for the attribute, and the convention shall be Ada. Additional requirements are defined for particular attributes. {mode conformance (required)} 6.a Ramification: This implies, for example, that if one writes: 6.b for T'Read use R; 6.c R has to be a procedure with two parameters with the appropriate subtypes and modes as shown in 13.13.2. Static Semantics 7/2 {AI95-00270-01} {Address clause} {Alignment clause} {Size clause} {Component_Size clause} {External_Tag clause} {Small clause} {Bit_Order clause} {Storage_Pool clause} {Storage_Size clause} {Stream_Size clause} {Read clause} {Write clause} {Input clause} {Output clause} {Machine_Radix clause} A Size clause is an attribute_definition_clause whose attribute_designator is Size. Similar definitions apply to the other specifiable attributes. 7.a To be honest: {type-related (attribute_definition_clause) [partial]} {subtype-specific (attribute_definition_clause) [partial]} An attribute_definition_clause is type-related or subtype-specific if the attribute_designator denotes a type-related or subtype-specific attribute, respectively. 8 {storage element} {byte: See storage element} A storage element is an addressable element of storage in the machine. {word} A word is the largest amount of storage that can be conveniently and efficiently manipulated by the hardware, given the implementation's run-time model. A word consists of an integral number of storage elements. 8.a Discussion: A storage element is not intended to be a single bit, unless the machine can efficiently address individual bits. 8.b Ramification: For example, on a machine with 8-bit storage elements, if there exist 32-bit integer registers, with a full set of arithmetic and logical instructions to manipulate those registers, a word ought to be 4 storage elements - that is, 32 bits. 8.c Discussion: The "given the implementation's run-time model" part is intended to imply that, for example, on an 80386 running MS-DOS, the word might be 16 bits, even though the hardware can support 32 bits. 8.d A word is what ACID refers to as a "natural hardware boundary". 8.e Storage elements may, but need not be, independently addressable (see 9.10, "Shared Variables"). Words are expected to be independently addressable. 8.1/2 {AI95-00133-01} {machine scalar} A machine scalar is an amount of storage that can be conveniently and efficiently loaded, stored, or operated upon by the hardware. Machine scalars consist of an integral number of storage elements. The set of machine scalars is implementation defined, but must include at least the storage element and the word. Machine scalars are used to interpret component_clauses when the nondefault bit ordering applies. 8.e.1/2 Implementation defined: The set of machine scalars. 9/1 {8652/0009} {AI95-00137-01} The following representation attributes are defined: Address, Alignment, Size, Storage_Size, and Component_Size. 10/1 For a prefix X that denotes an object, program unit, or label: 11 X'Address Denotes the address of the first of the storage elements allocated to X. For a program unit or label, this value refers to the machine code associated with the corresponding body or statement. The value of this attribute is of type System.Address. 11.a Ramification: Here, the "first of the storage elements" is intended to mean the one with the lowest address; the endianness of the machine doesn't matter. 12 {specifiable (of Address for stand-alone objects and for program units) [partial]} {Address clause} Address may be specified for stand-alone objects and for program units via an attribute_definition_clause. 12.a Ramification: Address is not allowed for enumeration literals, predefined operators, derived task types, or derived protected types, since they are not program units. 12.b The validity of a given address depends on the run-time model; thus, in order to use Address clauses correctly, one needs intimate knowledge of the run-time model. 12.c If the Address of an object is specified, any explicit or implicit initialization takes place as usual, unless a pragma Import is also specified for the object (in which case any necessary initialization is presumably done in the foreign language). 12.d Any compilation unit containing an attribute_reference of a given type depends semantically on the declaration of the package in which the type is declared, even if not mentioned in an applicable with_clause - see 10.1.1. In this case, it means that if a compilation unit contains X'Address, then it depends on the declaration of System. Otherwise, the fact that the value of Address is of a type in System wouldn't make sense; it would violate the "legality determinable via semantic dependences" Language Design Principle. 12.e AI83-00305 - If X is a task type, then within the body of X, X denotes the current task object; thus, X'Address denotes the object's address. 12.f Interrupt entries and their addresses are described in J.7.1, " Interrupt Entries". 12.g If X is not allocated on a storage element boundary, X'Address points at the first of the storage elements that contains any part of X. This is important for the definition of the Position attribute to be sensible. Erroneous Execution 13 {erroneous execution (cause) [partial]} If an Address is specified, it is the programmer's responsibility to ensure that the address is valid; otherwise, program execution is erroneous. Implementation Advice 14 For an array X, X'Address should point at the first component of the array, and not at the array bounds. 14.a.1/2 Implementation Advice: For an array X, X'Address should point at the first component of the array rather than the array bounds. 14.a Ramification: On the other hand, we have no advice to offer about discriminants and tag fields; whether or not the address points at them is not specified by the language. If discriminants are stored separately, then the Position of a discriminant might be negative, or might raise an exception. 15 {recommended level of support (Address attribute) [partial]} The recommended level of support for the Address attribute is: 16 * X'Address should produce a useful result if X is an object that is aliased or of a by-reference type, or is an entity whose Address has been specified. 16.a Reason: Aliased objects are the ones for which the Unchecked_Access attribute is allowed; hence, these have to be allocated on an addressable boundary anyway. Similar considerations apply to objects of a by-reference type. 16.b An implementation need not go to any trouble to make Address work in other cases. For example, if an object X is not aliased and not of a by-reference type, and the implementation chooses to store it in a register, X'Address might return System.Null_Address (assuming registers are not addressable). For a subprogram whose calling convention is Intrinsic, or for a package, the implementation need not generate an out-of-line piece of code for it. 17 * An implementation should support Address clauses for imported subprograms. 18/2 * This paragraph was deleted.{AI95-00291-02} 18.a/2 This paragraph was deleted. 19 * If the Address of an object is specified, or it is imported or exported, then the implementation should not perform optimizations based on assumptions of no aliases. 19.a/2 Implementation Advice: The recommended level of support for the Address attribute should be followed. NOTES 20 1 The specification of a link name in a pragma Export (see B.1) for a subprogram or object is an alternative to explicit specification of its link-time address, allowing a link-time directive to place the subprogram or object within memory. 21 2 The rules for the Size attribute imply, for an aliased object X, that if X'Size = Storage_Unit, then X'Address points at a storage element containing all of the bits of X, and only the bits of X. Wording Changes from Ada 83 21.a The intended meaning of the various attributes, and their attribute_definition_clauses, is more explicit. 21.b The address_clause has been renamed to at_clause and moved to Annex J, "Obsolescent Features". One can use an Address clause ("for T'Address use ...;") instead. 21.c The attributes defined in RM83-13.7.3 are moved to Annex G, A.5.3, and A.5.4. Language Design Principles 21.d By default, the Alignment of a subtype should reflect the " natural" alignment for objects of the subtype on the machine. The Alignment, whether specified or default, should be known at compile time, even though Addresses are generally not known at compile time. (The generated code should never need to check at run time the number of zero bits at the end of an address to determine an alignment). 21.e There are two symmetric purposes of Alignment clauses, depending on whether or not the implementation has control over object allocation. If the implementation allocates an object, the implementation should ensure that the Address and Alignment are consistent with each other. If something outside the implementation allocates an object, the implementation should be allowed to assume that the Address and Alignment are consistent, but should not assume stricter alignments than that. Static Semantics 22/2 {AI95-00291-02} For a prefix X that denotes an object: 23/2 X'Alignment {AI95-00291-02} The value of this attribute is of type universal_integer, and nonnegative; zero means that the object is not necessarily aligned on a storage element boundary. If X'Alignment is not zero, then X is aligned on a storage unit boundary and X'Address is an integral multiple of X'Alignment (that is, the Address modulo the Alignment is zero). 24/2 This paragraph was deleted.{AI95-00291-02} 24.a Ramification: The Alignment is passed by an allocator to the Allocate operation; the implementation has to choose a value such that if the address returned by Allocate is aligned as requested, the generated code can correctly access the object. 24.b The above mention of "modulo" is referring to the "mod" operator declared in System.Storage_Elements; if X mod N = 0, then X is by definition aligned on an N-storage-element boundary. 25/2 {AI95-00291-02} {specifiable (of Alignment for objects) [partial]} {Alignment clause} Alignment may be specified for [stand-alone] objects via an attribute_definition_clause; the expression of such a clause shall be static, and its value nonnegative. 26/2 This paragraph was deleted.{AI95-00247-01} 26.1/2 {AI95-00291-02} For every subtype S: 26.2/2 S'Alignment {AI95-00291-02} The value of this attribute is of type universal_integer, and nonnegative. 26.3/2 {AI95-00051-02} {AI95-00291-02} For an object X of subtype S, if S'Alignment is not zero, then X'Alignment is a nonzero integral multiple of S'Alignment unless specified otherwise by a representation item. 26.4/2 {AI95-00291-02} {specifiable (of Alignment for first subtypes) [partial]} {Alignment clause} Alignment may be specified for first subtypes via an attribute_definition_clause; the expression of such a clause shall be static, and its value nonnegative. Erroneous Execution 27 {erroneous execution (cause) [partial]} Program execution is erroneous if an Address clause is given that conflicts with the Alignment. 27.a Ramification: The user has to either give an Alignment clause also, or else know what Alignment the implementation will choose by default. 28/2 {AI95-00051-02} {AI95-00291-02} {erroneous execution (cause) [partial]} For an object that is not allocated under control of the implementation, execution is erroneous if the object is not aligned according to its Alignment. Implementation Advice 29 {recommended level of support (Alignment attribute for subtypes) [partial]} The recommended level of support for the Alignment attribute for subtypes is: 30/2 * {AI95-00051-02} An implementation should support an Alignment clause for a discrete type, fixed point type, record type, or array type, specifying an Alignment value that is zero or a power of two, subject to the following: 31/2 * {AI95-00051-02} An implementation need not support an Alignment clause for a signed integer type specifying an Alignment greater than the largest Alignment value that is ever chosen by default by the implementation for any signed integer type. A corresponding limitation may be imposed for modular integer types, fixed point types, enumeration types, record types, and array types. 32/2 * {AI95-00051-02} An implementation need not support a nonconfirming Alignment clause which could enable the creation of an object of an elementary type which cannot be easily loaded and stored by available machine instructions. 32.1/2 * {AI95-00291-02} An implementation need not support an Alignment specified for a derived tagged type which is not a multiple of the Alignment of the parent type. An implementation need not support a nonconfirming Alignment specified for a derived untagged by-reference type. 32.a/2 Ramification: {AI95-00291-02} There is no recommendation to support any nonconfirming Alignment clauses for types not mentioned above. Remember that 13.1 requires support for confirming Alignment clauses for all types. 33 {recommended level of support (Alignment attribute for objects) [partial]} The recommended level of support for the Alignment attribute for objects is: 34/2 * This paragraph was deleted.{AI95-00291-02} 35 * For stand-alone library-level objects of statically constrained subtypes, the implementation should support all Alignments supported by the target linker. For example, page alignment is likely to be supported for such objects, but not for subtypes. 35.1/2 * {AI95-00291-02} For other objects, an implementation should at least support the alignments supported for their subtype, subject to the following: 35.2/2 * {AI95-00291-02} An implementation need not support Alignments specified for objects of a by-reference type or for objects of types containing aliased subcomponents if the specified Alignment is not a multiple of the Alignment of the subtype of the object. 35.a/2 Implementation Advice: The recommended level of support for the Alignment attribute should be followed. NOTES 36 3 Alignment is a subtype-specific attribute. 37/2 This paragraph was deleted.{AI95-00247-01} 37.a/2 This paragraph was deleted. 38 4 A component_clause, Component_Size clause, or a pragma Pack can override a specified Alignment. 38.a Discussion: Most objects are allocated by the implementation; for these, the implementation obeys the Alignment. The implementation is of course allowed to make an object more aligned than its Alignment requires - an object whose Alignment is 4 might just happen to land at an address that's a multiple of 4096. For formal parameters, the implementation might want to force an Alignment stricter than the parameter's subtype. For example, on some systems, it is customary to always align parameters to 4 storage elements. 38.b Hence, one might initially assume that the implementation could evilly make all Alignments 1 by default, even though integers, say, are normally aligned on a 4-storage-element boundary. However, the implementation cannot get away with that - if the Alignment is 1, the generated code cannot assume an Alignment of 4, at least not for objects allocated outside the control of the implementation. 38.c Of course implementations can assume anything they can prove, but typically an implementation will be unable to prove much about the alignment of, say, an imported object. Furthermore, the information about where an address "came from" can be lost to the compiler due to separate compilation. 38.d/2 {AI95-00114-01} The Alignment of an object that is a component of a packed composite object will usually be 0, to indicate that the component is not necessarily aligned on a storage element boundary. For a subtype, an Alignment of 0 means that objects of the subtype are not normally aligned on a storage element boundary at all. For example, an implementation might choose to make Component_Size be 1 for an array of Booleans, even when pragma Pack has not been specified for the array. In this case, Boolean'Alignment would be 0. (In the presence of tasking, this would in general be feasible only on a machine that had atomic test-bit and set-bit instructions.) 38.e If the machine has no particular natural alignments, then all subtype Alignments will probably be 1 by default. 38.f Specifying an Alignment of 0 in an attribute_definition_clause does not require the implementation to do anything (except return 0 when the Alignment is queried). However, it might be taken as advice on some implementations. 38.g It is an error for an Address clause to disobey the object's Alignment. The error cannot be detected at compile time, in general, because the Address is not necessarily known at compile time (and is almost certainly not static). We do not require a run-time check, since efficiency seems paramount here, and Address clauses are treading on thin ice anyway. Hence, this misuse of Address clauses is just like any other misuse of Address clauses - it's erroneous. 38.h A type extension can have a stricter Alignment than its parent. This can happen, for example, if the Alignment of the parent is 4, but the extension contains a component with Alignment 8. The Alignment of a class-wide type or object will have to be the maximum possible Alignment of any extension. 38.i The recommended level of support for the Alignment attribute is intended to reflect a minimum useful set of capabilities. An implementation can assume that all Alignments are multiples of each other - 1, 2, 4, and 8 might be the only supported Alignments for subtypes. An Alignment of 3 or 6 is unlikely to be useful. For objects that can be allocated statically, we recommend that the implementation support larger alignments, such as 4096. We do not recommend such large alignments for subtypes, because the maximum subtype alignment will also have to be used as the alignment of stack frames, heap objects, and class-wide objects. Similarly, we do not recommend such large alignments for stack-allocated objects. 38.j If the maximum default Alignment is 8 (say, Long_Float'Alignment = 8), then the implementation can refuse to accept stricter alignments for subtypes. This simplifies the generated code, since the compiler can align the stack and class-wide types to this maximum without a substantial waste of space (or time). 38.k Note that the recommended level of support takes into account interactions between Size and Alignment. For example, on a 32-bit machine with 8-bit storage elements, where load and store instructions have to be aligned according to the size of the thing being loaded or stored, the implementation might accept an Alignment of 1 if the Size is 8, but might reject an Alignment of 1 if the Size is 32. On a machine where unaligned loads and stores are merely inefficient (as opposed to causing hardware traps), we would expect an Alignment of 1 to be supported for any Size. Wording Changes from Ada 83 38.l The nonnegative part is missing from RM83 (for mod_clauses, nee alignment_clauses, which are an obsolete version of Alignment clauses). Static Semantics 39/1 For a prefix X that denotes an object: 40 X'Size Denotes the size in bits of the representation of the object. The value of this attribute is of the type universal_integer. 40.a Ramification: Note that Size is in bits even if Machine_Radix is 10. Each decimal digit (and the sign) is presumably represented as some number of bits. 41 {specifiable (of Size for stand-alone objects) [partial]} {Size clause} Size may be specified for [stand-alone] objects via an attribute_definition_clause; the expression of such a clause shall be static and its value nonnegative. Implementation Advice 41.1/2 {AI95-00051-02} The size of an array object should not include its bounds. 41.a.1/2 Implementation Advice: The Size of an array object should not include its bounds. 42/2 {AI95-00051-02} {AI95-00291-02} {recommended level of support (Size attribute) [partial]} The recommended level of support for the Size attribute of objects is the same as for subtypes (see below), except that only a confirming Size clause need be supported for an aliased elementary object. 43/2 * This paragraph was deleted.{AI95-00051-02} Static Semantics 44 For every subtype S: 45 S'Size If S is definite, denotes the size [(in bits)] that the implementation would choose for the following objects of subtype S: 46 * A record component of subtype S when the record type is packed. 47 * The formal parameter of an instance of Unchecked_Conversion that converts from subtype S to some other subtype. 48 If S is indefinite, the meaning is implementation defined. The value of this attribute is of the type universal_integer. {specifiable (of Size for first subtypes) [partial]} {Size clause} The Size of an object is at least as large as that of its subtype, unless the object's Size is determined by a Size clause, a component_clause, or a Component_Size clause. Size may be specified for first subtypes via an attribute_- definition_clause; the expression of such a clause shall be static and its value nonnegative. 48.a Implementation defined: The meaning of Size for indefinite subtypes. 48.b Reason: The effects of specifying the Size of a subtype are: 48.c * Unchecked_Conversion works in a predictable manner. 48.d * A composite type cannot be packed so tightly as to override the specified Size of a component's subtype. 48.e * Assuming the Implementation Advice is obeyed, if the specified Size allows independent addressability, then the Size of certain objects of the subtype should be equal to the subtype's Size. This applies to stand-alone objects and to components (unless a component_clause or a Component_Size clause applies). 48.f A component_clause or a Component_Size clause can cause an object to be smaller than its subtype's specified size. A pragma Pack cannot; if a component subtype's size is specified, this limits how tightly the composite object can be packed. 48.g The Size of a class-wide (tagged) subtype is unspecified, because it's not clear what it should mean; it should certainly not depend on all of the descendants that happen to exist in a given program. Note that this cannot be detected at compile time, because in a generic unit, it is not necessarily known whether a given subtype is class-wide. It might raise an exception on some implementations. 48.h Ramification: A Size clause for a numeric subtype need not affect the underlying numeric type. For example, if I say: 48.i type S is range 1..2; for S'Size use 64; 48.j I am not guaranteed that S'Base'Last >= 2**63-1, nor that intermediate results will be represented in 64 bits. 48.k Reason: There is no need to complicate implementations for this sort of thing, because the right way to affect the base range of a type is to use the normal way of declaring the base range: 48.l type Big is range -2**63 .. 2**63 - 1; subtype Small is Big range 1..1000; 48.m Ramification: The Size of a large unconstrained subtype (e.g. String'Size) is likely to raise Constraint_Error, since it is a nonstatic expression of type universal_integer that might overflow the largest signed integer type. There is no requirement that the largest integer type be able to represent the size in bits of the largest possible object. Implementation Requirements 49 In an implementation, Boolean'Size shall be 1. Implementation Advice 50/2 {AI95-00051-02} If the Size of a subtype allows for efficient independent addressability (see 9.10) on the target architecture, then the Size of the following objects of the subtype should equal the Size of the subtype: 51 * Aliased objects (including components). 52 * Unaliased components, unless the Size of the component is determined by a component_clause or Component_Size clause. 52.a.1/2 Implementation Advice: If the Size of a subtype allows for efficient independent addressability, then the Size of most objects of the subtype should equal the Size of the subtype. 52.a Ramification: Thus, on a typical 32-bit machine, "for S'Size use 32;" will guarantee that aliased objects of subtype S, and components whose subtype is S, will have Size = 32 (assuming the implementation chooses to obey this Implementation Advice). On the other hand, if one writes, "for S2'Size use 5;" then stand-alone objects of subtype S2 will typically have their Size rounded up to ensure independent addressability. 52.b Note that "for S'Size use 32;" does not cause things like formal parameters to have Size = 32 - the implementation is allowed to make all parameters be at least 64 bits, for example. 52.c Note that "for S2'Size use 5;" requires record components whose subtype is S2 to be exactly 5 bits if the record type is packed. The same is not true of array components; their Size may be rounded up to the nearest factor of the word size. 52.d/2 Implementation Note: {AI95-00291-02} {gaps} On most machines, arrays don't contain gaps between elementary components; if the Component_Size is greater than the Size of the component subtype, the extra bits are generally considered part of each component, rather than gaps between components. On the other hand, a record might contain gaps between elementary components, depending on what sorts of loads, stores, and masking operations are generally done by the generated code. 52.e/2 {AI95-00291-02} For an array, any extra bits stored for each elementary component will generally be part of the component - the whole point of storing extra bits is to make loads and stores more efficient by avoiding the need to mask out extra bits. The PDP-10 is one counter-example; since the hardware supports byte strings with a gap at the end of each word, one would want to pack in that manner. 53 A Size clause on a composite subtype should not affect the internal layout of components. 53.a.1/2 Implementation Advice: A Size clause on a composite subtype should not affect the internal layout of components. 53.a Reason: That's what Pack pragmas, record_representation_clauses, and Component_Size clauses are for. 54 {recommended level of support (Size attribute) [partial]} The recommended level of support for the Size attribute of subtypes is: 55 * The Size (if not specified) of a static discrete or fixed point subtype should be the number of bits needed to represent each value belonging to the subtype using an unbiased representation, leaving space for a sign bit only if the subtype contains negative values. If such a subtype is a first subtype, then an implementation should support a specified Size for it that reflects this representation. 55.a Implementation Note: This applies to static enumeration subtypes, using the internal codes used to represent the values. 55.b For a two's-complement machine, this implies that for a static signed integer subtype S, if all values of S are in the range 0 .. 2(n)-1, or all values of S are in the range -2(n-1) .. 2(n-1)-1, for some n less than or equal to the word size, then S'Size should be <= the smallest such n. For a one's-complement machine, it is the same except that in the second range, the lower bound " -2(n-1)" is replaced by "-2(n-1)+1". 55.c If an integer subtype (whether signed or unsigned) contains no negative values, the Size should not include space for a sign bit. 55.d Typically, the implementation will choose to make the Size of a subtype be exactly the smallest such n. However, it might, for example, choose a biased representation, in which case it could choose a smaller value. 55.e On most machines, it is in general not a good idea to pack (parts of) multiple stand-alone objects into the same storage element, because (1) it usually doesn't save much space, and (2) it requires locking to prevent tasks from interfering with each other, since separate stand-alone objects are independently addressable. Therefore, if S'Size = 2 on a machine with 8-bit storage elements, the size of a stand-alone object of subtype S will probably not be 2. It might, for example, be 8, 16 or 32, depending on the availability and efficiency of various machine instructions. The same applies to components of composite types, unless packing, Component_Size, or record layout is specified. 55.f For an unconstrained discriminated object, if the implementation allocates the maximum possible size, then the Size attribute should return that maximum possible size. 55.g Ramification: The Size of an object X is not usually the same as that of its subtype S. If X is a stand-alone object or a parameter, for example, most implementations will round X'Size up to a storage element boundary, or more, so X'Size might be greater than S'Size. On the other hand, X'Size cannot be less than S'Size, even if the implementation can prove, for example, that the range of values actually taken on by X during execution is smaller than the range of S. 55.h For example, if S is a first integer subtype whose range is 0..3, S'Size will be probably be 2 bits, and components of packed composite types of this subtype will be 2 bits (assuming Storage_Unit is a multiple of 2), but stand-alone objects and parameters will probably not have a size of 2 bits; they might be rounded up to 32 bits, for example. On the other hand, Unchecked_Conversion will use the 2-bit size, even when converting a stand-alone object, as one would expect. 55.i Another reason for making the Size of an object bigger than its subtype's Size is to support the run-time detection of uninitialized variables. {uninitialized variables [partial]} The implementation might add an extra value to a discrete subtype that represents the uninitialized state, and check for this value on use. In some cases, the extra value will require an extra bit in the representation of the object. Such detection is not required by the language. If it is provided, the implementation has to be able to turn it off. For example, if the programmer gives a record_representation_clause or Component_Size clause that makes a component too small to allow the extra bit, then the implementation will not be able to perform the checking (not using this method, anyway). 55.j The fact that the size of an object is not necessarily the same as its subtype can be confusing: 55.k type Device_Register is range 0..2**8 - 1; for Device_Register'Size use 8; -- Confusing! My_Device : Device_Register; for My_Device'Address use To_Address(16#FF00#); 55.l The programmer might think that My_Device'Size is 8, and that My_Device'Address points at an 8-bit location. However, this is not true. In Ada 83 (and in Ada 95), My_Device'Size might well be 32, and My_Device'Address might well point at the high-order 8 bits of the 32-bit object, which are always all zero bits. If My_Device'Address is passed to an assembly language subprogram, based on the programmer's assumption, the program will not work properly. 55.m Reason: It is not reasonable to require that an implementation allocate exactly 8 bits to all objects of subtype Device_Register. For example, in many run-time models, stand-alone objects and parameters are always aligned to a word boundary. Such run-time models are generally based on hardware considerations that are beyond the control of the implementer. (It is reasonable to require that an implementation allocate exactly 8 bits to all components of subtype Device_Register, if packed.) 55.n Ramification: The correct way to write the above code is like this: 55.o type Device_Register is range 0..2**8 - 1; My_Device : Device_Register; for My_Device'Size use 8; for My_Device'Address use To_Address(16#FF00#); 55.p If the implementation cannot accept 8-bit stand-alone objects, then this will be illegal. However, on a machine where an 8-bit device register exists, the implementation will probably be able to accept 8-bit stand-alone objects. Therefore, My_Device'Size will be 8, and My_Device'Address will point at those 8 bits, as desired. 55.q If an object of subtype Device_Register is passed to a foreign language subprogram, it will be passed according to that subprogram's conventions. Most foreign language implementations have similar run-time model restrictions. For example, when passing to a C function, where the argument is of the C type char* (that is, pointer to char), the C compiler will generally expect a full word value, either on the stack, or in a register. It will not expect a single byte. Thus, Size clauses for subtypes really have nothing to do with passing parameters to foreign language subprograms. 56 * For a subtype implemented with levels of indirection, the Size should include the size of the pointers, but not the size of what they point at. 56.a Ramification: For example, if a task object is represented as a pointer to some information (including a task stack), then the size of the object should be the size of the pointer. The Storage_Size, on the other hand, should include the size of the stack. 56.1/2 * {AI95-00051-02} An implementation should support a Size clause for a discrete type, fixed point type, record type, or array type, subject to the following: 56.2/2 * {AI95-00051-02} An implementation need not support a Size clause for a signed integer type specifying a Size greater than that of the largest signed integer type supported by the implementation in the absence of a size clause (that is, when the size is chosen by default). A corresponding limitation may be imposed for modular integer types, fixed point types, enumeration types, record types, and array types. 56.b/2 Discussion: {AI95-00051-02} Note that the "corresponding limitation" for a record or array type implies that an implementation may impose some reasonable maximum size for records and arrays (e.g. 2**32 bits), which is an upper bound ("capacity" limit) on the size, whether chosen by default or by being specified by the user. The largest size supported for records need not be the same as the largest size supported for arrays. 56.3/2 * {AI95-00291-02} A nonconfirming size clause for the first subtype of a derived untagged by-reference type need not be supported. 56.c/2 Implementation Advice: The recommended level of support for the Size attribute should be followed. 56.d/2 Ramification: {AI95-00291-02} There is no recommendation to support any nonconfirming Size clauses for types not mentioned above. Remember that 13.1 requires support for confirming Size clauses for all types. NOTES 57 5 Size is a subtype-specific attribute. 58 6 A component_clause or Component_Size clause can override a specified Size. A pragma Pack cannot. Inconsistencies With Ada 83 58.a.1/2 {AI95-00114-01} We specify the meaning of Size in much more detail than Ada 83. This is not technically an inconsistency, but it is in practice, as most Ada 83 compilers use a different definition for Size than is required here. This should have been documented more explicitly during the Ada 9X process. Wording Changes from Ada 83 58.a The requirement for a nonnegative value in a Size clause was not in RM83, but it's hard to see how it would make sense. For uniformity, we forbid negative sizes, rather than letting implementations define their meaning. Static Semantics 59/1 For a prefix T that denotes a task object [(after any implicit dereference)]: 60 T'Storage_Size Denotes the number of storage elements reserved for the task. The value of this attribute is of the type universal_integer. The Storage_Size includes the size of the task's stack, if any. The language does not specify whether or not it includes other storage associated with the task (such as the "task control block" used by some implementations.) If a pragma Storage_Size is given, the value of the Storage_Size attribute is at least the value specified in the pragma. 60.a Ramification: The value of this attribute is never negative, since it is impossible to "reserve" a negative number of storage elements. 60.b If the implementation chooses to allocate an initial amount of storage, and then increase this as needed, the Storage_Size cannot include the additional amounts (assuming the allocation of the additional amounts can raise Storage_Error); this is inherent in the meaning of "reserved." 60.c The implementation is allowed to allocate different amounts of storage for different tasks of the same subtype. 60.d Storage_Size is also defined for access subtypes - see 13.11. 61 [{Storage_Size clause: See also pragma Storage_Size} A pragma Storage_Size specifies the amount of storage to be reserved for the execution of a task.] Syntax 62 The form of a pragma Storage_Size is as follows: 63 pragma Storage_Size(expression); 64 A pragma Storage_Size is allowed only immediately within a task_definition. Name Resolution Rules 65 {expected type (Storage_Size pragma argument) [partial]} The expression of a pragma Storage_Size is expected to be of any integer type. Dynamic Semantics 66 A pragma Storage_Size is elaborated when an object of the type defined by the immediately enclosing task_definition is created. {elaboration (Storage_Size pragma) [partial]} For the elaboration of a pragma Storage_Size, the expression is evaluated; the Storage_Size attribute of the newly created task object is at least the value of the expression. 66.a Ramification: The implementation is allowed to round up a specified Storage_Size amount. For example, if the implementation always allocates in chunks of 4096 bytes, the number 200 might be rounded up to 4096. Also, if the user specifies a negative number, the implementation has to normalize this to 0, or perhaps to a positive number. 67 {Storage_Check [partial]} {check, language-defined (Storage_Check)} {Storage_Error (raised by failure of run-time check)} At the point of task object creation, or upon task activation, Storage_Error is raised if there is insufficient free storage to accommodate the requested Storage_Size. Static Semantics 68/1 For a prefix X that denotes an array subtype or array object [(after any implicit dereference)]: 69 X'Component_Size Denotes the size in bits of components of the type of X. The value of this attribute is of type universal_integer. 70 {specifiable (of Component_Size for array types) [partial]} {Component_Size clause} Component_Size may be specified for array types via an attribute_definition_clause; the expression of such a clause shall be static, and its value nonnegative. 70.a Implementation Note: The intent is that the value of X'Component_Size is always nonnegative. If the array is stored " backwards" in memory (which might be caused by an implementation-defined pragma), X'Component_Size is still positive. 70.b Ramification: For an array object A, A'Component_Size = A(I)'Size for any index I. Implementation Advice 71 {recommended level of support (Component_Size attribute) [partial]} The recommended level of support for the Component_Size attribute is: 72 * An implementation need not support specified Component_Sizes that are less than the Size of the component subtype. 73 * An implementation should support specified Component_Sizes that are factors and multiples of the word size. For such Component_Sizes, the array should contain no gaps between components. For other Component_Sizes (if supported), the array should contain no gaps between components when packing is also specified; the implementation should forbid this combination in cases where it cannot support a no-gaps representation. 73.a Ramification: For example, if Storage_Unit = 8, and Word_Size = 32, then the user is allowed to specify a Component_Size of 1, 2, 4, 8, 16, and 32, with no gaps. In addition, n*32 is allowed for positive integers n, again with no gaps. If the implementation accepts Component_Size = 3, then it might allocate 10 components per word, with a 2-bit gap at the end of each word (unless packing is also specified), or it might not have any internal gaps at all. (There can be gaps at either end of the array.) 73.b/2 Implementation Advice: The recommended level of support for the Component_Size attribute should be followed. Static Semantics 73.1/1 {8652/0009} {AI95-00137-01} The following operational attribute is defined: External_Tag. 74/1 {8652/0009} {AI95-00137-01} For every subtype S of a tagged type T (specific or class-wide): 75/1 S'External_Tag {8652/0040} {AI95-00108-01} {External_Tag clause} {specifiable (of External_Tag for a tagged type) [partial]} S'External_Tag denotes an external string representation for S'Tag; it is of the predefined type String. External_Tag may be specified for a specific tagged type via an attribute_definition_clause; the expression of such a clause shall be static. The default external tag representation is implementation defined. See 3.9.2 and 13.13.2. The value of External_Tag is never inherited[; the default value is always used unless a new value is directly specified for a type]. 75.a Implementation defined: The default external representation for a type tag. Implementation Requirements 76 In an implementation, the default external tag for each specific tagged type declared in a partition shall be distinct, so long as the type is declared outside an instance of a generic body. If the compilation unit in which a given tagged type is declared, and all compilation units on which it semantically depends, are the same in two different partitions, then the external tag for the type shall be the same in the two partitions. What it means for a compilation unit to be the same in two different partitions is implementation defined. At a minimum, if the compilation unit is not recompiled between building the two different partitions that include it, the compilation unit is considered the same in the two partitions. 76.a Implementation defined: What determines whether a compilation unit is the same in two different partitions. 76.b Reason: These requirements are important because external tags are used for input/output of class-wide types. These requirements ensure that what is written by one program can be read back by some other program so long as they share the same declaration for the type (and everything it depends on). 76.c The user may specify the external tag if (s)he wishes its value to be stable even across changes to the compilation unit in which the type is declared (or changes in some unit on which it depends). 76.d/2 {AI95-00114-01} We use a String rather than a Stream_Element_Array to represent an external tag for portability. 76.e Ramification: Note that the characters of an external tag need not all be graphic characters. In other words, the external tag can be a sequence of arbitrary 8-bit bytes. NOTES 77/2 7 {AI95-00270-01} The following language-defined attributes are specifiable, at least for some of the kinds of entities to which they apply: Address, Alignment, Bit_Order, Component_Size, External_Tag, Input, Machine_Radix, Output, Read, Size, Small, Storage_Pool, Storage_Size, Stream_Size, and Write. 78 8 It follows from the general rules in 13.1 that if one writes "for X'Size use Y;" then the X'Size attribute_reference will return Y (assuming the implementation allows the Size clause). The same is true for all of the specifiable attributes except Storage_Size. 78.a Ramification: An implementation may specify that an implementation-defined attribute is specifiable for certain entities. This follows from the fact that the semantics of implementation-defined attributes is implementation defined. An implementation is not allowed to make a language-defined attribute specifiable if it isn't. Examples 79 Examples of attribute definition clauses: 80 Byte : constant := 8; Page : constant := 2**12; 81 type Medium is range 0 .. 65_000; for Medium'Size use 2*Byte; for Medium'Alignment use 2; Device_Register : Medium; for Device_Register'Size use Medium'Size; for Device_Register'Address use System.Storage_Elements.To_Address(16#FFFF_0020#); 82 type Short is delta 0.01 range -100.0 .. 100.0; for Short'Size use 15; 83 for Car_Name'Storage_Size use -- specify access type's storage pool size 2000*((Car'Size/System.Storage_Unit) +1); -- approximately 2000 cars 84/2 {AI95-00441-01} function My_Input(Stream : not null access Ada.Streams.Root_Stream_Type'Class) return T; for T'Input use My_Input; -- see 13.13.2 NOTES 85 9 Notes on the examples: In the Size clause for Short, fifteen bits is the minimum necessary, since the type definition requires Short'Small <= 2**(-7). Extensions to Ada 83 85.a {extensions to Ada 83} The syntax rule for length_clause is replaced with the new syntax rule for attribute_definition_clause, and it is modified to allow a name (as well as an expression). Wording Changes from Ada 83 85.b The syntax rule for attribute_definition_clause now requires that the prefix of the attribute be a local_name; in Ada 83 this rule was stated in the text. 85.c/2 {AI95-00114-01} In Ada 83, the relationship between a aspect_clause specifying a certain aspect and an attribute that queried that aspect was unclear. In Ada 95, they are the same, except for certain explicit exceptions. Wording Changes from Ada 95 85.d/2 {8652/0009} {AI95-00137-01} Corrigendum: Added wording to specify for each attribute whether it is an operational or representation attribute. 85.e/2 {8652/0040} {AI95-00108-01} Corrigendum: Added wording to specify that External_Tag is never inherited. 85.f/2 {AI95-00051-01} {AI95-00291-01} Adjusted the Recommended Level of Support for Alignment to eliminate nonsense requirements and to ensure that useful capabilities are required. 85.g/2 {AI95-00051-01} {AI95-00291-01} Adjusted the Recommended Level of Support for Size to eliminate nonsense requirements and to ensure that useful capabilities are required. Also eliminated any dependence on whether an aspect was specified (a confirming representation item should not affect the semantics). 85.h/2 {AI95-00133-01} Added the definition of machine scalar. 85.i/2 {AI95-00247-01} Removed the requirement that specified alignments for a composite type cannot override those for their components, because it was never intended to apply to components whose location was specified with a representation item. Moreover, it causes a difference in legality when a confirming alignment is specified for one of the composite types. 85.j/2 {AI95-00291-02} Removed recommended level of support rules about types with by-reference and aliased parts, because there are now blanket rules covering all recommended level of support rules. 85.k/2 {AI95-00291-02} Split the definition of Alignment for subtypes and for objects. This simplified the wording and eliminated confusion about which rules applied to objects, which applied to subtypes, and which applied to both. 13.4 Enumeration Representation Clauses 1 [An enumeration_representation_clause specifies the internal codes for enumeration literals.] Syntax 2 enumeration_representation_clause ::= for first_subtype_local_name use enumeration_aggregate; 3 enumeration_aggregate ::= array_aggregate Name Resolution Rules 4 {expected type (enumeration_representation_clause expressions) [partial]} The enumeration_aggregate shall be written as a one-dimensional array_aggregate, for which the index subtype is the unconstrained subtype of the enumeration type, and each component expression is expected to be of any integer type. 4.a Ramification: The "full coverage rules" for aggregates applies. An others is not allowed - there is no applicable index constraint in this context. Legality Rules 5 The first_subtype_local_name of an enumeration_representation_clause shall denote an enumeration subtype. 5.a Ramification: As for all type-related representation items, the local_name is required to denote a first subtype. 6/2 {AI95-00287-01} Each component of the array_aggregate shall be given by an expression rather than a <>. The expressions given in the array_aggregate shall be static, and shall specify distinct integer codes for each value of the enumeration type; the associated integer codes shall satisfy the predefined ordering relation of the type. 6.a Reason: Each value of the enumeration type has to be given an internal code, even if the first subtype of the enumeration type is constrained to only a subrange (this is only possible if the enumeration type is a derived type). This "full coverage" requirement is important because one may refer to Enum'Base'First and Enum'Base'Last, which need to have defined representations. Static Semantics 7 {aspect of representation (coding) [partial]} {coding (aspect of representation)} An enumeration_representation_clause specifies the coding aspect of representation. {internal code} The coding consists of the internal code for each enumeration literal, that is, the integral value used internally to represent each literal. Implementation Requirements 8 For nonboolean enumeration types, if the coding is not specified for the type, then for each value of the type, the internal code shall be equal to its position number. 8.a Reason: This default representation is already used by all known Ada compilers for nonboolean enumeration types. Therefore, we make it a requirement so users can depend on it, rather than feeling obliged to supply for every enumeration type an enumeration representation clause that is equivalent to this default rule. 8.b Discussion: For boolean types, it is relatively common to use all ones for True, and all zeros for False, since some hardware supports that directly. Of course, for a one-bit Boolean object (like in a packed array), False is presumably zero and True is presumably one (choosing the reverse would be extremely unfriendly!). Implementation Advice 9 {recommended level of support (enumeration_representation_clause) [partial]} The recommended level of support for enumeration_representation_clauses is: 10 * An implementation should support at least the internal codes in the range System.Min_Int..System.Max_Int. An implementation need not support enumeration_representation_clauses for boolean types. 10.a Ramification: The implementation may support numbers outside the above range, such as numbers greater than System.Max_Int. See AI83-00564. 10.b Reason: The benefits of specifying the internal coding of a boolean type do not outweigh the implementation costs. Consider, for example, the implementation of the logical operators on a packed array of booleans with strange internal codes. It's implementable, but not worth it. 10.c/2 Implementation Advice: The recommended level of support for enumeration_representation_clauses should be followed. NOTES 11/1 10 {8652/0009} {AI95-00137-01} Unchecked_Conversion may be used to query the internal codes used for an enumeration type. The attributes of the type, such as Succ, Pred, and Pos, are unaffected by the enumeration_representation_clause. For example, Pos always returns the position number, not the internal integer code that might have been specified in an enumeration_representation_clause}. 11.a Discussion: Suppose the enumeration type in question is derived: 11.b type T1 is (Red, Green, Blue); subtype S1 is T1 range Red .. Green; type S2 is new S1; for S2 use (Red => 10, Green => 20, Blue => 30); 11.c/1 {8652/0009} {AI95-00137-01} The enumeration_representation_clause has to specify values for all enumerals, even ones that are not in S2 (such as Blue). The Base attribute can be used to get at these values. For example: 11.d for I in S2'Base loop ... -- When I equals Blue, the internal code is 30. end loop; 11.e We considered allowing or requiring "for S2'Base use ..." in cases like this, but it didn't seem worth the trouble. Examples 12 Example of an enumeration representation clause: 13 type Mix_Code is (ADD, SUB, MUL, LDA, STA, STZ); 14 for Mix_Code use (ADD => 1, SUB => 2, MUL => 3, LDA => 8, STA => 24, STZ =>33); Extensions to Ada 83 14.a {extensions to Ada 83} As in other similar contexts, Ada 95 allows expressions of any integer type, not just expressions of type universal_integer, for the component expressions in the enumeration_aggregate. The preference rules for the predefined operators of root_integer eliminate any ambiguity. 14.b For portability, we now require that the default coding for an enumeration type be the "obvious" coding using position numbers. This is satisfied by all known implementations. Wording Changes from Ada 95 14.c/2 {8652/0009} {AI95-00137-01} Corrigendum: Updated to reflect that we no longer have something called representation_clause. 14.d/2 {AI95-00287-01} Added wording to prevent the use of <> in a enumeration_representation_clause. (<> is newly added to array_aggregates.) 13.5 Record Layout 1 {aspect of representation (layout) [partial]} {layout (aspect of representation)} {aspect of representation (record layout) [partial]} {record layout (aspect of representation)} {aspect of representation (storage place) [partial]} {storage place (of a component)} The (record) layout aspect of representation consists of the storage places for some or all components, that is, storage place attributes of the components. The layout can be specified with a record_- representation_clause. 13.5.1 Record Representation Clauses 1 [A record_representation_clause specifies the storage representation of records and record extensions, that is, the order, position, and size of components (including discriminants, if any). {bit field: See record_representation_clause} ] Language Design Principles 1.a/2 {AI95-00114-01} It should be feasible for an implementation to use negative offsets in the representation of composite types. However, no implementation should be forced to support negative offsets. Therefore, in the interest of uniformity, negative offsets should be disallowed in record_representation_clauses. Syntax 2 record_representation_clause ::= for first_subtype_local_name use record [mod_clause] {component_clause} end record; 3 component_clause ::= component_local_name at position range first_bit .. last_bit; 4 position ::= static_expression 5 first_bit ::= static_simple_expression 6 last_bit ::= static_simple_expression 6.a Reason: First_bit and last_bit need to be simple_expression instead of expression for the same reason as in range (see 3.5 , "Scalar Types"). Name Resolution Rules 7 {expected type (component_clause expressions) [partial]} {expected type (position) [partial]} {expected type (first_bit) [partial]} {expected type (last_bit) [partial]} Each position, first_bit, and last_bit is expected to be of any integer type. 7.a Ramification: These need not have the same integer type. Legality Rules 8/2 {AI95-00436-01} The first_subtype_local_name of a record_representation_clause shall denote a specific record or record extension subtype. 8.a Ramification: As for all type-related representation items, the local_name is required to denote a first subtype. 9 If the component_local_name is a direct_name, the local_name shall denote a component of the type. For a record extension, the component shall not be inherited, and shall not be a discriminant that corresponds to a discriminant of the parent type. If the component_local_name has an attribute_designator, the direct_name of the local_name shall denote either the declaration of the type or a component of the type, and the attribute_designator shall denote an implementation-defined implicit component of the type. 10 The position, first_bit, and last_bit shall be static expressions. The value of position and first_bit shall be nonnegative. The value of last_bit shall be no less than first_bit - 1. 10.a Ramification: A component_clause such as "X at 4 range 0..-1;" is allowed if X can fit in zero bits. 10.1/2 {AI95-00133-01} If the nondefault bit ordering applies to the type, then either: 10.2/2 * the value of last_bit shall be less than the size of the largest machine scalar; or 10.3/2 * the value of first_bit shall be zero and the value of last_bit + 1 shall be a multiple of System.Storage_Unit. 11 At most one component_clause is allowed for each component of the type, including for each discriminant (component_clauses may be given for some, all, or none of the components). Storage places within a component_list shall not overlap, unless they are for components in distinct variants of the same variant_part. 12 A name that denotes a component of a type is not allowed within a record_representation_clause for the type, except as the component_local_name of a component_clause. 12.a Reason: It might seem strange to make the record_representation_clause part of the declarative region, and then disallow mentions of the components within almost all of the record_representation_clause. The alternative would be to treat the component_local_name like a formal parameter name in a subprogram call (in terms of visibility). However, this rule would imply slightly different semantics, because (given the actual rule) the components can hide other declarations. This was the rule in Ada 83, and we see no reason to change it. The following, for example, was and is illegal: 12.b type T is record X : Integer; end record; X : constant := 31; -- Same defining name as the component. for T use record X at 0 range 0..X; -- Illegal! end record; 12.c The component X hides the named number X throughout the record_representation_clause. Static Semantics 13/2 {AI95-00133-01} A record_representation_clause (without the mod_clause) specifies the layout. 13.1/2 {AI95-00133-01} If the default bit ordering applies to the type, the position, first_bit, and last_bit of each component_clause directly specify the position and size of the corresponding component. 13.2/2 {AI95-00133-01} If the nondefault bit ordering applies to the type then the layout is determined as follows: 13.3/2 * the component_clauses for which the value of last_bit is greater than or equal to the size of the largest machine scalar directly specify the position and size of the corresponding component; 13.4/2 * for other component_clauses, all of the components having the same value of position are considered to be part of a single machine scalar, located at that position; this machine scalar has a size which is the smallest machine scalar size larger than the largest last_bit for all component_clauses at that position; the first_bit and last_bit of each component_clause are then interpreted as bit offsets in this machine scalar. 13.a/2 This paragraph was deleted.{AI95-00133-01} 13.b Ramification: A component_clause also determines the value of the Size attribute of the component, since this attribute is related to First_Bit and Last_Bit. 14 [A record_representation_clause for a record extension does not override the layout of the parent part;] if the layout was specified for the parent type, it is inherited by the record extension. Implementation Permissions 15 An implementation may generate implementation-defined components (for example, one containing the offset of another component). An implementation may generate names that denote such implementation-defined components; such names shall be implementation-defined attribute_references. An implemen- tation may allow such implementation-defined names to be used in record_- representation_clauses. An implementation can restrict such component_clauses in any manner it sees fit. 15.a Implementation defined: Implementation-defined components. 15.b Ramification: Of course, since the semantics of implementation-defined attributes is implementation defined, the implementation need not support these names in all situations. They might be purely for the purpose of component_clauses, for example. The visibility rules for such names are up to the implementation. 15.c We do not allow such component names to be normal identifiers - that would constitute blanket permission to do all kinds of evil things. 15.d Discussion: {dope} Such implementation-defined components are known in the vernacular as "dope." Their main purpose is for storing offsets of components that depend on discriminants. 16 If a record_representation_clause is given for an untagged derived type, the storage place attributes for all of the components of the derived type may differ from those of the corresponding components of the parent type, even for components whose storage place is not specified explicitly in the record_- representation_clause. 16.a Reason: This is clearly necessary, since the whole record may need to be laid out differently. Implementation Advice 17 {recommended level of support (record_representation_clause) [partial]} The recommended level of support for record_representation_clauses is: 17.1/2 * {AI95-00133-01} An implementation should support machine scalars that correspond to all of the integer, floating point, and address formats supported by the machine. 18 * An implementation should support storage places that can be extracted with a load, mask, shift sequence of machine code, and set with a load, shift, mask, store sequence, given the available machine instructions and run-time model. 19 * A storage place should be supported if its size is equal to the Size of the component subtype, and it starts and ends on a boundary that obeys the Alignment of the component subtype. 20/2 * {AI95-00133-01} For a component with a subtype whose Size is less than the word size, any storage place that does not cross an aligned word boundary should be supported. 20.a Reason: The above recommendations are sufficient to define interfaces to most interesting hardware. This causes less implementation burden than the definition in ACID, which requires arbitrary bit alignments of arbitrarily large components. Since the ACID definition is neither enforced by the ACVC, nor supported by all implementations, it seems OK for us to weaken it. 21 * An implementation may reserve a storage place for the tag field of a tagged type, and disallow other components from overlapping that place. 21.a Ramification: Similar permission for other dope is not granted. 22 * An implementation need not support a component_clause for a component of an extension part if the storage place is not after the storage places of all components of the parent type, whether or not those storage places had been specified. 22.a Reason: These restrictions are probably necessary if block equality operations are to be feasible for class-wide types. For block comparison to work, the implementation typically has to fill in any gaps with zero (or one) bits. If a "gap" in the parent type is filled in with a component in a type extension, then this won't work when a class-wide object is passed by reference, as is required. 22.b/2 Implementation Advice: The recommended level of support for record_representation_clauses should be followed. NOTES 23 11 If no component_clause is given for a component, then the choice of the storage place for the component is left to the implementation. If component_clauses are given for all components, the record_representation_clause completely specifies the representation of the type and will be obeyed exactly by the implementation. 23.a Ramification: The visibility rules prevent the name of a component of the type from appearing in a record_representation_clause at any place except for the component_local_name of a component_clause. However, since the record_representation_clause is part of the declarative region of the type declaration, the component names hide outer homographs throughout. 23.b/1 {8652/0009} {AI95-00137-01} A record_representation_clause cannot be given for a protected type, even though protected types, like record types, have components. The primary reason for this rule is that there is likely to be too much dope in a protected type - entry queues, bit maps for barrier values, etc. In order to control the representation of the user-defined components, simply declare a record type, give it a record_representation_clause, and give the protected type one component whose type is the record type. Alternatively, if the protected object is protecting something like a device register, it makes more sense to keep the thing being protected outside the protected object (possibly with a pointer to it in the protected object), in order to keep implementation-defined components out of the way. Examples 24 Example of specifying the layout of a record type: 25 Word : constant := 4; -- storage element is byte, 4 bytes per word 26 type State is (A,M,W,P); type Mode is (Fix, Dec, Exp, Signif); 27 type Byte_Mask is array (0..7) of Boolean; type State_Mask is array (State) of Boolean; type Mode_Mask is array (Mode) of Boolean; 28 type Program_Status_Word is record System_Mask : Byte_Mask; Protection_Key : Integer range 0 .. 3; Machine_State : State_Mask; Interrupt_Cause : Interruption_Code; Ilc : Integer range 0 .. 3; Cc : Integer range 0 .. 3; Program_Mask : Mode_Mask; Inst_Address : Address; end record; 29 for Program_Status_Word use record System_Mask at 0*Word range 0 .. 7; Protection_Key at 0*Word range 10 .. 11; -- bits 8,9 unused Machine_State at 0*Word range 12 .. 15; Interrupt_Cause at 0*Word range 16 .. 31; Ilc at 1*Word range 0 .. 1; -- second word Cc at 1*Word range 2 .. 3; Program_Mask at 1*Word range 4 .. 7; Inst_Address at 1*Word range 8 .. 31; end record; 30 for Program_Status_Word'Size use 8*System.Storage_Unit; for Program_Status_Word'Alignment use 8; NOTES 31 12 Note on the example: The record_representation_clause defines the record layout. The Size clause guarantees that (at least) eight storage elements are used for objects of the type. The Alignment clause guarantees that aliased, imported, or exported objects of the type will have addresses divisible by eight. Wording Changes from Ada 83 31.a The alignment_clause has been renamed to mod_clause and moved to Annex J, "Obsolescent Features". 31.b We have clarified that implementation-defined component names have to be in the form of an attribute_reference of a component or of the first subtype itself; surely Ada 83 did not intend to allow arbitrary identifiers. 31.c The RM83-13.4(7) wording incorrectly allows components in non-variant records to overlap. We have corrected that oversight. Incompatibilities With Ada 95 31.d/2 {AI95-00133-01} {incompatibilities with Ada 95} Amendment Correction: The meaning of a record_representation_clause for the nondefault bit order is now clearly defined. Thus, such clauses can be portably written. In order to do that though, the equivalence of bit 1 in word 1 to bit 9 in word 0 (for a machine with Storage_Unit = 8) had to be dropped for the nondefault bit order. Any record_representation_clauses which depends on that equivalence will break (although such code would imply a non-contiguous representation for a component, and it seems unlikely that compilers were supporting that anyway). Extensions to Ada 95 31.e/2 {AI95-00436-01} {extensions to Ada 95} Amendment Correction: The undocumented (and likely unintentional) incompatibility with Ada 83 caused by not allowing record_representation_clauses on limited record types is removed. 13.5.2 Storage Place Attributes Static Semantics 1 {storage place attributes (of a component)} For a component C of a composite, non-array object R, the storage place attributes are defined: 1.a Ramification: The storage place attributes are not (individually) specifiable, but the user may control their values by giving a record_representation_clause. 2/2 R.C'Position {AI95-00133-01} If the nondefault bit ordering applies to the composite type, and if a component_clause specifies the placement of C, denotes the value given for the position of the component_clause; otherwise, denotes the same value as R.C'Address - R'Address. The value of this attribute is of the type universal_integer. 2.a/2 Ramification: {AI95-00133-01} Thus, for the default bit order, R.C'Position is the offset of C in storage elements from the beginning of the object, where the first storage element of an object is numbered zero. R'Address + R.C'Position = R.C'Address. For record extensions, the offset is not measured from the beginning of the extension part, but from the beginning of the whole object, as usual. 2.b In "R.C'Address - R'Address", the "-" operator is the one in System.Storage_Elements that takes two Addresses and returns a Storage_Offset. 3/2 R.C'First_Bit {AI95-00133-01} If the nondefault bit ordering applies to the composite type, and if a component_clause specifies the placement of C, denotes the value given for the first_bit of the component_clause; otherwise, denotes the offset, from the start of the first of the storage elements occupied by C, of the first bit occupied by C. This offset is measured in bits. The first bit of a storage element is numbered zero. The value of this attribute is of the type universal_integer. 4/2 R.C'Last_Bit {AI95-00133-01} If the nondefault bit ordering applies to the composite type, and if a component_clause specifies the placement of C, denotes the value given for the last_bit of the component_clause; otherwise, denotes the offset, from the start of the first of the storage elements occupied by C, of the last bit occupied by C. This offset is measured in bits. The value of this attribute is of the type universal_integer. 4.a/2 Ramification: {AI95-00114-01} The ordering of bits in a storage element is defined in 13.5.3, "Bit Ordering". 4.b R.C'Size = R.C'Last_Bit - R.C'First_Bit + 1. (Unless the implementation chooses an indirection representation.) 4.c If a component_clause applies to a component, then that component will be at the same relative storage place in all objects of the type. Otherwise, there is no such requirement. Implementation Advice 5 {contiguous representation [partial]} {discontiguous representation [partial]} If a component is represented using some form of pointer (such as an offset) to the actual data of the component, and this data is contiguous with the rest of the object, then the storage place attributes should reflect the place of the actual data, not the pointer. If a component is allocated discontiguously from the rest of the object, then a warning should be generated upon reference to one of its storage place attributes. 5.a Reason: For discontiguous components, these attributes make no sense. For example, an implementation might allocate dynamic-sized components on the heap. For another example, an implementation might allocate the discriminants separately from the other components, so that multiple objects of the same subtype can share discriminants. Such representations cannot happen if there is a component_clause for that component. 5.b/2 Implementation Advice: If a component is represented using a pointer to the actual data of the component which is contiguous with the rest of the object, then the storage place attributes should reflect the place of the actual data. If a component is allocated discontiguously from the rest of the object, then a warning should be generated upon reference to one of its storage place attributes. Incompatibilities With Ada 95 5.c/2 {AI95-00133-01} {incompatibilities with Ada 95} Amendment Correction: The meaning of the storage place attributes for the nondefault bit order is now clearly defined, and can be different than that given by strictly following the Ada 95 wording. Any code which depends on the original Ada 95 values for a type using the nondefault bit order where they are different will break. 13.5.3 Bit Ordering 1 [The Bit_Order attribute specifies the interpretation of the storage place attributes.] 1.a Reason: The intention is to provide uniformity in the interpretation of storage places across implementations on a particular machine by allowing the user to specify the Bit_Order. It is not intended to fully support data interoperability across different machines, although it can be used for that purpose in some situations. 1.b/2 {AI95-00114-01} We can't require all implementations on a given machine to use the same bit ordering by default; if the user cares, a Bit_Order attribute_definition_clause can be used to force all implementations to use the same bit ordering. Static Semantics 2 {bit ordering} A bit ordering is a method of interpreting the meaning of the storage place attributes. {High_Order_First} {big endian} {endian (big)} High_Order_First [(known in the vernacular as "big endian")] means that the first bit of a storage element (bit 0) is the most significant bit (interpreting the sequence of bits that represent a component as an unsigned integer value). {Low_Order_First} {little endian} {endian (little)} Low_Order_First [(known in the vernacular as "little endian")] means the opposite: the first bit is the least significant. 3 For every specific record subtype S, the following attribute is defined: 4 S'Bit_Order Denotes the bit ordering for the type of S. The value of this attribute is of type System.Bit_Order. {specifiable (of Bit_Order for record types and record extensions) [partial]} {Bit_Order clause} Bit_Order may be specified for specific record types via an attribute_definition_clause; the expression of such a clause shall be static. 5 If Word_Size = Storage_Unit, the default bit ordering is implementation defined. If Word_Size > Storage_Unit, the default bit ordering is the same as the ordering of storage elements in a word, when interpreted as an integer. {byte sex: See ordering of storage elements in a word} 5.a Implementation defined: If Word_Size = Storage_Unit, the default bit ordering. 5.b Ramification: Consider machines whose Word_Size = 32, and whose Storage_Unit = 8. Assume the default bit ordering applies. On a machine with big-endian addresses, the most significant storage element of an integer is at the address of the integer. Therefore, bit zero of a storage element is the most significant bit. On a machine with little-endian addresses, the least significant storage element of an integer is at the address of the integer. Therefore, bit zero of a storage element is the least significant bit. 6 The storage place attributes of a component of a type are interpreted according to the bit ordering of the type. 6.a Ramification: This implies that the interpretation of the position, first_bit, and last_bit of a component_clause of a record_representation_clause obey the bit ordering given in a representation item. Implementation Advice 7 {recommended level of support (bit ordering) [partial]} The recommended level of support for the nondefault bit ordering is: 8/2 * {AI95-00133-01} The implementation should support the nondefault bit ordering in addition to the default bit ordering. 8.a/2 Ramification: {AI95-00133-01} The implementation should support both bit orderings. Implementations are required to support storage positions that cross storage element boundaries when Word_Size > Storage_Unit but the definition of the storage place attributes for the nondefault bit order ensures that such storage positions will not be split into two or three pieces. Thus, there is no significant implementation burden to supporting the nondefault bit order, given that the set of machine scalars is implementation-defined. 8.b/2 Implementation Advice: The recommended level of support for the nondefault bit ordering should be followed. NOTES 9/2 13 {AI95-00133-01} Bit_Order clauses make it possible to write record_representation_clauses that can be ported between machines having different bit ordering. They do not guarantee transparent exchange of data between such machines. Extensions to Ada 83 9.a {extensions to Ada 83} The Bit_Order attribute is new to Ada 95. Wording Changes from Ada 95 9.b/2 {AI95-00133-01} We now suggest that all implementations support the nondefault bit order. 13.6 Change of Representation 1 [{change of representation} {representation (change of)} A type_conversion (see 4.6) can be used to convert between two different representations of the same array or record. To convert an array from one representation to another, two array types need to be declared with matching component subtypes, and convertible index types. If one type has packing specified and the other does not, then explicit conversion can be used to pack or unpack an array. 2 To convert a record from one representation to another, two record types with a common ancestor type need to be declared, with no inherited subprograms. Distinct representations can then be specified for the record types, and explicit conversion between the types can be used to effect a change in representation.] 2.a Ramification: This technique does not work if the first type is an untagged type with user-defined primitive subprograms. It does not work at all for tagged types. Examples 3 Example of change of representation: 4 -- Packed_Descriptor and Descriptor are two different types -- with identical characteristics, apart from their -- representation 5 type Descriptor is record -- components of a descriptor end record; 6 type Packed_Descriptor is new Descriptor; 7 for Packed_Descriptor use record -- component clauses for some or for all components end record; 8 -- Change of representation can now be accomplished by explicit type conversions: 9 D : Descriptor; P : Packed_Descriptor; 10 P := Packed_Descriptor(D); -- pack D D := Descriptor(P); -- unpack P 13.7 The Package System 1 [For each implementation there is a library package called System which includes the definitions of certain configuration-dependent characteristics.] Static Semantics 2 The following language-defined library package exists: 2.a/2 Implementation defined: The contents of the visible part of package System. 3/2 {AI95-00362-01} package System is pragma Pure(System); 4 type Name is implementation-defined-enumeration-type; System_Name : constant Name := implementation-defined; 5 -- System-Dependent Named Numbers: 6 Min_Int : constant := root_integer'First; Max_Int : constant := root_integer'Last; 7 Max_Binary_Modulus : constant := implementation-defined; Max_Nonbinary_Modulus : constant := implementation-defined; 8 Max_Base_Digits : constant := root_real'Digits; Max_Digits : constant := implementation-defined; 9 Max_Mantissa : constant := implementation-defined; Fine_Delta : constant := implementation-defined; 10 Tick : constant := implementation-defined; 11 -- Storage-related Declarations: 12 type Address is implementation-defined; Null_Address : constant Address; 13 Storage_Unit : constant := implementation-defined; Word_Size : constant := implementation-defined * Storage_Unit; Memory_Size : constant := implementation-defined; 14 -- {address (comparison)} Address Comparison: function "<" (Left, Right : Address) return Boolean; function "<="(Left, Right : Address) return Boolean; function ">" (Left, Right : Address) return Boolean; function ">="(Left, Right : Address) return Boolean; function "=" (Left, Right : Address) return Boolean; -- function "/=" (Left, Right : Address) return Boolean; -- "/=" is implicitly defined pragma Convention(Intrinsic, "<"); ... -- and so on for all language-defined subprograms in this package 15/2 {AI95-00221-01} -- Other System-Dependent Declarations: type Bit_Order is (High_Order_First, Low_Order_First); Default_Bit_Order : constant Bit_Order := implementation-defined; 16 -- Priority-related declarations (see D.1): subtype Any_Priority is Integer range implementation-defined; subtype Priority is Any_Priority range Any_Priority'First .. implementation-defined; subtype Interrupt_Priority is Any_Priority range Priority'Last+1 .. Any_Priority'Last; 17 Default_Priority : constant Priority := (Priority'First + Priority'Last)/2; 18 private ... -- not specified by the language end System; 19 Name is an enumeration subtype. Values of type Name are the names of alternative machine configurations handled by the implementation. System_Name represents the current machine configuration. 20 The named numbers Fine_Delta and Tick are of the type universal_real; the others are of the type universal_integer. 21 The meanings of the named numbers are: 22 [ Min_Int The smallest (most negative) value allowed for the expressions of a signed_integer_type_definition. 23 Max_Int The largest (most positive) value allowed for the expressions of a signed_integer_type_definition. 24 Max_Binary_Modulus A power of two such that it, and all lesser positive powers of two, are allowed as the modulus of a modular_type_definition. 25 Max_Nonbinary_Modulus A value such that it, and all lesser positive integers, are allowed as the modulus of a modular_type_definition. 25.a Ramification: There is no requirement that Max_Nonbinary_Modulus be less than or equal to Max_Binary_Modulus, although that's what makes most sense. On a typical 32-bit machine, for example, Max_Binary_Modulus will be 2**32 and Max_Nonbinary_Modulus will be 2**31, because supporting nonbinary moduli in above 2**31 causes implementation difficulties. 26 Max_Base_Digits The largest value allowed for the requested decimal precision in a floating_point_definition. 27 Max_Digits The largest value allowed for the requested decimal precision in a floating_point_definition that has no real_range_specification. Max_Digits is less than or equal to Max_Base_Digits. 28 Max_Mantissa The largest possible number of binary digits in the mantissa of machine numbers of a user-defined ordinary fixed point type. (The mantissa is defined in Annex G.) 29 Fine_Delta The smallest delta allowed in an ordinary_fixed_point_definition that has the real_range_- specification range -1.0 .. 1.0. ] 30 Tick A period in seconds approximating the real time interval during which the value of Calendar.Clock remains constant. 30.a Ramification: There is no required relationship between System.Tick and Duration'Small, other than the one described here. 30.b The inaccuracy of the delay_statement has no relation to Tick. In particular, it is possible that the clock used for the delay_statement is less accurate than Calendar.Clock. 30.c We considered making Tick a run-time-determined quantity, to allow for easier configurability. However, this would not be upward compatible, and the desired configurability can be achieved using functionality defined in Annex D, "Real-Time Systems". 31 Storage_Unit The number of bits per storage element. 32 Word_Size The number of bits per word. 33 Memory_Size An implementation-defined value [that is intended to reflect the memory size of the configuration in storage elements.] 33.a Discussion: It is unspecified whether this refers to the size of the address space, the amount of physical memory on the machine, or perhaps some other interpretation of "memory size." In any case, the value has to be given by a static expression, even though the amount of memory on many modern machines is a dynamic quantity in several ways. Thus, Memory_Size is not very useful. 34/2 {AI95-00161-01} Address is a definite, nonlimited type with preelaborable initialization (see 10.2.1). Address represents machine addresses capable of addressing individual storage elements. Null_Address is an address that is distinct from the address of any object or program unit. {pointer: See type System.Address} 34.a Ramification: The implementation has to ensure that there is at least one address that nothing will be allocated to; Null_Address will be one such address. 34.b Ramification: Address is the type of the result of the attribute Address. 34.c Reason: Address is required to be nonlimited and definite because it is important to be able to assign addresses, and to declare uninitialized address variables. 34.d/2 Ramification: {AI95-00161-01} If System.Address is defined as a private type (as suggested below), it might be necessary to add a pragma Preelaborable_Initialization to the specification of System in order that Address have preelaborable initialization as required. 35/2 {AI95-00221-01} Default_Bit_Order shall be a static constant. See 13.5.3 for an explanation of Bit_Order and Default_Bit_Order. Implementation Permissions 36/2 {AI95-00362-01} An implementation may add additional implementation-defined declarations to package System and its children. [However, it is usually better for the implementation to provide additional functionality via implementation-defined children of System.] 36.a Ramification: The declarations in package System and its children can be implicit. For example, since Address is not limited, the predefined "=" and "/=" operations are probably sufficient. However, the implementation is not required to use the predefined "=". Implementation Advice 37 Address should be a private type. 37.a Reason: This promotes uniformity by avoiding having implementation-defined predefined operations for the type. We don't require it, because implementations may want to stick with what they have. 37.a.1/2 Implementation Advice: Type System.Address should be a private type. 37.b Implementation Note: It is not necessary for Address to be able to point at individual bits within a storage element. Nor is it necessary for it to be able to point at machine registers. It is intended as a memory address that matches the hardware's notion of an address. 37.c The representation of the null value of a general access type should be the same as that of Null_Address; instantiations of Unchecked_Conversion should work accordingly. If the implementation supports interfaces to other languages, the representation of the null value of a general access type should be the same as in those other languages, if appropriate. 37.d Note that the children of the Interfaces package will generally provide foreign-language-specific null values where appropriate. See UI-0065 regarding Null_Address. NOTES 38 14 There are also some language-defined child packages of System defined elsewhere. Extensions to Ada 83 38.a.1/1 {extensions to Ada 83} The declarations Max_Binary_Modulus, Max_Nonbinary_Modulus, Max_Base_Digits, Null_Address, Word_Size, Bit_Order, Default_Bit_Order, Any_Priority, Interrupt_Priority, and Default_Priority are added to System in Ada 95. The presence of ordering operators for type Address is also guaranteed (the existence of these depends on the definition of Address in an Ada 83 implementation). We do not list these as incompatibilities, as the contents of System can vary between implementations anyway; thus a program that depends on the contents of System (by using use System; for example) is already at risk of being incompatible when moved between Ada implementations. Wording Changes from Ada 83 38.a Much of the content of System is standardized, to provide more uniformity across implementations. Implementations can still add their own declarations to System, but are encouraged to do so via children of System. 38.b Some of the named numbers are defined more explicitly in terms of the standard numeric types. 38.c The pragmas System_Name, Storage_Unit, and Memory_Size are no longer defined by the language. However, the corresponding declarations in package System still exist. Existing implementations may continue to support the three pragmas as implementation-defined pragmas, if they so desire. 38.d Priority semantics, including subtype Priority, have been moved to the Real Time Annex. Extensions to Ada 95 38.e/2 {AI95-00161-01} {extensions to Ada 95} Amendment Correction: Type Address is defined to have preelaborable initialization, so that it can be used without restriction in preelaborated units. (If Address is defined to be a private type, as suggested by the Implementation Advice, in Ada 95 it cannot be used in some contexts in a preelaborated units. This is an unnecessary portability issue.) 38.f/2 {AI95-00221-01} Amendment Correction: Default_Bit_Order is now a static constant. 38.g/2 {AI95-00362-01} Package System is now Pure, so it can be portably used in more places. (Ada 95 allowed it to be Pure, but did not require that.) 13.7.1 The Package System.Storage_Elements Static Semantics 1 The following language-defined library package exists: 2/2 {AI95-00362-01} package System.Storage_Elements is pragma Pure(Storage_Elements); 3 type Storage_Offset is range implementation-defined; 4 subtype Storage_Count is Storage_Offset range 0..Storage_Offset'Last; 5 type Storage_Element is mod implementation-defined; for Storage_Element'Size use Storage_Unit; type Storage_Array is array (Storage_Offset range <>) of aliased Storage_Element; for Storage_Array'Component_Size use Storage_Unit; 6 -- {address (arithmetic)} Address Arithmetic: 7 function "+"(Left : Address; Right : Storage_Offset) return Address; function "+"(Left : Storage_Offset; Right : Address) return Address; function "-"(Left : Address; Right : Storage_Offset) return Address; function "-"(Left, Right : Address) return Storage_Offset; 8 function "mod"(Left : Address; Right : Storage_Offset) return Storage_Offset; 9 -- Conversion to/from integers: 10 type Integer_Address is implementation-defined; function To_Address(Value : Integer_Address) return Address; function To_Integer(Value : Address) return Integer_Address; 11 pragma Convention(Intrinsic, "+"); -- ...and so on for all language-defined subprograms declared in this package. end System.Storage_Elements; 11.a Reason: The Convention pragmas imply that the attribute Access is not allowed for those operations. 11.b The mod function is needed so that the definition of Alignment makes sense. 11.c/2 Implementation defined: The range of Storage_Elements.Storage_Offset, the modulus of Storage_Elements.Storage_Element, and the declaration of Storage_Elements.Integer_Address.. 12 Storage_Element represents a storage element. Storage_Offset represents an offset in storage elements. Storage_Count represents a number of storage elements. {contiguous representation [partial]} {discontiguous representation [partial]} Storage_Array represents a contiguous sequence of storage elements. 12.a Reason: The index subtype of Storage_Array is Storage_Offset because we wish to allow maximum flexibility. Most Storage_Arrays will probably have a lower bound of 0 or 1, but other lower bounds, including negative ones, make sense in some situations. 12.b/2 This paragraph was deleted.{AI95-00114-01} 13 Integer_Address is a [(signed or modular)] integer subtype. To_Address and To_Integer convert back and forth between this type and Address. Implementation Requirements 14 Storage_Offset'Last shall be greater than or equal to Integer'Last or the largest possible storage offset, whichever is smaller. Storage_Offset'First shall be <= (-Storage_Offset'Last). Implementation Permissions 15/2 This paragraph was deleted.{AI95-00362-01} Implementation Advice 16 Operations in System and its children should reflect the target environment semantics as closely as is reasonable. For example, on most machines, it makes sense for address arithmetic to "wrap around." {Program_Error (raised by failure of run-time check)} Operations that do not make sense should raise Program_Error. 16.a.1/2 Implementation Advice: Operations in System and its children should reflect the target environment; operations that do not make sense should raise Program_Error. 16.a Discussion: For example, on a segmented architecture, X < Y might raise Program_Error if X and Y do not point at the same segment (assuming segments are unordered). Similarly, on a segmented architecture, the conversions between Integer_Address and Address might not make sense for some values, and so might raise Program_Error. 16.b Reason: We considered making Storage_Element a private type. However, it is better to declare it as a modular type in the visible part, since code that uses it is already low level, and might as well have access to the underlying representation. We also considered allowing Storage_Element to be any integer type, signed integer or modular, but it is better to have uniformity across implementations in this regard, and viewing storage elements as unsigned seemed to make the most sense. 16.c Implementation Note: To_Address is intended for use in Address clauses. Implementations should overload To_Address if appropriate. For example, on a segmented architecture, it might make sense to have a record type representing a segment/offset pair, and have a To_Address conversion that converts from that record type to type Address. Extensions to Ada 95 16.d/2 {AI95-00362-01} {extensions to Ada 95} Package System.Storage_Elements is now Pure, so it can be portably used in more places. (Ada 95 allowed it to be Pure, but did not require that.) 13.7.2 The Package System.Address_To_Access_Conversions Static Semantics 1 The following language-defined generic library package exists: 2 generic type Object(<>) is limited private; package System.Address_To_Access_Conversions is pragma Preelaborate(Address_To_Access_Conversions); 3 type Object_Pointer is access all Object; function To_Pointer(Value : Address) return Object_Pointer; function To_Address(Value : Object_Pointer) return Address; 4 pragma Convention(Intrinsic, To_Pointer); pragma Convention(Intrinsic, To_Address); end System.Address_To_Access_Conversions; 5/2 {AI95-00230-01} The To_Pointer and To_Address subprograms convert back and forth between values of types Object_Pointer and Address. To_Pointer(X'Address) is equal to X'Unchecked_Access for any X that allows Unchecked_Access. To_Pointer(Null_Address) returns null. {unspecified [partial]} For other addresses, the behavior is unspecified. To_Address(null) returns Null_Address. To_Address(Y), where Y /= null, returns Y.all'Address. 5.a/2 Discussion: {AI95-00114-01} The programmer should ensure that the address passed to To_Pointer is either Null_Address, or the address of an object of type Object. (If Object is not a not by-reference type, the object ought to be aliased; recall that the Address attribute is not required to provide a useful result other objects.) Otherwise, the behavior of the program is unspecified; it might raise an exception or crash, for example. 5.b Reason: Unspecified is almost the same thing as erroneous; they both allow arbitrarily bad behavior. We don't say erroneous here, because the implementation might allow the address passed to To_Pointer to point at some memory that just happens to "look like" an object of type Object. That's not necessarily an error; it's just not portable. However, if the actual type passed to Object is (for example) an array type, the programmer would need to be aware of any dope that the implementation expects to exist, when passing an address that did not come from the Address attribute of an object of type Object. 5.c One might wonder why To_Pointer and To_Address are any better than unchecked conversions. The answer is that Address does not necessarily have the same representation as an access type. For example, an access value might point at the bounds of an array when an address would point at the first element. Or an access value might be an offset in words from someplace, whereas an address might be an offset in bytes from the beginning of memory. Implementation Permissions 6 An implementation may place restrictions on instantiations of Address_To_Access_Conversions. 6.a Ramification: For example, if the hardware requires aligned loads and stores, then dereferencing an access value that is not properly aligned might raise an exception. 6.b For another example, if the implementation has chosen to use negative component offsets (from an access value), it might not be possible to preserve the semantics, since negative offsets from the Address are not allowed. (The Address attribute always points at "the first of the storage elements....") Note that while the implementation knows how to convert an access value into an address, it might not be able to do the reverse. To avoid generic contract model violations, the restriction might have to be detected at run time in some cases. 13.8 Machine Code Insertions 1 [{machine code insertion} A machine code insertion can be achieved by a call to a subprogram whose sequence_of_statements contains code_statements.] Syntax 2 code_statement ::= qualified_expression; 3 A code_statement is only allowed in the handled_sequence_of_statements of a subprogram_body. If a subprogram_body contains any code_statements, then within this subprogram_body the only allowed form of statement is a code_statement (labeled or not), the only allowed declarative_items are use_clauses, and no exception_handler is allowed (comments and pragmas are allowed as usual). Name Resolution Rules 4 {expected type (code_statement) [partial]} The qualified_expression is expected to be of any type. Legality Rules 5 The qualified_expression shall be of a type declared in package System.Machine_Code. 5.a Ramification: This includes types declared in children of System.Machine_Code. 6 A code_statement shall appear only within the scope of a with_clause that mentions package System.Machine_Code. 6.a Ramification: Note that this is not a note; without this rule, it would be possible to write machine code in compilation units which depend on System.Machine_Code only indirectly. Static Semantics 7 {System.Machine_Code} The contents of the library package System.Machine_Code (if provided) are implementation defined. The meaning of code_statements is implementation defined. [Typically, each qualified_expression represents a machine instruction or assembly directive.] 7.a Discussion: For example, an instruction might be a record with an Op_Code component and other components for the operands. 7.b Implementation defined: The contents of the visible part of package System.Machine_Code, and the meaning of code_statements. Implementation Permissions 8 An implementation may place restrictions on code_statements. An implementation is not required to provide package System.Machine_Code. NOTES 9 15 An implementation may provide implementation-defined pragmas specifying register conventions and calling conventions. 10/2 16 {AI95-00318-02} Machine code functions are exempt from the rule that a return statement is required. In fact, return statements are forbidden, since only code_statements are allowed. 10.a Discussion: The idea is that the author of a machine code subprogram knows the calling conventions, and refers to parameters and results accordingly. The implementation should document where to put the result of a machine code function, for example, " Scalar results are returned in register 0." 11 17 Intrinsic subprograms (see 6.3.1, "Conformance Rules") can also be used to achieve machine code insertions. Interface to assembly language can be achieved using the features in Annex B, " Interface to Other Languages". Examples 12 Example of a code statement: 13 M : Mask; procedure Set_Mask; pragma Inline(Set_Mask); 14 procedure Set_Mask is use System.Machine_Code; -- assume "with System.Machine_Code;" appears somewhere above begin SI_Format'(Code => SSM, B => M'Base_Reg, D => M'Disp); -- Base_Reg and Disp are implementation-defined attributes end Set_Mask; Extensions to Ada 83 14.a {extensions to Ada 83} Machine code functions are allowed in Ada 95; in Ada 83, only procedures were allowed. Wording Changes from Ada 83 14.b The syntax for code_statement is changed to say " qualified_expression" instead of "subtype_mark'record_aggregate ". Requiring the type of each instruction to be a record type is overspecification. 13.9 Unchecked Type Conversions 1 [{unchecked type conversion} {type conversion (unchecked)} {conversion (unchecked)} {type_conversion: See also unchecked type conversion} {cast: See unchecked type conversion} An unchecked type conversion can be achieved by a call to an instance of the generic function Unchecked_Conversion.] Static Semantics 2 The following language-defined generic library function exists: 3 generic type Source(<>) is limited private; type Target(<>) is limited private; function Ada.Unchecked_Conversion(S : Source) return Target; pragma Convention(Intrinsic, Ada.Unchecked_Conversion); pragma Pure(Ada.Unchecked_Conversion); 3.a Reason: The pragma Convention implies that the attribute Access is not allowed for instances of Unchecked_Conversion. Dynamic Semantics 4 The size of the formal parameter S in an instance of Unchecked_Conversion is that of its subtype. [This is the actual subtype passed to Source, except when the actual is an unconstrained composite subtype, in which case the subtype is constrained by the bounds or discriminants of the value of the actual expression passed to S.] 5 If all of the following are true, the effect of an unchecked conversion is to return the value of an object of the target subtype whose representation is the same as that of the source object S: 6 * S'Size = Target'Size. 6.a Ramification: Note that there is no requirement that the Sizes be known at compile time. 7 * S'Alignment = Target'Alignment. 8 * The target subtype is not an unconstrained composite subtype. 9 * {contiguous representation [partial]} {discontiguous representation [partial]} S and the target subtype both have a contiguous representation. 10 * The representation of S is a representation of an object of the target subtype. 11/2 {AI95-00426-01} Otherwise, if the result type is scalar, the result of the function is implementation defined, and can have an invalid representation (see 13.9.1). If the result type is nonscalar, the effect is implementation defined; in particular, the result can be abnormal (see 13.9.1). 11.a.1/2 Implementation defined: The result of unchecked conversion for instances with scalar result types whose result is not defined by the language. 11.a/2 Implementation defined: The effect of unchecked conversion for instances with nonscalar result types whose effect is not defined by the language. 11.a.1/2 Reason: {AI95-00426-01} Note the difference between these sentences; the first only says that the bits returned are implementation defined, while the latter allows any effect. The difference is because scalar objects should never be abnormal unless their assignment was disrupted or if they are a subcomponent of an abnormal composite object. Neither exception applies to instances of Unchecked_Conversion. 11.a.2/2 Ramification: {AI95-00426-01} Whenever unchecked conversions are used, it is the programmer's responsibility to ensure that these conversions maintain the properties that are guaranteed by the language for objects of the target type. For nonscalar types, this requires the user to understand the underlying run-time model of the implementation. The execution of a program that violates these properties by means of unchecked conversions returning a nonscalar type is erroneous. Properties of scalar types can be checked by using the Valid attribute (see 13.9.2); programs can avoid violating properties of the type (and erroneous execution) by careful use of this attribute. 11.b An instance of Unchecked_Conversion can be applied to an object of a private type, assuming the implementation allows it. Implementation Permissions 12 An implementation may return the result of an unchecked conversion by reference, if the Source type is not a by-copy type. [In this case, the result of the unchecked conversion represents simply a different (read-only) view of the operand of the conversion.] 12.a Ramification: In other words, the result object of a call on an instance of Unchecked_Conversion can occupy the same storage as the formal parameter S. 13 An implementation may place restrictions on Unchecked_Conversion. 13.a Ramification: For example, an instantiation of Unchecked_Conversion for types for which unchecked conversion doesn't make sense may be disallowed. Implementation Advice 14/2 {AI95-00051-02} Since the Size of an array object generally does not include its bounds, the bounds should not be part of the converted data. 14.a.1/2 Implementation Advice: Since the Size of an array object generally does not include its bounds, the bounds should not be part of the converted data in an instance of Unchecked_Conversion. 14.a Ramification: On the other hand, we have no advice to offer about discriminants and tag fields. 15 The implementation should not generate unnecessary run-time checks to ensure that the representation of S is a representation of the target type. It should take advantage of the permission to return by reference when possible. Restrictions on unchecked conversions should be avoided unless required by the target environment. 15.a.1/2 Implementation Advice: There should not be unnecessary run-time checks on the result of an Unchecked_Conversion; the result should be returned by reference when possible. Restrictions on Unchecked_Conversions should be avoided. 15.a Implementation Note: As an example of an unnecessary run-time check, consider a record type with gaps between components. The compiler might assume that such gaps are always zero bits. If a value is produced that does not obey that assumption, then the program might misbehave. The implementation should not generate extra code to check for zero bits (except, perhaps, in a special error-checking mode). 16 {recommended level of support (unchecked conversion) [partial]} The recommended level of support for unchecked conversions is: 17 * Unchecked conversions should be supported and should be reversible in the cases where this clause defines the result. {contiguous representation [partial]} {discontiguous representation [partial]} To enable meaningful use of unchecked conversion, a contiguous representation should be used for elementary subtypes, for statically constrained array subtypes whose component subtype is one of the subtypes described in this paragraph, and for record subtypes without discriminants whose component subtypes are described in this paragraph. 17.a/2 Implementation Advice: The recommended level of support for Unchecked_Conversion should be followed. Wording Changes from Ada 95 17.b/2 {AI95-00051-02} The implementation advice about the size of array objects was moved to 13.3 so that all of the advice about Size is in one place. 17.c/2 {AI95-00426-01} Clarified that the result of Unchecked_Conversion for scalar types can be invalid, but not abnormal. 13.9.1 Data Validity 1 Certain actions that can potentially lead to erroneous execution are not directly erroneous, but instead can cause objects to become abnormal. Subsequent uses of abnormal objects can be erroneous. 2 A scalar object can have an invalid representation, which means that the object's representation does not represent any value of the object's subtype. {uninitialized variables [distributed]} The primary cause of invalid representations is uninitialized variables. 3 Abnormal objects and invalid representations are explained in this subclause. Dynamic Semantics 4 {normal state of an object [distributed]} {abnormal state of an object [distributed]} When an object is first created, and any explicit or default initializations have been performed, the object and all of its parts are in the normal state. Subsequent operations generally leave them normal. However, an object or part of an object can become abnormal in the following ways: 5 * {disruption of an assignment} An assignment to the object is disrupted due to an abort (see 9.8) or due to the failure of a language-defined check (see 11.6). 6/2 * {AI95-00426-01} The object is not scalar, and is passed to an in out or out parameter of an imported procedure, the Read procedure of an instance of Sequential_IO, Direct_IO, or Storage_IO, or the stream attribute T'Read, if after return from the procedure the representation of the parameter does not represent a value of the parameter's subtype. 6.1/2 * {AI95-00426-01} The object is the return object of a function call of a nonscalar type, and the function is an imported function, an instance of Unchecked_Conversion, or the stream attribute T'Input, if after return from the function the representation of the return object does not represent a value of the function's subtype. 6.a/2 Discussion: We explicitly list the routines involved in order to avoid future arguments. All possibilities are listed. 6.b/2 We did not include Stream_IO.Read in the list above. A Stream_Element should include all possible bit patterns, and thus it cannot be invalid. Therefore, the parameter will always represent a value of its subtype. By omitting this routine, we make it possible to write arbitrary I/O operations without any possibility of abnormal objects. 6.2/2 {AI95-00426-01} [For an imported object, it is the programmer's responsibility to ensure that the object remains in a normal state.] 6.c/2 Proof: This follows (and echos) the standard rule of interfacing; the programmer must ensure that Ada semantics are followed (see B.1). 7 {unspecified [partial]} Whether or not an object actually becomes abnormal in these cases is not specified. An abnormal object becomes normal again upon successful completion of an assignment to the object as a whole. Erroneous Execution 8 {erroneous execution (cause) [partial]} It is erroneous to evaluate a primary that is a name denoting an abnormal object, or to evaluate a prefix that denotes an abnormal object. 8.a/2 This paragraph was deleted.{AI95-00114-01} 8.b Ramification: The in out or out parameter case does not apply to scalars; bad scalars are merely invalid representations, rather than abnormal, in this case. 8.c/2 Reason: {AI95-00114-01} The reason we allow access objects, and objects containing subcomponents of an access type, to become abnormal is because the correctness of an access value cannot necessarily be determined merely by looking at the bits of the object. The reason we allow scalar objects to become abnormal is that we wish to allow the compiler to optimize assuming that the value of a scalar object belongs to the object's subtype, if the compiler can prove that the object is initialized with a value that belongs to the subtype. The reason we allow composite objects to become abnormal is that such object might be represented with implicit levels of indirection; if those are corrupted, then even assigning into a component of the object, or simply asking for its Address, might have an unpredictable effect. The same is true if the discriminants have been destroyed. Bounded (Run-Time) Errors 9 {invalid representation} {bounded error (cause) [partial]} If the representation of a scalar object does not represent a value of the object's subtype (perhaps because the object was not initialized), the object is said to have an invalid representation. It is a bounded error to evaluate the value of such an object. {Program_Error (raised by failure of run-time check)} {Constraint_Error (raised by failure of run-time check)} If the error is detected, either Constraint_Error or Program_Error is raised. Otherwise, execution continues using the invalid representation. The rules of the language outside this subclause assume that all objects have valid representations. The semantics of operations on invalid representations are as follows: 9.a Discussion: The AARM is more explicit about what happens when the value of the case expression is an invalid representation. 9.b/2 Ramification: {AI95-00426-01} This includes the result object of functions, including the result of Unchecked_Conversion, T'Input, and imported functions. 10 * If the representation of the object represents a value of the object's type, the value of the type is used. 11 * If the representation of the object does not represent a value of the object's type, the semantics of operations on such representations is implementation-defined, but does not by itself lead to erroneous or unpredictable execution, or to other objects becoming abnormal. 11.a/2 Implementation Note: {AI95-00426-01} This means that the implementation must take care not to use an invalid representation in a way that might cause erroneous execution. For instance, the exception mandated for case_statements must be raised. Array indexing must not cause memory outside of the array to be written (and usually, not read either). These cases and similar cases may require explicit checks by the implementation. Erroneous Execution 12/2 {AI95-00167-01} {erroneous execution (cause) [partial]} A call to an imported function or an instance of Unchecked_Conversion is erroneous if the result is scalar, the result object has an invalid representation, and the result is used other than as the expression of an assignment_statement or an object_declaration, or as the prefix of a Valid attribute. If such a result object is used as the source of an assignment, and the assigned value is an invalid representation for the target of the assignment, then any use of the target object prior to a further assignment to the target object, other than as the prefix of a Valid attribute reference, is erroneous. 12.a/2 Ramification: {AI95-00167-01} In a typical implementation, every bit pattern that fits in an object of a signed integer subtype will represent a value of the type, if not of the subtype. However, for an enumeration or floating point type, as well as some modular types, there are typically bit patterns that do not represent any value of the type. In such cases, the implementation ought to define the semantics of operations on the invalid representations in the obvious manner (assuming the bounded error is not detected): a given representation should be equal to itself, a representation that is in between the internal codes of two enumeration literals should behave accordingly when passed to comparison operators and membership tests, etc. We considered requiring such sensible behavior, but it resulted in too much arcane verbiage, and since implementations have little incentive to behave irrationally, such verbiage is not important to have. 12.b/2 {AI95-00167-01} If a stand-alone scalar object is initialized to a an in-range value, then the implementation can take advantage of the fact that the use of any out-of-range value has to be erroneous. Such an out-of-range value can be produced only by things like unchecked conversion, imported functions, and abnormal values caused by disruption of an assignment due to abort or to failure of a language-defined check. This depends on out-of-range values being checked before assignment (that is, checks are not optimized away unless they are proven redundant). 12.c Consider the following example: 12.d/2 {AI95-00167-01} type My_Int is range 0..99; function Safe_Convert is new Unchecked_Conversion(My_Int, Integer); function Unsafe_Convert is new Unchecked_Conversion(My_Int, Positive); X : Positive := Safe_Convert(0); -- Raises Constraint_Error. Y : Positive := Unsafe_Convert(0); -- Bounded Error, may be invalid. B : Boolean := Y'Valid; -- OK, B = False. Z : Positive := Y+1; -- Erroneous to use Y. 12.e/2 {AI95-00167-01} {AI95-00426-01} The call to Unsafe_Convert is a bounded error, which might raise Constraint_Error, Program_Error, or return an invalid value. Moreover, if an exception is not raised, most uses of that invalid value (including the use of Y) cause erroneous execution. The call to Safe_Convert is not erroneous. The result object is an object of subtype Integer containing the value 0. The assignment to X is required to do a constraint check; the fact that the conversion is unchecked does not obviate the need for subsequent checks required by the language rules. 12.e.1/2 {AI95-00167-01} {AI95-00426-01} The reason for delaying erroneous execution until the object is used is so that the invalid representation can be tested for validity using the Valid attribute (see 13.9.2) without causing execution to become erroneous. Note that this delay does not imply an exception will not be raised; an implementation could treat both conversions in the example in the same way and raise Constraint_Error. 12.f Implementation Note: If an implementation wants to have a " friendly" mode, it might always assign an uninitialized scalar a default initial value that is outside the object's subtype (if there is one), and check for this value on some or all reads of the object, so as to help detect references to uninitialized scalars. Alternatively, an implementation might want to provide an "unsafe" mode where it presumed even uninitialized scalars were always within their subtype. 12.g Ramification: The above rules imply that it is a bounded error to apply a predefined operator to an object with a scalar subcomponent having an invalid representation, since this implies reading the value of each subcomponent. Either Program_Error or Constraint_Error is raised, or some result is produced, which if composite, might have a corresponding scalar subcomponent still with an invalid representation. 12.h Note that it is not an error to assign, convert, or pass as a parameter a composite object with an uninitialized scalar subcomponent. In the other hand, it is a (bounded) error to apply a predefined operator such as =, <, and xor to a composite operand with an invalid scalar subcomponent. 13 {erroneous execution (cause) [partial]} The dereference of an access value is erroneous if it does not designate an object of an appropriate type or a subprogram with an appropriate profile, if it designates a nonexistent object, or if it is an access-to-variable value that designates a constant object. [Such an access value can exist, for example, because of Unchecked_Deallocation, Unchecked_Access, or Unchecked_Conversion.] 13.a Ramification: The above mentioned Unchecked_... features are not the only causes of such access values. For example, interfacing to other languages can also cause the problem. 13.b One obscure example is if the Adjust subprogram of a controlled type uses Unchecked_Access to create an access-to-variable value designating a subcomponent of its controlled parameter, and saves this access value in a global object. When Adjust is called during the initialization of a constant object of the type, the end result will be an access-to-variable value that designates a constant object. NOTES 14 18 Objects can become abnormal due to other kinds of actions that directly update the object's representation; such actions are generally considered directly erroneous, however. Wording Changes from Ada 83 14.a In order to reduce the amount of erroneousness, we separate the concept of an undefined value into objects with invalid representation (scalars only) and abnormal objects. 14.b Reading an object with an invalid representation is a bounded error rather than erroneous; reading an abnormal object is still erroneous. In fact, the only safe thing to do to an abnormal object is to assign to the object as a whole. Wording Changes from Ada 95 14.c/2 {AI95-00167-01} The description of erroneous execution for Unchecked_Conversion and imported objects was tightened up so that using the Valid attribute to test such a value is not erroneous. 14.d/2 {AI95-00426-01} Clarified the definition of objects that can become abnormal; made sure that all of the possibilities are included. 13.9.2 The Valid Attribute 1 The Valid attribute can be used to check the validity of data produced by unchecked conversion, input, interface to foreign languages, and the like. Static Semantics 2 For a prefix X that denotes a scalar object [(after any implicit dereference)], the following attribute is defined: 3 X'Valid Yields True if and only if the object denoted by X is normal and has a valid representation. The value of this attribute is of the predefined type Boolean. 3.a Ramification: Having checked that X'Valid is True, it is safe to read the value of X without fear of erroneous execution caused by abnormality, or a bounded error caused by an invalid representation. Such a read will produce a value in the subtype of X. NOTES 4 19 Invalid data can be created in the following cases (not counting erroneous or unpredictable execution): 5 * an uninitialized scalar object, 6 * the result of an unchecked conversion, 7 * input, 8 * interface to another language (including machine code), 9 * aborting an assignment, 10 * disrupting an assignment due to the failure of a language-defined check (see 11.6), and 11 * use of an object whose Address has been specified. 12 20 X'Valid is not considered to be a read of X; hence, it is not an error to check the validity of invalid data. 13/2 21 {AI95-00426-01} The Valid attribute may be used to check the result of calling an instance of Unchecked_Conversion (or any other operation that can return invalid values). However, an exception handler should also be provided because implementations are permitted to raise Constraint_Error or Program_Error if they detect the use of an invalid representation (see 13.9.1). 13.a Ramification: If X is of an enumeration type with a representation clause, then X'Valid checks that the value of X when viewed as an integer is one of the specified internal codes. 13.b Reason: Valid is defined only for scalar objects because the implementation and description burden would be too high for other types. For example, given a typical run-time model, it is impossible to check the validity of an access value. The same applies to composite types implemented with internal pointers. One can check the validity of a composite object by checking the validity of each of its scalar subcomponents. The user should ensure that any composite types that need to be checked for validity are represented in a way that does not involve implementation-defined components, or gaps between components. Furthermore, such types should not contain access subcomponents. 13.c/2 This paragraph was deleted.{AI95-00114-01} Extensions to Ada 83 13.d {extensions to Ada 83} X'Valid is new in Ada 95. Wording Changes from Ada 95 13.e/2 {AI95-00426-01} Added a note explaining that handlers for Constraint_Error and Program_Error are needed in the general case of testing for validity. (An implementation could document cases where these are not necessary, but there is no language requirement. 13.10 Unchecked Access Value Creation 1 [The attribute Unchecked_Access is used to create access values in an unsafe manner - the programmer is responsible for preventing "dangling references."] Static Semantics 2 The following attribute is defined for a prefix X that denotes an aliased view of an object: 3 X'Unchecked_Access All rules and semantics that apply to X'Access (see 3.10.2) apply also to X'Unchecked_Access, except that, for the purposes of accessibility rules and checks, it is as if X were declared immediately within a library package. {Access attribute: See also Unchecked_Access attribute} NOTES 4 22 This attribute is provided to support the situation where a local object is to be inserted into a global linked data structure, when the programmer knows that it will always be removed from the data structure prior to exiting the object's scope. The Access attribute would be illegal in this case (see 3.10.2, " Operations of Access Types"). 4.a Ramification: {expected type (Unchecked_Access attribute) [partial]} The expected type for X'Unchecked_Access is as for X'Access. 4.b If an attribute_reference with Unchecked_Access is used as the actual parameter for an access parameter, an Accessibility_Check can never fail on that access parameter. 5 23 There is no Unchecked_Access attribute for subprograms. 5.a/2 Reason: {AI95-00254-01} Such an attribute would allow unsafe " downward closures", where an access value designating a more nested subprogram is passed to a less nested subprogram. (Anonymous access-to-subprogram parameters provide safe "downward closures".) This requires some means of reconstructing the global environment for the more nested subprogram, so that it can do up-level references to objects. The two methods of implementing up-level references are displays and static links. If unsafe downward closures were supported, each access-to-subprogram value would have to carry the static link or display with it. We don't want to require the space and time overhead of requiring the extra information for all access-to-subprogram types, especially as including it would make interfacing to other languages (like C) harder. 5.b If desired, an instance of Unchecked_Conversion can be used to create an access value of a global access-to-subprogram type that designates a local subprogram. The semantics of using such a value are not specified by the language. In particular, it is not specified what happens if such subprograms make up-level references; even if the frame being referenced still exists, the up-level reference might go awry if the representation of a value of a global access-to-subprogram type doesn't include a static link. 13.11 Storage Management 1 [ {user-defined storage management} {storage management (user-defined)} {user-defined heap management} {heap management (user-defined)} Each access-to-object type has an associated storage pool. The storage allocated by an allocator comes from the pool; instances of Unchecked_Deallocation return storage to the pool. Several access types can share the same pool.] 2/2 {AI95-00435-01} [A storage pool is a variable of a type in the class rooted at Root_Storage_Pool, which is an abstract limited controlled type. By default, the implementation chooses a standard storage pool for each access-to-object type. The user may define new pool types, and may override the choice of pool for an access-to-object type by specifying Storage_Pool for the type.] 2.a Ramification: By default, the implementation might choose to have a single global storage pool, which is used (by default) by all access types, which might mean that storage is reclaimed automatically only upon partition completion. Alternatively, it might choose to create a new pool at each accessibility level, which might mean that storage is reclaimed for an access type when leaving the appropriate scope. Other schemes are possible. Legality Rules 3 If Storage_Pool is specified for a given access type, Storage_Size shall not be specified for it. 3.a Reason: The Storage_Pool determines the Storage_Size; hence it would not make sense to specify both. Note that this rule is simplified by the fact that the aspects in question cannot be specified for derived types, nor for non-first subtypes, so we don't have to worry about whether, say, Storage_Pool on a derived type overrides Storage_Size on the parent type. For the same reason, "specified" means the same thing as "directly specified" here. Static Semantics 4 The following language-defined library package exists: 5 with Ada.Finalization; with System.Storage_Elements; package System.Storage_Pools is pragma Preelaborate(System.Storage_Pools); 6/2 {AI95-00161-01} type Root_Storage_Pool is abstract new Ada.Finalization.Limited_Controlled with private; pragma Preelaborable_Initialization(Root_Storage_Pool); 7 procedure Allocate( Pool : in out Root_Storage_Pool; Storage_Address : out Address; Size_In_Storage_Elements : in Storage_Elements.Storage_Count; Alignment : in Storage_Elements.Storage_Count) is abstract; 8 procedure Deallocate( Pool : in out Root_Storage_Pool; Storage_Address : in Address; Size_In_Storage_Elements : in Storage_Elements.Storage_Count; Alignment : in Storage_Elements.Storage_Count) is abstract; 9 function Storage_Size(Pool : Root_Storage_Pool) return Storage_Elements.Storage_Count is abstract; 10 private ... -- not specified by the language end System.Storage_Pools; 10.a Reason: The Alignment parameter is provided to Deallocate because some allocation strategies require it. If it is not needed, it can be ignored. 11 {storage pool type} {pool type} A storage pool type (or pool type) is a descendant of Root_Storage_Pool. {storage pool element} {pool element} {element (of a storage pool)} The elements of a storage pool are the objects allocated in the pool by allocators. 11.a Discussion: In most cases, an element corresponds to a single memory block allocated by Allocate. However, in some cases the implementation may choose to associate more than one memory block with a given pool element. 12/2 {8652/0009} {AI95-00137-01} {AI95-00435-01} For every access-to-object subtype S, the following representation attributes are defined: 13 S'Storage_Pool Denotes the storage pool of the type of S. The type of this attribute is Root_Storage_Pool'Class. 14 S'Storage_Size Yields the result of calling Storage_Size(S'Storage_Pool)[, which is intended to be a measure of the number of storage elements reserved for the pool.] The type of this attribute is universal_integer. 14.a Ramification: Storage_Size is also defined for task subtypes and objects - see 13.3. 14.b Storage_Size is not a measure of how much un-allocated space is left in the pool. That is, it includes both allocated and unallocated space. Implementations and users may provide a Storage_Available function for their pools, if so desired. 15 {specifiable (of Storage_Size for a non-derived access-to-object type) [partial]} {specifiable (of Storage_Pool for a non-derived access-to-object type) [partial]} {Storage_Pool clause} {Storage_Size clause} Storage_Size or Storage_Pool may be specified for a non-derived access-to-object type via an attribute_definition_clause; the name in a Storage_Pool clause shall denote a variable. 16 An allocator of type T allocates storage from T's storage pool. If the storage pool is a user-defined object, then the storage is allocated by calling Allocate, passing T'Storage_Pool as the Pool parameter. The Size_In_Storage_Elements parameter indicates the number of storage elements to be allocated, and is no more than D'Max_Size_In_Storage_Elements, where D is the designated subtype. The Alignment parameter is D'Alignment. {contiguous representation [partial]} {discontiguous representation [partial]} The result returned in the Storage_Address parameter is used by the allocator as the address of the allocated storage, which is a contiguous block of memory of Size_In_Storage_Elements storage elements. [Any exception propagated by Allocate is propagated by the allocator.] 16.a Ramification: If the implementation chooses to represent the designated subtype in multiple pieces, one allocator evaluation might result in more than one call upon Allocate. In any case, allocators for the access type obtain all the required storage for an object of the designated type by calling the specified Allocate procedure. 16.b Note that the implementation does not turn other exceptions into Storage_Error. 16.b.1/1 {8652/0111} {AI95-00103-01} If D (the designated type of T) includes subcomponents of other access types, they will be allocated from the storage pools for those types, even if those allocators are executed as part of the allocator of T (as part of the initialization of the object). For instance, an access-to-task type TT may allocate the data structures used to implement the task value from other storage pools. (In particular, the task stack does not necessarily need to be allocated from the storage pool for TT.) 17 {standard storage pool} If Storage_Pool is not specified for a type defined by an access_to_object_definition, then the implementation chooses a standard storage pool for it in an implementation-defined manner. {Storage_Check [partial]} {check, language-defined (Storage_Check)} {Storage_Error (raised by failure of run-time check)} In this case, the exception Storage_Error is raised by an allocator if there is not enough storage. It is implementation defined whether or not the implementation provides user-accessible names for the standard pool type(s). 17.a/2 This paragraph was deleted. 17.a.1/2 Discussion: The manner of choosing a storage pool is covered by a Documentation Requirement below, so it is not summarized here. 17.b Implementation defined: Whether or not the implementation provides user-accessible names for the standard pool type(s). 17.c/2 Ramification: {AI95-00230-01} An access-to-object type defined by a derived_type_definition inherits its pool from its parent type, so all access-to-object types in the same derivation class share the same pool. Hence the "defined by an access_to_object_definition" wording above. 17.d {contiguous representation [partial]} {discontiguous representation [partial]} There is no requirement that all storage pools be implemented using a contiguous block of memory (although each allocation returns a pointer to a contiguous block of memory). 18 If Storage_Size is specified for an access type, then the Storage_Size of this pool is at least that requested, and the storage for the pool is reclaimed when the master containing the declaration of the access type is left. {Storage_Error (raised by failure of run-time check)} If the implementation cannot satisfy the request, Storage_Error is raised at the point of the attribute_definition_clause. If neither Storage_Pool nor Storage_Size are specified, then the meaning of Storage_Size is implementation defined. 18.a/2 Implementation defined: The meaning of Storage_Size when neither the Storage_Size nor the Storage_Pool is specified for an access type. 18.b Ramification: The Storage_Size function and attribute will return the actual size, rather than the requested size. Comments about rounding up, zero, and negative on task Storage_Size apply here, as well. See also AI83-00557, AI83-00558, and AI83-00608. 18.c The expression in a Storage_Size clause need not be static. 18.d The reclamation happens after the master is finalized. 18.e Implementation Note: For a pool allocated on the stack, normal stack cut-back can accomplish the reclamation. For a library-level pool, normal partition termination actions can accomplish the reclamation. 19 If Storage_Pool is specified for an access type, then the specified pool is used. 20 {unspecified [partial]} The effect of calling Allocate and Deallocate for a standard storage pool directly (rather than implicitly via an allocator or an instance of Unchecked_Deallocation) is unspecified. 20.a Ramification: For example, an allocator might put the pool element on a finalization list. If the user directly Deallocates it, instead of calling an instance of Unchecked_Deallocation, then the implementation would probably try to finalize the object upon master completion, which would be bad news. Therefore, the implementation should define such situations as erroneous. Erroneous Execution 21 {erroneous execution (cause) [partial]} If Storage_Pool is specified for an access type, then if Allocate can satisfy the request, it should allocate a contiguous block of memory, and return the address of the first storage element in Storage_Address. The block should contain Size_In_Storage_Elements storage elements, and should be aligned according to Alignment. The allocated storage should not be used for any other purpose while the pool element remains in existence. If the request cannot be satisfied, then Allocate should propagate an exception [(such as Storage_Error)]. If Allocate behaves in any other manner, then the program execution is erroneous. Documentation Requirements 22 An implementation shall document the set of values that a user-defined Allocate procedure needs to accept for the Alignment parameter. An implementation shall document how the standard storage pool is chosen, and how storage is allocated by standard storage pools. 22.a/2 This paragraph was deleted. 22.b/2 Documentation Requirement: The set of values that a user-defined Allocate procedure needs to accept for the Alignment parameter. How the standard storage pool is chosen, and how storage is allocated by standard storage pools. Implementation Advice 23 An implementation should document any cases in which it dynamically allocates heap storage for a purpose other than the evaluation of an allocator. 23.a.1/2 Implementation Advice: Any cases in which heap storage is dynamically allocated other than as part of the evaluation of an allocator should be documented. 23.a Reason: This is "Implementation Advice" because the term "heap storage" is not formally definable; therefore, it is not testable whether the implementation obeys this advice. 24 A default (implementation-provided) storage pool for an access-to-constant type should not have overhead to support deallocation of individual objects. 24.a.1/2 Implementation Advice: A default storage pool for an access-to-constant type should not have overhead to support deallocation of individual objects. 24.a Ramification: Unchecked_Deallocation is not defined for such types. If the access-to-constant type is library-level, then no deallocation (other than at partition completion) will ever be necessary, so if the size needed by an allocator of the type is known at link-time, then the allocation should be performed statically. If, in addition, the initial value of the designated object is known at compile time, the object can be allocated to read-only memory. 24.b Implementation Note: If the Storage_Size for an access type is specified, the storage pool should consist of a contiguous block of memory, possibly allocated on the stack. The pool should contain approximately this number of storage elements. These storage elements should be reserved at the place of the Storage_Size clause, so that allocators cannot raise Storage_Error due to running out of pool space until the appropriate number of storage elements has been used up. This approximate (possibly rounded-up) value should be used as a maximum; the implementation should not increase the size of the pool on the fly. If the Storage_Size for an access type is specified as zero, then the pool should not take up any storage space, and any allocator for the type should raise Storage_Error. 24.c Ramification: Note that most of this is approximate, and so cannot be (portably) tested. That's why we make it an Implementation Note. There is no particular number of allocations that is guaranteed to succeed, and there is no particular number of allocations that is guaranteed to fail. 25/2 {AI95-00230-01} The storage pool used for an allocator of an anonymous access type should be determined as follows: 25.1/2 * {AI95-00230-01} {AI95-00416-01} If the allocator is defining a coextension (see 3.10.2) of an object being created by an outer allocator, then the storage pool used for the outer allocator should also be used for the coextension; 25.2/2 * {AI95-00230-01} For other access discriminants and access parameters, the storage pool should be created at the point of the allocator, and be reclaimed when the allocated object becomes inaccessible; 25.3/2 * {AI95-00230-01} Otherwise, a default storage pool should be created at the point where the anonymous access type is elaborated; such a storage pool need not support deallocation of individual objects. 25.a.1/2 Implementation Advice: Usually, a storage pool for an access discriminant or access parameter should be created at the point of an allocator, and be reclaimed when the designated object becomes inaccessible. For other anonymous access types, the pool should be created at the point where the type is elaborated and need not support deallocation of individual objects. 25.a/2 Implementation Note: {AI95-00230-01} For access parameters and access discriminants, the "storage pool" for an anonymous access type would not normally exist as a separate entity. Instead, the designated object of the allocator would be allocated, in the case of an access parameter, as a local aliased variable at the call site, and in the case of an access discriminant, contiguous with the object containing the discriminant. This is similar to the way storage for aggregates is typically managed. 25.b/2 {AI95-00230-01} For other sorts of anonymous access types, this implementation is not possible in general, as the accessibility of the anonymous access type is that of its declaration, while the allocator could be more nested. In this case, a "real" storage pool is required. Note, however, that this storage pool need not support (separate) deallocation, as it is not possible to instantiate Unchecked_Deallocation with an anonymous access type. (If deallocation is needed, the object should be allocated for a named access type and converted.) Thus, deallocation only need happen when the anonymous access type itself goes out of scope; this is similar to the case of an access-to-constant type. NOTES 26 24 A user-defined storage pool type can be obtained by extending the Root_Storage_Pool type, and overriding the primitive subprograms Allocate, Deallocate, and Storage_Size. A user-defined storage pool can then be obtained by declaring an object of the type extension. The user can override Initialize and Finalize if there is any need for non-trivial initialization and finalization for a user-defined pool type. For example, Finalize might reclaim blocks of storage that are allocated separately from the pool object itself. 27 25 The writer of the user-defined allocation and deallocation procedures, and users of allocators for the associated access type, are responsible for dealing with any interactions with tasking. In particular: 28 * If the allocators are used in different tasks, they require mutual exclusion. 29 * If they are used inside protected objects, they cannot block. 30 * If they are used by interrupt handlers (see C.3, " Interrupt Support"), the mutual exclusion mechanism has to work properly in that context. 31 26 The primitives Allocate, Deallocate, and Storage_Size are declared as abstract (see 3.9.3), and therefore they have to be overridden when a new (non-abstract) storage pool type is declared. 31.a Ramification: Note that the Storage_Pool attribute denotes an object, rather than a value, which is somewhat unusual for attributes. 31.b The calls to Allocate, Deallocate, and Storage_Size are dispatching calls - this follows from the fact that the actual parameter for Pool is T'Storage_Pool, which is of type Root_Storage_Pool'Class. In many cases (including all cases in which Storage_Pool is not specified), the compiler can determine the tag statically. However, it is possible to construct cases where it cannot. 31.c All access types in the same derivation class share the same pool, whether implementation defined or user defined. This is necessary because we allow type conversions among them (even if they are pool-specific), and we want pool-specific access values to always designate an element of the right pool. 31.d Implementation Note: If an access type has a standard storage pool, then the implementation doesn't actually have to follow the pool interface described here, since this would be semantically invisible. For example, the allocator could conceivably be implemented with inline code. Examples 32 To associate an access type with a storage pool object, the user first declares a pool object of some type derived from Root_Storage_Pool. Then, the user defines its Storage_Pool attribute, as follows: 33 Pool_Object : Some_Storage_Pool_Type; 34 type T is access Designated; for T'Storage_Pool use Pool_Object; 35 Another access type may be added to an existing storage pool, via: 36 for T2'Storage_Pool use T'Storage_Pool; 37 The semantics of this is implementation defined for a standard storage pool. 37.a Reason: For example, the implementation is allowed to choose a storage pool for T that takes advantage of the fact that T is of a certain size. If T2 is not of that size, then the above will probably not work. 38 As usual, a derivative of Root_Storage_Pool may define additional operations. For example, presuming that Mark_Release_Pool_Type has two additional operations, Mark and Release, the following is a possible use: 39/1 {8652/0041} {AI95-00066-01} type Mark_Release_Pool_Type (Pool_Size : Storage_Elements.Storage_Count; Block_Size : Storage_Elements.Storage_Count) is new Root_Storage_Pool with private; 40 ... 41 MR_Pool : Mark_Release_Pool_Type (Pool_Size => 2000, Block_Size => 100); 42 type Acc is access ...; for Acc'Storage_Pool use MR_Pool; ... 43 Mark(MR_Pool); ... -- Allocate objects using "new Designated(...)". Release(MR_Pool); -- Reclaim the storage. Extensions to Ada 83 43.a {extensions to Ada 83} User-defined storage pools are new to Ada 95. Wording Changes from Ada 83 43.b Ada 83 had a concept called a "collection," which is similar to what we call a storage pool. All access types in the same derivation class shared the same collection. In Ada 95, all access types in the same derivation class share the same storage pool, but other (unrelated) access types can also share the same storage pool, either by default, or as specified by the user. A collection was an amorphous collection of objects; a storage pool is a more concrete concept - hence the different name. 43.c RM83 states the erroneousness of reading or updating deallocated objects incorrectly by missing various cases. Incompatibilities With Ada 95 43.d/2 {AI95-00435-01} {incompatibilities with Ada 95} Amendment Correction: Storage pools (and Storage_Size) are not defined for access-to-subprogram types. The original Ada 95 wording defined the attributes, but said nothing about their values. If a program uses attributes Storage_Pool or Storage_Size on an access-to-subprogram type, it will need to be corrected for Ada 2005. That's a good thing, as such a use is a bug - the concepts never were defined for such types. Extensions to Ada 95 43.e/2 {AI95-00161-01} {extensions to Ada 95} Amendment Correction: Added pragma Preelaborable_Initialization to type Root_Storage_Pool, so that extensions of it can be used to declare default-initialized objects in preelaborated units. Wording Changes from Ada 95 43.f/2 {8652/0009} {AI95-00137-01} Corrigendum: Added wording to specify that these are representation attributes. 43.g/2 {AI95-00230-01} {AI95-00416-01} Added wording to clarify that an allocator for a coextension nested inside an outer allocator shares the pool with the outer allocator. 13.11.1 The Max_Size_In_Storage_Elements Attribute 1 [The Max_Size_In_Storage_Elements attribute is useful in writing user-defined pool types.] Static Semantics 2 For every subtype S, the following attribute is defined: 3/2 S'Max_Size_In_Storage_Elements {AI95-00256-01} {AI95-00416-01} Denotes the maximum value for Size_In_Storage_Elements that could be requested by the implementation via Allocate for an access type whose designated subtype is S. For a type with access discriminants, if the implementation allocates space for a coextension in the same pool as that of the object having the access discriminant, then this accounts for any calls on Allocate that could be performed to provide space for such coextensions. The value of this attribute is of type universal_integer. 3.a Ramification: If S is an unconstrained array subtype, or an unconstrained subtype with discriminants, S'Max_Size_In_Storage_Elements might be very large. Wording Changes from Ada 95 3.b/2 {AI95-00256-01} Corrected the wording so that a fortune-telling compiler that can see the future execution of the program is not required. 13.11.2 Unchecked Storage Deallocation 1 [{unchecked storage deallocation} {storage deallocation (unchecked)} {deallocation of storage} {reclamation of storage} {freeing storage} Unchecked storage deallocation of an object designated by a value of an access type is achieved by a call to an instance of the generic procedure Unchecked_Deallocation.] Static Semantics 2 The following language-defined generic library procedure exists: 3 generic type Object(<>) is limited private; type Name is access Object; procedure Ada.Unchecked_Deallocation(X : in out Name); pragma Convention(Intrinsic, Ada.Unchecked_Deallocation); pragma Preelaborate(Ada.Unchecked_Deallocation); 3.a Reason: The pragma Convention implies that the attribute Access is not allowed for instances of Unchecked_Deallocation. Dynamic Semantics 4 Given an instance of Unchecked_Deallocation declared as follows: 5 procedure Free is new Ada.Unchecked_Deallocation( object_subtype_name, access_to_variable_subtype_name); 6 Procedure Free has the following effect: 7 1. After executing Free(X), the value of X is null. 8 2. Free(X), when X is already equal to null, has no effect. 9/2 3. {AI95-00416-01} Free(X), when X is not equal to null first performs finalization of the object designated by X (and any coextensions of the object - see 3.10.2), as described in 7.6.1. It then deallocates the storage occupied by the object designated by X (and any coextensions). If the storage pool is a user-defined object, then the storage is deallocated by calling Deallocate, passing access_to_- variable_subtype_name'Storage_Pool as the Pool parameter. Storage_Address is the value returned in the Storage_Address parameter of the corresponding Allocate call. Size_In_Storage_Elements and Alignment are the same values passed to the corresponding Allocate call. There is one exception: if the object being freed contains tasks, the object might not be deallocated. 9.a Ramification: Free calls only the specified Deallocate procedure to do deallocation. For any given object deallocation, the number of calls to Free (usually one) will be equal to the number of Allocate calls it took to allocate the object. We do not define the relative order of multiple calls used to deallocate the same object - that is, if the allocator allocated two pieces x and y, then Free might deallocate x and then y, or it might deallocate y and then x. 10/2 {AI95-00416-01} {freed: See nonexistent} {nonexistent} {exist (cease to) [partial]} {cease to exist (object) [partial]} After Free(X), the object designated by X, and any subcomponents (and coextensions) thereof, no longer exist; their storage can be reused for other purposes. Bounded (Run-Time) Errors 11 {bounded error (cause) [partial]} It is a bounded error to free a discriminated, unterminated task object. The possible consequences are: 11.a Reason: This is an error because the task might refer to its discriminants, and the discriminants might be deallocated by freeing the task object. 12 * No exception is raised. 13 * {Program_Error (raised by failure of run-time check)} {Tasking_Error (raised by failure of run-time check)} Program_Error or Tasking_Error is raised at the point of the deallocation. 14 * {Program_Error (raised by failure of run-time check)} {Tasking_Error (raised by failure of run-time check)} Program_Error or Tasking_Error is raised in the task the next time it references any of the discriminants. 14.a Implementation Note: This last case presumes an implementation where the task references its discriminants indirectly, and the pointer is nulled out when the task object is deallocated. 15 In the first two cases, the storage for the discriminants (and for any enclosing object if it is designated by an access discriminant of the task) is not reclaimed prior to task termination. 15.a Ramification: The storage might never be reclaimed. Erroneous Execution 16 {nonexistent} {erroneous execution (cause) [partial]} Evaluating a name that denotes a nonexistent object is erroneous. The execution of a call to an instance of Unchecked_Deallocation is erroneous if the object was created other than by an allocator for an access type whose pool is Name'Storage_Pool. Implementation Advice 17 For a standard storage pool, Free should actually reclaim the storage. 17.a.1/2 Implementation Advice: For a standard storage pool, an instance of Unchecked_Deallocation should actually reclaim the storage. 17.a/2 Ramification: {AI95-00114-01} This is not a testable property, since we do not know how much storage is used by a given pool element, nor whether fragmentation can occur. NOTES 18 27 The rules here that refer to Free apply to any instance of Unchecked_Deallocation. 19 28 Unchecked_Deallocation cannot be instantiated for an access-to-constant type. This is implied by the rules of 12.5.4. Wording Changes from Ada 95 19.a/2 {AI95-00416-01} The rules for coextensions are clarified (mainly by adding that term). In theory, this reflects no change from Ada 95 (coextensions existed in Ada 95, they just didn't have a name). 13.11.3 Pragma Controlled 1 [Pragma Controlled is used to prevent any automatic reclamation of storage (garbage collection) for the objects created by allocators of a given access type.] Syntax 2 The form of a pragma Controlled is as follows: 3 pragma Controlled(first_subtype_local_name); 3.a Discussion: Not to be confused with type Finalization.Controlled. Legality Rules 4 The first_subtype_local_name of a pragma Controlled shall denote a non-derived access subtype. Static Semantics 5 {representation pragma (Controlled) [partial]} {pragma, representation (Controlled) [partial]} A pragma Controlled is a representation pragma {aspect of representation (controlled) [partial]} {controlled (aspect of representation)} that specifies the controlled aspect of representation. 6 {garbage collection} Garbage collection is a process that automatically reclaims storage, or moves objects to a different address, while the objects still exist. 6.a Ramification: Storage reclamation upon leaving a master is not considered garbage collection. 6.b Note that garbage collection includes compaction of a pool (" moved to a different Address"), even if storage reclamation is not done. 6.c Reason: Programs that will be damaged by automatic storage reclamation are just as likely to be damaged by having objects moved to different locations in memory. A pragma Controlled should turn off both flavors of garbage collection. 6.d Implementation Note: If garbage collection reclaims the storage of a controlled object, it should first finalize it. Finalization is not done when moving an object; any self-relative pointers will have to be updated by the garbage collector. If an implementation provides garbage collection for a storage pool containing controlled objects (see 7.6), then it should provide a means for deferring garbage collection of those controlled objects. 6.e Reason: This allows the manager of a resource released by a Finalize operation to defer garbage collection during its critical regions; it is up to the author of the Finalize operation to do so. Garbage collection, at least in some systems, can happen asynchronously with respect to normal user code. Note that it is not enough to defer garbage collection during Initialize, Adjust, and Finalize, because the resource in question might be used in other situations as well. For example: 6.f with Ada.Finalization; package P is 6.g type My_Controlled is new Ada.Finalization.Limited_Controlled with private; procedure Finalize(Object : in out My_Controlled); type My_Controlled_Access is access My_Controlled; 6.h procedure Non_Reentrant; 6.i private ... end P; 6.j package body P is X : Integer := 0; A : array(Integer range 1..10) of Integer; 6.k procedure Non_Reentrant is begin X := X + 1; -- If the system decides to do a garbage collection here, -- then we're in trouble, because it will call Finalize on -- the collected objects; we essentially have two threads -- of control erroneously accessing shared variables. -- The garbage collector behaves like a separate thread -- of control, even though the user hasn't declared -- any tasks. A(X) := ...; end Non_Reentrant; 6.l procedure Finalize(Object : in out My_Controlled) is begin Non_Reentrant; end Finalize; end P; 6.m with P; use P; procedure Main is begin ... new My_Controlled ... -- allocate some objects ... forget the pointers to some of them, so they become garbage Non_Reentrant; end Main; 6.n It is the user's responsibility to protect against this sort of thing, and the implementation's responsibility to provide the necessary operations. 6.o We do not give these operations names, nor explain their exact semantics, because different implementations of garbage collection might have different needs, and because garbage collection is not supported by most Ada implementations, so portability is not important here. Another reason not to turn off garbage collection during each entire Finalize operation is that it would create a serial bottleneck; it might be only part of the Finalize operation that conflicts with some other resource. It is the intention that the mechanisms provided be finer-grained than pragma Controlled. 7 If a pragma Controlled is specified for an access type with a standard storage pool, then garbage collection is not performed for objects in that pool. 7.a Ramification: If Controlled is not specified, the implementation may, but need not, perform garbage collection. If Storage_Pool is specified, then a pragma Controlled for that type is ignored. 7.b Reason: Controlled means that implementation-provided garbage collection is turned off; if the Storage_Pool is specified, the pool controls whether garbage collection is done. Implementation Permissions 8 An implementation need not support garbage collection, in which case, a pragma Controlled has no effect. Wording Changes from Ada 83 8.a Ada 83 used the term "automatic storage reclamation" to refer to what is known traditionally as "garbage collection". Because of the existence of storage pools (see 13.11), we need to distinguish this from the storage reclamation that might happen upon leaving a master. Therefore, we now use the term "garbage collection" in its normal computer-science sense. This has the additional advantage of making our terminology more accessible to people outside the Ada world. 13.12 Pragma Restrictions 1 [A pragma Restrictions expresses the user's intent to abide by certain restrictions. This may facilitate the construction of simpler run-time environments.] Syntax 2 The form of a pragma Restrictions is as follows: 3 pragma Restrictions(restriction{, restriction}); 4/2 {AI95-00381-01} restriction ::= restriction_identifier | restriction_parameter_identifier => restriction_parameter_argument 4.1/2 {AI95-00381-01} restriction_parameter_argument ::= name | expression Name Resolution Rules 5 {expected type (restriction parameter expression) [partial]} Unless otherwise specified for a particular restriction, the expression is expected to be of any integer type. Legality Rules 6 Unless otherwise specified for a particular restriction, the expression shall be static, and its value shall be nonnegative. Static Semantics 7/2 {AI95-00394-01} The set of restrictions is implementation defined. 7.a/2 Implementation defined: The set of restrictions allowed in a pragma Restrictions. Post-Compilation Rules 8 {configuration pragma (Restrictions) [partial]} {pragma, configuration (Restrictions) [partial]} A pragma Restrictions is a configuration pragma; unless otherwise specified for a particular restriction, a partition shall obey the restriction if a pragma Restrictions applies to any compilation unit included in the partition. 8.1/1 {8652/0042} {AI95-00130-01} For the purpose of checking whether a partition contains constructs that violate any restriction (unless specified otherwise for a particular restriction): 8.2/1 * {8652/0042} {AI95-00130-01} Generic instances are logically expanded at the point of instantiation; 8.3/1 * {8652/0042} {AI95-00130-01} If an object of a type is declared or allocated and not explicitly initialized, then all expressions appearing in the definition for the type and any of its ancestors are presumed to be used; 8.4/1 * {8652/0042} {AI95-00130-01} A default_expression for a formal parameter or a generic formal object is considered to be used if and only if the corresponding actual parameter is not provided in a given call or instantiation. Implementation Permissions 9 An implementation may place limitations on the values of the expression that are supported, and limitations on the supported combinations of restrictions. The consequences of violating such limitations are implementation defined. 9.a Implementation defined: The consequences of violating limitations on Restrictions pragmas. 9.b Ramification: Such limitations may be enforced at compile time or at run time. Alternatively, the implementation is allowed to declare violations of the restrictions to be erroneous, and not enforce them at all. 9.1/1 {8652/0042} {AI95-00130-01} An implementation is permitted to omit restriction checks for code that is recognized at compile time to be unreachable and for which no code is generated. 9.2/1 {8652/0043} {AI95-00190-01} Whenever enforcement of a restriction is not required prior to execution, an implementation may nevertheless enforce the restriction prior to execution of a partition to which the restriction applies, provided that every execution of the partition would violate the restriction. NOTES 10/2 29 {AI95-00347-01} Restrictions intended to facilitate the construction of efficient tasking run-time systems are defined in D.7. Restrictions intended for use when constructing high integrity systems are defined in H.4. 11 30 An implementation has to enforce the restrictions in cases where enforcement is required, even if it chooses not to take advantage of the restrictions in terms of efficiency. 11.a Discussion: It is not the intent that an implementation will support a different run-time system for every possible combination of restrictions. An implementation might support only two run-time systems, and document a set of restrictions that is sufficient to allow use of the more efficient and safe one. Extensions to Ada 83 11.b {extensions to Ada 83} Pragma Restrictions is new to Ada 95. Wording Changes from Ada 95 11.c/2 {8652/0042} {AI95-00130-01} Corrigendum: Corrected the wording so that restrictions are checked inside of generic instantiations and in default expressions. Since not making these checks would violate the purpose of restrictions, we are not documenting this as an incompatibility. 11.d/2 {8652/0043} {AI95-00190-01} Corrigendum: Added a permission that restrictions can be enforced at compile-time. While this is technically incompatible, documenting it as such would be unnecessarily alarming - there should not be any programs depending on the runtime failure of restrictions. 11.e/2 {AI95-00381-01} The syntax of a restriction_parameter_argument has been defined to better support restriction No_Dependence (see 13.12.1). 13.12.1 Language-Defined Restrictions Static Semantics 1/2 {AI95-00257-01} The following restriction_identifiers are language-defined (additional restrictions are defined in the Specialized Needs Annexes): 2/2 {AI95-00257-01} {Restrictions (No_Implementation_Attributes)} No_Implementation_Attributes There are no implementation-defined attributes. This restriction applies only to the current compilation or environment, not the entire partition. 2.a/2 Discussion: This restriction (as well as No_Implementation_Pragmas) only applies to the current compilation, because it is likely that the runtime (and possibly user-written low-level code) will need to use implementation-defined entities. But a partition-wide restriction applies everywhere, including the runtime. 3/2 {AI95-00257-01} {Restrictions (No_Implementation_Pragmas)} No_Implementation_Pragmas There are no implementation-defined pragmas or pragma arguments. This restriction applies only to the current compilation or environment, not the entire partition. 4/2 {AI95-00368-01} {Restrictions (No_Obsolescent_Features)} No_Obsolescent_Features There is no use of language features defined in Annex J. It is implementation-defined if uses of the renamings of J.1 are detected by this restriction. This restriction applies only to the current compilation or environment, not the entire partition. 4.a/2 Reason: A user could compile a rename like 4.b/2 with Ada.Text_IO; package Text_IO renames Ada.Text_IO; 4.c/2 Such a rename must not be disallowed by this restriction, nor should the compilation of such a rename be restricted by an implementation. Many implementations implement the renames of J.1 by compiling them normally; we do not want to require implementations to use a special mechanism to implement these renames. 5/2 {AI95-00381-01} The following restriction_parameter_identifier is language defined: 6/2 {AI95-00381-01} {Restrictions (No_Dependence)} No_Dependence Specifies a library unit on which there are no semantic dependences. Legality Rules 7/2 {AI95-00381-01} The restriction_parameter_argument of a No_Dependence restriction shall be a name; the name shall have the form of a full expanded name of a library unit, but need not denote a unit present in the environment. 7.a/2 Ramification: This name is not resolved. Post-Compilation Rules 8/2 {AI95-00381-01} No compilation unit included in the partition shall depend semantically on the library unit identified by the name. 8.a/2 Ramification: There is no requirement that the library unit actually exist. One possible use of the pragma is to prevent the use of implementation-defined units; when the program is ported to a different compiler, it is perfectly reasonable that no unit with the name exist. Extensions to Ada 95 8.b/2 {AI95-00257-01} {AI95-00368-01} {extensions to Ada 95} Restrictions No_Implementation_Attributes, No_Implementation_Pragmas, and No_Obsolescent_Features are new. 8.c/2 {AI95-00381-01} Restriction No_Dependence is new. 13.13 Streams 1 {stream} {stream type} A stream is a sequence of elements comprising values from possibly different types and allowing sequential access to these values. A stream type is a type in the class whose root type is Streams.Root_Stream_Type. A stream type may be implemented in various ways, such as an external sequential file, an internal buffer, or a network channel. 1.a Discussion: A stream element will often be the same size as a storage element, but that is not required. Extensions to Ada 83 1.b {extensions to Ada 83} Streams are new in Ada 95. 13.13.1 The Package Streams Static Semantics 1 The abstract type Root_Stream_Type is the root type of the class of stream types. The types in this class represent different kinds of streams. A new stream type is defined by extending the root type (or some other stream type), overriding the Read and Write operations, and optionally defining additional primitive subprograms, according to the requirements of the particular kind of stream. The predefined stream-oriented attributes like T'Read and T'Write make dispatching calls on the Read and Write procedures of the Root_Stream_Type. (User-defined T'Read and T'Write attributes can also make such calls, or can call the Read and Write attributes of other types.) 2 package Ada.Streams is pragma Pure(Streams){unpolluted} ; 3/2 {AI95-00161-01} type Root_Stream_Type is abstract tagged limited private; pragma Preelaborable_Initialization(Root_Stream_Type); 4/1 {8652/0044} {AI95-00181-01} type Stream_Element is mod implementation-defined; type Stream_Element_Offset is range implementation-defined; subtype Stream_Element_Count is Stream_Element_Offset range 0..Stream_Element_Offset'Last; type Stream_Element_Array is array(Stream_Element_Offset range <>) of aliased Stream_Element; 5 procedure Read( Stream : in out Root_Stream_Type; Item : out Stream_Element_Array; Last : out Stream_Element_Offset) is abstract; 6 procedure Write( Stream : in out Root_Stream_Type; Item : in Stream_Element_Array) is abstract; 7 private ... -- not specified by the language end Ada.Streams; 8/2 {AI95-00227-01} The Read operation transfers stream elements from the specified stream to fill the array Item. Elements are transferred until Item'Length elements have been transferred, or until the end of the stream is reached. If any elements are transferred, the index of the last stream element transferred is returned in Last. Otherwise, Item'First - 1 is returned in Last. Last is less than Item'Last only if the end of the stream is reached. 9 The Write operation appends Item to the specified stream. 9.a/2 Discussion: {AI95-00114-01} The index subtype of Stream_Element_Array is Stream_Element_Offset because we wish to allow maximum flexibility. Most Stream_Element_Arrays will probably have a lower bound of 0 or 1, but other lower bounds, including negative ones, make sense in some situations. 9.b/2 {AI95-00114-01} Note that there are some language-defined subprograms that fill part of a Stream_Element_Array, and return the index of the last element filled as a Stream_Element_Offset. The Read procedures declared here, Streams.Stream_IO (see A.12.1 ), and System.RPC (see E.5) behave in this manner. These will raise Constraint_Error if the resulting Last value is not in Stream_Element_Offset. This implies that the Stream_Element_Array passed to these subprograms should not have a lower bound of Stream_Element_Offset'First, because then a read of 0 elements would always raise Constraint_Error. A better choice of lower bound is 1. Implementation Permissions 9.1/1 {8652/0044} {AI95-00181-01} If Stream_Element'Size is not a multiple of System.Storage_Unit, then the components of Stream_Element_Array need not be aliased. 9.b.1/2 Ramification: {AI95-00114-01} If the Stream_Element'Size is less than the size of System.Storage_Unit, then components of Stream_- Element_Array need not be aliased. This is necessary as the components of type Stream_Element size might not be addressable on the target architecture. NOTES 10 31 See A.12.1, "The Package Streams.Stream_IO" for an example of extending type Root_Stream_Type. 11/2 32 {AI95-00227-01} If the end of stream has been reached, and Item'First is Stream_Element_Offset'First, Read will raise Constraint_Error. 11.a/2 Ramification: Thus, Stream_Element_Arrays should start at 0 or 1, not Stream_Element_Offset'First. Extensions to Ada 95 11.b/2 {AI95-00161-01} {extensions to Ada 95} Amendment Correction: Added pragma Preelaborable_Initialization to type Root_Stream_Type. Wording Changes from Ada 95 11.c/2 {8652/0044} {AI95-00181-01} Corrigendum: Stream elements are aliased presuming that makes sense. 11.d/2 {AI95-00227-01} Fixed the wording for Read to properly define the result in Last when no stream elements are transfered. 13.13.2 Stream-Oriented Attributes 1/1 {8652/0009} {AI95-00137-01} The operational attributes Write, Read, Output, and Input convert values to a stream of elements and reconstruct values from a stream. Static Semantics 1.1/2 {AI95-00270-01} For every subtype S of an elementary type T, the following representation attribute is defined: 1.2/2 S'Stream_Size {AI95-00270-01} Denotes the number of bits occupied in a stream by items of subtype S. Hence, the number of stream elements required per item of elementary type T is: 1.3/2 T'Stream_Size / Ada.Streams.Stream_Element'Size 1.4/2 The value of this attribute is of type universal_integer and is a multiple of Stream_Element'Size. 1.5/2 Stream_Size may be specified for first subtypes via an attribute_definition_clause; the expression of such a clause shall be static, nonnegative, and a multiple of Stream_Element'Size. 1.a/2 Discussion: Stream_Size is a type-related attribute (see 13.1). Implementation Advice 1.6/2 {AI95-00270-01} If not specified, the value of Stream_Size for an elementary type should be the number of bits that corresponds to the minimum number of stream elements required by the first subtype of the type, rounded up to the nearest factor or multiple of the word size that is also a multiple of the stream element size. 1.b/2 Implementation Advice: If not specified, the value of Stream_Size for an elementary type should be the number of bits that corresponds to the minimum number of stream elements required by the first subtype of the type, rounded up to the nearest factor or multiple of the word size that is also a multiple of the stream element size. 1.c/2 Reason: {AI95-00270-01} This is Implementation Advice because we want to allow implementations to remain compatible with their Ada 95 implementations, which may have a different handling of the number of stream elements. Users can always specify Stream_Size if they need a specific number of stream elements. 1.7/2 {AI95-00270-01} {recommended level of support (Stream_Size attribute) [partial]} The recommended level of support for the Stream_Size attribute is: 1.8/2 * {AI95-00270-01} A Stream_Size clause should be supported for a discrete or fixed point type T if the specified Stream_Size is a multiple of Stream_Element'Size and is no less than the size of the first subtype of T, and no greater than the size of the largest type of the same elementary class (signed integer, modular integer, enumeration, ordinary fixed point, or decimal fixed point). 1.d/2 Implementation Advice: The recommended level of support for the Stream_Size attribute should be followed. 1.e/2 Ramification: There are no requirements beyond supporting confirming Stream_Size clauses for floating point and access types. Floating point and access types usually only have a handful of defined formats, streaming anything else makes no sense for them. 1.f/2 For discrete and fixed point types, this may require support for sizes other than the "natural" ones. For instance, on a typical machine with 32-bit integers and a Stream_Element'Size of 8, setting Stream_Size to 24 must be supported. This is required as such formats can be useful for interoperability with unusual machines, and there is no difficulty with the implementation (drop extra bits on output, sign extend on input). Static Semantics 2 For every subtype S of a specific type T, the following attributes are defined. 3 S'Write S'Write denotes a procedure with the following specification: 4/2 {AI95-00441-01} procedure S'Write( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : in T) 5 S'Write writes the value of Item to Stream. 6 S'Read S'Read denotes a procedure with the following specification: 7/2 {AI95-00441-01} procedure S'Read( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : out T) 8 S'Read reads the value of Item from Stream. 8.1/2 {8652/0040} {AI95-00108-01} {AI95-00444-01} For an untagged derived type, the Write (resp. Read) attribute is inherited according to the rules given in 13.1 if the attribute is available for the parent type at the point where T is declared. For a tagged derived type, these attributes are not inherited, but rather the default implementations are used. 8.2/2 {AI95-00444-01} The default implementations of the Write and Read attributes, where available, execute as follows: 9/2 {8652/0040} {AI95-00108-01} {AI95-00195-01} {AI95-00251-01} {AI95-00270-01} For elementary types, Read reads (and Write writes) the number of stream elements implied by the Stream_Size for the type T; the representation of those stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in canonical order, which is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if T is an array type. If T is a discriminated type, discriminants are included only if they have defaults. If T is a tagged type, the tag is not included. For type extensions, the Write or Read attribute for the parent type is called, followed by the Write or Read attribute of each component of the extension part, in canonical order. For a limited type extension, if the attribute of the parent type or any progenitor type of T is available anywhere within the immediate scope of T, and the attribute of the parent type or the type of any of the extension components is not available at the freezing point of T, then the attribute of T shall be directly specified. 9.a/2 Implementation defined: The contents of the stream elements read and written by the Read and Write attributes of elementary types. 9.b Reason: A discriminant with a default value is treated simply as a component of the object. On the other hand, an array bound or a discriminant without a default value, is treated as " descriptor" or "dope" that must be provided in order to create the object and thus is logically separate from the regular components. Such "descriptor" data are written by 'Output and produced as part of the delivered result by the 'Input function, but they are not written by 'Write nor read by 'Read. A tag is like a discriminant without a default. 9.b.1/1 {8652/0040} {AI95-00108-01} For limited type extensions, we must have a definition of 'Read and 'Write if the parent type has one, as it is possible to make a dispatching call through the attributes. The rule is designed to automatically do the right thing in as many cases as possible. 9.b.2/1 {AI95-00251-01} Similarly, a type that has a progenitor with an available attribute must also have that attribute, for the same reason. 9.c/2 Ramification: {AI95-00195-01} For a composite object, the subprogram denoted by the Write or Read attribute of each component is called, whether it is the default or is user-specified. Implementations are allowed to optimize these calls (see below), presuming the properties of the attributes are preserved. 9.1/2 {AI95-00270-01} Constraint_Error is raised by the predefined Write attribute if the value of the elementary item is outside the range of values representable using Stream_Size bits. For a signed integer type, an enumeration type, or a fixed point type, the range is unsigned only if the integer code for the lower bound of the first subtype is nonnegative, and a (symmetric) signed range that covers all values of the first subtype would require more than Stream_Size bits; otherwise the range is signed. 10 For every subtype S'Class of a class-wide type T'Class: 11 S'Class'Write S'Class'Write denotes a procedure with the following specification: 12/2 {AI95-00441-01} procedure S'Class'Write( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : in T'Class) 13 Dispatches to the subprogram denoted by the Write attribute of the specific type identified by the tag of Item. 14 S'Class'Read S'Class'Read denotes a procedure with the following specification: 15/2 {AI95-00441-01} procedure S'Class'Read( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : out T'Class) 16 Dispatches to the subprogram denoted by the Read attribute of the specific type identified by the tag of Item. 16.a Reason: It is necessary to have class-wide versions of Read and Write in order to avoid generic contract model violations; in a generic, we don't necessarily know at compile time whether a given type is specific or class-wide. Implementation Advice 17/2 This paragraph was deleted.{AI95-00270-01} Static Semantics 18 For every subtype S of a specific type T, the following attributes are defined. 19 S'Output S'Output denotes a procedure with the following specification: 20/2 {AI95-00441-01} procedure S'Output( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : in T) 21 S'Output writes the value of Item to Stream, including any bounds or discriminants. 21.a Ramification: Note that the bounds are included even for an array type whose first subtype is constrained. 22 S'Input S'Input denotes a function with the following specification: 23/2 {AI95-00441-01} function S'Input( Stream : not null access Ada.Streams.Root_Stream_Type'Class) return T 24 S'Input reads and returns one value from Stream, using any bounds or discriminants written by a corresponding S'Output to determine how much to read. 25/2 {8652/0040} {AI95-00108-01} {AI95-00444-01} For an untagged derived type, the Output (resp. Input) attribute is inherited according to the rules given in 13.1 if the attribute is available for the parent type at the point where T is declared. For a tagged derived type, these attributes are not inherited, but rather the default implementations are used. 25.1/2 {AI95-00444-01} The default implementations of the Output and Input attributes, where available, execute as follows: 26 * If T is an array type, S'Output first writes the bounds, and S'Input first reads the bounds. If T has discriminants without defaults, S'Output first writes the discriminants (using S'Write for each), and S'Input first reads the discriminants (using S'Read for each). 27/2 * {AI95-00195-01} S'Output then calls S'Write to write the value of Item to the stream. S'Input then creates an object (with the bounds or discriminants, if any, taken from the stream), passes it to S'Read, and returns the value of the object. Normal default initialization and finalization take place for this object (see 3.3.1, 7.6, and 7.6.1). 27.1/2 {AI95-00251-01} If T is an abstract type, then S'Input is an abstract function. 27.a/2 Ramification: For an abstract type T, S'Input can be called in a dispatching call, or passed to a abstract formal subprogram. But it cannot be used in non-dispatching contexts, because we don't allow objects of abstract types to exist. The designation of this function as abstract has no impact on descendants of T, as T'Input is not inherited for tagged types, but rather recreated (and the default implementation of T'Input calls T'Read, not the parent type's T'Input). Note that T'Input cannot be specified in this case, as any function with the proper profile is necessarily abstract, and specifying abstract subprograms in an attribute_definition_clause is illegal. 28 For every subtype S'Class of a class-wide type T'Class: 29 S'Class'Output S'Class'Output denotes a procedure with the following specification: 30/2 {AI95-00441-01} procedure S'Class'Output( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : in T'Class) 31/2 {AI95-00344-01} First writes the external tag of Item to Stream (by calling String'Output(Stream, Tags.External_Tag(Item'Tag)) - see 3.9) and then dispatches to the subprogram denoted by the Output attribute of the specific type identified by the tag. Tag_Error is raised if the tag of Item identifies a type declared at an accessibility level deeper than that of S. 31.a/2 Reason: {AI95-00344-01} We raise Tag_Error here for nested types as such a type cannot be successfully read with S'Class'Input, and it doesn't make sense to allow writing a value that cannot be read. 32 S'Class'Input S'Class'Input denotes a function with the following specification: 33/2 {AI95-00441-01} function S'Class'Input( Stream : not null access Ada.Streams.Root_Stream_Type'Class) return T'Class 34/2 {AI95-00279-01} {AI95-00344-01} First reads the external tag from Stream and determines the corresponding internal tag (by calling Tags.Descendant_Tag(String'Input(Stream), S'Tag) which might raise Tag_Error - see 3.9) and then dispatches to the subprogram denoted by the Input attribute of the specific type identified by the internal tag; returns that result. If the specific type identified by the internal tag is not covered by T'Class or is abstract, Constraint_Error is raised. 35/2 {AI95-00195-01} {Range_Check [partial]} {check, language-defined (Range_Check)} In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or whose component_declaration includes a default_expression, a check is made that the value returned by Read for the component belongs to its subtype. {Constraint_Error (raised by failure of run-time check)} Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). In the default implementation of Read for a composite type with defaulted discriminants, if the actual parameter of Read is constrained, a check is made that the discriminants read from the stream are equal to those of the actual parameter. Constraint_Error is raised if this check fails. 36/2 {AI95-00195-01} {unspecified [partial]} It is unspecified at which point and in which order these checks are performed. In particular, if Constraint_Error is raised due to the failure of one of these checks, it is unspecified how many stream elements have been read from the stream. 37/1 {8652/0045} {AI95-00132-01} {End_Error (raised by failure of run-time check)} In the default implementation of Read and Input for a type, End_Error is raised if the end of the stream is reached before the reading of a value of the type is completed. 38/2 {8652/0040} {AI95-00108-01} {AI95-00195-01} {AI95-00251-01} {specifiable (of Read for a type) [partial]} {specifiable (of Write for a type) [partial]} {specifiable (of Input for a type) [partial]} {specifiable (of Output for a type) [partial]} {Read clause} {Write clause} {Input clause} {Output clause} The stream-oriented attributes may be specified for any type via an attribute_definition_clause. The subprogram name given in such a clause shall not denote an abstract subprogram. Furthermore, if a stream-oriented attribute is specified for an interface type by an attribute_definition_clause, the subprogram name given in the clause shall statically denote a null procedure. 38.a/2 This paragraph was deleted.{AI95-00195-01} 38.a.1/2 This paragraph was deleted.{8652/0040} {AI95-00108-01} {AI95-00195-01} 38.b/2 Discussion: {AI95-00251-01} Stream attributes (other than Input) are always null procedures for interface types (they have no components). We need to allow explicit setting of the Read and Write attributes in order that the class-wide attributes like LI'Class'Input can be made available. (In that case, any descendant of the interface type would require available attributes.) But we don't allow any concrete implementation because these don't participate in extensions (unless the interface is the parent type). If we didn't ban concrete implementations, the order of declaration of a pair of interfaces would become significant. For example, if Int1 and Int2 are interfaces with concrete implementations of 'Read, then the following declarations would have different implementations for 'Read: 38.c/2 type Con1 is new Int1 and Int2 with null record; type Con2 is new Int2 and Int1 with null record; 38.d/2 This would violate our design principle that the order of the specification of the interfaces in a derived_type_definition doesn't matter. 38.e/2 Ramification: The Input attribute cannot be specified for an interface. As it is a function, a null procedure is impossible; a concrete function is not possible anyway as any function returning an abstract type must be abstract. And we don't allow specifying stream attributes to be abstract subprograms. This has no impact, as the availability of Int'Class'Input (where Int is a limited interface) depends on whether Int'Read (not Int'Input) is specified. There is no reason to allow Int'Output to be specified, either, but there is equally no reason to disallow it, so we don't have a special rule for that. 38.f/2 Discussion: {AI95-00195-01} Limited types generally do not have default implementations of the stream-oriented attributes. The rules defining when a stream-oriented attribute is available (see below) determine when an attribute of a limited type is in fact well defined and usable. The rules are designed to maximize the number of cases in which the attributes are usable. For instance, when the language provides a default implementation of an attribute for a limited type based on a specified attribute for the parent type, we want to be able to call that attribute. 39/2 {AI95-00195-01} A stream-oriented attribute for a subtype of a specific type T is available at places where one of the following conditions is true: {available (stream attribute)} 40/2 * T is nonlimited. 41/2 * The attribute_designator is Read (resp. Write) and T is a limited record extension, and the attribute Read (resp. Write) is available for the parent type of T and for the types of all of the extension components. 41.a/2 Reason: In this case, the language provides a well-defined default implementation, which we want to be able to call. 42/2 * T is a limited untagged derived type, and the attribute was inherited for the type. 42.a/2 Reason: Attributes are only inherited for untagged derived types, and surely we want to be able to call inherited attributes. 43/2 * The attribute_designator is Input (resp. Output), and T is a limited type, and the attribute Read (resp. Write) is available for T. 43.a/2 Reason: The default implementation of Input and Output are based on Read and Write; so if the implementation of Read or Write is good, so is the matching implementation of Input or Output. 44/2 * The attribute has been specified via an attribute_definition_clause, and the attribute_definition_clause is visible. 44.a/2 Reason: We always want to allow calling a specified attribute. But we don't want availability to break privacy. Therefore, only attributes whose specification can be seen count. Yes, we defined the visibility of an attribute_definition_clause (see 8.3). 45/2 {AI95-00195-01} A stream-oriented attribute for a subtype of a class-wide type T'Class is available at places where one of the following conditions is true: 46/2 * T is nonlimited; 47/2 * the attribute has been specified via an attribute_definition_clause, and the attribute_definition_clause is visible; or 48/2 * the corresponding attribute of T is available, provided that if T has a partial view, the corresponding attribute is available at the end of the visible part where T is declared. 48.a/2 Reason: The rules are stricter for class-wide attributes because (for the default implementation) we must ensure that any specific attribute that might ever be dispatched to is available. Because we require specification of attributes for extensions of limited parent types with available attributes, we can in fact know this. Otherwise, we would not be able to use default class-wide attributes with limited types, a significant limitation. 49/2 {AI95-00195-01} An attribute_reference for one of the stream-oriented attributes is illegal unless the attribute is available at the place of the attribute_reference. Furthermore, an attribute_reference for T'Input is illegal if T is an abstract type. 49.a/2 Discussion: Stream attributes always exist. It is illegal to call them in some cases. Having the attributes not be defined for some limited types would seem to be a cleaner solution, but it would lead to contract model problems for limited private types. 49.b/2 T'Input is available for abstract types so that T'Class'Input is available. But we certainly don't want to allow calls that could create an object of an abstract type. Remember that T'Class is never abstract, so the above legality rule doesn't apply to it. We don't have to discuss whether the attribute is specified, as it cannot be: any function returning the type would have to be abstract, and we do not allow specifying an attribute with an abstract subprogram. 50/2 {AI95-00195-01} In the parameter_and_result_profiles for the stream-oriented attributes, the subtype of the Item parameter is the base subtype of T if T is a scalar type, and the first subtype otherwise. The same rule applies to the result of the Input attribute. 51/2 {AI95-00195-01} For an attribute_definition_clause specifying one of these attributes, the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise. The same rule applies to the result of the Input function. 51.a/2 Reason: This is to simplify implementation. 51.b/2 Ramification: The view of the type at the point of the attribute_definition_clause determines whether the first subtype or base subtype is required. Thus, for a scalar type with a partial view (which is never scalar), whether the first subtype or the base subtype is required is determined by whether the attribute_definition_clause occurs before or after the full definition of the scalar type. 52/2 {AI95-00366-01} {support external streaming} {external streaming (type supports)} [A type is said to support external streaming if Read and Write attributes are provided for sending values of such a type between active partitions, with Write marshalling the representation, and Read unmarshalling the representation.] A limited type supports external streaming only if it has available Read and Write attributes. A type with a part that is of an access type supports external streaming only if that access type or the type of some part that includes the access type component, has Read and Write attributes that have been specified via an attribute_definition_clause, and that attribute_definition_clause is visible. [An anonymous access type does not support external streaming. ]All other types support external streaming. 52.a/2 Ramification: A limited type with a part that is of an access type needs to satisfy both rules. Erroneous Execution 53/2 {AI95-00279-01} {AI95-00344-01} {erroneous execution (cause) [partial]} If the internal tag returned by Descendant_Tag to T'Class'Input identifies a type that is not library-level and whose tag has not been created, or does not exist in the partition at the time of the call, execution is erroneous. 53.a/2 Ramification: The definition of Descendant_Tag prevents such a tag from being provided to T'Class'Input if T is a library-level type. However, this rule is needed for nested tagged types. Implementation Requirements 54/1 {8652/0040} {AI95-00108-01} For every subtype S of a language-defined nonlimited specific type T, the output generated by S'Output or S'Write shall be readable by S'Input or S'Read, respectively. This rule applies across partitions if the implementation conforms to the Distributed Systems Annex. 55/2 {AI95-00195-01} If Constraint_Error is raised during a call to Read because of failure of one the above checks, the implementation must ensure that the discriminants of the actual parameter of Read are not modified. Implementation Permissions 56/2 {AI95-00195-01} The number of calls performed by the predefined implementation of the stream-oriented attributes on the Read and Write operations of the stream type is unspecified. An implementation may take advantage of this permission to perform internal buffering. However, all the calls on the Read and Write operations of the stream type needed to implement an explicit invocation of a stream-oriented attribute must take place before this invocation returns. An explicit invocation is one appearing explicitly in the program text, possibly through a generic instantiation (see 12.3). NOTES 57 33 For a definite subtype S of a type T, only T'Write and T'Read are needed to pass an arbitrary value of the subtype through a stream. For an indefinite subtype S of a type T, T'Output and T'Input will normally be needed, since T'Write and T'Read do not pass bounds, discriminants, or tags. 58 34 User-specified attributes of S'Class are not inherited by other class-wide types descended from S. Examples 59 Example of user-defined Write attribute: 60/2 {AI95-00441-01} procedure My_Write( Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : My_Integer'Base); for My_Integer'Write use My_Write; 60.a Discussion: Example of network input/output using input output attributes: 60.b with Ada.Streams; use Ada.Streams; generic type Msg_Type(<>) is private; package Network_IO is -- Connect/Disconnect are used to establish the stream procedure Connect(...); procedure Disconnect(...); 60.c -- Send/Receive transfer messages across the network procedure Send(X : in Msg_Type); function Receive return Msg_Type; private type Network_Stream is new Root_Stream_Type with ... procedure Read(...); -- define Read/Write for Network_Stream procedure Write(...); end Network_IO; 60.d with Ada.Streams; use Ada.Streams; package body Network_IO is Current_Stream : aliased Network_Stream; . . . procedure Connect(...) is ...; procedure Disconnect(...) is ...; 60.e procedure Send(X : in Msg_Type) is begin Msg_Type'Output(Current_Stream'Access, X); end Send; 60.f function Receive return Msg_Type is begin return Msg_Type'Input(Current_Stream'Access); end Receive; end Network_IO; Inconsistencies With Ada 95 60.g/2 {8652/0040} {AI95-00108-01} {inconsistencies with Ada 95} Corrigendum: Clarified how the default implementation for stream attributes is determined (eliminating conflicting language). The new wording provides that attributes for type extensions are created by composing the parent's attribute with those for the extension components if any. If a program was written assuming that the extension components were not included in the stream (as in original Ada 95), it would fail to work in the language as corrected by the Corrigendum. 60.h/2 {AI95-00195-01} Amendment Correction: Explicitly provided a permission that the number of calls to the underlying stream Read and Write operations may differ from the number determined by the canonical operations. If Ada 95 code somehow depended on the number of calls to Read or Write, it could fail with an Ada 2005 implementation. Such code is likely to be very rare; moreover, such code is really wrong, as the permission applies to Ada 95 as well. Extensions to Ada 95 60.i/2 {AI95-00270-01} {extensions to Ada 95} The Stream_Size attribute is new. It allows specifying the number of bits that will be streamed for a type. The Implementation Advice involving this also was changed; this is not incompatible because Implementation Advice does not have to be followed. 60.j/2 {8652/0040} {AI95-00108-01} {AI95-00195-01} {AI95-00444-01} Corrigendum: Limited types may have default constructed attributes if all of the parent and (for extensions) extension components have available attributes. Ada 2005 adds the notion of availability to patch up some holes in the Corrigendum model. Wording Changes from Ada 95 60.k/2 {8652/0009} {AI95-00137-01} Corrigendum: Added wording to specify that these are operational attributes. 60.l/2 {8652/0045} {AI95-00132-01} Corrigendum: Clarified that End_Error is raised by the default implementation of Read and Input if the end of the stream is reached. (The result could have been abnormal without this clarification, thus this is not an inconsistency, as the programmer could not have depended on the previous behavior.) 60.m/2 {AI95-00195-01} Clarified that the default implementation of S'Input does normal initialization on the object that it passes to S'Read. 60.n/2 {AI95-00195-01} Explicitly stated that what is read from a stream when a required check fails is unspecified. 60.o/2 {AI95-00251-01} Defined availability and default implementations for types with progenitors. 60.p/2 {AI95-00279-01} Specified that Constraint_Error is raised if the internal tag retrieved for S'Class'Input is for some type not covered by S'Class or is abstract. We also explicitly state that the program is erroneous if the tag has not been created or does not currently exist in the partition. (Ada 95 did not specify what happened in these cases; it's very unlikely to have provided some useful result, so this is not considered an inconsistency.) 60.q/2 {AI95-00344-01} Added wording to support nested type extensions. S'Input and S'Output always raise Tag_Error for such extensions, and such extensions were not permitted in Ada 95, so this is neither an extension nor an incompatibility. 60.r/2 {AI95-00366-01} Defined supports external streaming to put all of the rules about "good" stream attributes in one place. This is used for distribution and for defining pragma Pure. 60.s/2 {AI95-00441-01} Added the not null qualifier to the first parameter of all of the stream attributes, so that the semantics doesn't change between Ada 95 and Ada 2005. This change is compatible, because mode conformance is required for subprograms specified as stream attributes, and null_exclusions are not considered for mode conformance. 60.t/2 {AI95-00444-01} Improved the wording to make it clear that we don't define the default implementations of attributes that cannot be called (that is, aren't "available"). Also clarified when inheritance takes place. 13.14 Freezing Rules 1 [This clause defines a place in the program text where each declared entity becomes "frozen." A use of an entity, such as a reference to it by name, or (for a type) an expression of the type, causes freezing of the entity in some contexts, as described below. The Legality Rules forbid certain kinds of uses of an entity in the region of text where it is frozen.] 1.a Reason: This concept has two purposes: a compile-time one and a run-time one. 1.b The compile-time purpose of the freezing rules comes from the fact that the evaluation of static expressions depends on overload resolution, and overload resolution sometimes depends on the value of a static expression. (The dependence of static evaluation upon overload resolution is obvious. The dependence in the other direction is more subtle. There are three rules that require static expressions in contexts that can appear in declarative places: The expression in an attribute_designator shall be static. In a record aggregate, variant-controlling discriminants shall be static. In an array aggregate with more than one named association, the choices shall be static. The compiler needs to know the value of these expressions in order to perform overload resolution and legality checking.) We wish to allow a compiler to evaluate static expressions when it sees them in a single pass over the compilation_unit. The freezing rules ensure that. 1.c The run-time purpose of the freezing rules is called the "linear elaboration model." This means that declarations are elaborated in the order in which they appear in the program text, and later elaborations can depend on the results of earlier ones. The elaboration of the declarations of certain entities requires run-time information about the implementation details of other entities. The freezing rules ensure that this information has been calculated by the time it is used. For example, suppose the initial value of a constant is the result of a function call that takes a parameter of type T. In order to pass that parameter, the size of type T has to be known. If T is composite, that size might be known only at run time. 1.d (Note that in these discussions, words like "before" and " after" generally refer to places in the program text, as opposed to times at run time.) 1.e Discussion: The "implementation details" we're talking about above are: 1.f * For a tagged type, the implementations of all the primitive subprograms of the type - that is (in the canonical implementation model), the contents of the type descriptor, which contains pointers to the code for each primitive subprogram. 1.g * For a type, the full type declaration of any parts (including the type itself) that are private. 1.h * For a deferred constant, the full constant declaration, which gives the constant's value. (Since this information necessarily comes after the constant's type and subtype are fully known, there's no need to worry about its type or subtype.) 1.i * For any entity, representation information specified by the user via representation items. Most representation items are for types or subtypes; however, various other kinds of entities, such as objects and subprograms, are possible. 1.j Similar issues arise for incomplete types. However, we do not use freezing there; incomplete types have different, more severe, restrictions. Similar issues also arise for subprograms, protected operations, tasks and generic units. However, we do not use freezing there either; 3.11 prevents problems with run-time Elaboration_Checks. Language Design Principles 1.k An evaluable construct should freeze anything that's needed to evaluate it. 1.l However, if the construct is not evaluated where it appears, let it cause freezing later, when it is evaluated. This is the case for default_expressions and default_names. (Formal parameters, generic formal parameters, and components can have default_expressions or default_names.) 1.m The compiler should be allowed to evaluate static expressions without knowledge of their context. (I.e. there should not be any special rules for static expressions that happen to occur in a context that requires a static expression.) 1.n Compilers should be allowed to evaluate static expressions (and record the results) using the run-time representation of the type. For example, suppose Color'Pos(Red) = 1, but the internal code for Red is 37. If the value of a static expression is Red, some compilers might store 1 in their symbol table, and other compilers might store 37. Either compiler design should be feasible. 1.o Compilers should never be required to detect erroneousness or exceptions at compile time (although it's very nice if they do). This implies that we should not require code-generation for a nonstatic expression of type T too early, even if we can prove that that expression will be erroneous, or will raise an exception. 1.p Here's an example (modified from AI83-00039, Example 3): 1.q type T is record ... end record; function F return T; function G(X : T) return Boolean; Y : Boolean := G(F); -- doesn't force T in Ada 83 for T use record ... end record; 1.r AI83-00039 says this is legal. Of course, it raises Program_Error because the function bodies aren't elaborated yet. A one-pass compiler has to generate code for an expression of type T before it knows the representation of T. Here's a similar example, which AI83-00039 also says is legal: 1.s package P is type T is private; function F return T; function G(X : T) return Boolean; Y : Boolean := G(F); -- doesn't force T in Ada 83 private type T is record ... end record; end P; 1.t If T's size were dynamic, that size would be stored in some compiler-generated dope; this dope would be initialized at the place of the full type declaration. However, the generated code for the function calls would most likely allocate a temp of the size specified by the dope before checking for Program_Error. That dope would contain uninitialized junk, resulting in disaster. To avoid doing that, the compiler would have to determine, at compile time, that the expression will raise Program_Error. 1.u This is silly. If we're going to require compilers to detect the exception at compile time, we might as well formulate the rule as a legality rule. 1.v Compilers should not be required to generate code to load the value of a variable before the address of the variable has been determined. 1.w After an entity has been frozen, no further requirements may be placed on its representation (such as by a representation item or a full_type_declaration). 2 {freezing (entity) [distributed]} {freezing points (entity)} The freezing of an entity occurs at one or more places (freezing points) in the program text where the representation for the entity has to be fully determined. Each entity is frozen from its first freezing point to the end of the program text (given the ordering of compilation units defined in 10.1.4). 2.a Ramification: The "representation" for a subprogram includes its calling convention and means for referencing the subprogram body, either a "link-name" or specified address. It does not include the code for the subprogram body itself, nor its address if a link-name is used to reference the body. 3/1 {8652/0014} {freezing (entity caused by the end of an enclosing construct)} The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity declared within it, except for incomplete types. {freezing (entity caused by a body)} A noninstance body other than a renames-as-body causes freezing of each entity declared before it within the same declarative_part. 3.a Discussion: This is worded carefully to handle nested packages and private types. Entities declared in a nested package_specification will be frozen by some containing construct. 3.b An incomplete type declared in the private part of a library package_specification can be completed in the body. 3.c Ramification: The part about bodies does not say immediately within. A renaming-as-body does not have this property. Nor does a pragma Import. 3.d Reason: The reason bodies cause freezing is because we want proper_bodies and body_stubs to be interchangeable - one should be able to move a proper_body to a subunit, and vice-versa, without changing the semantics. Clearly, anything that should cause freezing should do so even if it's inside a proper_body. However, if we make it a body_stub, then the compiler can't see that thing that should cause freezing. So we make body_stubs cause freezing, just in case they contain something that should cause freezing. But that means we need to do the same for proper_bodies. 3.e Another reason for bodies to cause freezing, there could be an added implementation burden if an entity declared in an enclosing declarative_part is frozen within a nested body, since some compilers look at bodies after looking at the containing declarative_part. 4/1 {8652/0046} {AI95-00106-01} {freezing (entity caused by a construct) [distributed]} A construct that (explicitly or implicitly) references an entity can cause the freezing of the entity, as defined by subsequent paragraphs. {freezing (by a constituent of a construct) [partial]} At the place where a construct causes freezing, each name, expression, implicit_dereference[, or range] within the construct causes freezing: 4.a Ramification: Note that in the sense of this paragraph, a subtype_mark "references" the denoted subtype, but not the type. 5 * {freezing (generic_instantiation) [partial]} The occurrence of a generic_instantiation causes freezing; also, if a parameter of the instantiation is defaulted, the default_expression or default_name for that parameter causes freezing. 6 * {freezing (object_declaration) [partial]} The occurrence of an object_declaration that has no corresponding completion causes freezing. 6.a Ramification: Note that this does not include a formal_object_declaration. 7 * {freezing (subtype caused by a record extension) [partial]} The declaration of a record extension causes freezing of the parent subtype. 7.a Ramification: This combined with another rule specifying that primitive subprogram declarations shall precede freezing ensures that all descendants of a tagged type implement all of its dispatching operations. 7.b/2 {AI95-00251-01} The declaration of a private extension does not cause freezing. The freezing is deferred until the full type declaration, which will necessarily be for a record extension, task, or protected type (the latter only for a limited private extension derived from an interface). 7.1/2 * {AI95-00251-01} The declaration of a record extension, interface type, task unit, or protected unit causes freezing of any progenitor types specified in the declaration. 7.b.1/2 Reason: This rule has the same purpose as the one above: ensuring that all descendants of an interface tagged type implement all of its dispatching operations. As with the previous rule, a private extension does not freeze its progenitors; the full type declaration (which must have the same progenitors) will do that. 7.b.2/2 Ramification: An interface type can be a parent as well as a progenitor; these rules are similar so that the location of an interface in a record extension does not have an effect on the freezing of the interface type. 8/1 {8652/0046} {AI95-00106-01} {freezing (by an expression) [partial]} A static expression causes freezing where it occurs. {freezing (by an object name) [partial]} An object name or nonstatic expression causes freezing where it occurs, unless the name or expression is part of a default_expression, a default_name, or a per-object expression of a component's constraint, in which case, the freezing occurs later as part of another construct. 8.1/1 {8652/0046} {AI95-00106-01} {freezing (by an implicit call) [partial]} An implicit call freezes the same entities that would be frozen by an explicit call. This is true even if the implicit call is removed via implementation permissions. 8.2/1 {8652/0046} {AI95-00106-01} {freezing (subtype caused by an implicit conversion) [partial]} If an expression is implicitly converted to a type or subtype T, then at the place where the expression causes freezing, T is frozen. 9 The following rules define which entities are frozen at the place where a construct causes freezing: 10 * {freezing (type caused by an expression) [partial]} At the place where an expression causes freezing, the type of the expression is frozen, unless the expression is an enumeration literal used as a discrete_choice of the array_aggregate of an enumeration_representation_clause. 10.a Reason: We considered making enumeration literals never cause freezing, which would be more upward compatible, but examples like the variant record aggregate (Discrim => Red, ...) caused us to change our mind. Furthermore, an enumeration literal is a static expression, so the implementation should be allowed to represent it using its representation. 10.b Ramification: The following pathological example was legal in Ada 83, but is illegal in Ada 95: 10.c package P1 is type T is private; package P2 is type Composite(D : Boolean) is record case D is when False => Cf : Integer; when True => Ct : T; end case; end record; end P2; X : Boolean := P2."="( (False,1), (False,1) ); private type T is array(1..Func_Call) of Integer; end; 10.d In Ada 95, the declaration of X freezes Composite (because it contains an expression of that type), which in turn freezes T (even though Ct does not exist in this particular case). But type T is not completely defined at that point, violating the rule that a type shall be completely defined before it is frozen. In Ada 83, on the other hand, there is no occurrence of the name T, hence no forcing occurrence of T. 11 * {freezing (entity caused by a name) [partial]} At the place where a name causes freezing, the entity denoted by the name is frozen, unless the name is a prefix of an expanded name; {freezing (nominal subtype caused by a name) [partial]} at the place where an object name causes freezing, the nominal subtype associated with the name is frozen. 11.a/2 Ramification: {AI95-00114-01} This only matters in the presence of deferred constants or access types; an object_declaration other than a deferred constant declaration causes freezing of the nominal subtype, plus all component junk. 11.b/1 This paragraph was deleted.{8652/0046} {AI95-00106-01} 11.1/1 * {8652/0046} {AI95-00106-01} {freezing (subtype caused by an implicit dereference) [partial]} At the place where an implicit_dereference causes freezing, the nominal subtype associated with the implicit_dereference is frozen. 11.c/2 Discussion: This rule ensures that X.D freezes the same entities that X.all.D does. Note that an implicit_dereference is neither a name nor expression by itself, so it isn't covered by other rules. 12 * [{freezing (type caused by a range) [partial]} At the place where a range causes freezing, the type of the range is frozen.] 12.a Proof: This is consequence of the facts that expressions freeze their type, and the Range attribute is defined to be equivalent to a pair of expressions separated by "..".} 13 * {freezing (designated subtype caused by an allocator) [partial]} At the place where an allocator causes freezing, the designated subtype of its type is frozen. If the type of the allocator is a derived type, then all ancestor types are also frozen. 13.a Ramification: Allocators also freeze the named subtype, as a consequence of other rules. 13.b The ancestor types are frozen to prevent things like this: 13.c type Pool_Ptr is access System.Storage_Pools.Root_Storage_Pool'Class; function F return Pool_Ptr; 13.d package P is type A1 is access Boolean; type A2 is new A1; type A3 is new A2; X : A3 := new Boolean; -- Don't know what pool yet! for A1'Storage_Pool use F.all; end P; 13.e This is necessary because derived access types share their parent's pool. 14 * {freezing (subtypes of the profile of a callable entity) [partial]} At the place where a callable entity is frozen, each subtype of its profile is frozen. If the callable entity is a member of an entry family, the index subtype of the family is frozen. {freezing (function call) [partial]} At the place where a function call causes freezing, if a parameter of the call is defaulted, the default_- expression for that parameter causes freezing. 14.a Discussion: We don't worry about freezing for procedure calls or entry calls, since a body freezes everything that precedes it, and the end of a declarative part freezes everything in the declarative part. 15 * {freezing (type caused by the freezing of a subtype) [partial]} At the place where a subtype is frozen, its type is frozen. {freezing (constituents of a full type definition) [partial]} {freezing (first subtype caused by the freezing of the type) [partial]} At the place where a type is frozen, any expressions or names within the full type definition cause freezing; the first subtype, and any component subtypes, index subtypes, and parent subtype of the type are frozen as well. {freezing (class-wide type caused by the freezing of the specific type) [partial]} {freezing (specific type caused by the freezing of the class-wide type) [partial]} For a specific tagged type, the corresponding class-wide type is frozen as well. For a class-wide type, the corresponding specific type is frozen as well. 15.a Ramification: Freezing a type needs to freeze its first subtype in order to preserve the property that the subtype-specific aspects of statically matching subtypes are the same. 15.b Freezing an access type does not freeze its designated subtype. 15.1/2 * {AI95-00341-01} At the place where a specific tagged type is frozen, the primitive subprograms of the type are frozen. 15.c/2 Reason: We have a language design principle that all of the details of a specific tagged type are known at its freezing point. But that is only true if the primitive subprograms are frozen at this point as well. Late changes of Import and address clauses violate the principle. 15.d/2 Implementation Note: This rule means that no implicit call to Initialize or Adjust can freeze a subprogram (the type and thus subprograms would have been frozen at worst at the same point). Legality Rules 16 [The explicit declaration of a primitive subprogram of a tagged type shall occur before the type is frozen (see 3.9.2).] 16.a Reason: This rule is needed because (1) we don't want people dispatching to things that haven't been declared yet, and (2) we want to allow tagged type descriptors to be static (allocated statically, and initialized to link-time-known symbols). Suppose T2 inherits primitive P from T1, and then overrides P. Suppose P is called before the declaration of the overriding P. What should it dispatch to? If the answer is the new P, we've violated the first principle above. If the answer is the old P, we've violated the second principle. (A call to the new one necessarily raises Program_Error, but that's beside the point.) 16.b Note that a call upon a dispatching operation of type T will freeze T. 16.c We considered applying this rule to all derived types, for uniformity. However, that would be upward incompatible, so we rejected the idea. As in Ada 83, for an untagged type, the above call upon P will call the old P (which is arguably confusing). 17 [A type shall be completely defined before it is frozen (see 3.11.1 and 7.3).] 18 [The completion of a deferred constant declaration shall occur before the constant is frozen (see 7.4).] 18.a/2 Proof: {AI95-00114-01} The above Legality Rules are stated " officially" in the referenced clauses. 19/1 {8652/0009} {AI95-00137-01} An operational or representation item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.1). 19.a/1 Discussion: {8652/0009} {AI95-00137-01} From RM83-13.1(7). The wording here forbids freezing within the aspect_clause itself, which was not true of the Ada 83 wording. The wording of this rule is carefully written to work properly for type-related representation items. For example, an enumeration_representation_- clause is illegal after the type is frozen, even though the _clause refers to the first subtype. 19.a.1/2 {AI95-00114-01} The above Legality Rule is stated for types and subtypes in 13.1, but the rule here covers all other entities as well. 19.b/2 This paragraph was deleted.{AI95-00114-01} . 19.c Discussion: Here's an example that illustrates when freezing occurs in the presence of defaults: 19.d type T is ...; function F return T; type R is record C : T := F; D : Boolean := F = F; end record; X : R; 19.e Since the elaboration of R's declaration does not allocate component C, there is no need to freeze C's subtype at that place. Similarly, since the elaboration of R does not evaluate the default_expression "F = F", there is no need to freeze the types involved at that point. However, the declaration of X does need to freeze these things. Note that even if component C did not exist, the elaboration of the declaration of X would still need information about T - even though D is not of type T, its default_expression requires that information. 19.f Ramification: Although we define freezing in terms of the program text as a whole (i.e. after applying the rules of Section 10), the freezing rules actually have no effect beyond compilation unit boundaries. 19.g Reason: That is important, because Section 10 allows some implementation definedness in the order of things, and we don't want the freezing rules to be implementation defined. 19.h Ramification: These rules also have no effect in statements - they only apply within a single declarative_part, package_specification, task_definition, protected_definition, or protected_body. 19.i Implementation Note: An implementation may choose to generate code for default_expressions and default_names in line at the place of use. {thunk} Alternatively, an implementation may choose to generate thunks (subprograms implicitly generated by the compiler) for evaluation of defaults. Thunk generation cannot, in general, be done at the place of the declaration that includes the default. Instead, they can be generated at the first freezing point of the type(s) involved. (It is impossible to write a purely one-pass Ada compiler, for various reasons. This is one of them - the compiler needs to store a representation of defaults in its symbol table, and then walk that representation later, no earlier than the first freezing point.) 19.j In implementation terms, the linear elaboration model can be thought of as preventing uninitialized dope. For example, the implementation might generate dope to contain the size of a private type. This dope is initialized at the place where the type becomes completely defined. It cannot be initialized earlier, because of the order-of-elaboration rules. The freezing rules prevent elaboration of earlier declarations from accessing the size dope for a private type before it is initialized. 19.k 2.8 overrides the freezing rules in the case of unrecognized pragmas. 19.l/1 {8652/0009} {AI95-00137-01} An aspect_clause for an entity should most certainly not be a freezing point for the entity. Dynamic Semantics 20/2 {AI95-00279-01} The tag (see 3.9) of a tagged type T is created at the point where T is frozen.{creation (of a tag) [partial]} Incompatibilities With Ada 83 20.a {incompatibilities with Ada 83} RM83 defines a forcing occurrence of a type as follows: "A forcing occurrence is any occurrence [of the name of the type, subtypes of the type, or types or subtypes with subcomponents of the type] other than in a type or subtype declaration, a subprogram specification, an entry declaration, a deferred constant declaration, a pragma, or a representation_clause for the type itself. In any case, an occurrence within an expression is always forcing." 20.b It seems like the wording allows things like this: 20.c type A is array(Integer range 1..10) of Boolean; subtype S is Integer range A'Range; -- not forcing for A 20.d Occurrences within pragmas can cause freezing in Ada 95. (Since such pragmas are ignored in Ada 83, this will probably fix more bugs than it causes.) Extensions to Ada 83 20.e {extensions to Ada 83} In Ada 95, generic_formal_parameter_declarations do not normally freeze the entities from which they are defined. For example: 20.f package Outer is type T is tagged limited private; generic type T2 is new T with private; -- Does not freeze T -- in Ada 95. package Inner is ... end Inner; private type T is ...; end Outer; 20.g This is important for the usability of generics. The above example uses the Ada 95 feature of formal derived types. Examples using the kinds of formal parameters already allowed in Ada 83 are well known. See, for example, comments 83-00627 and 83-00688. The extensive use expected for formal derived types makes this issue even more compelling than described by those comments. Unfortunately, we are unable to solve the problem that explicit_generic_actual_parameters cause freezing, even though a package equivalent to the instance would not cause freezing. This is primarily because such an equivalent package would have its body in the body of the containing program unit, whereas an instance has its body right there. Wording Changes from Ada 83 20.h The concept of freezing is based on Ada 83's concept of "forcing occurrences." The first freezing point of an entity corresponds roughly to the place of the first forcing occurrence, in Ada 83 terms. The reason for changing the terminology is that the new rules do not refer to any particular "occurrence" of a name of an entity. Instead, we refer to "uses" of an entity, which are sometimes implicit. 20.i In Ada 83, forcing occurrences were used only in rules about representation_clauses. We have expanded the concept to cover private types, because the rules stated in RM83-7.4.1(4) are almost identical to the forcing occurrence rules. 20.j The Ada 83 rules are changed in Ada 95 for the following reasons: 20.k * The Ada 83 rules do not work right for subtype-specific aspects. In an earlier version of Ada 9X, we considered allowing representation items to apply to subtypes other than the first subtype. This was part of the reason for changing the Ada 83 rules. However, now that we have dropped that functionality, we still need the rules to be different from the Ada 83 rules. 20.l * The Ada 83 rules do not achieve the intended effect. In Ada 83, either with or without the AIs, it is possible to force the compiler to generate code that references uninitialized dope, or force it to detect erroneousness and exception raising at compile time. 20.m * It was a goal of Ada 83 to avoid uninitialized access values. However, in the case of deferred constants, this goal was not achieved. 20.n * The Ada 83 rules are not only too weak - they are also too strong. They allow loopholes (as described above), but they also prevent certain kinds of default_expressions that are harmless, and certain kinds of generic_declarations that are both harmless and very useful. 20.o/2 * {AI95-00114-01} Ada 83 had a case where a aspect_clause had a strong effect on the semantics of the program - 'Small. This caused certain semantic anomalies. There are more cases in Ada 95, because the attribute_definition_clause has been generalized. Incompatibilities With Ada 95 20.p/2 {8652/0046} {AI95-00106-01} {AI95-00341-01} {incompatibilities with Ada 95} Corrigendum: Various freezing rules were added to fix holes in the rules. Most importantly, implicit calls are now freezing, which make some representation clauses illegal in Ada 2005 that were legal (but dubious) in Ada 95. Amendment Correction: Similarly, the primitive subprograms of a specific tagged type are frozen when the type is frozen, preventing dubious convention changes (and address clauses) after the freezing point. In both cases, the code is dubious and the workaround is easy. Wording Changes from Ada 95 20.q/2 {8652/0009} {AI95-00137-01} Corrigendum: Added wording to specify that both operational and representation attributes must be specified before the type is frozen. 20.r/2 {AI95-00251-01} Added wording that declaring a specific descendant of an interface type freezes the interface type. 20.s/2 {AI95-00279-01} Added wording that defines when a tag is created for a type (at the freezing point of the type). This is used to specify checking for uncreated tags (see 3.9).