Using Clang Contracts¶
This document specifies how to use C++ Contracts in Clang, including how to install the compiler and enable contract checking.
See https://godbolt.org/z/azdnqxn87 for a live example.
Getting Started¶
For instructions on installing clang contracts or building from source please seethe Building and Installing section.
Required Flags¶
The following flags are required to enable contract checking in Clang:
-fcontractsEnables C++ contracts support. This flag must be specified to compile code that uses contracts syntax (
pre,post,contract_assert). Without this flag, contract declarations will result in compilation errors.-stdlib=libc++Use the libc++ standard library implementation. This is required when using contracts because the contracts implementation is integrated with libc++. The standard library components like
std::contracts::contract_violationand violation handler functions are provided by libc++.-fcontract-evaluation-semantic=<value>Controls how contracts are evaluated. Valid values are:
ignore- Contract assertions are not evaluated (contracts are disabled)observe- Contract assertions are evaluated but violations do not terminate the programenforce- Contract assertions are evaluated and violations terminate the programquick_enforce- Like enforce, but uses optimized evaluation that may skip some checks
Optional Flags¶
The following flags control additional aspects of contract checking:
-fcontract-group-evaluation-semantic=<group>=<semantic>Allows fine-grained control over contract evaluation for specific groups. For example:
-fcontract-group-evaluation-semantic=std=quick_enforcesets standard library contracts to quick_enforce mode, while-fcontract-group-evaluation-semantic=mylib=observesets custom “mylib” group contracts to observe mode.
See the Contract Groups section for more details.
Examples¶
// Use -std=c++23 -fcontracts -stdlib=libc++
//
// Change the evaluation semantic using
// -fcontract-evaluation-semantic=<ignore|observe|enforce|quick_enforce>
//
// Change evaluation in the standard library using:
// -fcontract-group-evaluation-semantic=std=<...>@
//
#include <string_view>
#include <iostream>
#include <contracts>
int f(const int x)
pre(x != 0)
post(r : r != x) {
return x + 1;
}
void try_contract_groups() {
// Turn on all "mylib" assertions using.
// -fcontract-group-evaluation-semantic=mylib=enforce
// Disable the debug group with
// -fcontract-group-evaluation-semantic=mylib=enforce,mylib.debug=ignore
// Or change "mylib.other" to quick_enforce with
// -fcontract-group-evaluation-semantic=mylib.hardening=quick_enforce
//
// Currently the flag is -fcontract-group-evaluation-semantic=mylib=observe
contract_assert [[clang::contract_group("mylib")]] (true);
contract_assert [[clang::contract_group("mylib.debug")]] (false && "mylib.debug");
contract_assert [[clang::contract_group("mylib.other")]] (false && "mylib.other");
}
void stdlib_using_contracts() {
std::cerr << "stdlib_using_contracts is about to quick_enforce and trap!" << std::endl;
std::string_view sv;
(void)sv.back();
}
// Try overriding the violation handler
void handle_contract_violation(std::contracts::contract_violation const& violation) {
if (violation.semantic() == std::contracts::evaluation_semantic::observe) {
std::cerr << violation.location().function_name() << ":"
<< violation.location().line()
<< ": observing violation my way: "
<< violation.comment()
<< std::endl;
return;
}
std::contracts::invoke_default_contract_violation_handler(violation);
}
int main() {
int r = f(1);
try_contract_groups();
stdlib_using_contracts();
}