6.1.1 Preconditions and Postconditions
For a noninstance subprogram
(including a generic formal subprogram), a generic subprogram, an entry,
or an access-to-subprogram type, the following language-defined assertion
aspects may be specified with an
aspect_specification
(see
13.1.1):
Pre
This aspect specifies a specific precondition for a callable entity or
an access-to-subprogram type; it shall be specified by an
expression,
called a
specific precondition expression.
If not specified for an entity, the specific precondition expression
for the entity is the enumeration literal True.
Pre'Class
This aspect specifies a class-wide precondition for a dispatching operation
of a tagged type and its descendants; it shall be specified by an
expression,
called a
class-wide precondition expression.
If not specified for an entity, then if no other class-wide precondition
applies to the entity, the class-wide precondition expression for the
entity is the enumeration literal True.
Post
This aspect specifies a specific postcondition for a callable entity
or an access-to-subprogram type; it shall be specified by an
expression,
called a
specific postcondition expression.
If not specified for an entity, the specific postcondition expression
for the entity is the enumeration literal True.
Post'Class
This aspect specifies a class-wide postcondition for a dispatching operation
of a tagged type and its descendants; it shall be specified by an
expression,
called a
class-wide postcondition expression.
If not specified for an entity, the class-wide postcondition expression
for the entity is the enumeration literal True.
Name Resolution Rules
The expected type for a precondition or postcondition
expression is any boolean type.
Within the expression for a Pre'Class or Post'Class
aspect for a primitive subprogram
S of a tagged type
T,
a
name that
denotes a formal parameter (or
S'Result) of type
T is interpreted
as though it had a (notional) nonabstract type
NT that is a formal
derived type whose ancestor type is
T, with directly visible primitive
operations. Similarly, a
name
that denotes a formal access parameter (or
S'Result for an access
result) of type access-to-
T is interpreted as having type access-to-
NT.
The result of this interpretation is that the only operations that can
be applied to such
names
are those defined for such a formal derived type.
For an
attribute_reference
with
attribute_designator
Old, if the attribute reference has an expected type (or class of types)
or shall resolve to a given type, the same applies to the
prefix;
otherwise, the
prefix
shall be resolved independently of context.
Legality Rules
The Pre or Post aspect shall not be specified for
an abstract subprogram or a null procedure. Only the Pre'Class and Post'Class
aspects may be specified for such a subprogram.
If a type
T
has an implicitly declared subprogram
P inherited from a parent
type
T1 and a homograph (see
8.3) of
P from a progenitor type
T2, and
the corresponding primitive subprogram P1
of type T1 is neither null nor abstract; and
the class-wide precondition expression True does
not apply to P1 (implicitly or explicitly); and
there is a class-wide precondition expression that
applies to the corresponding primitive subprogram P2 of T2
that does not fully conform to any class-wide precondition expression
that applies to P1,
then:
If the type T is abstract, the implicitly
declared subprogram P is abstract.
Otherwise, the subprogram
P requires
overriding and shall be overridden with a nonabstract subprogram.
If a renaming of a subprogram or entry S1
overrides an inherited subprogram S2, then the overriding is illegal
unless each class-wide precondition expression that applies to S1
fully conforms to some class-wide precondition expression that applies
to S2 and each class-wide precondition expression that applies
to S2 fully conforms to some class-wide precondition expression
that applies to S1.
Pre'Class shall not be specified for an overriding
primitive subprogram of a tagged type T unless the Pre'Class aspect
is specified for the corresponding primitive subprogram of some ancestor
of T.
In addition to the places where
Legality Rules normally apply (see
12.3),
these rules also apply in the private part of an instance of a generic
unit.
Static Semantics
If a Pre'Class or Post'Class aspect is specified
for a primitive subprogram
S of a tagged type
T, or such
an aspect defaults to True, then a corresponding expression also applies
to the corresponding primitive subprogram
S of each descendant
of
T (including
T itself). The
corresponding expression
is constructed from the associated expression as follows:
References to formal parameters of S (or
to S itself) are replaced with references to the corresponding
formal parameters of the corresponding inherited or overriding subprogram
S (or to the corresponding subprogram S itself).
If the primitive subprogram
S is not abstract,
but the given descendant of
T is abstract, then a nondispatching
call on
S is illegal if any Pre'Class or Post'Class aspect that
applies to
S is other than a static boolean expression. Similarly,
a primitive subprogram of an abstract type
T, to which a non-static
Pre'Class or Post'Class aspect applies, shall neither be the prefix of
an Access attribute_reference, nor shall it be a generic actual subprogram
for a formal subprogram declared by a
formal_concrete_subprogram_declaration.
If performing checks is required by the Pre, Pre'Class,
Post, or Post'Class assertion policies (see
11.4.2)
in effect at the point of a corresponding aspect specification applicable
to a given subprogram, entry, or access-to-subprogram type, then the
respective precondition or postcondition expressions are considered
enabled.
A subexpression of
a postcondition expression is
known on entry if it is any of:
a static subexpression (see
4.9);
a literal whose type does not have any Integer_Literal,
Real_Literal, or String_Literal aspect specified, or the function specified
by such an attribute has aspect Global specified to be null;
a name statically denoting a full constant declaration
which is known to have no variable views (see
3.3);
a name statically denoting a nonaliased in
parameter of an elementary type;
an invocation of a predefined operator where all
of the operands are known on entry;
a function call where the function has aspect Global
=> null where all of the actual parameters are known on entry;
A subexpression of a postcondition expression
is
unconditionally evaluated,
conditionally
evaluated, or
repeatedly evaluated. A subexpression is considered
unconditionally evaluated unless it is conditionally evaluated or repeatedly
evaluated.
The following subexpressions
are repeatedly evaluated:
For a subexpression
that is conditionally evaluated, there is a set of
determining expressions
that determine whether the subexpression is actually evaluated at run
time. Subexpressions that are conditionally evaluated
and their determining expressions are as follows:
For an
if_expression
that is not repeatedly evaluated, a subexpression of any part other than
the first condition is conditionally evaluated, and its determining expressions
include all
conditions
of the
if_expression
that precede the subexpression textually;
For a short-circuit control form that is not repeatedly
evaluated, a subexpression of the right-hand operand is conditionally
evaluated, and its determining expressions include the left-hand operand
of the short-circuit control form;
For a membership test that is not repeatedly evaluated,
a subexpression of a
membership_choice
other than the first is conditionally evaluated, and its determining
expressions include the
tested_simple_expression
and the preceding
membership_choices
of the membership test.
A conditionally evaluated subexpression is
determined
to be unevaluated at run time if its set of determining expressions
are all known on entry, and when evaluated on entry their values are
such that the given subexpression is not evaluated.
For a
prefix
X that denotes an object of a nonlimited type, the following attribute
is defined:
X'Old
Each X'Old in a postcondition
expression that is enabled, other than those that occur in subexpressions
that are determined to be unevaluated, denotes a constant that is implicitly
declared at the beginning of the subprogram body, entry body, or accept
statement.
The implicitly
declared entity denoted by each occurrence of X'Old is declared as follows:
X'Old : constant A := X;
If X is
of a specific tagged type T then
anonymous : constant T'Class := T'Class(X);
X'Old : T renames T(anonymous);
where the name X'Old denotes
the object renaming.
Otherwise
X'Old : constant S := X;
where S is the nominal
subtype of X. This includes the case where the type of S is an
anonymous array type or a universal type.
The type and nominal subtype of X'Old are
as implied by the above definitions.
Reference to this attribute is only allowed
within a postcondition expression. The
prefix
of an Old
attribute_reference
shall not contain a Result
attribute_reference,
nor an Old
attribute_reference,
nor a use of an entity declared within the postcondition expression but
not within
prefix
itself (for example, the loop parameter of an enclosing
quantified_expression).
The
prefix
of an Old
attribute_reference
shall statically name (see
4.9) an entity,
unless the
attribute_reference
is unconditionally evaluated, or is conditionally evaluated where all
of the determining expressions are known on entry.
For a
prefix
F that denotes a function declaration or an access-to-function type,
the following attribute is defined:
F'Result
Within a postcondition expression
for F, denotes the return object of the function call for which the postcondition
expression is evaluated. The type of this attribute is that of the result
subtype of the function or access-to-function type except within a Post'Class
postcondition expression for a function with a controlling result or
with a controlling access result; in those cases the type of the attribute
is described above as part of the Name Resolution Rules for Post'Class.
Use of this attribute is allowed only within
a postcondition expression for F.
For a
prefix
E that denotes an entry declaration of an entry family (see
9.5.2),
the following attribute is defined:
E'Index
Within a precondition or postcondition
expression for entry family E, denotes the value of the entry index for
the call of E. The nominal subtype of this attribute is the entry index
subtype.
Use of this attribute is allowed only within
a precondition or postcondition expression for E.
Dynamic Semantics
Upon a call of the
subprogram or entry, after evaluating any actual parameters, precondition
checks are performed as follows:
The specific precondition check begins with the
evaluation of the specific precondition expression that applies to the
subprogram or entry, if it is enabled; if the expression evaluates to
False, Assertions.Assertion_Error is raised; if the expression is not
enabled, the check succeeds.
The class-wide precondition check begins with the
evaluation of any enabled class-wide precondition expressions that apply
to the subprogram or entry. If and only if all the class-wide precondition
expressions evaluate to False, Assertions.Assertion_Error is raised.
The precondition checks are performed in an arbitrary
order, and if any of the class-wide precondition expressions evaluate
to True, it is not specified whether the other class-wide precondition
expressions are evaluated. The precondition checks and any check for
elaboration of the subprogram body are performed in an arbitrary order.
In a call on a protected operation, the checks are performed before starting
the protected action. For an entry call, the checks are performed prior
to checking whether the entry is open.
Upon successful return from a call of the subprogram
or entry, prior to copying back any by-copy
in out or
out
parameters, the postcondition check is performed. This consists of the
evaluation of any enabled specific and class-wide postcondition expressions
that apply to the subprogram or entry. If any of the postcondition expressions
evaluate to False, then Assertions.Assertion_Error is raised. The postcondition
expressions are evaluated in an arbitrary order, and if any postcondition
expression evaluates to False, it is not specified whether any other
postcondition expressions are evaluated. The postcondition check, and
any constraint or predicate checks associated with
in out or
out
parameters are performed in an arbitrary order.
For a call to a task entry, the postcondition check
is performed before the end of the rendezvous; for a call to a protected
operation, the postcondition check is performed before the end of the
protected action of the call. The postcondition check for any call is
performed before the finalization of any implicitly-declared constants
associated (as described above) with Old
attribute_references
but after the finalization of any other entities whose accessibility
level is that of the execution of the callable construct.
If a precondition or postcondition check fails, the
exception is raised at the point of the call; the exception cannot be
handled inside the called subprogram or entry. Similarly, any exception
raised by the evaluation of a precondition or postcondition expression
is raised at the point of call.
For any call to a subprogram or entry S (including
dispatching calls), the checks that are performed to verify specific
precondition expressions and specific and class-wide postcondition expressions
are determined by those for the subprogram or entry actually invoked.
Note that the class-wide postcondition expressions verified by the postcondition
check that is part of a call on a primitive subprogram of type T
includes all class-wide postcondition expressions originating in any
progenitor of T, even if the primitive subprogram called is inherited
from a type T1 and some of the postcondition expressions do not
apply to the corresponding primitive subprogram of T1. Any operations
within a class-wide postcondition expression that were resolved as primitive
operations of the (notional) formal derived type NT, are in the
evaluation of the postcondition bound to the corresponding operations
of the type identified by the controlling tag of the call on S.
This applies to both dispatching and non-dispatching calls on S.
The class-wide precondition check for a call to a
subprogram or entry S consists solely of checking the class-wide
precondition expressions that apply to the denoted callable entity (not
necessarily to the one that is invoked). Any operations within such an
expression that were resolved as primitive operations of the (notional)
formal derived type NT are in the evaluation of the precondition
bound to the corresponding operations of the type identified by the controlling
tag of the call on S. This applies to both dispatching and non-dispatching
calls on S.
For the purposes of the above rules, a call on an
inherited subprogram is considered to involve a call on a subprogram
S' whose body consists only of a call (with appropriate conversions)
on the non-inherited subprogram S from which the inherited subprogram
was derived. It is not specified whether class-wide precondition or postcondition
expressions that are equivalent (with respect to which non-inherited
function bodies are executed) for S and S' are evaluated
once or twice. If evaluated only once, the value returned is used for
both associated checks.
For a call via an access-to-subprogram value, precondition
and postcondition checks performed are as determined by the subprogram
or entry denoted by the prefix of the Access attribute reference that
produced the value. In addition, a precondition check of any precondition
expression associated with the access-to-subprogram type is performed.
Similarly, a postcondition check of any postcondition expression associated
with the access-to-subprogram type is performed.
For a call on a generic formal subprogram, precondition
and postcondition checks performed are as determined by the subprogram
or entry denoted by the actual subprogram, along with any specific precondition
and specific postcondition of the formal subprogram itself.
Implementation Permissions
An implementation may evaluate a known-on-entry subexpression
of a postcondition expression of an entity at the place where X'Old constants
are created for the entity, with the normal evaluation of the postcondition
expression, or both.
NOTE 1 A precondition is checked
just before the call. If another task can change any value that the precondition
expression depends on, the precondition can evaluate to False within
the subprogram or entry body.
NOTE 2 For an example of the use
of these aspects and attributes, see the Streams Subsystem definitions
in
13.13.1.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe