---
title: "Integrating Existing Assertions with Contracts"
document: P3290R6
date: 2026-07-15
audience: LEWG
reply-to:
  - "Joshua Berne <jberne4@bloomberg.net>"
  - "Timur Doumler <papers@timur.audio>"
  - "John Lakos <jlakos@gmail.com>"
---

Revision 6, July 2026 Mailing

* Presenting feedback from SG22 on the `assert` macro choices, including new subsections on
implementation-defined integration and throwing violation handlers

Revision 5, as presented to July 8, 2026 SG22 telecon

* Wording formatting and fixes

* Changed `assert` proposal to always `abort()` when the violation-handler completes

* Implementation experience with links on compiler explorer

* Proposing a more C-compatible control macro, `__STDC_WANT_ASSERT_USES_CONTRACTS__`

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++, which we elaborate on further in Section 3.

## 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.

* 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 have
allowed 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, increase 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::contracts::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 compile-time 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 approach 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 !defined(__cpp_lib_contracts_api)
  #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 !defined(__cpp_lib_contracts_api)
  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 `nothrow_t` 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`, and `abort` is the only mechanism used to terminate the program after the violation handler completes.

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 state of affairs 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 exit the program (through `std::abort()`, matching how `assert` historically terminates the program) if the violation handler does throw (similarly to calling one of the `nothrow_t` overloads from Proposal 1.3, except that it calls `std::abort` instead of `std::terminate` when an exception is thrown).

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.

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 contractchecking
 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.

* Alternatively, because `assert` is primarily a C facility, a macro that begins with `STDC` could
be considered, or a reserved name macro that begins with `__STDC` and ends with `__`. C23
introduced three control macros to control the behavior of `<math.h>` that can be used as a
naming precedent:

Following that precedent, we could choose to use a `__STDC_WANT` prefix on our macro, or alternatively keep the macro C++-specific and use a `__STDCPP_WANT` prefix2.

* 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

2It might be a concern that we are aiming to introduce a `__STDC`-prefixed macro into the C++ Standard. This is being done intentionally as we hope to see the same macro eventually introduced in C, with the same effective semantics, and having multiple distinct mechanisms for achieving the same results is harmful in the long term. SG22 discussed this design decision and approved of that direction, noting that the poll itself was asking whether there was a desire to change the paper and there was consensus against doing so:

`ASSERT_IS_ENFORCED` as a name.

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

Following the precedent of WG14 (where macro use is much more common in the first place, and which we hope will follow through with adopting a compatible Contracts facility and support integration in the same way), we suggest the use of the name `__STDC_WANT_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 `__STDC_WANT_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::contracts::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, `std::abort()` will be invoked.

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, and any completion of the contract-violation handler results in calling `std::abort()`. This choice results in the smallest change possible to the behaviors of `assert()` while integrating it with the

SG22, Telecon, 2026-07-09

[P3290R5]: We disapprove the use of a `__STDC_WANT_*` macro. WG14: SF F N A SA 0 0 2 4 1 Result: Consensus against WG21: SF F N A SA 1 0 2 7 2 Result: Consensus against contract-violation handler.

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 of `assert` depends on the value of `__STDC_WANT_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 __STDC_WANT_ASSERT_USES_CONTRACTS__
#include <source_location>
                            // for std::source_location
[[noreturn]] void __cxa_handle_cassert_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, then invokes std::abort()
  #define assert(...)
                                                                           \
    ((__VA_ARGS__)
                                                                           \
     ? static_cast<void>(0)
                                                                           \
     : __cxa_handle_cassert_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 error 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.

### 2.3

Earlier versions of this paper proposed making the choice of integrating `assert` with the contractviolation handler one that was implementation-defined — i.e., a command line flag outside of the language. An alternative proposal, [P3311R0], proposed using a user-defined macro to control that choice (on the command line or in code).

SG21, when discussing these two proposals, 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

After that poll was taken in SG21, this paper updated to propose the use of a control macro and that is the version which has been forwarded since then.

When discussing this paper again in SG22, the C Liaison group, the same question was raised and there was no group consensus to move back to the original design. There was, however, some interest in allowing the compiler to integrate with contracts (as a conforming implementation-defined choice) without the use of the control macro. The primary motivation for this approach is to remove the need to have user code depend on this new macro for the indefinite future. The group was polled about how much they desired to take this approach:

SG22, Telecon, 2026-07-09

[P3290R5]: We want to allow integration of the assert macro with contracts even if no `*_WANT_*` macro is defined. WG14: SF F N A SA 0 1 1 2 1 Result: Weak consensus against WG21: SF F N A SA 1 3 4 2 0 Result: No consensus

Though there wasn’t consensus for change, it is notable that this behavior can still be achieved in various conforming and non-conforming manners:

* A compiler is not restricted to define macros only when the user uses `#define` in their
source code or `-D` on the command line. A compiler is free to document that the control
macro will be defined when used or when other command line arguments are provided. This
introduction of the control macro can be based on an opt-in command line flag such as

### 2.3

Earlier versions of this paper proposed making the choice of integrating `assert` with the contractviolation handler one that was implementation-defined — i.e., a command line flag outside of the language. An alternative proposal, [P3311R0], proposed using a user-defined macro to control that choice (on the command line or in code).

SG21, when discussing these two proposals, 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

After that poll was taken in SG21, this paper updated to propose the use of a control macro and that is the version which has been forwarded since then.

When discussing this paper again in SG22, the C Liaison group, the same question was raised and there was no group consensus to move back to the original design. There was, however, some interest in allowing the compiler to integrate with contracts (as a conforming implementation-defined choice) without the use of the control macro. The primary motivation for this approach is to remove the need to have user code depend on this new macro for the indefinite future. The group was polled about how much they desired to take this approach:

SG22, Telecon, 2026-07-09

[P3290R5]: We want to allow integration of the assert macro with contracts even if no `*_WANT_*` macro is defined. WG14: SF F N A SA 0 1 1 2 1 Result: Weak consensus against WG21: SF F N A SA 1 3 4 2 0 Result: No consensus

Though there wasn’t consensus for change, it is notable that this behavior can still be achieved in various conforming and non-conforming manners:

* A compiler is not restricted to define macros only when the user uses `#define` in their
source code or `-D` on the command line. A compiler is free to document that the control
macro will be defined when used or when other command line arguments are provided. This
introduction of the control macro can be based on an opt-in command line flag such as

`-fcontracts-assert-calls-violation-handler`, or even when a particular standard version is chosen (such as `-std=c++29`). Following this route leaves the option open to developers to then opt *out* of the behavior by adding `#undef` `__STDC_WANT_ASSERT_USES_CONTRACTS__` prior to `#include` `<cassert>`.

* A compiler and standard library are also free to have extensions where the behavior of `assert`
is modified based on other command-line flags. Though not a conforming extension, this is not
an unfamiliar practice and would not be problematic for users who don’t try to take advantage
of the new command line options.

Given the lack of consensus for change, our suggestion is for compilers to eventually take the first approach (always integrating by default) when future C++ versions are chosen, and to achieve that goal by predefining the control macro.

### 2.4

Another concern that has been raised is the lack of support for throwing violation handlers when using the `assert` macro. This paper does *not* propose allowing exceptions to escape when the user has chosen to integrate `assert` with the contract-violation handler.

The primary goal of the integration with `cassert` is not to change the semantics of `cassert` itself but to allow integration with the user’s violation reporting mechanisms. Throwing violations sit on the edge of this design since they mix both violation handling and, to some extent, violation mitigation approaches. While we could make that change soundly, it is also a concern for many people that we might be introducing a new potential control flow path where none previously existed to vast swaths of existing code.

SG21 when originally considering this integration was consistently against the idea of allowing throwing violations from `assert`. SG22 discussed this concern and polled on their desire to support it:

SG22, Telecon, 2026-07-09

[P3290R5]: The assert macro should allow for exceptions thrown from contract violation handlers to propagate. WG14: SF F N A SA 0 0 0 5 2 Result: Consensus against WG21: SF F N A SA 1 0 2 7 2 Result: Consensus against

Given those results we continue to not propose allowing a throwing violation handler to emit an exception when using `assert`.

Note some important facts that some have found non-obvious:

* Unlike with a contract assertion (`pre`, `post`, or `contract-assert`), if an exception escapes
the predicate of a checked `assert` then that exception will propagate normally from where
the `assert` is evaluated. This proposal has not (and would not) changed that aspect of the
semantics of `assert` — and the purpose here has been to show that we can integrate an existing
assertion facility with the contract-violation handler without changing such semantics.

* Just as with using a throwing violation handler in other contexts where `noexcept` is in play, if the
violation handler invoked from the `assert` macro does throw an exception then `std::terminate`
will be invoked.

* Since `assert` is a macro defined in a Standard Library header and not a keyword, users are
of course more than capable of both defining their own `assert` macro that makes different
choices, or, as is much more commonplace, defining their own (differently-named) macros
that allow for throwing violation handlers. Integrating with throwing violation handlers is
completely possible by using one of the non-`noexcept` entry point functions introduced earlier
in this paper.

### 3

The library API and `assert` integration proposed in this paper have been implemented in branches of GCC (libstdc++) and Clang (libc++) that are available on Compiler Explorer: `https://godbolt.` `org/z/7nvPdYzfc`.

Both implementations provide the full set of programmatic violation-reporting functions as well as integration of the C `assert` macro with the contract-violation handler. The library API has also been updated with new enumerators. Both compilers define the feature-test macros `__cpp_lib_contracts_api` and `__cpp_lib_assert_can_use_contracts` with matching values.

Both implementations make these features available with the use of the `-fcontracts-p3290` commandline flag. They are also available with the flag `-fcontracts-p3850` that enables prototype implementations of many of the papers described in the overall plan in [P3850R1].

The two standard libraries share a single ABI entry point for the `assert` integration. This ABI is implemented in both compilers, and will be proposed as part of the Itanium ABI in the future. The library API proposed in this paper is implemented by both libraries as a relatively thin layer around that shared ABI.

The changes to assert are similar, with the most impactful one being that both libraries needed to begin providing their own versions of `assert.h` that delegates to the underlying C library header using `#include_next`. This mimics similar choices already made for other headers such as `stdio.h` or `stdlib.h`.

Overall, neither implementation was very involved and rested mostly on the shared ABI and existing practices with other C library headers.

### 4

These wording changes are relative to the C++29 working draft with git hash [9fd05919](https://github.com/cplusplus/draft/tree/9fd05919b0fde82d7d82a87cb706f440761af906), last modified on Thu, 4 Jun 2026 21:25:15 +0200.

| 17 Language support library | [support] |
| --- | --- |
| 17*.*3 **Implementation** **properties** | **[support.limits]** |
| 17*.*3*.*2 **Header** `<version>` **synopsis** | **[version.syn]** |

Modify section 17.3.2[version.syn], paragraph 2:

2 Each of the macros defined in `<version>` is also defined after inclusion of any member of the set of library headers indicated in the corresponding comment in this synopsis.

[*Note* *1*: Future revisions of this document might replace the values of these macros with greater values. *— end* *note*]

:::wording-add

... 15 lines elided ... // freestanding, also in <iterator>, <array> #define __cpp_lib_as_const 201510L // freestanding, also in <utility> <ins>#define __cpp_lib_assert_can_use_contracts</ins> <ins>yyyymmL // freestanding, also in <assert.h> and <cassert>←�</ins> #define __cpp_lib_associative_heterogeneous_erasure 202110L // also in <map>, <set>, <unordered_map>, <unordered_set>

:::

:::wording-add

... 72 lines elided ... // also in <vector>, <list>, <forward_list>, <map>, <set>, <unordered_map>, <unordered_set>, // <deque>, <queue>, <stack>, <string> #define __cpp_lib_contracts 202502L // freestanding, also in <contracts>←� <ins>#define __cpp_lib_contracts_api</ins> <ins>yyyymmL // freestanding, also in <contracts></ins> #define __cpp_lib_copyable_function 202306L // also in <functional> #define __cpp_lib_coroutine 201902L // freestanding, also in <coroutine>

:::

```cpp
...
         224 lines elided
                                                               ...
```

| 17*.*10 Contract-violation handling | [support.contract] |
| --- | --- |
| 17*.*10*.*1 **Header** `<contracts>` **synopsis** | **[contracts.syn]** |

Modify section 17.10.1[contracts.syn], paragraph 1:

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

:::wording-add

// all freestanding 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 }; class contract_violation { // no user-accessible constructor public: contract_violation(const contract_violation&) = delete; contract_violation& operator=(const contract_violation&) = delete; see below ~contract_violation(); const char* comment() const noexcept; contracts::detection_mode detection_mode() const noexcept; bool is_terminating() const noexcept; assertion_kind kind() const noexcept; source_location location() const noexcept; evaluation_semantic semantic() const noexcept; }; void invoke_default_contract_violation_handler(const contract_violation&);←� <ins>←�</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> <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> }

:::

#### 17*.*10*.*2 Enumerations

Modify section 17.10.2[support.contract.enum], Table 44 [support.contract.enum.kind]:

**Table** **44** **—** **Enum** `assertion_kind` **[tab:support.contract.enum.kind]**

:::wording-add

Name Meaning pre A precondition assertion post A postcondition assertion assert An assertion-statement <ins>manual</ins> <ins>A manually triggered violation</ins> <ins>cassert</ins> <ins>The assert macro (19.3.3[assertions.assert])</ins>

:::

Modify section 17.10.2[support.contract.enum], Table 46 [support.contract.enum.detection]:

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

:::wording-add

Name Meaning <ins>unspecified</ins> <ins>The</ins> <ins>mode</ins> <ins>of</ins> <ins>detection</ins> <ins>was</ins> <ins>not</ins> <ins>provided</ins> <ins>to</ins> <ins>the</ins> <ins>contract-violation 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.

:::

#### 17*.*10*.4* + *a* Manual violation-handler invocation

:::wording-add

Add a new section <ins>17.10.4+a</ins>[support.contract.handle] after 17.10.4[support.contract.invoke]

:::

:::wording-add

<ins>17.10.4+a Manual violation-handler invocation</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>

:::

:::wording-add

<ins>= std::source_location::current()) noexcept;</ins> <ins>1</ins> <ins>Effects:</ins>

:::

:::wording-add

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

:::

:::wording-add

<ins>—</ins> <ins>(1.1.1)</ins> <ins>The comment, if populated, will be the comment passed to this function.</ins> <ins>—</ins> <ins>(1.1.2)</ins> <ins>The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins> <ins>—</ins> <ins>(1.1.3)</ins> <ins>The kind will be manual.</ins>

:::

:::wording-add

<ins>—</ins> <ins>(1.1.4)</ins> <ins>The detection_mode will be unspecified.</ins> <ins>—</ins> <ins>(1.1.5)</ins> <ins>The evaluation_semantic will be enforce.</ins> <ins>—</ins> <ins>(1.2)</ins> <ins>If</ins> <ins>the</ins> <ins>violation</ins> <ins>handler</ins> <ins>returns</ins> <ins>normally,</ins> <ins>the</ins> <ins>program</ins> <ins>is</ins> <ins>contractterminated</ins> <ins>(6.11.2[basic.contract.eval]).</ins> <ins>2</ins> <ins>Throws: Nothing if the nothrow_t overload is selected, otherwise any exception thrown</ins> <ins>from the contract-violation handler.</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> <ins>3</ins> <ins>Effects:</ins>

:::

:::wording-add

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

:::

:::wording-add

<ins>—</ins> <ins>(3.1.1)</ins> <ins>The comment, if populated, will be the comment passed to this function.</ins> <ins>—</ins> <ins>(3.1.2)</ins> <ins>The location, if populated, will be the location passed to this function or the</ins> <ins>location of the function invocation.</ins> <ins>—</ins> <ins>(3.1.3)</ins> <ins>The kind will be manual.</ins> <ins>—</ins> <ins>(3.1.4)</ins> <ins>The detection_mode will be unspecified.</ins> <ins>—</ins> <ins>(3.1.5)</ins> <ins>The evaluation_semantic will be observe.</ins> <ins>4</ins> <ins>Throws: Nothing if the nothrow_t overload is selected, otherwise any exception thrown</ins> <ins>from the contract-violation handler.</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>5</ins> <ins>Effects: Contract-terminate the program (6.11.2[basic.contract.eval]).</ins>

:::

| 19 Diagnostics library | [diagnostics] |
| --- | --- |
| 19*.*3 **Assertions** | **[assertions]** |
| 19*.*3*.*1 **General** | **[assertions.general]** |

Modify section 19.3.1[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>__STDC_WANT_ASSERT_USES_CONTRACTS__</ins>.

:::

#### 19*.*3*.*3 The `assert` macro

Modify section 19.3.3[assertions.assert], paragraphs 1-2:

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` which has the following effects:

— (2.1) `__VA_ARGS__` is evaluated and contextually converted to `bool`.

:::wording-add

<ins>[Note a: If an exception escapes the evaluation of __VA_ARGS__, it propagates normally.</ins>

:::

:::wording-add

<ins>— end note]</ins>

:::

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

:::wording-add

<ins>—</ins> (<ins>2.2+a</ins>) <ins>Otherwise, if __STDC_WANT_ASSERT_USES_CONTRACTS__ is defined as a macro name at the</ins> <ins>point in the source file where <cassert> or <assert.h> is included, the assert macro’s</ins> <ins>expression</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.1</ins>) <ins>invokes the contract-violation handler (6.11.3[basic.contract.handler]), and</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.2</ins>) <ins>then, if the contract-violation handler returns normally or exits via an exception, calls</ins> <ins>abort().</ins>

:::

:::wording-add

<ins>The contract_violation object passed to the handler will be populated as follows:</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.3</ins>) <ins>The kind will be the value cassert.</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.4</ins>) <ins>The detection_mode will be the value predicate_false.</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.5</ins>) <ins>The evaluation_semantic will be the value enforce.</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.6</ins>) <ins>The location will, if populated, represent the source file, line number, and name of the</ins> <ins>enclosing function.</ins>

:::

:::wording-add

<ins>—</ins> (<ins>2.2+a.7</ins>) <ins>The comment will, if populated, contain #__VA_ARGS__.</ins>

:::

— (2.3) Otherwise, the `assert` macro’s expression creates a diagnostic on the standard error stream (ISO/IEC 9899:2024, 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()`).

### 5

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. Thanks to Jens Gustedt for feedback on an earlier version of this paper.

Claude (Anthropic) was used for editorial assistance during the preparation of this paper, as well as significant parts of the prototype implementations.

## Bibliography

[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` |

| [P3290R0] | Joshua Berne, Timur Doumler, and John Lakos, “Integrating Existing Assertions | With Contracts”, 2024 |
| --- | --- | --- |
| `http://wg21.link/P3290R0`[P3290R5] | Joshua Berne, Timur Doumler, and John Lakos, “Integrating Existing Assertions | With Contracts”, 2026 |

```cpp
http://wg21.link/P3290R5
```

| [P3311R0] | Tom Honermann, “An opt-in approach for integration of traditional assert facilities | in C++ contracts”, 2024 | `http://wg21.link/P3311R0` |
| --- | --- | --- | --- |
| [P3850R1] | Timur Doumler and Joshua Berne, “A proposed plan for extending Contracts in | C++29”, 2026 | `http://wg21.link/P3850R1` |
