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:

-fcontracts

Enables 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_violation and 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 program

  • enforce - Contract assertions are evaluated and violations terminate the program

  • quick_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_enforce sets standard library contracts to quick_enforce mode, while -fcontract-group-evaluation-semantic=mylib=observe sets 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();
}

Indices and tables