On 2025-09-24 15:36, René Ferdinand Rivera Morell wrote:
The
Swedish SC22 mirror committee TK611/AG09 has discussed the
current
working draft of C++26 and identified concerns regarding
contract
assertions. We have summarized these in the attached
document.
As convener, I see it as my duty to mediate these concerns.
I would
therefore appreciate guidance on how to proceed and to
ensure that our
experts’ concerns, as well as similar concerns from others,
are taken
into account.
From
the comments:
Contracts introduce
several new build configurations. The impact on the build
system and binary
dependency management has not received sufficient focus.
I
personally don't remember any concerns by build and
packaging ecosystem experts on this subject when it's been
discussed. Contracts mirror existing practice for binary
linking and is easily managed with existing build systems
and package managers.
--
-- René
Ferdinand Rivera Morell
-- Don't Assume Anything -- No Supongas Nada
-- Robot Dreams - http://robot-dreams.net
Thanks for the reply. Rene
Having some interest on the build issue myself, I would be
thankful to learn about the following topics:
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.
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.
If you want to provide binary dependencies, does that mean you
need to have each build in 4 variations, per contract variations.
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). The actual contract evaluation mode is then selected in a compiler-specific mechanism from among those that are available. When such a contract then fails and goes to the contract violation handler, it will go to the globally set contract violation handler. That's either the default, or whichever your program provides, but only one at link time. Usual link time rules work here.
So to be a conforming compiler it's 100% legal to compile your code to be able to check contracts, be able to call a violation handler, be able to terminate, and to do whichever of those based on a runtime selection which mechanism should be used. This has the obvious disadvantage of not allowing the optimizer to do much - it will have to leave all the checks in, making it not much better than the old version with manual asserts and iterator debugging, and likely to be slow.
Compilers (and linkers) can do smarter things though. To start, they can use knowledge of invariants and function preconditions to optimize out checks to functions called from this one. They can emit function entry points that are beyond the pre-check of the function (see P3267 $3.3). They can offer compiler flags that omit the ability to skip a contract, or omit the ability to not terminate when it fails. This allows the compiler to emit faster code and optimize better, at the expense of requiring all of its output to be compiled in the same way.
Which is exactly how we have done this so far all the time. We can have our code run on all i386, or we can turn on AVX2 and run only on machines that support that.
If you want the maximally compatible variant, use the first strategy. If you want a faster implementation, use it in the way that that implementation specifies you do. ABIs can be created and modified to make any violation a linker failure, but the language doesn't at this point say anything about how the build tools and compiler optimize. There are papers scheduled for C++29 (P3400 for example) that do go into these details, so for P3400 this is definitely a point to bring up.
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. The function would be linked in in much the same way that other functions would be found. If your operating system does weird things here then maybe? - I know that Apple does not use a flat namespace, so that might result in this in one way or another. This is completely out of scope of the C++ standard though, and fully down to platform specifics on how they do dynamic linking and finding symbols.
What will, for example, Linux
distributions add to their build, will it be implementation
defined? And I can tell from the binary in the system what it is.
P3267 provides some approaches that work. They have their own up- and downsides. My personal preference is the 3rd approach listed, which expands the ABI but keeps all guarantees intact while allowing major optimization to happen. I do know that neither the current Clang nor GCC implement it in this approach, as it will also involve an ABI change (albeit one that is 100% invisible to software that does not understand C++ contracts)
Whether Linux distributions will limit libraries to be more optimized and only be runnable with terminating contract checks, or slower with observe semantics - I have no idea. That's a choice the distribution gets to make.
> Except on Windows you might, which is yet another unanswered question in the face of lack of both implementation and deployment experience.
It would help if the prevalent Windows compiler would implement contracts so that we could get this experience. Sadly, it is not available cross platform nor open source, making it impossible for others to do this for them.
Peter