[basic.contract] (original) (raw)
6.10.1 General [basic.contract.general]
Contract assertionsallow the programmer to specify properties of the state of the program that are expected to hold at certain points during execution.
Each contract assertion has a contract-assertion predicate, which is an expression of type bool.
[Note 1:
The value of the predicate is used to identify program states that are expected.
— _end note_]
An invocation of the macro va_start ([cstdarg.syn]) shall not be a subexpression of the predicate of a contract assertion, no diagnostic required.
6.10.2 Evaluation [basic.contract.eval]
An evaluation of a contract assertion uses one of the following four evaluation semantics:ignore,observe,enforce, orquick-enforce.
Observe, enforce, and quick-enforce are checking semantics; enforce and quick-enforce are terminating semantics.
It isimplementation-defined which evaluation semantic is used for any given evaluation of a contract assertion.
[Note 1:
The range and flexibility of available choices of evaluation semantics depends on the implementation and need not allow all four evaluation semantics as possibilities.
The evaluation semantics can differ for different evaluations of the same contract assertion, including evaluations during constant evaluation.
— _end note_]
Recommended practice: An implementation should provide the option to translate a program such that all evaluations of contract assertions use the ignore semantic as well as the option to translate a program such that all evaluations of contract assertions use the enforce semantic.
By default, evaluations of contract assertions should use the enforce semantic.
The evaluation of a contract assertion using the ignore semantic has no effect.
[Note 2:
The predicate is potentially evaluated ([basic.def.odr]), but not evaluated.
— _end note_]
The evaluation A of a contract assertion using a checking semantic determines the value of the predicate.
It is unspecified whether the predicate is evaluated.
Let B be the value that would result from evaluating the predicate.
[Note 3:
To determine whether a predicate would evaluate to true or false, an alternative evaluation that produces the same value as the predicate but has no side effects can occur.
[Example 1: struct S { mutable int g = 5;} s;void f() pre(( s.g++, false )); void g() { f(); } — _end example_]
— _end note_]
There is an observable checkpoint ([intro.abstract]) Cthat happens before Asuch that any other operation Othat happens before Aalso happens before C.
A contract violation occurs when
- B is false,
- the evaluation of the predicate exits via an exception, or
- the evaluation of the predicate is performed in a context that is manifestly constant-evaluated ([expr.const]) and the predicate is not a core constant expression.
[Note 4:
If B is true, no contract violation occurs and control flow continues normally after the point of evaluation of the contract assertion.
The evaluation of the predicate can fail to produce a value without causing a contract violation, for example, by calling longjmp ([csetjmp.syn]) or terminating the program.
— _end note_]
If a contract violation occurs in a context that is manifestly constant-evaluated ([expr.const]), and the evaluation semantic is a terminating semantic, the program is ill-formed.
[Note 5:
A diagnostic is produced if the evaluation semantic is observe ([intro.compliance]).
— _end note_]
[Note 6:
Different evaluation semantics chosen for the same contract assertion in different translation units can result in violations of the one-definition rule ([basic.def.odr]) when a contract assertion has side effects that alter the value produced by a constant expression.
[Example 2: constexpr int f(int i) { contract_assert((++const_cast<int&>(i), true));return i;} inline void g() { int a[f(1)]; } — _end example_]
— _end note_]
When the program is contract-terminated, it isimplementation-defined (depending on context) whether
- std::terminate is called,
- std::abort is called, or
- execution is terminated.
[Note 8:
Performing the actions ofstd::terminate or std::abortwithout actually making a library call is a conforming implementation of contract-termination ([intro.abstract]).
— _end note_]
If a contract violation occurs in a context that is not manifestly constant-evaluated and the evaluation semantic is quick-enforce, the program is contract-terminated.
If a contract violation occurs in a context that is not manifestly constant-evaluated and the evaluation semantic is enforce or observe, the contract-violation handler ([basic.contract.handler]) is invoked with an lvalue referring to an object vof type const std::contracts::contract_violation ([support.contract.violation]) containing information about the contract violation.
The lifetime of vpersists for the duration of the invocation of the contract-violation handler.
If the contract violation occurred because the evaluation of the predicate exited via an exception, the contract-violation handler is invoked from within an active implicit handler for that exception ([except.handle]).
If the contract-violation handler returns normally and the evaluation semantic is observe, that implicit handler is no longer considered active.
[Note 9:
The exception can be inspected or rethrown within the contract-violation handler.
— _end note_]
If the contract-violation handler returns normally and the evaluation semantic is enforce, the program is contract-terminated; if violation occurred as the result of an uncaught exception from the evaluation of the predicate, the implicit handler remains active when contract termination occurs.
[Note 10:
If the contract-violation handler returns normally and the evaluation semantic is observe, control flow continues normally after the point of evaluation of the contract assertion.
— _end note_]
There is an observable checkpoint ([intro.abstract]) Cthat happens after the contract-violation handler returns normally such that any other operation Othat happens after the contract-violation handler returns also happens after C.
[Note 11:
The terminating semantics terminate the program if execution would otherwise continue normally past a contract violation: the enforce semantic provides the opportunity to log information about the contract violation before terminating the program or to throw an exception to avoid termination, and the quick-enforce semantic is intended to terminate the program as soon as possible as well as to minimize the impact of contract checks on the generated code size.
Conversely, the observe semantic provides the opportunity to log information about the contract violation without having to terminate the program.
— _end note_]
If a contract-violation handler invoked from the evaluation of a function contract assertion ([dcl.contract.func]) exits via an exception, the behavior is as if the function body exits via that same exception.
[Note 12:
A function-try-block ([except.pre]) is the function body when present and thus does not have an opportunity to catch the exception.
If the function has a non-throwing exception specification, the function std::terminate is invoked ([except.terminate]).
— _end note_]
[Note 13:
If a contract-violation handler invoked from an assertion-statement ([stmt.contract.assert])) exits via an exception, the search for a handler continues from the execution of that statement.
— _end note_]
To evaluate in sequence a list R of contract assertions:
- Construct a list of contract assertions S such that
- all elements of R are in S,
- each element of Rmay be repeated animplementation-defined number of times within S, and
- if a contract assertion Aprecedes another contract assertion Bin R, then the first occurrence of Aprecedes the first occurrence of Bin S.
- Evaluate each element of S such that, if a contract assertion Aprecedes a contract assertion Bin S, then the evaluation of Ais sequenced before the evaluation of B.
[Example 3: void f(int i) { contract_assert(i > 0); contract_assert(i < 10); } — _end example_]
Recommended practice: An implementation should provide an option to perform a specified number of repeated evaluations for contract assertions.
By default, no repeated evaluations should be performed.
6.10.3 Contract-violation handler [basic.contract.handler]
The contract-violation handlerof a program is a function named::handle_contract_violation.
The contract-violation handler shall have a single parameter of type “lvalue reference to const std::contracts::contract_violation” and shall return void.
The contract-violation handler may have a non-throwing exception specification.
The implementation shall provide a definition of the contract-violation handler, called the default contract-violation handler.
[Note 1:
No declaration for the default contract-violation handler is provided by any standard library header.
— _end note_]
Recommended practice: The default contract-violation handler should produce diagnostic output that suitably formats the most relevant contents of the std::contracts::contract_violation object, rate-limited for potentially repeated violations of observed contract assertions, and then return normally.
It isimplementation-defined whether the contract-violation handler is replaceable ([dcl.fct.def.replace]).
If the contract-violation handler is not replaceable, a declaration of a replacement function for the contract-violation handler is ill-formed, no diagnostic required.