11.5 Suppressing Checks
{
AI95-00224-01}
Checking pragmas give instructions to an implementation
on handling language-defined checks. A
pragma
Suppress gives permission to an implementation to omit certain language-defined
checks, while a
pragma
Unsuppress revokes the permission to omit checks.
Term entry: suppress a check —
assert that the check cannot fail, and request that the compiler optimize
by disabling the check
Note: The compiler is not required to honor this request. Suppressing
checks that can fail can cause a program to behave in arbitrary ways.
{
AI05-0264-1}
A
language-defined check (or simply, a “check”) is one
of the situations defined by this document that requires a check to be
made at run time to determine whether some condition is true.
A
check
fails when the condition being checked is False, causing
an exception to be raised.
Discussion: All such checks are defined
under “Dynamic Semantics” in clauses and subclauses throughout
the standard.
Term entry: check — test
made during execution to determine whether a language rule has been violated
Syntax
Legality Rules
Static Semantics
{
AI95-00224-01}
A checking pragma applies to the named check in a specific region, and
applies to all entities in that region. A checking pragma given in a
declarative_part
or immediately within a
package_specification
applies from the place of the
pragma
to the end of the innermost enclosing declarative region. The region
for a checking pragma given as a configuration pragma is the declarative
region for the entire compilation unit (or units) to which it applies.
Ramification: {
AI05-0290-1}
This means that a Suppress pragma that occurs in a scope enclosing the
declaration of a generic unit but not also enclosing the declaration
of a given instance of that generic unit will not apply to constructs
within the given instance.
{
AI95-00224-01}
A
pragma Suppress
gives permission to an implementation to omit the named check (or every
check in the case of All_Checks) for any entities to which it applies.
If permission has been given to suppress a given
check, the check is said to be
suppressed.
Ramification: A check is suppressed even
if the implementation chooses not to actually generate better code.
This
allows the implementation to raise Program_Error, for example, if the
erroneousness is detected.
{
AI95-00224-01}
A
pragma Unsuppress
revokes the permission to omit the named check (or every check in the
case of All_Checks) given by any
pragma
Suppress that applies at the point of the
pragma
Unsuppress. The permission is revoked for the region to which the
pragma
Unsuppress applies. If there is no such permission at the point of a
pragma Unsuppress,
then the
pragma
has no effect. A later
pragma
Suppress can renew the permission.
The following are the
language-defined checks:
{
AI12-0309-1}
[The following checks correspond to situations in
which the exception Constraint_Error is raised upon failure of a language-defined
check.]
When evaluating a dereference (explicit or implicit), check that the
value of the
name
is not
null. When converting to a subtype that excludes null,
check that the converted value is not
null.
Check that the discriminants of a composite value have the values imposed
by a discriminant constraint. Also, when accessing a record component,
check that it exists for the current discriminant values.
Check that the second operand is not zero for the operations /, rem
and mod.
Check that the bounds of an array value are equal to the corresponding
bounds of an index constraint. Also, when accessing a component of an
array object, check for each dimension that the given index value belongs
to the range defined by the bounds of the array object. Also, when accessing
a slice of an array object, check that the given discrete range is compatible
with the range defined by the bounds of the array object.
Check that two arrays have matching components, in the case of array
subtype conversions, and logical operators for arrays of boolean components.
Check that a scalar value is within the base range of its type, in cases
where the implementation chooses to raise an exception instead of returning
the correct mathematical result.
Check that a scalar value satisfies a range constraint. Also, for the
elaboration of a
subtype_indication,
check that the
constraint
(if present) is compatible with the subtype denoted by the
subtype_mark.
Also, for an
aggregate,
check that an index or discriminant value belongs to the corresponding
subtype. Also, check that when the result of an operation yields an array,
the value of each component belongs to the component subtype. Also, for
the attributes Value, Wide_Value, and Wide_Wide_Value, check that the
given string has the appropriate syntax and value for the base subtype
of the
prefix
of the
attribute_reference.
Check that operand tags in a dispatching call are all equal. Check for
the correct tag on tagged type conversions, for an
assignment_statement,
and when returning a tagged limited object from a function.
{
AI12-0309-1}
[The following checks correspond to situations in
which the exception Program_Error is raised upon failure of a language-defined
check.]
Check the accessibility level of an entity or view.
For an
allocator,
check that the master of any tasks to be created by the
allocator
is not yet completed or some dependents have not yet terminated, and
that the finalization of the collection has not started.
When a subprogram or protected entry is called, a task activation is
accomplished, or a generic instantiation is elaborated, check that the
body of the corresponding unit has already been elaborated.
Other language-defined checks that raise Program_Error: that subtypes
with predicates are not used to index an array in a generic unit; that
the maximum number of chunks is greater than zero; that the default value
of an out parameter is convertible; that there is no misuse of functions
in a generic with a class-wide actual type; that there are not colliding
External_Tag values; that there is no misuse of operations of unchecked
union types.
{
AI12-0309-1}
[The following check corresponds to situations in which the exception
Storage_Error is raised upon failure of a language-defined check.]
Check that evaluation of an
allocator
does not require more space than is available for a storage pool. Check
that the space available for a task or subprogram has not been exceeded.
Reason: We considered splitting this
out into three categories: Pool_Check (for
allocators),
Stack_Check (for stack usage), and Heap_Check (for implicit use of the
heap — use of the heap other than through an
allocator).
Storage_Check would then represent the union of these three. However,
there seems to be no compelling reason to do this, given that it is not
feasible to split Storage_Error.
{
AI12-0309-1}
[The following check corresponds to situations in which the exception
Tasking_Error is raised upon failure of a language-defined check.]
Check that all tasks activated successfully. Check that a called task
has not yet terminated.
{
AI12-0112-1}
{
AI12-0311-1}
[The following checks correspond to situations in which the exception
Assertion_Error is raised upon failure of a language-defined check.]
For a language-defined unit
U associated with one of these checks
in the list below, the check refers to performance of checks associated
with the Pre, Static_Predicate, and Dynamic_Predicate aspects associated
with any entity declared in a descendant of
U, or in an instance
of a generic unit which is, or is declared in, a descendant of
U.
Each check is associated with one or more units:
Calendar.
Characters, Wide_Characters, and Wide_Wide_Characters.
Containers.
Interfaces.
Sequential_IO, Direct_IO, Text_IO, Wide_Text_IO, Wide_Wide_Text_IO, Storage_IO,
Streams.Stream_IO, and Directories.
Numerics.
Strings.
System.
Ramification: {
AI12-0311-1}
Any unit
U is a descendant of itself.
Reason: {
AI12-0112-1}
One could use
pragma Assertion_Policy to eliminate such checks,
but that would require recompiling the language defined packages (the
assertion policy that determines whether the assertion checks are made
is that used to compile the unit). In addition, we do not want to specify
the behavior of language-defined operations if the precondition fails;
that is different than the usual behavior of Assertion_Policy. By using
Suppress for this purpose, we make it clear that a failed check that
is suppressed means erroneous execution.
To be honest: {
AI12-0311-1}
The preceding rule about an instance of a generic where the generic is
declared in
U really extends recursively to handle the case of
a generic package
G1 which declares another generic package
G1.G2, which declares another generic package
G1.G2.G3,
and so on. So if
G1 is declared in some predefined unit
U
then, for purposes of defining these checks,
Some_Instance_Of_G1.G2
is also considered to be declared in
U.
{
AI12-0309-1}
[The following check corresponds to all situations in which any predefined
exception is raised upon failure of a check.]
Represents the union of all checks; suppressing All_Checks suppresses
all checks other than those associated with assertions. In addition,
an implementation is allowed (but not required) to behave as if a pragma
Assertion_Policy(Ignore) applies to any region to which pragma Suppress(All_Checks)
applies.
Ramification: {
AI12-0309-1}
All_Checks may include implementation-defined checks. It does not include,
however, explicit raises of predefined exceptions (including those mandated
for language constructs), nor those propagated from language-defined
subprograms.
To be honest: {
AI05-0005-1}
There are additional checks defined in various Specialized Needs Annexes
that are not listed here. Nevertheless, they are included in All_Checks
and named in a Suppress pragma on implementations that support the relevant
annex. Look up “check, language-defined” in the index to
find the complete list.
Discussion: {
AI05-0290-1}
We don't want to say that assertions are suppressed, because we don't
want the potential failure of an assertion to cause erroneous execution
(see below). Thus they are excluded from the suppression part of the
above rule and then handled with an implicit Ignore policy.
Erroneous Execution
{
AI12-0112-1}
{
AI12-0311-1}
If a given check has been suppressed, and the corresponding
error situation occurs, the execution of the program is erroneous. Similarly,
if a precondition check has been suppressed and the evaluation of the
precondition would have raised an exception, execution is erroneous.
Reason: {
AI12-0112-1}
It's unclear that a precondition expression that executes
raise
some_exception is an "error situation"; the precondition
never actually evaluates to False in that case. Thus, we spell out that
case. We only allow suppressing preconditions associated with language-defined
units; other preconditions follow the rules of the appropriate Assertion_Policy.
Implementation Permissions
{
AI95-00224-01}
An implementation is allowed to place restrictions on checking pragmas,
subject only to the requirement that
pragma
Unsuppress shall allow any check names supported by
pragma
Suppress. An implementation is allowed to add additional check names,
with implementation-defined semantics.
When Overflow_Check
has been suppressed, an implementation may also suppress an unspecified
subset of the Range_Checks.
Implementation defined: Implementation-defined
check names.
Discussion: For Overflow_Check, the intention
is that the implementation will suppress any Range_Checks that are implemented
in the same manner as Overflow_Checks (unless they are free).
{
AI95-00224-01}
An implementation may support an additional parameter on
pragma
Unsuppress similar to the one allowed for
pragma
Suppress (see
J.10). The meaning of such a
parameter is implementation-defined.
Implementation defined: Existence and
meaning of second parameter of
pragma
Unsuppress.
Implementation Advice
The implementation should minimize the code executed
for checks that have been suppressed.
Implementation Advice: Code executed
for checks that have been suppressed should be minimized.
Implementation Note: However, if a given
check comes for free (for example, the hardware automatically performs
the check in parallel with doing useful work) or nearly free (for example,
the check is a tiny portion of an expensive run-time system call), the
implementation should not bother to suppress the check. Similarly, if
the implementation detects the failure at compile time and provides a
warning message, there is no need to actually suppress the check.
NOTE 1 {
AI12-0442-1}
There is no guarantee that a
suppressed check is actually removed; hence a
pragma
Suppress is useful only to improve efficiency.
NOTE 2 {
AI95-00224-01}
It is possible to give both a
pragma
Suppress and Unsuppress for the same check immediately within the same
declarative_part.
In that case, the last
pragma
given determines whether or not the check is suppressed. Similarly, it
is possible to resuppress a check which has been unsuppressed by giving
a
pragma Suppress
in an inner declarative region.
Examples
{
AI95-00224-01}
Examples of suppressing and unsuppressing checks:
{
AI95-00224-01}
pragma Suppress(Index_Check);
pragma Unsuppress(Overflow_Check);
Extensions to Ada 83
Additional check names are added. We allow implementations
to define their own checks.
Wording Changes from Ada 83
We define the checks in a distributed manner.
Therefore, the long list of what checks apply to what is merely a NOTE.
We have removed the detailed rules about what
is allowed in a
pragma
Suppress, and allow implementations to invent their own. The RM83 rules
weren't quite right, and such a change is necessary anyway in the presence
of implementation-defined checks.
We make it clear that the difference between
a Range_Check and an Overflow_Check is fuzzy. This was true in Ada 83,
given RM83-11.6, but it was not clear. We considered removing Overflow_Check
from the language or making it obsolescent, just as we did for Numeric_Error.
However, we kept it for upward compatibility, and because it may be useful
on machines where range checking costs more than overflow checking, but
overflow checking still costs something. Different compilers will suppress
different checks when asked to suppress Overflow_Check — the nonuniformity
in this case is not harmful, and removing it would have a serious impact
on optimizers.
Extensions to Ada 95
Wording Changes from Ada 95
{
8652/0036}
{
AI95-00176-01}
{
AI95-00224-01}
The description of Access_Check was corrected by the Corrigendum to include
the discriminant case. This change was then replaced by the more general
notion of checking conversions to subtypes that exclude null in Ada 2005.
{
AI95-00224-01}
The On parameter of pragma Suppress was moved to Annex J (see
J.10).
This feature's effect is inherently nonportable, depending on the implementation's
model of computation. Compiler surveys demonstrated this, showing that
implementations vary widely in the interpretation of these parameters,
even on the same target. While this is relatively harmless for Suppress
(which is never required to do anything), it would be a significant problem
for Unsuppress (we want the checks to be made for all implementations).
By moving it, we avoid needing to define the meaning of Unsuppress with
an On parameter.
{
AI95-00280-01}
The order of the Program_Error checks was corrected to be alphabetical.
Wording Changes from Ada 2005
{
AI05-0290-1}
{
AI12-0005-1}
The effect of a checking pragma no longer applies inside an inlined subprogram
body. While this could change the behavior of a program that depends
on a check being suppressed in an inlined body, such a program is erroneous
and thus no behavior can be depended upon anyway. It's also likely to
be very rare. We make this change so that inlining has no effect on the
meaning of the subprogram body (since inlining is never required, this
is necessary in order to be able to reason about the body), and so that
assertion policies and suppress work the same way for inlining.
Extensions to Ada 2012
{
AI12-0309-1}
Program_Error_Check and Tasking_Check are new; all core language-defined
checks are now covered with check names.
Wording Changes from Ada 2012
{
AI12-0244-1}
Correction: Range_Check is defined to include checks associated
with the Value and related attributes.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe