Profiles take shape, and the contract C++26 left behind comes back
If the undefined-behavior catalogue was Brno’s structural move, profiles and contracts were the concrete one. Both are mechanisms for opting in to more checking than baseline C++ gives you, and both moved at the meeting. All of this targets C++29, not C++26 (which is done).
Profiles get a framework
A “profile” is a named bundle of restrictions a compiler enforces, a dialect of C++ that forbids some unsafe operations. The idea has floated for a couple of years; what was missing was the plumbing. P3589R2, “C++ Profiles: The Framework” (Dos Reis) supplies it, and the important detail is that it is built from attributes, not pragmas:
[[profiles::enforce(std::type, std::ranges)]]; // file scope, before any declaration
// Opt a single statement back out, with a required justification:
[[profiles::suppress(std::type,
justification: "ABI shim into a C API",
rule: "type.reinterpret")]]
int* p = reinterpret_cast<int*>(addr);
enforce turns a profile on for a translation unit; require can demand one on an import; suppress is the local escape hatch, scoped to a statement and forced to carry a justification string. The asymmetry is deliberate. As Dos Reis puts it, the purpose of profiles is to enforce additional rules, not to opt out of existing ones, so enforcement is broad and suppression is narrow and loud.
Two profiles to enforce
Stroustrup brought two concrete profiles built on that framework.
P4222, “An initialization profile” has one job: “every object is initialized or noted by the compiler not to be,” and “an object that is uninitialized cannot be read.” It is fully compile-time enforced, and backward-compatible: code that already initializes everything means exactly the same thing with the profile on. When you genuinely want uninitialized storage, you say so:
[[profiles::enforce(std::initialization)]];
int x; // diagnosed: could be read uninitialized
[[uninitialized]] char buf[N]; // explicitly opted out, intentional
P3984, “A type-safety profile” is the broader one, pursuing two guarantees: every object is used according to its type, and no resource is leaked. It works by composing smaller companion profiles: casting (no old-style unverifiable casts), union (use std::variant instead of raw unions), ranges (all subscripting and pointer arithmetic range-checked), and arithmetic (no implicit narrowing, overflow, or underflow). The model Stroustrup keeps returning to: subset a superset of C++. Add safe facilities, then statically forbid the unsafe ones.
These are still moving. Per the trip report, SG23 is building the formal specification, with the profiles targeting C++29 or a concurrent white paper. But the framework now has syntax you can read, which is further than “profiles” has ever been.
The contract C++26 left behind
The cleanest single adoption for anyone who followed the contracts saga: P3097, “Contracts for C++: Virtual functions” (Doumler, Berne).
C++26 shipped contracts (pre, post, contract_assert) with four evaluation semantics (ignore, observe, enforce, quick_enforce). But virtual functions were cut from that MVP at Hagenberg in early 2025. The reason, from the paper itself: the design drew objections that it diverged from the inheritance model in Eiffel and D and lacked deployment experience, and EWG could not resolve the disagreement in time, so C++26 shipped contracts without virtual-function support.
P3097 brings them back, and the key decision is what it does not do: there is no implicit inheritance of assertions. An override’s contracts are independent of the function it overrides.
struct Base {
virtual int f(int x) pre(x > 0) post(r: r >= 0);
};
struct Derived : Base {
int f(int x) override
pre(x > 1) // independent -- NOT inherited from Base::f
post(r: r > 0);
};
On a virtual call, the assertions of both the statically chosen function and the final overrider are evaluated. Eiffel-style automatic inheritance was rejected on purpose: it interacts badly with type erasure, and base and derived classes often live in separate libraries that have to evolve independently. The re-proposal rebases its wording on the finished C++26 draft and ships with a complete implementation in GCC, which is a large part of why it was ready to move where it was not in 2025.
A fuller treatment of the C++26 contracts model itself (the four semantics, the migration path) is coming to the wro.cpp toolset later this summer. The Brno news is narrower and satisfying: the one piece the MVP deferred is already on its way back.
The shape of C++29
Put the three Brno safety threads together and the next standard’s outline is visible. The UB catalogue enumerates what to fix. Profiles give you an opt-in switch to enforce the fixes a translation unit at a time. Contracts (now including the virtual-function piece) give you the runtime checks the UB program leans on. C++26 was the features release. C++29 is being built, deliberately, as the safety one.
Sources: Herb Sutter, Brno trip report (June 13, 2026). P3589R2, C++ Profiles: The Framework (Dos Reis). P4222R0, An initialization profile (Stroustrup). P3984R0, A type-safety profile (Stroustrup). P3097, Contracts for C++: Virtual functions (Doumler, Berne; latest published revision R1, the trip report cites a newer one). C++26 contracts MVP: P2900R14. Brno dispositions are from Sutter’s report; other trip reports had not published at the time of writing.