June 13, 2026·6 min read·engineeringcppcxx29contractssafety

C++29 begins by cataloging undefined behavior

The Brno meeting adds UB and IFNDR catalogs and virtual-function contracts to draft C++29. Documentation, runtime checks and safety profiles address different parts of the problem.

Before a committee can systematically change undefined behavior, it needs a shared inventory of the cases it intends to address. The first C++29 meeting adopts that inventory alongside an extension allowing contracts on virtual functions. Herb Sutter reports from Brno on June 13 that both changes entered the working draft. They represent different kinds of progress. A catalog makes existing rules inspectable, while an interface extension changes which program requirements can appear in declarations.

The catalog comes from P3596R3, by Joshua Berne, Timur Doumler, Jens Maurer and Shafik Yaghmour. It adds separate annexes for undefined behavior and programs that are ill-formed with no diagnostic required. That separation matters because the two categories describe different failures of a program to meet the language requirements. Collecting them does not itself make either category safe or require a new compiler diagnostic.

After a decade with C++, I still value the combination of RAII and abstractions that can compile without runtime overhead. The difficulty is understanding the accumulated language rules in a large codebase. A maintained catalog offers a concrete reference for that problem, particularly when an implementation, an analysis tool and a proposal need to refer to the same case precisely.

The annexes provide names and examples

P3596 explains that earlier attempts to collect the information preceded this work. It cites P1705 and subsequent calls to place a catalog within the standard itself. Developing the annexes alongside the working draft makes maintenance part of the standardization process. The inventory can change when the rules change instead of remaining a separate historical list.

Each potential issue receives a tentative stable name. The paper uses those names to connect the primary wording to the annex entry and back. The same identifiers already support discussion in the P3100 work on mitigating undefined behavior. Stable references are useful when the surrounding clause numbering changes, since a discussion can continue to identify the particular behavior it means.

The authors set an important requirement for examples. An example must demonstrate the behavior described by its entry and must not be incorrect for an unrelated reason. That sounds modest, but it is essential to useful compiler experiments. A program with several independent defects cannot establish which rule caused a diagnostic or an optimizer transformation.

The annex text is nonnormative. It aims to be thorough without duplicating the full core wording that defines each case. This gives the catalog a specific role as a reference and index. When an entry raises a question about the exact language requirement, the linked normative text remains the place that defines it.

Organization also involves a maintenance tradeoff. P3596 considers grouping entries by category or mirroring different levels of the main document structure. Categories could make related issues easier to study, but assigning them requires additional design work. A mechanical organization offers a more direct way to integrate the catalog while preserving connections to the defining clauses.

A catalog does not eliminate the listed behaviors

The Brno report distinguishes adoption of the annexes from further work on P3100. The language evolution group plans detailed review of that framework over the following months. This means the meeting produces a reference for the problem and a commitment to examine possible remedies. It does not announce that the catalog entries have all acquired defined runtime behavior.

That distinction affects how the change should be communicated to users. A newly documented case can remain undefined under the same conditions as before. A tool may use the catalog to improve explanations, but the existence of an identifier does not establish that a particular compiler detects the case. The catalog supplies common terminology for subsequent decisions about detection and semantics.

It also keeps different kinds of remedies distinguishable. Some problems can be diagnosed from a declaration, while others depend on execution state. A proposal to restrict a construct and a proposal to check a runtime condition make different demands on implementations. Naming the underlying issue lets those approaches be compared without treating every safety change as one undifferentiated feature.

Virtual contracts distinguish the interface from the implementation

The adopted virtual-function extension is P3097R3, by Doumler, Berne and Gašper Ažman. C++26 does not permit pre and post on virtual function declarations. The extension allows them and specifies how assertions interact with dynamic dispatch. The central rule is that an override does not implicitly inherit the assertions of every overridden function.

Instead, a call has caller-facing assertions belonging to the function named by the call expression and callee-facing assertions belonging to the function actually invoked. In a virtual call, those can be different functions. Both sets participate in evaluation. This preserves the distinction between the interface through which a caller operates and the implementation selected at runtime.

The sequence begins with caller-facing preconditions and then callee-facing preconditions. The function body runs next. Callee-facing postconditions precede caller-facing postconditions on return. Those ordering rules define which part of the interface the evaluation is checking at each stage. They also keep the model connected to the existing contract-evaluation semantics.

For a direct call, the two sets can identify the same function and redundant checks can be deduplicated. An indirect call through a function pointer has no caller-facing assertions because the pointer has none associated with it. The implementation assertions still participate. Virtual dispatch therefore fits within a broader model of the call boundary instead of requiring assertion inheritance to explain every invocation.

The design deliberately permits different override assertions

The paper allows an overriding function to specify assertions different from those of the base declaration. A call through the base interface still evaluates the assertions attached to that interface as well as those attached to the final override. A direct call naming the derived interface has its own caller-facing requirements. The route by which the function is invoked consequently matters to the assertions associated with the call.

This differs from the Eiffel and D model discussed in the proposal, where inherited assertions constrain how preconditions and postconditions change across overrides. P3097 argues that independent assertions better accommodate C++ code and its existing violation-handling model. The extension does not claim that an override with arbitrary requirements automatically satisfies the behavioral expectations of its base interface.

The authors distinguish an interface contract in ordinary prose from the subset expressible as assertions. A correct caller meets the statically selected interface requirements. The implementation must then meet the promised result or use an appropriate error-handling mechanism. Assertions can check part of that relationship, but a predicate declaration cannot encode every semantic obligation of substitutability.

The history explains why this work arrives early in C++29. A previous version gained support and entered the main contracts proposal, but disagreement about its model led to removal before C++26. The Brno revision records renewed language evolution support and core wording review. It is a previously developed design returning after the first contracts release, rather than an unrelated replacement for that facility.

Profiles remain separate work

Sutter reports progress on a Profiles specification and an initialization profile, while explicitly placing them among work not yet merged at this meeting. Profiles aim to restrict selected language operations and support analysis of desired properties. That is different from documenting an existing UB case or adding a runtime assertion to an interface.

The distinction is useful for evaluating the direction of C++29. The annexes establish a shared inventory. Virtual-function contracts extend where programmers can state and check requirements. Profiles pursue restrictions that can rule out certain operations in selected code. Their relationship does not make them interchangeable, and the report does not present all of them as adopted features.

I find the catalog especially valuable as a basis for specific technical discussion. It lets an argument identify the rule being changed and the example that demonstrates it. The virtual-contract work is similarly concrete about which function declaration supplies each assertion. Those details make it possible to assess a proposed guarantee without assuming a general claim of safety covers every program or every build configuration.

For compiler and library users, the immediate status is draft C++29 adoption for the catalog and virtual-function contracts, with additional safety work still under review. Implementation availability remains a separate question. The new annex entries and the call-boundary rules provide precise material for experiments and documentation as that implementation work proceeds.