Date: Fri, 26 Sep 2025 10:12:37 +0300
Hi all, and apologies for being late to the party here.
Harald, you are asking excellent questions, and I want to make sure you (and everyone else) get clear answers to them.
All of this has been discussed before and can be found in published papers, but it is admittedly a lot of material and history to go through and the answers can be hard to find. Because of this, I and others are putting together a new consolidated paper for the October mailing with clear and concise answers to the questions that the latest papers and NB comments (including yours) are raising.
Harald, to help make this happen, can you please give me permission to quote, in that upcoming paper, the document you shared here? Please give it a paper number or NB comment number that I can cite directly and let me know what that number is. Thanks!
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_at_[hidden]> 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:
> On 24 Sep 2025, at 17:26, Ville Voutilainen via SG15 <sg15_at_[hidden]> wrote:
> The C++26 Contracts do not support per-library violation handlers. But
> on Windows you may end up getting such.
Ville, are you referring to the usual thing with DLLs here (which I mentioned above) or is there something else going on here that I'm not aware of?
> On 24 Sep 2025, at 17:35, Peter Bindels via SG21 <sg21_at_[hidden]> wrote:
> First of, the point of view of the standard. As far as the standard is concerned, the compiler outputs a binary that is able to evaluate all contract evaluation modes that should be possible (pending a compiler-specific mechanism to choose this).
That doesn't sound right. As Ville correctly said, there is no such thing in the Standard. As I said above, this is one possible implementation strategy, and one that is currently being prototyped in GCC, but it's not what we have by default in GCC and Clang today and I don't expect it to ever be the default (as it would mean potential runtime overhead on ignored assertions, which would be a dealbreaker for many people).
>>> And is it even possible to have different contract handlers set, in dependencies, or do people make that up?
>> I have no idea where such an idea would come from.
>
> That a particular piece of code would like to define how violations in
> it or in the code it calls are handled? The section "Local Violation
> Handlers"
> in P3400?
Ville, P3400 is a potential C++29 extension, which is not the topic of discussion here. We're talking about what's in the C++26 working draft, where the contract-violation handler is always global (with the DLL caveat).
If anyone on this thread has any further questions, clarifications, or suggestions, please let me know – this is all very helpful as I want to make sure our upcoming paper covers any concerns people have at this point.
Thanks,
Timur
Harald, you are asking excellent questions, and I want to make sure you (and everyone else) get clear answers to them.
All of this has been discussed before and can be found in published papers, but it is admittedly a lot of material and history to go through and the answers can be hard to find. Because of this, I and others are putting together a new consolidated paper for the October mailing with clear and concise answers to the questions that the latest papers and NB comments (including yours) are raising.
Harald, to help make this happen, can you please give me permission to quote, in that upcoming paper, the document you shared here? Please give it a paper number or NB comment number that I can cite directly and let me know what that number is. Thanks!
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_at_[hidden]> 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:
> On 24 Sep 2025, at 17:26, Ville Voutilainen via SG15 <sg15_at_[hidden]> wrote:
> The C++26 Contracts do not support per-library violation handlers. But
> on Windows you may end up getting such.
Ville, are you referring to the usual thing with DLLs here (which I mentioned above) or is there something else going on here that I'm not aware of?
> On 24 Sep 2025, at 17:35, Peter Bindels via SG21 <sg21_at_[hidden]> wrote:
> First of, the point of view of the standard. As far as the standard is concerned, the compiler outputs a binary that is able to evaluate all contract evaluation modes that should be possible (pending a compiler-specific mechanism to choose this).
That doesn't sound right. As Ville correctly said, there is no such thing in the Standard. As I said above, this is one possible implementation strategy, and one that is currently being prototyped in GCC, but it's not what we have by default in GCC and Clang today and I don't expect it to ever be the default (as it would mean potential runtime overhead on ignored assertions, which would be a dealbreaker for many people).
>>> And is it even possible to have different contract handlers set, in dependencies, or do people make that up?
>> I have no idea where such an idea would come from.
>
> That a particular piece of code would like to define how violations in
> it or in the code it calls are handled? The section "Local Violation
> Handlers"
> in P3400?
Ville, P3400 is a potential C++29 extension, which is not the topic of discussion here. We're talking about what's in the C++26 working draft, where the contract-violation handler is always global (with the DLL caveat).
If anyone on this thread has any further questions, clarifications, or suggestions, please let me know – this is all very helpful as I want to make sure our upcoming paper covers any concerns people have at this point.
Thanks,
Timur
Received on 2025-09-26 07:13:46