Now, I'd like to briefly reply directly to your questions here. I hope that helps.
On 24 Sep 2025, at 17:06, Harald Achitz via SG21 <sg21@lists.isocpp.org> wrote:
Will it be easily manageable to tell the linker: hey, give me
libfoo with contract assertions enabled, and that is using this
special contract handler? And get an error if libfoo in that
flavor is not available, but only in others other configuration.
You may have the wrong mental model here.
When the compiler compiles your code, it decides which semantic (ignore, observe, enforce, or quick-enforce) to apply to which contact assertion and how. The compiler will give you some build flags to guide that decision. Typically this is just a flag like -fcontract-semantic=ignore / enforce / etc. which sets all assertions in that TU to the same chosen semantic — that's what we have implemented in GCC and Clang now — but more interesting options like "enforce all preconditions, ignore all postconditions" or "insert a branch/hook for every assertion and delay the decision whether to check it until link time or runtime" are certainly possible (the latter is currently being prototyped in GCC). In case compilers eventually choose to ship these more advanced options, they will give you flags to select those options.
Now, the correct mental model to think about contract semantics is that whatever compiler flags end up controlling them, they work just like every other build flag we have today. There is no new magic of any kind going on. To make this really obvious, consider build flags like -ftrapv or -fwrapv or flags to instrument your translation unit with ASan or MSan. All these build flags preserve the ODR but change what your code does when there is a bug. A flag like -fcontract-semantic=enforce that enables contract checks does exactly the same thing, and interacts with the rest of the toolchain in exactly the same way.
So to come back to your question: no, you can't "tell the linker to give me libfoo with contract assertions enabled" just like you can't tell the linker to give you libfoo compiled with any other compiler-specific build flag that the owner of libfoo may or may not have chosen to use when they compiled it. Instead, you get libfoo compiled in whichever way the owner of libfoo compiled libfoo (ideally they have thought about what is best for their users), and then you get to link against that libfoo and rely on ABI compatibility to get a working program in the end. This is what we've been doing for the last 50 years. Contracts do not introduce anything new here, and they do not change anything about how toolchains and linkers work.
Now, there is one interesting caveat here: further down the line, vendors may come up with new compiler and linker technology where the linker is somehow aware of the contract semantic (we can't do it through name mangling as all pointers to the same function still need to compare equal – we'd have to do it through some kind of side channel), and you could potentially do stuff like what you describe. To my best knowledge, we do not have that technology today. Importantly, C++26 contract assertions are specified in such a way that they allow such technology (and you'll be able to do more interesting things if and when that technology becomes available), but do not require it. They must not require it, because:
1. If a new language feature requires new tooling in order to be usable, the result will be that the feature simply won't be adopted by the community (see Modules) so that's a non-starter. A new language feature must be compatible with existing toolchains.
2. Even in a brave new world where new toolchains exist that are aware of contract semantics across different object files, you might still have to link against binaries that have been compiled before such technology existed, with whatever contract semantic baked into them at that time. That's just the same ABI compatibility problem we always had to deal with. Note that most people don't compile their entire program from source – at the very least you have to link against system libraries.
or is it only easily manageable when
you build the whole source tree including dependencies with
profiles / tripplets, or what ever your control file is.
Indeed, if you get to build the whole source tree then (and only then) do YOU get to decide the contract semantic for all the assertions in your program, but as I said above I don't expect this to be the case for most people (maybe some large tech companies).
If you want to provide binary dependencies, does that mean you
need to have each build in 4 variations, per contract variations.
If you want to provide binary dependencies, then you get to choose what's best for your users. You can compile your binaries with all assertions ignored (if you don't want your users to pay the runtime cost of checking them), or you can compile them with quick_enforce (if your checks are security-critical) or if you ship two binaries already such as debug + release, you can ship debug with assertions enforced and release with assertions ignored. Or you can ship four binaries if you think your users need that flexibility and are willing to pay the price for it.
The main thing to understand here is that you have to let go of the idea that the person compiling the final program can somehow control the evaluation semantics of all the assertions in the program including those object files they did not compile themselves. That's not how the compilation model of C++ works, or has ever worked. Note that this has *nothing* to do with the specific design in the C++26 working draft, but would be equally true for any viable assertion facility in C++, or in fact any facility that changes how C++ code gets compiled into machine code based on a build option.
And is it even possible to have
different contract handlers set, in dependencies, or do people
make that up?
People make that up. In C++26, there is always exactly one contract-violation handler for the entire program. The story here is the same as for user-defined global operator new/delete. There may be *one* case where you get more than one handler (again, same as for global operator new/delete): you have a dynamic library which has internal linkage for all its symbols and does not expose any of them to the program loading it (other than through a C interface), as is commonly done for plug-ins. in that case the plug-in would end up with its own handler. But that case is well outside of the scope of the C++ Standard.
What will, for example, Linux
distributions add to their build, will it be implementation
defined?
Linux distributions will add to their build whatever they consider best for their users. Do any of them distribute "cassert ON" and "cassert OFF" builds? If they don't do that today, then my guess is that they won't start doing it with contract assertions, either. Remember, contract assertions are not magic, fundamentally they are just "assert" with a few more bells and whistles that make them more usable at scale.
And I can tell from the binary in the system what it is.
No.
If such questions have been discussed, is there some
documentation to read up on the outcome?
There is P2899R1 which contains references to everything, there is also P3321 which has been discussed by SG15 in Wroclaw (no concerns were raised there), and there will be a new paper in the October mailing summarising all this more concisely. Meanwhile, was this email helpful?
Now I'd like to also comment on a few things other folks posted on this thread: