Go to the first, previous, next, last section, table of contents.


Representation Issues

  1. This section describes features for querying and controlling aspects of representation and for interfacing to hardware.

Representation Items

  1. There are three kinds of representation items: representation_clauses, component_clauses, and representation pragmas. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). Representation items also specify other specifiable properties of entities. A representation item applies to an entity identified by a local_name, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a compilation. Syntax
  2. representation_clause ::=
         attribute_definition_clause
       | enumeration_representation_clause
       | record_representation_clause
       | at_clause
    
  3. local_name ::=
         direct_name
       | direct_name'attribute_designator
       | library_unit_name
    
    1. A representation pragma is allowed only at places where a representation_clause or compilation_unit is allowed.

Name Resolution Rules

  1. In a representation item, if the local_name is a direct_name, then it shall resolve to denote a declaration (or, in the case of a pragma, one or more declarations) that occurs immediately within the same declarative_region as the representation item. If the local_name has an attribute_designator, then it shall resolve to denote an implementation-defined component, see section Record Representation Clauses, or a class-wide type implicitly declared immediately within the same declarative_region as the representation item. A local_name that is a library_unit_name (only permitted in a representation pragma) shall resolve to denote the library_item that immediately precedes (except for other pragmas) the representation pragma. Legality Rules
  2. The local_name of a representation_clause or representation pragma shall statically denote an entity (or, in the case of a pragma, one or more entities) declared immediately preceding it in a compilation, or within the same declarative_part, package_specification, task_definition, protected_definition, or record_definition as the representation item. If a local_name denotes a local callable entity, it may do so through a local subprogram_renaming_declaration (as a way to resolve ambiguity in the presence of overloading); otherwise, the local_name shall not denote a renaming_declaration.
  3. The representation of an object consists of a certain number of bits (the size of the object). These are the bits that are normally read or updated by the machine code when loading, storing, or operating-on the value of the object. This includes some padding bits, when the size of the object is greater than the size of its subtype. Such padding bits are considered to be part of the representation of the object, rather than being gaps between objects, if these bits are normally read and updated.
  4. A representation item directly specifies an aspect of representation of the entity denoted by the local_name, except in the case of a type-related representation item, whose local_name shall denote a first subtype, and which directly specifies an aspect of the subtype's type. A representation item that names a subtype is either subtype-specific (Size and Alignment clauses) or type-related (all others). Subtype-specific aspects may differ for different subtypes of the same type.
  5. A representation item that directly specifies an aspect of a subtype or type shall appear after the type is completely defined, see section Completions of Declarations, and before the subtype or type is frozen, see section Freezing Rules. 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.
  6. 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.
  7. Representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type.
  8. 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.
  9. A representation item that is not supported by the implementation is illegal, or raises an exception at run time. Static Semantics
  10. If two subtypes statically match, then their subtype-specific aspects (Size and Alignment) are the same.
  11. A derived type inherits each type-related aspect of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype.
  12. Each aspect of representation of an entity is as follows:
    1. 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.
    2. If an aspect of representation of an entity is not specified, it is chosen by default in an unspecified manner.

Dynamic Semantics

  1. For the elaboration of a representation_clause, any evaluable constructs within it are evaluated. Implementation Permissions
  2. An implementation may interpret aspects of representation in an implementation-defined manner. An implementation may place implementation-defined restrictions on representation items. A recommended level of support is specified for representation items and related features in each subclause. These recommendations are changed to requirements for implementations that support the Systems Programming Annex, see section Required Representation Support. Implementation Advice
  3. The recommended level of support for all representation items is qualified as follows:
    1. 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.
    2. 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.
    3. An aliased component, or a component whose type is by-reference, should always be allocated at an addressable location.

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. 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. 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.
  7. The recommended level of support for pragma Pack is:
    1. 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.
    2. 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.

Representation Attributes

  1. The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate representation attributes. Some of these attributes are specifiable via an attribute_definition_clause. 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. 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. 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. Legality Rules
  5. 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. Each specifiable attribute constitutes an aspect of representation.
  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. Static Semantics
  7. A Size clause is an attribute_definition_clause whose attribute_designator is Size. Similar definitions apply to the other specifiable attributes.
  8. A storage element is an addressable element of storage in the machine. 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.
  9. The following attributes are defined:
  10. 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.
    
  12. Address may be specified for stand-alone objects and for
    program units via an attribute_definition_clause.
    
    Erroneous Execution
  13. 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.
  15. The recommended level of support for the Address attribute is:
    1. 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.
    2. An implementation should support Address clauses for imported subprograms.
    3. Objects (including subcomponents) that are aliased or of a by-reference type should be allocated on storage element boundaries.
    4. 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.
    NOTES
  1. (1) The specification of a link name in a pragma Export, see section Interfacing Pragmas 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.
  2. (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. Static Semantics
  3. For a prefix X that denotes a subtype or object:
  4. X'Alignment
    The Address of an object that is allocated under control of
    the implementation is an integral multiple of the Alignment
    of the object (that is, the Address modulo the Alignment is
    zero). The offset of a record component is a multiple of the
    Alignment of the component. For an object that is not
    allocated under control of the implementation (that is, one
    that is imported, that is allocated by a user-defined
    allocator, whose Address has been specified, or is designated
    by an access value returned by an instance of
    Unchecked_Conversion), the implementation may assume that the
    Address is an integral multiple of its Alignment. The
    implementation shall not assume a stricter alignment.
    
  5. 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.
    
  6. Alignment may be specified for first subtypes and
    stand-alone objects via an attribute_definition_clause; the
    expression of such a clause shall be static, and its value
    nonnegative. If the Alignment of a subtype is specified,
    then the Alignment of an object of the subtype is at least as
    strict, unless the object's Alignment is also specified. The
    Alignment of an object created by an allocator is that of the
    designated subtype.
    
  7. If an Alignment is specified for a composite subtype or
    object, this Alignment shall be equal to the least common
    multiple of any specified Alignments of the subcomponent
    subtypes, or an integer multiple thereof.
    
    Erroneous Execution
  8. Program execution is erroneous if an Address clause is given that conflicts with the Alignment.
  9. If the Alignment is specified for an object that is not allocated under control of the implementation, execution is erroneous if the object is not aligned according to the Alignment. Implementation Advice
  10. The recommended level of support for the Alignment attribute for subtypes is:
    1. An implementation should support specified Alignments that are factors and multiples of the number of storage elements per word, subject to the following:
    2. An implementation need not support specified Alignments for combinations of Sizes and Alignments that cannot be easily loaded and stored by available machine instructions.
    3. An implementation need not support specified Alignments that are greater than the maximum Alignment the implementation ever returns by default.
  1. The recommended level of support for the Alignment attribute for objects is:
    1. Same as above, for subtypes, but in addition:
    2. 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.
    NOTES
  1. (3) Alignment is a subtype-specific attribute.
  2. (4) The Alignment of a composite object is always equal to the least common multiple of the Alignments of its components, or a multiple thereof.
  3. (5) A component_clause, Component_Size clause, or a pragma Pack can override a specified Alignment. Static Semantics
  4. For a prefix X that denotes an object:
  5. X'Size
    Denotes the size in bits of the representation of the object.
    The value of this attribute is of the type universal_integer.
    
    1. 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

  1. The recommended level of support for the Size attribute of objects is:
    1. A Size clause should be supported for an object if the specified Size is at least as large as its subtype's Size, and corresponds to a size in storage elements that is a multiple of the object's Alignment (if the Alignment is nonzero).

Static Semantics

  1. For every subtype S:
  2. S'Size
    If S is definite, denotes the size (in bits) that the
    implementation would choose for the following objects of
    subtype S:
    
    1. A record component of subtype S when the record type is packed.
    2. The formal parameter of an instance of Unchecked_Conversion that converts from subtype S to some other subtype.
    3. If S is indefinite, the meaning is implementation defined. The value of this attribute is of the type universal_integer. 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.

Implementation Requirements

  1. In an implementation, Boolean'Size shall be 1. Implementation Advice
  2. If the Size of a subtype is specified, and allows for efficient independent addressability, see section Shared Variables, on the target architecture, then the Size of the following objects of the subtype should equal the Size of the subtype:
    1. Aliased objects (including components).
    2. Unaliased components, unless the Size of the component is determined by a component_clause or Component_Size clause.
  1. A Size clause on a composite subtype should not affect the internal layout of components.
  2. The recommended level of support for the Size attribute of subtypes is:
    1. 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.
    2. 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.
    NOTES
  1. (6) Size is a subtype-specific attribute.
  2. (7) A component_clause or Component_Size clause can override a specified Size. A pragma Pack cannot. Static Semantics
  3. For a prefix T that denotes a task object (after any implicit dereference):
  4. 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.
    
  5. A pragma Storage_Size specifies the amount of storage to be reserved for the execution of a task. Syntax
  6. The form of a pragma Storage_Size is as follows:
  7. pragma Storage_Size(expression);
    
    1. A pragma Storage_Size is allowed only immediately within a task_definition.

Name Resolution Rules

  1. The expression of a pragma Storage_Size is expected to be of any integer type. Dynamic Semantics
  2. A pragma Storage_Size is elaborated when an object of the type defined by the immediately enclosing task_definition is created. 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.
  3. 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
  4. For a prefix X that denotes an array subtype or array object (after any implicit dereference):
  5. 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.
    
    1. 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.

Implementation Advice

  1. The recommended level of support for the Component_Size attribute is:
    1. An implementation need not support specified Component_Sizes that are less than the Size of the component subtype.
    2. 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.

Static Semantics

  1. For every subtype S of a tagged type T (specific or class-wide), the following attribute is defined:
  2. S'External_Tag
    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 section Dispatching Operations of Tagged Types, and
    See section Stream-Oriented Attributes.
    
    Implementation Requirements
  3. 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. NOTES
  4. (8) The following language-defined attributes are specifiable, at least for some of the kinds of entities to which they apply: Address, Size, Component_Size, Alignment, External_Tag, Small, Bit_Order, Storage_Pool, Storage_Size, Write, Output, Read, Input, and Machine_Radix.
  5. (9) It follows from the general rules in section Representation Items, 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. Examples
  6. Examples of attribute definition clauses:
  7. Byte : constant := 8;
    Page : constant := 2**12;
    
  8. 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#);
    
  9. type Short is delta 0.01 range -100.0 .. 100.0;
    for Short'Size use 15;
    
  10. for Car_Name'Storage_Size use
    -- specify access type's storage pool size
      2000*((Car'Size/System.Storage_Unit) +1);
      -- approximately 2000 cars
    
  11. function My_Read(Stream : access Ada.Streams.Root_Stream_Type'Class)
      return T;
    for T'Read use My_Read;  --  see section Stream-Oriented Attributes
    
    NOTES
  12. (10) 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).

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. 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. Legality Rules
  5. The first_subtype_local_name of an enumeration_representation_clause shall denote an enumeration subtype.
  6. 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. Static Semantics
  7. An enumeration_representation_clause specifies the coding aspect of representation. 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. Implementation Advice
  9. The recommended level of support for enumeration_representation_clauses is:
    1. 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.
    NOTES
  1. (11) 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 representation_clause. For example, Pos always returns the position number, not the internal integer code that might have been specified in a representation_clause. Examples
  2. Example of an enumeration representation clause:
  3. type Mix_Code is (ADD, SUB, MUL, LDA, STA, STZ);
    
  4. for Mix_Code use
       (ADD => 1, SUB => 2, MUL => 3, LDA => 8, STA => 24, STZ =>33);
    

Record Layout

  1. 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.

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). 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
    
    Name Resolution Rules
  7. Each position, first_bit, and last_bit is expected to be of any integer type. Legality Rules
  8. The first_subtype_local_name of a record_representation_clause shall denote a specific nonlimited record or record extension subtype.
  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.
  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. Static Semantics
  13. A record_representation_clause (without the mod_clause) specifies the layout. The storage place attributes, see section Storage Place Attributes, are taken from the values of the position, first_bit, and last_bit expressions after normalizing those values so that first_bit is less than Storage_Unit.
  14. A record_representation_clause for a record extension does not override the layout of the parent part; if the layout was specified for the parent type, it is inherited by the record extension. Implementation Permissions
  15. An implementation may generate implementation-defined components (for example, one containing the offset of another component). An implementation may generate names that denote such implementation-defined components; such names shall be implementation-defined attribute_references. An implementation may allow such implementation-defined names to be used in record_ representation_clauses. An implementation can restrict such component_clauses in any manner it sees fit.
  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. Implementation Advice
  17. The recommended level of support for record_representation_clauses is:
    1. 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.
    2. 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.
    3. If the default bit ordering applies to the declaration of a given type, then for a component whose subtype's Size is less than the word size, any storage place that does not cross an aligned word boundary should be supported.
    4. An implementation may reserve a storage place for the tag field of a tagged type, and disallow other components from overlapping that place.
    5. 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.
    NOTES
  1. (12) If no component_clause is given for a component, then the choice of the storage place for the component is left to the implementation. If component_clauses are given for all components, the record_representation_clause completely specifies the representation of the type and will be obeyed exactly by the implementation. Examples
  2. Example of specifying the layout of a record type:
  3. Word : constant := 4;  --  storage element is byte, 4 bytes per word
    
  4. type State      is (A,M,W,P);
    type Mode       is (Fix, Dec, Exp, Signif);
    
  5. 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;
    
  6. 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;
    
  7. 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;
    
  8. for Program_Status_Word'Size use 8*System.Storage_Unit;
    for Program_Status_Word'Alignment use 8;
    
    NOTES
  9. (13) Note on the example: The record_representation_clause defines the record layout. The Size clause guarantees that (at least) eight storage elements are used for objects of the type. The Alignment clause guarantees that aliased, imported, or exported objects of the type will have addresses divisible by eight.

Storage Place Attributes

Static Semantics

  1. For a component C of a composite, non-array object R, the storage place attributes are defined:
  2. R.C'Position
    Denotes the same value as R.C'Address - R'Address. The value
    of this attribute is of the type universal_integer.
    
  3. R.C'First_Bit
    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. R.C'Last_Bit
    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.
    
    Implementation Advice
  5. 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.

Bit Ordering

  1. The Bit_Order attribute specifies the interpretation of the storage place attributes. Static Semantics
  2. A bit ordering is a method of interpreting the meaning of the storage place attributes. 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 (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. 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.
  6. The storage place attributes of a component of a type are interpreted according to the bit ordering of the type. Implementation Advice
  7. The recommended level of support for the nondefault bit ordering is:
    1. If Word_Size = Storage_Unit, then the implementation should support the nondefault bit ordering in addition to the default bit ordering.

Change of Representation

  1. A type_conversion, see section Type Conversions 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. 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
    

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:
  3. package System is
       pragma Preelaborate(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:
       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.    -- Other System-Dependent Declarations:
       type Bit_Order is (High_Order_First, Low_Order_First);
       Default_Bit_Order : constant Bit_Order;
    
  16.    -- Priority-related declarations, see section Task Priorities.:
       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.
    
  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  See section Numerics (normative).)
    
  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.
    
  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.
    
  34. Address is of a definite, nonlimited type. 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.
  35. See section Bit Ordering, for an explanation of Bit_Order and Default_Bit_Order. Implementation Permissions
  36. 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. Package System may be declared pure. Implementation Advice
  37. Address should be of a private type. NOTES
  38. (14) There are also some language-defined child packages of System defined elsewhere.

The Package System.Storage_Elements

Static Semantics

  1. The following language-defined library package exists:
  2. package System.Storage_Elements is
       pragma Preelaborate(System.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:
    
  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;
    
  12. Storage_Element represents a storage element. Storage_Offset represents an offset in storage elements. Storage_Count represents a number of storage elements. Storage_Array represents a contiguous sequence of storage elements.
  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. Package System.Storage_Elements may be declared pure. 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." Operations that do not make sense should raise Program_Error.

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. 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. For other addresses, the behavior is unspecified. To_Address(null) returns Null_Address (for null of the appropriate type). To_Address(Y), where Y /= null, returns Y.all'Address. Implementation Permissions
  6. An implementation may place restrictions on instantiations of Address_To_Access_Conversions.

Machine Code Insertions

  1. 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;
    
    1. 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

  1. The qualified_expression is expected to be of any type. Legality Rules
  2. The qualified_expression shall be of a type declared in package System.Machine_Code.
  3. A code_statement shall appear only within the scope of a with_clause that mentions package System.Machine_Code. Static Semantics
  4. 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. Implementation Permissions
  5. An implementation may place restrictions on code_statements. An implementation is not required to provide package System.Machine_Code. NOTES
  6. (15) An implementation may provide implementation-defined pragmas specifying register conventions and calling conventions.
  7. (16) 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.
  8. (17) Intrinsic subprograms, see section Conformance Rules, can also be used to achieve machine code insertions. Interface to assembly language can be achieved using the features in Annex B, see section Interface to Other Languages (normative). Examples
  9. Example of a code statement:
  10. M : Mask;
    procedure Set_Mask; pragma Inline(Set_Mask);
    
  11. 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;
    

Unchecked Type Conversions

  1. 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);
    
    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:
    1. S'Size = Target'Size.
    2. S'Alignment = Target'Alignment.
    3. The target subtype is not an unconstrained composite subtype.
    4. S and the target subtype both have a contiguous representation.
    5. The representation of S is a representation of an object of the target subtype.
  1. Otherwise, the effect is implementation defined; in particular, the result can be abnormal, see section Data Validity. Implementation Permissions
  2. 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.
  3. An implementation may place restrictions on Unchecked_Conversion. Implementation Advice
  4. The Size of an array object should not include its bounds; hence, the bounds should not be part of the converted data.
  5. 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.
  6. The recommended level of support for unchecked conversions is:
      Unchecked conversions should be supported and should be reversible in the cases where this clause defines the result. 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.

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. The primary cause of invalid representations is uninitialized variables.
  3. Abnormal objects and invalid representations are explained in this subclause. Dynamic Semantics
  4. 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:
    1. An assignment to the object is disrupted due to an abort, see section Abort of a Task - Abort of a Sequence of Statements, or due to the failure of a language-defined check, see section Exceptions and Optimization.
    2. The object is not scalar, and is passed to an in out or out parameter of an imported procedure or language-defined input procedure, if after return from the procedure the representation of the parameter does not represent a value of the parameter's subtype.
  1. 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
  2. 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. Bounded (Run-Time) Errors
  3. 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. 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:
    1. If the representation of the object represents a value of the object's type, the value of the type is used.
    2. 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.

Erroneous Execution

  1. A call to an imported function or an instance of Unchecked_Conversion is erroneous if the result is scalar, and the result object has an invalid representation.
  2. 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. NOTES
  3. (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.

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.
    
    NOTES
  4. (19) Invalid data can be created in the following cases (not counting erroneous or unpredictable execution):
    1. an uninitialized scalar object,
    2. the result of an unchecked conversion,
    3. input,
    4. interface to another language (including machine code),
    5. aborting an assignment,
    6. disrupting an assignment due to the failure of a language-defined check, See section Exceptions and Optimization, and
    7. use of an object whose Address has been specified.
  1. (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.

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 section Operations of Access Types,
    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.
    
    NOTES
  4. (21) 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 section Operations of Access Types.
  5. (22) There is no Unchecked_Access attribute for subprograms.

Storage Management

  1. 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. 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 type. The user may define new pool types, and may override the choice of pool for an access type by specifying Storage_Pool for the type. Legality Rules
  3. If Storage_Pool is specified for a given access type, Storage_Size shall not be specified for it. 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.     type Root_Storage_Pool is
            abstract new
              Ada.Finalization.Limited_Controlled with private;
    
  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;
    
  11. A storage pool type (or pool type) is a descendant of Root_Storage_Pool. The elements of a storage pool are the objects allocated in the pool by allocators.
  12. For every access subtype S, the following 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.
    
  15. 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. 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.
  17. 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. 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).
  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. 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.
  19. If Storage_Pool is specified for an access type, then the specified pool is used.
  20. 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. Erroneous Execution
  21. 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. 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.
  24. A default (implementation-provided) storage pool for an access-to-constant type should not have overhead to support deallocation of individual objects.
  25. A storage pool for an anonymous access type should be created at the point of an allocator for the type, and be reclaimed when the designated object becomes inaccessible. NOTES
  26. (23) 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. (24) 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:
    1. If the allocators are used in different tasks, they require mutual exclusion.
    2. If they are used inside protected objects, they cannot block.
    3. If they are used by interrupt handlers, see section Interrupt Support, the mutual exclusion mechanism has to work properly in that context.
  1. (25) The primitives Allocate, Deallocate, and Storage_Size are declared as abstract, see section Abstract Types and Subprograms, and therefore they have to be overridden when a new (non-abstract) storage pool type is declared. Examples
  2. 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:
  3. Pool_Object : Some_Storage_Pool_Type;
    
  4. type T is access Designated;
    for T'Storage_Pool use Pool_Object;
    
  5. Another access type may be added to an existing storage pool, via:
  6. for T2'Storage_Pool use T'Storage_Pool;
    
  7. The semantics of this is implementation defined for a standard storage pool.
  8. 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:
  9. type Mark_Release_Pool_Type
       (Pool_Size : Storage_Elements.Storage_Count;
        Block_Size : Storage_Elements.Storage_Count)
            is new Root_Storage_Pool with limited private;
    
  10. ...
    
  11. MR_Pool : Mark_Release_Pool_Type (Pool_Size => 2000,
                                      Block_Size => 100);
    
  12. type Acc is access ...;
    for Acc'Storage_Pool use MR_Pool;
    ...
    
  13. Mark(MR_Pool);
    ... -- Allocate objects using ``new Designated(...)''.
    Release(MR_Pool); -- Reclaim the storage.
    

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. S'Max_Size_In_Storage_Elements
  4. Denotes the maximum value for Size_In_Storage_Elements that
    will be requested via Allocate for an access type whose
    designated subtype is S. The value of this attribute is of
    type universal_integer.
    

Unchecked Storage Deallocation

  1. 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);
    
    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:
    1. After executing Free(X), the value of X is null.
    2. Free(X), when X is already equal to null, has no effect.
    3. Free(X), when X is not equal to null first performs finalization, as described in section User-Defined Assignment and Finalization. It then deallocates the storage occupied by the object designated by X. 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.
  1. After Free(X), the object designated by X, and any subcomponents thereof, no longer exist; their storage can be reused for other purposes. Bounded (Run-Time) Errors
  2. It is a bounded error to free a discriminated, unterminated task object. The possible consequences are:
    1. No exception is raised.
    2. Program_Error or Tasking_Error is raised at the point of the deallocation.
    3. Program_Error or Tasking_Error is raised in the task the next time it references any of the discriminants.
  1. 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. Erroneous Execution
  2. 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
  3. For a standard storage pool, Free should actually reclaim the storage. NOTES
  4. (26) The rules here that refer to Free apply to any instance of Unchecked_Deallocation.
  5. (27) Unchecked_Deallocation cannot be instantiated for an access-to-constant type. This is implied by the rules of 12.5.4.

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);
    
    Legality Rules
  4. The first_subtype_local_name of a pragma Controlled shall denote a non-derived access subtype. Static Semantics
  5. A pragma Controlled is a representation pragma that specifies the controlled aspect of representation.
  6. Garbage collection is a process that automatically reclaims storage, or moves objects to a different address, while the objects still exist.
  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. Implementation Permissions
  8. An implementation need not support garbage collection, in which case, a pragma Controlled has no effect.

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. restriction ::= restriction_identifier
       | restriction_parameter_identifier => expression
    
    Name Resolution Rules
  5. 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. The set of restrictions is implementation defined. Post-Compilation Rules
  8. 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. 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. NOTES
  10. (28) Restrictions intended to facilitate the construction of efficient tasking run-time systems are defined in section Tasking Restrictions. Safety- and security-related restrictions are defined in section Safety and Security Restrictions.
  11. (29) 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.

Streams

  1. 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.

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);
    
  3.     type Root_Stream_Type is abstract tagged limited private;
    
  4.     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 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. The Read operation transfers Item'Length stream elements from the specified stream to fill the array Item. The index of the last stream element transferred 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. NOTES
  10. (30) See section The Package Streams.Stream_IO, for an example of extending type Root_Stream_Type.

Stream-Oriented Attributes

  1. The Write, Read, Output, and Input attributes convert values to a stream of elements and reconstruct values from a stream. 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:
    
    1. procedure S'Write(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item : in T)
      
    2. S'Write writes the value of Item to Stream.
  1. S'Read
    S'Read denotes a procedure with the following specification:
    
    1. procedure S'Read(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item : out T)
      
    2. S'Read reads the value of Item from Stream.
  1. For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in a canonical order. The canonical order of components 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.
  2. For every subtype S'Class of a class-wide type T'Class:
  3. S'Class'Write
    S'Class'Write denotes a procedure with the following
    specification:
    
    1. procedure S'Class'Write(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item   : in T'Class)
      
    2. Dispatches to the subprogram denoted by the Write attribute of the specific type identified by the tag of Item.
  1. S'Class'Read
    S'Class'Read denotes a procedure with the following
    specification:
    
    1. procedure S'Class'Read(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item : out T'Class)
      
    2. Dispatches to the subprogram denoted by the Read attribute of the specific type identified by the tag of Item.

Implementation Advice

  1. If a stream element is the same size as a storage element, then the normal in-memory representation should be used by Read and Write for scalar objects. Otherwise, Read and Write should use the smallest number of stream elements needed to represent all values in the base range of the scalar type. Static Semantics
  2. For every subtype S of a specific type T, the following attributes are defined.
  3. S'Output
    S'Output denotes a procedure with the following specification:
    
    1. procedure S'Output(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item : in T)
      
    2. S'Output writes the value of Item to Stream, including any bounds or discriminants.
  1. S'Input
    S'Input denotes a function with the following specification:
    
    1. function S'Input(
         Stream : access Ada.Streams.Root_Stream_Type'Class)
         return T
      
    2. 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.
  1. Unless overridden by an attribute_definition_clause, these subprograms execute as follows:
    1. 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).
    2. 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), initializes it with S'Read, and returns the value of the object.
  1. For every subtype S'Class of a class-wide type T'Class:
  2. S'Class'Output
    S'Class'Output denotes a procedure with the following
    specification:
    
    1. procedure S'Class'Output(
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item   : in T'Class)
      
    2. First writes the external tag of Item to Stream (by calling String'Output(Tags.External_Tag(Item'Tag) -- see section Tagged Types and Type Extensions.) and then dispatches to the subprogram denoted by the Output attribute of the specific type identified by the tag.
  1. S'Class'Input
    S'Class'Input denotes a function with the following
    specification:
    
    1. function S'Class'Input(
         Stream : access Ada.Streams.Root_Stream_Type'Class)
         return T'Class
      
    2. First reads the external tag from Stream and determines the corresponding internal tag (by calling Tags.Internal_Tag(String'Input(Stream)) -- see section Tagged Types and Type Extensions.) and then dispatches to the subprogram denoted by the Input attribute of the specific type identified by the internal tag; returns that result.
  1. 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 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 section Data Validity.
  2. The stream-oriented attributes may be specified for any type via an attribute_definition_clause. All nonlimited types have default implementations for these operations. An attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute_definition_clause. 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. NOTES
  3. (31) 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.
  4. (32) User-specified attributes of S'Class are not inherited by other class-wide types descended from S. Examples
  5. Example of user-defined Write attribute:
  6. procedure My_Write
      (Stream : access Ada.Streams.Root_Stream_Type'Class;
       Item   : My_Integer'Base);
    for My_Integer'Write use My_Write;
    

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.
  2. 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 section The Compilation Process.
  3. 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. A noninstance body causes freezing of each entity declared before it within the same declarative_part.
  4. A construct that (explicitly or implicitly) references an entity can cause the freezing of the entity, as defined by subsequent paragraphs. At the place where a construct causes freezing, each name, expression, or range within the construct causes freezing:
    1. 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.
    2. The occurrence of an object_declaration that has no corresponding completion causes freezing.
    3. The declaration of a record extension causes freezing of the parent subtype.
  1. A static expression causes freezing where it occurs. A nonstatic expression causes freezing where it occurs, unless the 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.
  2. The following rules define which entities are frozen at the place where a construct causes freezing:
    1. 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.
    2. 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; at the place where an object name causes freezing, the nominal subtype associated with the name is frozen.
    3. At the place where a range causes freezing, the type of the range is frozen.
    4. 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.
    5. 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. 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.
    6. At the place where a subtype is frozen, its type is frozen. 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. 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.

Legality Rules

  1. The explicit declaration of a primitive subprogram of a tagged type shall occur before the type is frozen, see section Dispatching Operations of Tagged Types.
  2. A type shall be completely defined before it is frozen (see section Completions of Declarations, and section Private Types and Private Extensions.).
  3. The completion of a deferred constant declaration shall occur before the constant is frozen, see section Deferred Constants.
  4. A representation item that directly specifies an aspect of an entity shall appear before the entity is frozen, see section Representation Items.


Go to the first, previous, next, last section, table of contents.