7 Implementation Defined Characteristics

In addition to the implementation dependent pragmas and attributes, and the implementation advice, there are a number of other Ada features that are potentially implementation dependent and are designated as implementation-defined. These are mentioned throughout the Ada Reference Manual, and are summarized in Annex M.

A requirement for conforming Ada compilers is that they provide documentation describing how the implementation deals with each of these issues. In this chapter you will find each point in Annex M listed, followed by a description of how GNAT handles the implementation dependence.

You can use this chapter as a guide to minimizing implementation dependent features in your programs if portability to other compilers and other operating systems is an important consideration. The numbers in each entry below correspond to the paragraph numbers in the Ada Reference Manual.

See Implementation Advice.

The complexity of programs that can be processed is limited only by the total amount of available virtual memory, and disk space for the generated object files.

There are no variations from the standard.

Any `code_statement' can potentially cause external interactions.

See separate section on source representation.

See separate section on source representation.

See separate section on source representation.

The maximum line length is 255 characters and the maximum length of a lexical element is also 255 characters. This is the default setting if not overridden by the use of compiler switch `-gnaty' (which sets the maximum to 79) or `-gnatyMnn' which allows the maximum line length to be specified to be any value up to 32767. The maximum length of a lexical element is the same as the maximum line length.

See Implementation Defined Pragmas.

Pragma Optimize, if given with a Time or Space parameter, checks that the optimization flag is set, and aborts if it is not.

In the case of a Dynamic_Predicate aspect, the string is “Dynamic_Predicate failed at <source position>”, where “<source position>” might be something like “foo.adb:123”. The Static_Predicate case is handled analogously.

TypeRepresentation
`Short_Short_Integer'8-bit signed
`Short_Integer'16-bit signed
`Integer'32-bit signed
`Long_Integer'64-bit signed (on most 64-bit targets, depending on the C definition of long) 32-bit signed (on all other targets)
`Long_Long_Integer'64-bit signed
`Long_Long_Long_Integer'128-bit signed (on 64-bit targets) 64-bit signed (on 32-bit targets)

There are no nonstandard integer types.

There are no nonstandard real types.

The precision and range are defined by the IEEE Standard for Floating-Point Arithmetic (IEEE 754-2019).

TypeRepresentation
`Short_Float'IEEE Binary32 (Single)
`Float'IEEE Binary32 (Single)
`Long_Float'IEEE Binary64 (Double)
`Long_Long_Float'IEEE Binary64 (Double) on non-x86 architectures IEEE 80-bit Extended on x86 architecture

The default rounding mode specified by the IEEE 754 Standard is assumed both for static and dynamic computations (that is, round to nearest, ties to even). The input routines yield correctly rounded values for Short_Float, Float, and Long_Float at least. The output routines can compute up to twice as many exact digits as the value of T'Digits for any type, for example 30 digits for Long_Float; if more digits are requested, zeros are printed.

The small is the largest power of two that does not exceed the delta.

For an ordinary fixed point type, on 32-bit platforms, the small must lie in 2.0**(-80) .. 2.0**80 and the range in -9.0E+36 .. 9.0E+36; any combination is permitted that does not result in a mantissa larger than 63 bits.

On 64-bit platforms, the small must lie in 2.0**(-127) .. 2.0**127 and the range in -1.0E+76 .. 1.0E+76; any combination is permitted that does not result in a mantissa larger than 63 bits, and any combination is permitted that results in a mantissa between 64 and 127 bits if the small is the ratio of two integers that lie in 1 .. 2.0**127.

If the small is the ratio of two integers with 64-bit magnitude on 32-bit platforms and 128-bit magnitude on 64-bit platforms, which is the case if no small clause is provided, then the operations of the fixed point type are entirely implemented by means of integer instructions. In the other cases, some operations, in particular input and output, may be implemented by means of floating-point instructions and may be affected by accuracy issues on architectures other than x86.

For a decimal fixed point type, on 32-bit platforms, the small must lie in 1.0E-18 .. 1.0E+18 and the digits in 1 .. 18. On 64-bit platforms, the small must lie in 1.0E-38 .. 1.0E+38 and the digits in 1 .. 38.

Block numbers of the form B`nnn', where `nnn' is a decimal integer are allocated.

This is handled in the same way as the implementation-defined behavior referenced in A.4.12(34).

See Implementation Defined Attributes.

As per the suggestion given in the Annotated Ada RM, the default value of the formal parameter is used if one exists and zero is used otherwise.

Feature unimplemented.

Round to even is used in all such cases.

Feature unimplemented.

Feature unimplemented.

Feature unimplemented.

Difficult to characterize.

SPARK allows specifying `null' as the Default_Initial_Condition aspect of a type. See the SPARK reference manual for further details.

There are no implementation-defined time types.

See 9.6(20). The time base used is that provided by the C library function gettimeofday.

The time base used is that provided by the C library function gettimeofday.

The time zone used by package Calendar is the current system time zone setting for local time, as accessed by the C library function localtime.

There are no such limits.

Calendar.Time_Error is raised.

There are no implementation-defined conflict check policies.

A compilation is represented by a sequence of files presented to the compiler in a single invocation of the `gcc' command.

No single file can contain more than one compilation unit, but any sequence of files can be presented to the compiler as a single compilation.

See separate section on compilation model.

If a unit contains an Ada main program, then the Ada units for the partition are determined by recursive application of the rules in the Ada Reference Manual section 10.2(2-6). In other words, the Ada units will be those that are needed by the main program, and then this definition of need is applied recursively to those units, and the partition contains the transitive closure determined by this relationship. In short, all the necessary units are included, with no need to explicitly specify the list. If additional units are required, e.g., by foreign language units, then all units must be mentioned in the context clause of one of the needed Ada units.

If the partition contains no main program, or if the main program is in a language other than Ada, then GNAT provides the binder options `-z' and `-n' respectively, and in this case a list of units can be explicitly supplied to the binder for inclusion in the partition (all units needed by these units will also be included automatically). For full details on the use of these options, refer to `GNAT Make Program gnatmake' in the GNAT User’s Guide.

The units needed by a given compilation unit are as defined in the Ada Reference Manual section 10.2(2-6). There are no implementation-defined pragmas or other implementation-defined means for specifying needed units.

The main program is designated by providing the name of the corresponding ALI file as the input parameter to the binder.

The first constraint on ordering is that it meets the requirements of Chapter 10 of the Ada Reference Manual. This still leaves some implementation-dependent choices, which are resolved by analyzing the elaboration code of each unit and identifying implicit elaboration-order dependencies.

The main program has no parameters. It may be a procedure, or a function returning an integer type. In the latter case, the returned integer value is the return code of the program (overriding any value that may have been set by a call to Ada.Command_Line.Set_Exit_Status).

GNAT itself supports programs with only a single partition. The GNATDIST tool provided with the GLADE package (which also includes an implementation of the PCS) provides a completely flexible method for building and running programs consisting of multiple partitions. See the separate GLADE manual for details.

See separate section on compilation model.

Passive partitions are supported on targets where shared memory is provided by the operating system. See the GLADE reference manual for further details.

Exception message returns the null string unless a specific message has been passed by the program.

Blocks have implementation defined names of the form B`nnn' where `nnn' is an integer.

Exception_Information returns a string in the following format:

*Exception_Name:* nnnnn
*Message:* mmmmm
*PID:* ppp
*Load address:* 0xhhhh
*Call stack traceback locations:*
0xhhhh 0xhhhh 0xhhhh ... 0xhhh

where

This is handled in the same way as the implementation-defined behavior referenced in A.4.12(34).

The exception name and the source location at which the exception was raised are included.

Implementation-defined assertion_aspect_marks include Assert_And_Cut, Assume, Contract_Cases, Debug, Ghost, Initial_Condition, Loop_Invariant, Loop_Variant, Postcondition, Precondition, Predicate, Refined_Post, Statement_Assertions, and Subprogram_Variant. Implementation-defined policy_identifiers include Ignore and Suppressible.

The default assertion policy is Ignore, although this can be overridden via compiler switches such as “-gnata”.

The implementation defined check names include Alignment_Check, Atomic_Synchronization, Duplicated_Tag_Check, Container_Checks, Tampering_Check, Predicate_Check, and Validity_Check. In addition, a user program can add implementation-defined check names by means of the pragma Check_Name. See the description of pragma Suppress for full details.

The legality rules for and semantics of the second parameter of pragma Unsuppress match those for the second argument of pragma Suppress.

No such cases exist.

See separate section on data representations.

See separate section on data representations.

See Implementation Defined Aspects.

See separate section on data representations.

The Size attribute of an indefinite subtype is not less than the Size attribute of any object of that type.

The Object_Size attribute of an indefinite subtype is not less than the Object_Size attribute of any object of that type.

The default external representation for a type tag is the fully expanded name of the type in upper case letters.

A compilation unit is the same in two different partitions if and only if it derives from the same source file.

The only implementation defined component is the tag for a tagged type, which contains a pointer to the dispatching table.

Word_Size (32) is not the same as Storage_Unit (8) for this implementation, so no non-default bit ordering is supported. The default bit ordering corresponds to the natural endianness of the target architecture.

See the definition of package System in system.ads. Note that two declarations are added to package System.

Max_Priority           : constant Positive := Priority'Last;
Max_Interrupt_Priority : constant Positive := Interrupt_Priority'Last;

See the definition of package System.Storage_Elements in s-stoele.ads.

See the definition and documentation in file s-maccod.ads.

Unchecked conversion between types of the same size results in an uninterpreted transmission of the bits from one type to the other. If the types are of unequal sizes, then in the case of discrete types, a shorter source is first zero or sign extended as necessary, and a shorter target is simply truncated on the left. For all non-discrete types, the source is first copied if necessary to ensure that the alignment requirements of the target are met, then a pointer is constructed to the source value, and the result is obtained by dereferencing this pointer after converting it to be a pointer to the target type. Unchecked conversions where the target subtype is an unconstrained array are not permitted. If the target alignment is greater than the source alignment, then a copy of the result is made with appropriate alignment

See preceding definition for the scalar result case.

There are 3 different standard pools used by the compiler when Storage_Pool is not specified depending whether the type is local to a subprogram or defined at the library level and whether Storage_Size``is specified or not. See documentation in the runtime library units ``System.Pool_Global, System.Pool_Size and System.Pool_Local in files s-poosiz.ads, s-pooglo.ads and s-pooloc.ads for full details on the default pools used. All these pools are accessible by means of withing these units.

Storage_Size is measured in storage units, and refers to the total space available for an access type collection, or to the primary stack space for a task.

Instances of language-defined generic units are treated the same as other instances with respect to the Default_Storage_Pool aspect.

See Standard and Implementation Defined Restrictions.

Restrictions that can be checked at compile time are enforced at compile time; violations are illegal. For other restrictions, any violation during program execution results in erroneous execution.

See Implementation Defined Pragmas.

The representation is the in-memory representation of the base type of the type, using the number of bits corresponding to the type'Size value, and the natural ordering of the machine.

See items describing the integer and floating-point types supported.

This hash function has predictable collisions and is subject to equivalent substring attacks. It is not suitable for construction of a hash table keyed on possibly malicious user input.

The contents of a buffer is represented internally as a UTF_8 string. The value return by Text_Buffer.Get is the result of passing that UTF_8 string to UTF_Encoding.Strings.Decode.

The contents of a buffer is represented internally as a UTF_8 string. The value return by Text_Buffer.Wide_Get is the result of passing that UTF_8 string to UTF_Encoding.Wide_Strings.Decode.

The elementary functions correspond to the functions available in the C library. Only fast math mode is implemented.

The sign of zeroes follows the requirements of the IEEE 754 standard on floating-point.

Maximum image width is 6864, see library file s-rannum.ads.

Maximum image width is 6864, see library file s-rannum.ads.

The value returned by the Image function is the concatenation of the fixed-width decimal representations of the 624 32-bit integers of the state vector.

Running the compiler with `-gnatS' to produce a listing of package Standard displays the values of these attributes.

All type representations are contiguous, and the Buffer_Size is the value of type'Size rounded up to the next storage unit boundary.

These files are mapped onto the files provided by the C streams libraries. See source file i-cstrea.ads for further details.

If more digits are requested in the output than are represented by the precision of the value, zeroes are output in the corresponding least significant digit positions.

Positioning is supported.

These are mapped onto the argv and argc parameters of the main program in the natural manner.

These names are interpreted consistently with the underlying file system.

Directories.File_Size’Last is equal to Long_Long_Integer’Last .

Name_Error is raised.

Name_Error is raised.

When the Pattern parameter is not the null string, it is interpreted according to the syntax of regular expressions as defined in the GNAT.Regexp package.

See GNAT.Regexp (g-regexp.ads).

The effect of a call to Get_Next_Entry is determined by the current state of the directory.

This definition is determined by the underlying operating system.

There are no such names.

Containers.Hash_Type’Modulus is 2**32. Containers.Count_Type’Last is 2**31 - 1.

The following convention names are supported

Convention NameInterpretation
`Ada'Ada
`Ada_Pass_By_Copy'Allowed for any types except by-reference types such as limited records. Compatible with convention Ada, but causes any parameters with this convention to be passed by copy.
`Ada_Pass_By_Reference'Allowed for any types except by-copy types such as scalars. Compatible with convention Ada, but causes any parameters with this convention to be passed by reference.
`Assembler'Assembly language
`Asm'Synonym for Assembler
`Assembly'Synonym for Assembler
`C'C
`C_Pass_By_Copy'Allowed only for record types, like C, but also notes that record is to be passed by copy rather than reference.
`COBOL'COBOL
`C_Plus_Plus (or CPP)'C++
`Default'Treated the same as C
`External'Treated the same as C
`Fortran'Fortran
`Intrinsic'For support of pragma Import with convention Intrinsic, see separate section on Intrinsic Subprograms.
`Stdcall'Stdcall (used for Windows implementations only). This convention correspond to the WINAPI (previously called Pascal convention) C/C++ convention under Windows. A routine with this convention cleans the stack before exit. This pragma cannot be applied to a dispatching call.
`DLL'Synonym for Stdcall
`Win32'Synonym for Stdcall
`Stubbed'Stubbed is a special convention used to indicate that the body of the subprogram will be entirely ignored. Any call to the subprogram is converted into a raise of the Program_Error exception. If a pragma Import specifies convention stubbed then no body need be present at all. This convention is useful during development for the inclusion of subprograms whose body has not yet been written. In addition, all otherwise unrecognized convention names are also treated as being synonymous with convention C. In all implementations, use of such other names results in a warning.

Link names are the actual names used by the linker.

The default linker name is that which would be assigned by the relevant external language, interpreting the Ada name as being in all lower case letters.

The string passed to Linker_Options is presented uninterpreted as an argument to the link command, unless it contains ASCII.NUL characters. NUL characters if they appear act as argument separators, so for example

pragma Linker_Options ("-labc" & ASCII.NUL & "-ldef");

causes two separate arguments -labc and -ldef to be passed to the linker. The order of linker options is preserved for a given unit. The final list of options passed to the linker is in reverse order of the elaboration order. For example, linker options for a body always appear before the options from the corresponding package spec.

See files with prefix i- in the distributed library.

See files with prefix i- in the distributed library.

See source file i-c.ads.

COBOLAda
`Floating'Float
`Long_Floating'(Floating) Long_Float
`Binary'Integer
`Long_Binary'Long_Long_Integer
`Decimal_Element'Character
`COBOL_Character'Character

For initialization, see the file i-cobol.ads in the distributed library.

See source file i-fortra.ads. These types are derived, respectively, from Integer, Float, Long_Float, and Character.

See separate section on Intrinsic Subprograms.

There are no such restrictions.

There are no such forms.

If Discard_Names is True for an enumeration type, the Image attribute provides the image of the Pos of the literal, and Value accepts Pos values.

If both of the aspects‘‘Discard_Names‘‘ and No_Tagged_Streams are true for a tagged type, its Expanded_Name and External_Tag values are empty strings. This is useful to avoid exposing entity names at binary level.

The modulus is 2**8. The size is 8.

The value is 1.

The result of this attribute is a string that identifies the object or component that denotes a given task. If a variable Var has a task type, the image for this task will have the form Var_`XXXXXXXX', where the suffix `XXXXXXXX' is the hexadecimal representation of the virtual address of the corresponding task control block. If the variable is an array of tasks, the image of each task will have the form of an indexed component indicating the position of a given task in the array, e.g., Group(5)_`XXXXXXX'. If the task is a component of a record, the image of the task will have the form of a selected component. These rules are fully recursive, so that the image of a task that is a subcomponent of a composite object corresponds to the expression that designates this task.

If a task is created by an allocator, its image depends on the context. If the allocator is part of an object declaration, the rules described above are used to construct its image, and this image is not affected by subsequent assignments. If the allocator appears within an expression, the image includes only the name of the task type.

If the configuration pragma Discard_Names is present, or if the restriction No_Implicit_Heap_Allocation is in effect, the image reduces to the numeric suffix, that is to say the hexadecimal representation of the virtual address of the control block of the task.

Protected entries or interrupt handlers can be executed by any convenient thread, so the value of Current_Task is undefined.

No locking is needed if the formal type Attribute has the size and alignment of either Integer or System.Address and the bit representation of Initial_Value is all zeroes. Otherwise, locking is performed.

See declarations in file system.ads.

There are no implementation-defined execution resources.

On a multi-processor, a task that is waiting for access to a protected object does not keep its processor busy.

Tasks map to threads in the threads package used by GNAT. Where possible and appropriate, these threads correspond to native threads of the underlying operating system.

There are no implementation-defined task dispatching policies.

The value is 10 milliseconds.

The two implementation defined policies permitted in GNAT are Inheritance_Locking and Concurrent_Readers_Locking. On targets that support the Inheritance_Locking policy, locking is implemented by inheritance, i.e., the task owning the lock operates at a priority equal to the highest priority of any task currently requesting the lock. On targets that support the Concurrent_Readers_Locking policy, locking is implemented with a read/write lock allowing multiple protected object functions to enter concurrently.

The ceiling priority of protected objects of the type System.Interrupt_Priority'Last as described in the Ada Reference Manual D.3(10),

The ceiling priority of internal protected objects is System.Priority'Last.

There are no implementation-defined queuing policies.

There are no implementation-defined admission policies.

The only operation that implicitly requires heap storage allocation is task creation.

Unknown.

Execution is erroneous in that case.

Execution is erroneous in that case.

Execution is erroneous in that case.

Execution is erroneous in that case.

Synchronous_Barriers.Barrier_Limit’Last is Integer’Last .

Difficult to characterize.

See source file a-etgrbu.ads.

See source file s-multip.ads.

Unknown.

The GLADE package provides a utility GNATDIST for creating and executing distributed programs. See the GLADE reference manual for further details.

See the GLADE reference manual for full details on such events.

See the GLADE reference manual for full details on these aspects of multi-partition execution.

See the GLADE reference manual for details on the effect of abort in a distributed application.

System.RPC.Partion_ID’Last is Integer’Last. See source file s-rpc.ads.

See the GLADE reference manual for a full description of all implementation defined interfaces.

Named NumberValue
`Max_Scale'+18
`Min_Scale'-18
`Min_Delta'1.0E-18
`Max_Delta'1.0E+18
`Max_Decimal_Digits'18

64

64

Standard library functions are used for the complex arithmetic operations. Only fast math mode is currently supported.

The signs of zero values are as recommended by the relevant implementation advice.

The signs of zero values are as recommended by the relevant implementation advice.

The strict mode is the default. There is no separate relaxed mode. GNAT provides a highly efficient implementation of strict mode.

For cases where the result interval is implementation dependent, the accuracy is that provided by performing all operations in 64-bit IEEE floating-point format.

Infinite and NaN values are produced as dictated by the IEEE floating-point standard. Note that on machines that are not fully compliant with the IEEE floating-point standard, such as Alpha, the `-mieee' compiler flag must be used for achieving IEEE conforming behavior (although at the cost of a significant performance penalty), so infinite and NaN values are properly generated.

Not relevant, division is IEEE exact.

Operations in the close result set are performed using IEEE long format floating-point arithmetic. The input operands are converted to floating-point, the operation is done in floating-point, and the result is converted to the target type.

The result is only defined to be in the perfect result set if the result can be computed by a single scaling operation involving a scale factor representable in 64 bits.

Not relevant, Machine_Overflows is True for fixed-point types.

IEEE infinite and Nan values are produced as appropriate.

Information on this subject is not yet available.

Information on this subject is not yet available.

IEEE infinite and Nan values are produced as appropriate.

Information on those subjects is not yet available.

Information on those subjects is not yet available.

Information on those subjects is not yet available.

Execution is erroneous in that case.