---
title: Integrating Existing Assertions with Contracts
document: P3290R4
date: 2026-05-02
audience: LEWG
reply-to:
  - "Joshua Berne < <jberne4@bloomberg.net>"
  - "Timur Doumler < <papers@timur.audio>"
  - "John Lakos < <jlakos@gmail.com>"
paper-type: proposal
---

* Revision 4, post-C++26, April 2026

**–** Rebased on C++26 as shipped

**–** Update to be ready to present to LEWG

**–** Wording cleanup and bug fixes

**–** Added feature test macros

* Revision 3, post–Sofia meeting, June 2025

**–** Rebased on draft Standard after adoption of [P2900R14]

**–** Specified use of `source_location::current()` and discussed implementation choices

**–** Made `nothrow_t` parameters first parameters passed by value when used

**–** Discussed implementation experience

**–** Change `detection_mode::manual` to `detection_mode::unspecified`

**–** Addressed handling of `<assert.h>` vs. `<cassert>`

* Revision 2, post September 5, 2024 SG21 telecon

**–** Minor bug fixes and clarifications

**–** Usage examples for library API

* Revision 1, post–St. Louis meeting, July 2024

**–** Added `source_location` overloads to library API

**–** Added control macro for change in behavior of `assert`

**–** Removed proposal for `partial_contract_assert`

* Revision 0, for SG21 Telecon, May 2024

**–** Original version of the paper for discussion during an SG21 telecon

## 1

The C++ Standard now includes a Contracts feature, first introduced in [P2900R14] and shipped in C++26. This facility is exceedingly useful for *incrementally* enhancing safety, security, and correctness in both new and legacy code. Through its previous incarnations and especially within SG21, capturing the ability to express and take advantage of discrete contract checks in the language has been a priority, whereas exactly replicating the preprocessor-derived semantics of the standard `assert` macro and similar bespoke macro-based facilities has not.

One of the central features of the Contracts MVP, however, has nothing to do with the semantics of predicate evaluation and simply addresses what happens when a violation occurs, i.e., the contract-violation handling process. For the *observe* and *enforce* evaluation semantics, this process involves invoking the contract-violation handler. For the *enforce* and *quick-enforce* semantics, the program is terminated in an implementation-defined manner. For all three checked semantics, this violation-handling behavior is quite useful to existing contract-checking facilities as well.

Because many existing assertion facilities will need to remain committed to behaviors and control mechanisms that may never be perfectly replicated by the core-language Contracts facility, this paper proposes two independent additions that allow for effective integration of any such alternate tools with Contracts.

1. **Directly** **calling** **the** **contract-violation** **handler:** Provide a mechanism to integrate existing contract-checking facilities with the central contract-violation handling mechanism of C++.

2. **Conditionally** **integrating** `assert` **with** **Contracts:** Augment the specification for the standard `assert` macro to conditionally support invoking the (nonthrowing) C++ contractviolation handler (instead of outputting a message to the standard error stream) before aborting; this semantic would be similar to the *enforce* semantic.

Each of these individual proposals adds distinct value and is aimed at providing immediate support for easily allowing existing code to use the new C++ Contracts facility. With the adoption of one or both of these independent proposals, we hope to improve the use of Contracts in C++29, addressing many of the concerns that were raised in the C++26 cycle due to Contracts not providing an exact drop-in replacement for the `assert` macro.

Earlier versions of this paper were seen by SG21 and EWG, in both cases forwarding on these proposals to later groups:

SG21, Teleconference, 2024-09-05

Forward Proposals 1.1-1.3 of D3290R2 as presented, as a separate proposal on top of P2900, to EWG and LEWG for design review. SF F N A SA 8 3 1 0 0

Result: Consensus

SG21, Teleconference, 2024-09-05

Forward Proposal 2 of D3290R2, with the polarity of NDEBUG switched and the suggested improvements in phrasing applied, as a separate proposal on top of P2900, to EWG and LEWG for design review. SF F N A SA 5 7 0 0 0

Result: Consensus

EWG, Sofia, 2025-06-18

EWG approves the design of this paper and forwards this to LEWG and wants SG22 (C/C++ liaison group) to see the paper. SF F N A SA 4 17 6 5 1

Result: Consensus

After the last poll in EWG, the majority of those against confirmed that implementation experience was the only concern. Implementations have been performed in both libc++ and libstdc++, although they have not yet been updated and upstreamed as the updates to the shared Itanium ABI that those implementations will call into are still in progress.

## 2

In this section, we provide two independent, mutually compatible proposals that provide support for immediately allowing existing contract-checking facilities to integrate with C++ Contracts in a variety of ways. Our goal in each case is to provide exactly what users of legacy assertion facilities need.

All names are merely initial suggestions, with proposed reasoning and are highly likely to be changed during the standardization process.

### 2.1

One of the primary purposes of adopting a Contracts facility into the Standard in lieu of continuing to use bespoke solutions is to centralize the management, response, and mitigation approach to detected bugs in large-scale software. By having a central and user-selectable contract-violation handler, those who assemble large programs can avoid having distinct libraries producing different bug responses that do not fit into a single and consistent diagnostic and mitigation strategy.

All uses of `pre`, `post`, and `contract_assert` will, when a contract violation is detected by evaluation with the *enforce* or *observe* semantic, invoke the same contract-violation handler regardless of where in the program the violated contract assertion might be. This centralized reporting facility is one of the core benefits of having a Contracts facility in the language itself. With the C++ Contracts facility, users of legacy contract-checking facilities do not (yet) have a mechanism to integrate with that same reporting mechanism.

We propose to address the current inability to integrate the contract-violation handler with legacy assertion mechanisms by providing a library API to replicate the behaviors of the various contractevaluation semantics when a contract violation has been detected. These utility functions then provide a direct mechanism to invoke the contract-violation handler as well as to terminate execution in a fashion that matches the termination behavior of a contract-assertion evaluation having the *enforce* or *quick-enforce* semantic. Several design considerations have been identified during the process of developing what we propose.

<!-- tomd:uncertain:L106-L160 -->

• Each distinct checked semantic has, associated with it, different behaviors related to how
violations are handled. A contract assertion evaluated with the observe semantic will continue
execution when the contract-violation handler returns; evaluations with the enforce semantic
will instead terminate the program in an implementation-defined fashion; and evaluations with
the quick-enforce semantic do not call the contract-violation handler and have a potentially
distinct mechanism for terminating the program but might also record data about the violation
in debug information that is not accessible at run time. To that end, we propose that the
name of each semantic be embedded in the function name so that these properties can be
annotated on the function when possible.

• A mechanism need not trigger the handling of a contract violation the way an evaluation with
the ignore semantic would since that semantic never identifies contract violations and has no
runtime behavior to emulate.

• A more targeted function that simply took all the properties of a contract_violation object,
populated one, and invoked the contract-violation handler but did nothing else would have a
more fundamental problem: The contract-violation handler would be unable to depend on any
promises inherent in the values provided, such as a guarantee that the program will terminate
if the violation handler returns when the evaluation semantic on the contract_violation object is

enforce.

• Perhaps a feasible approach would be to pass to a more general function a semantic as
a value of type std::contracts::evaluation_semantic, but that approach would bring along the
need to answer the complex question of how it should behave when given unknown or
implementation-defined values for the semantic. For the same reason, we carefully crafted

std::contracts::contract_violation so that it cannot be created by users, which would allow users
to pass an arbitrary such object to ::handle_contract_violation. It’s certainly likely that most
implementations will have such a general function underlying those proposed here, but we do
not want to prematurely restrict implementation options by designing and demanding that
general facility.

• Another suggestion that has been made is to introduce a function template with one nontype
template parameter that is a value of type std::contracts::evaluation_semantic. This option seems
to increase complexity while bringing only the slight benefit of not needing new names when
new semantics are introduced. Because the properties (such as being [[noreturn]]) of each
semantic-specific overload set can be fundamentally different, this approach of a single function
template seems a likely source of confusion. New standard semantics are expected to happen
only infrequently, so the cost of one new library function in a rarely used namespace seems
like a small concern.

• A different function we might propose would use the same semantic as is configured for other
contract assertions, but that value is not a well-defined one. While compiling a translation
unit such that all contract assertions within it will be evaluated with the same semantic is
possible, the expectation that all code will be compiled in such a way is mistaken, and we
do not want to build features that would work correctly only when programs are built that
way. The flexibility of that choice of semantic is, in large part, a source of problems when
migrating from older facilities directly to contract assertions. Such a utility function would also
be confusing when integrated with an existing assertion facility because it would result in two
layers of configuration — i.e., the existing macro-based controls and the controls that impact
all other contract assertions — determining the resulting semantic of older macros. Rather
than provide yet another point where implementation-defined controls can alter program
behaviors, we are focusing instead on providing a more concrete building block to use as a
foundation for existing facilities.

* Two recommended practices for contract-semantic configuration are put forth in C++. Providing
a function that ties into builds where these recommended practices are in play, however, might
be possible.
**–** Those recommended practices are just a minimum for what we expect, and any richer or
nonglobal configuration of Contracts does not fit into that model.
**–** If the global configuration is to *ignore* all contract assertions, then by the time an assertion
from an existing facility has decided to invoke the handler, that assertion’s evaluation
has also already decided to forgo *ignoring* the assertion since the predicate in question
has already been evaluated.
**–** The only other recommended practice is to *enforce*, and for that we are providing explicit
functions to execute the behavior of the *enforce* semantic.

* Converting a predicate expression to a comment field in the `contract_violation` object can be
easily accomplished using the stringizing operator `#`, and often an expression is not even apt
for capturing the form of violation that is being manually detected; hence, we propose that
the comment be provided via a `const` `char*` function parameter.
Just as is expected by the violation handler, this should be a null-terminated multibyte string
in the ordinary literal encoding.
Because it is helpful to have these functions maintain a wide contract — reducing the chance
of new bugs creeping in during the handling of a violation — a `nullptr` for `comment` should be
interpreted as an empty string (although an implementation is free to provide a comment
indicating the particular library function that was used to trigger the contract-violation
handling process).

* We could consider limiting the use of these functions to compile-time strings using the
same functionality that is leveraged by `std::format`. While this option might lead to improved
implementation behavior, it might also limit usability with some legacy assertion facilities that
produce an error message with more detailed information. Nothing precludes an implementation
from providing different overloads that behave better when offered a compile-time string instead
of a runtime one.

* To produce a `contract_violation` object, a `std::source_location` must be populated, which can occur
in two distinct ways.
1. When
not
provided,
the
defaulted
`source_location`
parameter
is
initialized
to
`std::source_location::current()`, producing the location where the function is invoked. Because
 this is a Standard Library function and thus the exact signature of the function
is not guaranteed it is possible for an implementation to provide an overload with no
defaulted parameter and instead acquire the source location of the caller in some other,
implementation-defined manner. Such overloads would also be appropriate on platforms
designed to strip out all identifying information from generated binaries.

2. It is also possible to provide the `source_location` parameter explicitly. This parameter will be recommended for use in the `contract_violation` object that will be passed to the contract-violation handler.1

* The enumerated `kind` and `detection_mode` values could be passed as arguments to our new
functions, but doing so would greatly increase the number of overloads we would need to
provide for each checked semantic that might invoke the handler and, therefore, increases the
complexity of using this otherwise fairly straightforward facility. Hence, we instead suggest,
for these enumerations, new values that simply capture that a manually detected contract
violation was encountered.
Introducing parameters of these types would also require that we answer the question of what
happens if an invalid enumeration value is passed to these functions. Overloads avoid having
to decide if we narrow the contract to preclude such cases or expect violation handlers to
support arbitrary values from any source.

The names presented for all of these functions have been selected to be clear, distinct, and to capture the meaning of their intended behaviors. Putting all these considerations together, we suggest the following initial minimal proposal for an API. 1SG21, when discussing this proposal, expressed a desire to provide a source location from the caller since the use of this API might be embedded in a legacy contract-checking facility’s own violation handler and thus might be far from the location of the assertion itself. SG21, St. Louis, 2024-06-27 Amend [P3290R0] Proposals 1.1–1.3 to support an optional additional function argument that is a `std::source_location`. SF F N A SA 2 11 5 0 0 Result: Consensus

Proposal 1.1: Triggering *Enforce* and *Observe* Semantics

Add the following to the header `<contracts>`:

```cpp
namespace std::contracts {
  [[noreturn]] void handle_enforced_contract_violation(
      const char* comment,
      const std::source_location &location = std::source_location::current());
  void handle_observed_contract_violation(
      const char* comment,
      const std::source_location &location = std::source_location::current());
}
```

Each of these functions will perform similarly but has unique behavior.

* Create and populate an object of type `std::contract_violation`.
**–** The `comment` property is recommended to be the value provided as a function
argument if not `nullptr`; Otherwise, a textual representation of the invoked overload
is the recommended value.
**–** The `location` property is recommended to be the `location` parameter if one is specified.
 Otherwise, the recommended value is the location where the `handle` function
was invoked. As usual, these are recommended practices, and a conforming implementation
 might strip out some or all information that would be used to populate
the `location` property of the `contract_violation` object.
**–** The `kind` property will be a new value, `manual`, of the `std::contracts::assertion_kind`
enumeration.
**–** The
`detection_mode` property will be a newly added value,
`unspecified`, of the
`std::contracts::detection_mode` enumeration.
**–** The `evaluation_semantic` property will be the semantic value that matches the particular
 function being invoked.

* The installed contract-violation handler will be invoked with this generated
`contract_violation` object.

* If the contract-violation handler returns normally within `handle_enforced_contract_violation`,
the program will be terminated in an implementation-defined manner.

* If the contract-violation handler returns normally within `handle_observed_contract_violation`,
this function returns normally.

* If an exception escapes from the contract-violation handler, it propagates normally.

The above proposal covers all semantics that invoke the contract-violation handler, which is the primary purpose of this proposal.

The most recently added semantic, however, does have some functionality that is not easily reproduced elsewhere. As a second proposal, we propose a third overload set that has the semantics of handling a contract violation for a contract-assertion evaluation having the *quick-enforce* semantic, introduced in [P3191R0].

Proposal 1.2: Triggering *Quick-Enforce* Violations

Add the following to the header `<contracts>`:

```cpp
[[noreturn]] void handle_quick_enforced_contract_violation(
    const char* comment,
    const std::source_location& location
        = std::source_location::current()) noexcept;
```

* Terminate the program in an implementation-defined manner.

In addition to the specified runtime behavior, just as with a contract evaluated with the *quick-enforce* semantic, we can gain non-normative benefits from invoking the above function. If `comment` is a compiletime string, it may be embedded in debug information in a manner outside the purview of the abstract machine and the Standard itself but still provide useful information when applying some forms of diagnostic tools.

As a separate proposal on top of the above, we also suggest having `noexcept` overloads of the functions that might invoke the contract-violation handler.

This behavior can be achieved in (at least) other ways that come with associated drawbacks.

1. Invocations of the `handle` functions can be placed inside `try`/`catch` blocks that then manually invoke `std::terminate()`:

```cpp
try {
  handle_enforced_contract_violation(comment);
} catch (...) {
  std::terminate();
}
```

This approach achieves the goal of not allowing an exception to escape but at the cost of potentially significantly greater code-size overhead compared to a `noexcept` function that needs only to mark a stack frame as being a `noexcept` boundary. When a codebase has enough assertions, this overhead has shown to be a concern for some developers.

2. The `handle` function can be wrapped in a user-provided `noexcept` function:

```cpp
[[noreturn]] void my_handle_enforced_contract_violation(
    const char* comment) noexcept
{
  std::contracts::handle_enforced_contract_violation(comment);
}
```

This approach will potentially have improved code generation but at the cost of the call location of the `handle` function always being within the same wrapper function, thereby losing valuable information that was intended to be conveyed to the contract-violation handler.

3. The same wrapping approach can be taken while forwarding a `source_location` value that is defaulted at the call site of the wrapper:

```cpp
[[noreturn]] void my_handle_enforced_contract_violation(
    const char* comment,
    const std::source_location& location
        = std::source_location::current()) noexcept
{
  std::contracts::handle_enforced_contract_violation(comment, location);
}
```

This forwards the caller’s source location, but also makes it much harder for a platform that wants to strip out uses of source location to do so, as the `source_location` is now baked in as part of a user-provided API that is not easily optimized away.

Therefore, we propose adding overloads to the proposed API that take an additional argument of type `std::nothrow_t` passed by value, similarly to how that type is used for nonthrowing operator `new`. Because the ordering of this parameter should not change with respect to a source location when provided, we make it the first parameter (similarly to how tag types are used through the rest of the standard library, although not how `nothrow_t` is used currently with `operator` `new` and `operator` `delete`). Because it is an empty and trivial type, we pass it by value to avoid needing to resolve a pointer to a static instance of this type (`std::nothrow`) whenever these functions are invoked.

Proposal 1.3: `noexcept` Overloads

Add the following to the header `<contracts>`:

```cpp
namespace std::contracts {
  [[noreturn]] void handle_enforced_contract_violation(
      std::nothrow_t,
      const char* comment,
      const std::source_location& location
          = std::source_location::current()) noexcept;
  void handle_observed_contract_violation(
      std::nothrow_t,
      const char* comment,
      const std::source_location& location
          = std::source_location::current()) noexcept;
}
```

If an exception escapes the invocation of the contract-violation handler made by these functions, `std::terminate` will be invoked. Otherwise, these functions behave identically to the corresponding overloads without the `std::nothrow_t` parameter.

No overload that takes a `std::nothrow_t` is necessary for `handle_quick_enforced_contract_violation` since, in this case, no invocation of a contract-violation handler could exit via an exception (and the function itself is already marked `noexcept`).

Should a new checking semantic be added to the Standard in the future, we would need to add, in a similar fashion, corresponding functions to manually trigger that semantic’s behavior upon detecting a contract violation. Given that any new semantic potentially has a distinct interface, each is equally likely to result in a new function or set of functions to parallel those we propose here.

Finally, there seems to be no compelling reason to implement the above library additions incrementally, so a single feature test macro suffices to indicate that the whole suite of free functions is available:

Proposal 2: Feature test macro for library API

The feature test macro `__cpp_lib_contracts_api` will have a value of `yyyymmL` if the free functions proposed above are available. This macro will be defined by both `<version>` and `<contracts>`.

Using this API within an assertion macro provided by an existing contract-checking facility is fairly straightforward. Consider a simple facility that should be enforced when `ENFORCE_MY_ASSERTIONS` is defined and otherwise compiled out:

```cpp
#ifndef ENFORCE_MY_ASSERTIONS
  #define MY_ASSERT(X) ((void)sizeof((~X))?true:false)
#elif __cpp_lib_contracts < 20260101
  #define MY_ASSERT(X)
                                                                          \
    if (!(X)) {
                                                                          \
      ::MyLib::invokeViolationHandler(#X,__FILE__,__LINE__);
                                                                          \
    }
#else
  #define MY_ASSERT(X)
                                                                          \
    if (!(X)) {
                                                                          \
      std::contracts::handle_enforced_contract_violation(std::nothrow,#X);\
    }
#endif
```

In another case, a facility might already be using `std::source_location` and determining runtime behavior based on runtime queries to free functions in a `Configuration` namespace, so a macro such as

`MY_ASSERT` above might invoke the following function when a violation is detected:

```cpp
namespace MyLib {
void invokeViolationHandler(
    const char *comment,
    std::source_location location = std::source_location::current()) noexcept
{
#if __cpp_lib_contracts < 20260101
  if (MyLib::Configuration::abortFastOnViolations()) {
    // Immediately abort, do not continue, and do not attempt to log.
    std::abort();
  } else if (MyLib::Configuration::enforceViolations()) {
    // Log a custom message and terminate.
    MyLib::logContractViolation(comment,location);
    std::abort();
  } else {
    // When neither above configuration is selected, we log and continue.
    MyLib::logContractViolation(comment,location);
  }
#else
  if (MyLib::Configuration::abortFastOnViolations()) {
    // Go directly to termination.
    std::contracts::handle_quick_enforced_contract_violation(comment,location);
  } else if (MyLib::Configuration::enforceViolations()) {
    // Hook into the user-defined contract-violation handler, and then terminate.
    std::contracts::handle_enforced_contract_violation(std::nothrow,comment,location);
  } else {
    // When neither above configuration is selected, we log and continue.
    std::contracts::handle_observed_contract_violation(std::nothrow,comment,location);
  }
#endif
}
```

Note that in the above code, we would be ill served by not being able to pass in a `std::source_location` since it would end up always being the location within the function `MyLib::invokeViolationHandler`, not the calling code where the assertion macro is used. Instead, through the magic of `location` being a function parameter with a default argument that is an immediate function, the source location that will be used when the macro expands to `invokeViolationHandler(#X)` will be that of the call site where the macro is expanded.

### 2.2

Direct use of the standard `assert` macro is commonly taught and used widely in industry for a variety of purposes. In our experience, the overwhelming majority of such uses of `assert` involve no side effects whatsoever. The remaining side effects are often just temporary print statements or inadvertent errors, yet some practicable, valuable uses remain.

Requiring an organization to pore over all their legacy uses of `assert` to ensure that no destructive side effects occur before benefiting from a central contract-violation handler provided by C++ seems time-consuming and counterproductive. Therefore it is not feasible to consider redefining `assert` in terms of `contract_assert`.

Even given the ability for user-defined macro-based facilities to integrate with the contract-violation handler, as proposed in the previous section, direct users of the standard `assert` macro still have no similar mechanism, and requiring each organization to write their own assertion facility and then rename each `assert` to that new macro seems needlessly user hostile.

We recommend, as a simple change with vast potential benefit, an addendum to the C++ specification for the `assert` macro, allowing it to invoke the C++ contract-violation handler instead of merely outputting a diagnostic message to the standard error stream. By default, behavior would not change, and users would have to explicitly opt in, thereby making this a fully backward-compatible, *conditionally* *supported* extension. Note that the behavior would be almost equivalent to the twoargument overload of `handle_enforced_contract_violation` (see section 2.1), with the change that `kind` will be a new enumeration value, `cassert`, and the `detection_mode` will be the value `predicate_false`.

As with the current state of the `assert` macro, this behavior when compiling in C++ should be consistent regardless of whether the macro came via including `<cassert>` or `<assert.h>`. This is already the case in existing implementations and the behavior already differs from the C behavior of the macro since the adoption of [P2264R7].

An often cited concern with this integration is that it might enable the `assert` macro to suddenly become the source of an exception, something that legacy code is unlikely to be ready to deal with. Due to that, we do not allow exceptions from the invoked violation handler to escape and instead terminate if the violation handler does throw (effectively calling one of the `nothrow_t` overloads from Proposal **??**).

Just as the basic control of the behavior of `assert` is done through defining or not defining `NDEBUG`, we propose a similar macro that chooses whether `assert` integrates with the violation handler.2

2SG21, when discussing this proposal, expressed a preference for the use of a control macro along the same lines as `NDEBUG` instead of making this choice an implementation-defined behavior.

SG21, St. Louis, 2024-06-27

Amend [P3290R0] Proposal 2 to have a control macro to opt into the assert macro calling the contract-violation handler, rather than making this choice implementation-defined.

SF F N A SA 1 8 4 3 0

Result: Consensus

The name of this control macro is an open question, and many possibilities can be considered.

* In another, similar proposal, [P3311R0], the name `ASSERT_USES_CONTRACTS` was proposed.

* Whatever choice we make, this new macro will sit alongside `NDEBUG` as one of two macros that
control the behavior of the `assert` macro. Neither the authors of this paper nor any of the
people with whom we have discussed this new macro have been able to come up with an
alternative as obtuse as `NDEBUG`, so achieving consistency with `NDEBUG` is a nongoal. An attempt at
something similarly obtuse was proposed in the form of `NASSERT_DOES_NOT_USE_CONTRACTS`, which is
clear due to the large number of words it makes use of, confusing due to the double negative,
and not a spelling that seems overly compelling.

* We could choose a macro name that refers to `assert` as either `ASSERT` or `CASSERT`. Given that we
hope WG14, the C Standard committee, also pursues adopting a compatible contract-checking
facility and integrates it with the same contract-violation handler, we suggest using the
common term `ASSERT` instead of the C++-specific spelling of `CASSERT`.

* The macro name could indicate that it is a C++ specifier by including `CPP`, but fundamentally
this behavior is not C++-specific, and having `CPP` in its name would make it inappropriate as
part of a WG14 proposal.

* The fundamental function of this macro is to change `assert` so that it uses the contractviolation
 handling mechanism of an *enforced* contract assertion. Therefore, we could consider

`ASSERT_IS_ENFORCED` as a name.

* Alternatively,
since
we
are
integrating
`assert`
with
the
contract-violation
handlers,
the
name
could
focus
on
that
action
and
thus
be
something
like

For simplicity, and because it in general is the name with the most support, our preference is to move forward with the name proposed in [P3311R0], `ASSERT_USES_CONTRACTS`.

Note that, just like the `contract_violation` objects populated when a `pre`, `post`, or `contract_assert` detects a violation, some fields in the `contract_violation` object populated by the `assert` macro have recommended values that might, in practice, also be empty, truncated, or populated differently based on how the compiler is configured.

Proposal 3: Integration of `assert` with the Contract-Violation Handler

When `NDEBUG` is not defined and `ASSERT_USES_CONTRACTS` is defined as a macro name at the point in the source file where `<cassert>` or `<assert.h>` is included, the `assert` macro will put into the program a diagnostic test that has the following effects when its evaluation yields `false`.

* The
contract-violation
handler
will
be
invoked
with
an
object
of
type
`std::contract_violation` having the following properties.

**–** `comment` has a recommended value of `#__VA_ARGS__`. **–** `location` has a recommended value of the location where the `assert` macro was expanded. **–** `kind` will be a new value of `std::contracts::assertion_kind`, `cassert`. **–** `detection_mode` will be the value `predicate_false`. **–** `evaluation_semantic` will be `enforce`. If the contract-violation handler returns normally or an exception escapes the contractviolation handler’s evaluation, the program will terminate in an implementation-defined manner.

Note that the above description is roughly equivalent to an invocation of `handle_enforced_contract_violation(std::nothrow,#__VA_ARGS__)` with the caveat that different values for `kind` and `detection_mode` are passed through to the contract-violation handler as well.

As always, a feature test macro should also be provided to identify whether the current platform has implemented the associated functionality:

Proposal 4: Feature test macro for `assert` integration

The feature test macro `__cpp_lib_assert_can_use_contracts` will have a value of `yyyymmL` if the behavior `assert` depends on the value of `ASSERT_USES_CONTRACTS` as described above. This macro will be defined in `<version>`, `<assert.h>`, and `<cassert>`.

A possible implementation of `<cassert>` might be something like this:

```cpp
#ifdef NDEBUG
  #define assert(...) (static_cast<void>(0))
#elif defined ASSERT_USES_CONTRACTS
#include <source_location>
#include <contracts>
[[noreturn]] void __handle_assert_violation(
    const char* comment,
    std::source_location = std::source_location::current() ) noexcept;
  // ABI function that invokes the contract-violation handler with an appropriately
  // populated contract_violation object, using the source_location where this
  // function is invoked
  #define assert(...)
                                                                           \
    ((__VA_ARGS__)
                                                                           \
     ? static_cast<void>(0)
                                                                           \
     : __handle_assert_violation(#__VA_ARGS__)
#else
[[noreturn]] void __assert_fail(const char* comment,
                                const char* file,
                                unsigned int line,
                                const char* function);
  // ABI function to print "Assertion failed" message to standard output and abort
  #define assert(...)
                                                                           \
    ((__VA_ARGS__)
                                                                           \
     ? static_cast<void>(0)
                                                                           \
     : __assert_fail( #__VA_ARGS__,
                                                                           \
                      __FILE__,
                                                                           \
                      __LINE__,
                                                                           \
                      __PRETTY_FUNCTION__ )
#endif
```

Note that in the above we made the choice to directly `#include` the `source_location` header. A compiler and Standard Library implementation need not do so necessarily, but could instead opt to introduce additional compiler builtins or internal headers to achieve the same net result.

### 3

All of these changes have been implemented (but not yet made publicly available at the time of this revision) in libc++ and libstdc++, alongside the ongoing implementations of [P2900R14] in those compilers.

### 4

Wording changes are relative to [N5032], the last published draft available at the time of this writing. No changes to these sections are

Modify [contracts.syn] paragraph 1:

1 The header `<contracts>` defines types for reporting information about contract violations ([basic.contract.eval]).

:::wording-add

namespace std::contracts { enum class assertion_kind : unspecified { pre = 1, post = 2, assert = 3, <ins>manual = 4,</ins> <ins>cassert = 5</ins> }; enum class evaluation_semantic : unspecified { ignore = 1, observe = 2, enforce = 3, quick_enforce = 4 }; enum class detection_mode : unspecified { <ins>unspecified = 0,</ins> predicate_false = 1, evaluation_exception = 2 };

:::

...

:::wording-add

void invoke_default_contract_violation_handler(const contract_violation&); <ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins> <ins>void handle_observed_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>void handle_observed_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins> <ins>[[noreturn]] void handle_quick_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins> }

:::

...

Modify [support.contract.enums] table [tab:support.contract.enum.kind]:

Table — Enum `assertion_kind` [tab:support.contract.enum.kind] Name Meaning

| `pre` | A precondition assertion |
| --- | --- |
| `post` | A postcondition assertion |
| `assert` | An *assertion-statement* |
| `cassert` | The `assert` macro ([assertions.assert]) |
| `manual` | A manually triggered violation. |

Modify [support.contract.enums] table [tab:support.contract.enum.detection]:

Table — Enum `detection_mode` [tab:support.contract.enum.detection]

:::wording-add

Name Meaning <ins>unspecified</ins> <ins>The mode of detection was not</ins> <ins>provided to the contract-violation</ins> <ins>handling process</ins> predicate_false The predicate of the contract assertion evaluated to false or would have evaluated to false.

:::

`evaluation_exception` An uncaught exception occurred during evaluation of the contract assertion.

Add a new section after [support.contract.invoke]:

:::wording-add

<ins>handle_enforced_contract_violation</ins> <ins>[support.contract.handle]</ins>

:::

:::wording-add

<ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins>

:::

1 *Effects*:

:::wording-add

<ins>— Invoke the contract-violation handler with a contract_violation object populated</ins> <ins>as follows:</ins>

:::

:::wording-add

<ins>— The comment, if populated, will be the comment passed to this function.</ins>

:::

:::wording-add

<ins>— The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins>

:::

:::wording-add

<ins>— The kind will be manual.</ins>

:::

:::wording-add

<ins>— The detection_mode will be unspecified.</ins>

:::

:::wording-add

<ins>— The evaluation_semantic will be enforce.</ins>

:::

:::wording-add

<ins>— If the violation handler returns normally, the program is contract-terminated</ins> <ins>([basic.contract.eval]).</ins>

:::

:::wording-add

<ins>void handle_observed_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>void handle_observed_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins>

:::

## 2 *Effects*:

:::wording-add

<ins>— Invoke the contract-violation handler with a contract_violation object populated</ins> <ins>as follows:</ins>

:::

:::wording-add

<ins>— The comment will be the comment passed to this function.</ins>

:::

:::wording-add

<ins>— The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins>

:::

:::wording-add

<ins>— The kind will be manual.</ins>

:::

:::wording-add

<ins>— The detection_mode will be unspecified.</ins>

:::

:::wording-add

<ins>— The evaluation_semantic will be observe.</ins>

:::

:::wording-add

<ins>[[noreturn]] void handle_quick_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins> <ins>handle_enforced_contract_violation</ins> <ins>[support.contract.handle]</ins>

:::

:::wording-add

<ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>[[noreturn]] void handle_enforced_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins>

:::

1 *Effects*:

:::wording-add

<ins>— Invoke the contract-violation handler with a contract_violation object populated</ins> <ins>as follows:</ins>

:::

:::wording-add

<ins>— The comment, if populated, will be the comment passed to this function.</ins>

:::

:::wording-add

<ins>— The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins>

:::

:::wording-add

<ins>— The kind will be manual.</ins>

:::

:::wording-add

<ins>— The detection_mode will be unspecified.</ins>

:::

:::wording-add

<ins>— The evaluation_semantic will be enforce.</ins>

:::

:::wording-add

<ins>— If the violation handler returns normally, the program is contract-terminated</ins> <ins>([basic.contract.eval]).</ins>

:::

:::wording-add

<ins>void handle_observed_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location &location</ins> <ins>= std::source_location::current());</ins> <ins>void handle_observed_contract_violation(</ins> <ins>std::nothrow_t,</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins>

:::

## 2 *Effects*:

:::wording-add

<ins>— Invoke the contract-violation handler with a contract_violation object populated</ins> <ins>as follows:</ins>

:::

:::wording-add

<ins>— The comment will be the comment passed to this function.</ins>

:::

:::wording-add

<ins>— The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins>

:::

:::wording-add

<ins>— The kind will be manual.</ins>

:::

:::wording-add

<ins>— The detection_mode will be unspecified.</ins>

:::

:::wording-add

<ins>— The evaluation_semantic will be observe.</ins>

:::

:::wording-add

<ins>[[noreturn]] void handle_quick_enforced_contract_violation(</ins> <ins>const char* comment,</ins> <ins>const std::source_location& location</ins> <ins>= std::source_location::current()) noexcept;</ins>

:::

## 3 *Effects*: Terminate the program in an implementation-defined manner.

Modify [assertions.general] paragraph 1:

:::wording-add

1 The header <cassert> provides a macro for documenting C++ program assertions, and a mechanism for disabling the assertion checks through defining the macro NDEBUG., and a <ins>mechanism to integrate with the contract-violation handler through defining the macro</ins> <ins>ASSERT_USES_CONTRACTS.</ins>

:::

Modify [assertions.assert] paragraph 1:

1 If `NDEBUG` is defined as a macro name at the point in the source file where `<cassert>` or

`<assert.h>` is included, the `assert` macro is defined as

```cpp
#define assert(...) ((void)0)
```

2 Otherwise, the `assert` macro puts a diagnostic test into programs; it expands to an expression of type `void` that has the following effects:

— `__VA_ARGS__` is evaluated and contextually converted to `bool`.

— If the evaluation yields `true` there are no further effects.

:::wording-add

— <ins>Otherwise, if ASSERT_USES_CONTRACTS is defined as a macro name at the point in</ins> <ins>the source file where <cassert> or <assert.h> is included, the assert macro’s</ins> <ins>expansion invokes the contract-violation handler ([basic.contract.handler]). The</ins> <ins>contract_violation object passed to the handler will be populated as follows:</ins>

:::

:::wording-add

<ins>— The kind will be the value cassert.</ins>

:::

:::wording-add

<ins>— The detection_mode will be the value predicate_false.</ins>

:::

:::wording-add

<ins>— The evaluation_semantic will be the value enforce.</ins>

:::

:::wording-add

<ins>— The location will, if populated, represent the source file, line number, and</ins> <ins>name of the enclosing function.</ins>

:::

:::wording-add

<ins>— The comment will, if populated, contain #__VA_ARGS__.</ins>

:::

— Otherwise, the `assert` macro’s expression creates a diagnostic on the standard error stream (ISO/IEC 9899:2018, 7.23.3) in an implementation-defined format and calls `abort()`. The diagnostic contains `#__VA_ARGS__` and information on the name of the source file, the source line number, and the name of the enclosing function (such as provided by `source_location::current()`).

Modify [diff.header.assert.h] paragraph 1:

:::wording-add

The token static_assert is a keyword in C++. It does not appear as a macro name defined in `<cassert>`. <ins>The assert macro is more restrictive about the expression used and</ins> <ins>behaves differently when ASSERT_USES_CONTRACTS is defined ([assertions.assert]).</ins>

:::

Modify [version.syn] paragraph 2:

```cpp
...
  #define __cpp_lib_as_const
                                                           201510L
    // freestanding, also in <utility>
```

:::wording-add

<ins>#define __cpp_lib_assert_can_use_contracts</ins> <ins>yyyymmL</ins> <ins>// freestanding, also in <assert.h>, <cassert></ins> #define __cpp_lib_associative_heterogeneous_erasure 202110L // also in <map>, <set>, <unordered_map>, <unordered_set> ... #define __cpp_lib_contracts 202502L // freestanding, also in <contracts> <ins>#define __cpp_lib_contracts_api</ins> <ins>yyyymmL</ins> <ins>// freestanding, also in <contracts></ins> #define __cpp_lib_copyable_function 202306L // also in <functional> ... 5 Conclusion Providing the beginnings of a migration path for users of legacy assertion facilities — both assert and homegrown solutions — is an essential part of making early use of the Contracts facility viable for many users. The hooks proposed in this paper allow for such legacy facilities to live side-by-side with C++ contracts, require no major changes to legacy facilities’ existing semantics, and open the door to integration with Contracts as soon as they are available. — Existing facilities will have the ability to easily integrate with the violation-handling capabilities of C++. — The assert macro will expose this same kind of optional functionality. Support for a widened set of use cases is a natural extension to the functionality provided by Standard Contracts, and we hope to see this proposal adopted to facilitate a vastly widened integration of existing contract-checking facilities with the central violation-handling mechanisms of C++ Contracts. Acknowledgements Thanks to John Spicer, Tom Honermann, and the rest of SG21 for the discussions that led to these proposals and to Lori Hughes for helping to greatly increase the readability and quality of this paper. Thanks to Eric Fiselier, Nina Ranns, Iain Sandoe, and Ville Voutilainen for excellent feedback when implementing this proposal. Bibliography

:::

| [N5032] | Thomas Köppe, “Working Draft, Standard for Programming Language C++”, 2025 | `http://wg21.link/N5032` |
| --- | --- | --- |
| [P2264R7] | Peter Sommerlad, “Make assert() macro user friendly for C and C++”, 2023 | `http://wg21.link/P2264R7` |

| [P2900R14] | Joshua Berne, Timur Doumler, and Andrzej Krzemieński, “Contracts for C++”, | 2025 | `http://wg21.link/P2900R14` |
| --- | --- | --- | --- |
| [P3191R0] | Louis Dionne, Yeoul Na, and Konstantin Varlamov, “Feedback on the scalability of | contract violation handlers in P2900”, 2024 | `http://wg21.link/P3191R0` |

<!-- tomd:uncertain:L936-L945 -->

[P3290R0]
Joshua Berne, Timur Doumler, and John Lakos, “Integrating Existing Assertions
With Contracts”, 2024

http://wg21.link/P3290R0

[P3311R0]
Tom Honermann, “An opt-in approach for integration of traditional assert facilities
in C++ contracts”, 2024
http://wg21.link/P3311R0
