pragma Extensions_Allowed (On | Off);
This configuration pragma enables or disables the implementation extension mode (the use of Off as a parameter cancels the effect of the `-gnatX' command switch).
In extension mode, the latest version of the Ada language is implemented (currently Ada 2022), and in addition a number of GNAT specific extensions are recognized as follows:
Constrained attribute is permitted for objects of
generic types. The result indicates if the corresponding actual
Staticaspect on intrinsic functions
The Ada 202x
Static aspect can be specified on Intrinsic imported
functions and the compiler will evaluate some of these intrinsic statically,
in particular the
This attribute part of the Ada 202x language definition is provided for now under -gnatX to confirm and potentially refine its usage and syntax.
This new aggregate syntax for arrays and containers is provided under -gnatX to experiment and confirm this new language syntax.
In addition to the
exit when CONDITION control structure, several
additional constructs are allowed following this format. Including
return when CONDITION,
goto when CONDITION, and
raise [with EXCEPTION_MESSAGE] when CONDITION.
return Result when Variable > 10; raise Program_Error with "Element is null" when Element = null; goto End_Of_Subprogram when Variable = -1;
The selector for a case statement may be of a composite type, subject to some restrictions (described below). Aggregate syntax is used for choices of such a case statement; however, in cases where a “normal” aggregate would require a discrete value, a discrete subtype may be used instead; box notation can also be used to match all values.
Consider this example:
type Rec is record F1, F2 : Integer; end record; procedure Caser_1 (X : Rec) is begin case X is when (F1 => Positive, F2 => Positive) => Do_This; when (F1 => Natural, F2 => <>) | (F1 => <>, F2 => Natural) => Do_That; when others => Do_The_Other_Thing; end case; end Caser_1;
If Caser_1 is called and both components of X are positive, then Do_This will be called; otherwise, if either component is nonnegative then Do_That will be called; otherwise, Do_The_Other_Thing will be called.
If the set of values that match the choice(s) of an earlier alternative overlaps the corresponding set of a later alternative, then the first set shall be a proper subset of the second (and the later alternative will not be executed if the earlier alternative “matches”). All possible values of the composite type shall be covered. The composite type of the selector shall be a nonlimited untagged (but possibly discriminated) record type, all of whose subcomponent subtypes are either static discrete subtypes or record types that meet the same restrictions.
Support for casing on arrays (and on records that contain arrays) is currently subject to some restrictions. Non-positional array aggregates are not supported as (or within) case choices. Likewise for array type and subtype names. The current implementation exceeds compile-time capacity limits in some annoyingly common scenarios; the message generated in such cases is usually “Capacity exceeded in compiling case statement with composite selector type”.
In addition, pattern bindings are supported. This is a mechanism for binding a name to a component of a matching value for use within an alternative of a case statement. For a component association that occurs within a case choice, the expression may be followed by “is <identifier>”. In the special case of a “box” component association, the identifier may instead be provided within the box. Either of these indicates that the given identifer denotes (a constant view of) the matching subcomponent of the case selector. Binding is not yet supported for arrays or subcomponents thereof.
Consider this example (which uses type Rec from the previous example):
procedure Caser_2 (X : Rec) is begin case X is when (F1 => Positive is Abc, F2 => Positive) => Do_This (Abc) when (F1 => Natural is N1, F2 => <N2>) | (F1 => <N2>, F2 => Natural is N1) => Do_That (Param_1 => N1, Param_2 => N2); when others => Do_The_Other_Thing; end case; end Caser_2;
This example is the same as the previous one with respect to determining whether Do_This, Do_That, or Do_The_Other_Thing will be called. But for this version, Do_This takes a parameter and Do_That takes two parameters. If Do_This is called, the actual parameter in the call will be X.F1.
If Do_That is called, the situation is more complex because there are two choices for that alternative. If Do_That is called because the first choice matched (i.e., because X.F1 is nonnegative and either X.F1 or X.F2 is zero or negative), then the actual parameters of the call will be (in order) X.F1 and X.F2. If Do_That is called because the second choice matched (and the first one did not), then the actual parameters will be reversed.
Within the choice list for single alternative, each choice must define the same set of bindings and the component subtypes for for a given identifer must all statically match. Currently, the case of a binding for a nondiscrete component is not implemented.
Unconstrained array types and subtypes can be specified with a lower bound that is fixed to a certain value, by writing an index range that uses the syntax “<lower-bound-expression> .. <>”. This guarantees that all objects of the type or subtype will have the specified lower bound.
For example, a matrix type with fixed lower bounds of zero for each dimension can be declared by the following:
type Matrix is array (Natural range 0 .. <>, Natural range 0 .. <>) of Integer;
Objects of type Matrix declared with an index constraint must have index ranges starting at zero:
M1 : Matrix (0 .. 9, 0 .. 19); M2 : Matrix (2 .. 11, 3 .. 22); -- Warning about bounds; will raise CE
Similarly, a subtype of String can be declared that specifies the lower bound of objects of that subtype to be 1:
subtype String_1 is String (1 .. <>);
If a string slice is passed to a formal of subtype String_1 in a call to a subprogram S, the slice’s bounds will “slide” so that the lower bound is 1. Within S, the lower bound of the formal is known to be 1, so, unlike a normal unconstrained String formal, there is no need to worry about accounting for other possible lower-bound values. Sliding of bounds also occurs in other contexts, such as for object declarations with an unconstrained subtype with fixed lower bound, as well as in subtype conversions.
Use of this feature increases safety by simplifying code, and can also improve the efficiency of indexing operations, since the compiler statically knows the lower bound of unconstrained array formals when the formal’s subtype has index ranges with static fixed lower bounds.
Since Ada 2005, calls to primitive subprograms of a tagged type that have a “prefixed view” (see RM 4.1.3(9.2)) have been allowed to be written using the form of a selected_component, with the first actual parameter given as the prefix and the name of the subprogram as a selector. This prefixed-view notation for calls is extended so as to also allow such syntax for calls to primitive subprograms of untagged types. The primitives of an untagged type T that have a prefixed view are those where the first formal parameter of the subprogram either is of type T or is an anonymous access parameter whose designated type is T. For a type that has a component that happens to have the same simple name as one of the type’s primitive subprograms, where the component is visible at the point of a selected_component using that name, preference is given to the component in a selected_component (as is currently the case for tagged types with such component names).