Date: Wed, 19 Aug 2026 00:37:05 +0100
On 18/08/2026 23:25, Peter Bindels wrote:
> Hi Jonathan,
>
> On Tue, Aug 18, 2026 at 11:30 PM Jonathan Grant <jgrantonline_at_[hidden] <mailto:jgrantonline_at_[hidden]>> wrote:
>
> > compile_assert, if I understand it correctly, is identical to contracts in P2900 when set up to have a C++ library that does not implement its violation handler function. Your program will link if and only if it could be proven during compilation. That already works like that - in fact, I at first didn't notice I had forgotten to switch over to my experimental libc++ until it failed to link after adding a few contracts. The first few in the places they were called were always true and didn't emit a symbol to link to in the first place.
> >
>
> compile_assert() is eloquent, just a few lines of code, it uses the compiler's internal knowledge and exposes it to the programmer, compile_assert isn't present in any compiled code. The sample works in GCC since version 4.5.3 (2011). The Linux Kernel has had similar for over a decade. So my proposal would standardize existing use.
>
> Matt Borland's SafeNumbers uses compile_assert for Compile Time Pre-Condition checks
> https://develop.safe-numbers.cpp.al/compile_time_checks.html <https://develop.safe-numbers.cpp.al/compile_time_checks.html>
>
> I've read P2900 C++ Contracts and it's very different. P2900 is a very large specification and at runtime.
>
> It's a functional safety concern to have runtime behaviour in callbacks, and ignore. observe - continuing means the issue is missed, enforce - very difficult to recover from such a callback - far better to identify such bugs at compile-time. quick-enforce, is just std::terminate()?
>
> On top of the simple statement form of compile_assert() it's possible to implement more advanced Rust style ownership models, optionality etc. P2900 does look very large for what could can be achieved at compile-time in a few lines. Compile-time Contracts I put in one of the testsuite files was 3 lines of code on top of compile_assert().
>
> Maybe with your knowledge and experience of P2900 C++ Contracts you'd like to see the compile_assert example of contracts? It's here on godbolt, see it find the bugs at compile time on lines 78 and 79.
>
> https://godbolt.org/z/9P731ozzz <https://godbolt.org/z/9P731ozzz>
>
>
> https://godbolt.org/z/PTMbMY1MW <https://godbolt.org/z/PTMbMY1MW> is the same in P2900, on the stock GCC 16.1 that you also used. I made a custom violation handler that calls a nonexistent function called "failed to prove" if the compiler fails to prove them. It behaves the same as your example, and similarly relies on the optimizer to accomplish this. P2900 has different ways to be usable, and this is one of them. It's not one that I think most people will want to use, because of fragility, but it definitely works. This is also the approach I described in the previous message, see above. The contract violation handler is defined inline to make the compiler not output a copy if it's not used; otherwise it functions as described.
I think you've shared this before, I recall speaking on this list a few months ago. I see missing symbol error in the P2900 example, which isn't as good as compile_assert() achieves, and compile_assert works in GCC since version 5.
/tmp/cchKdbjo.o: in function `handle_contract_violation(std::contracts::contract_violation const&)':
<source>:86:(.text.startup+0x72): undefined reference to `failed_to_prove()'
Missing symbol is the fallback method I use for MSVC support in compile_assert().
Can you see a use-case for P2900 runtime callbacks?
It looks like P2900 doesn't offer advantages over compile_assert() in the detection of the issues, it doesn't show file and line like compile_assert does. Now you have tried out compile_assert, you can see it is a a useful direction? It's elegantly simple.
>
> For a targeted embedded target this is probably usable. For any general use it is not.
>
>
> > With regards to proving things at compile time, the current definition of contracts is enough for simple assertions. Anything that is too complicated (lamdbas, usually) or that passes through an opaque interface that the compiler cannot see into, cannot be optimized. In particular, a sequence f(g(x)) where both g(x) has a postcondition r:p(rv) and f(r) has a precondition p(r), cannot forward the result of a postcondition on g(x) to f, as there is no way to explain that evaluating p with the same argument twice will do the same thing twice. For repeated checks on a precondition we have taken that allowance into the standard, but for this specific situation we'd need something like [[reproducible]] or [[unsequenced]] as in C.
> >
>
> Do you mean though abstract base classes with virtual functions?
>
> compile_assert works through APIs, but I have not tried opaque interfaces. It might work.
>
>
> No, this is for general function contracts. Compilers cannot in general look into functions unless they are available to the compiler to use (without runtime substitutability, see also gcc bugs) or are sufficiently clear from their declaration (ie, reproducible, unsequenced, return-type constrained or some such).
>
Maybe you can give an example of a function contract with compile_assert() checking it?
I have some multi-file compile_assert examples, and LTO you could try out for those use-cases.
> > Beyond that, I know that multiple different groups of people are looking into what specifically we can do with contracts as specified, and what we'd need to change or add. So far the results seem to be that it works well enough, but that with minor tweaks we can make it more powerful. A hypothetical [[mustprove]] attribute could exist in a compiler, requesting it to fail the build if it cannot prove a functions' calls' pre-contracts, and its postcontract, based on its own pre-contracts and its calls' postcontracts. Basically, asking the compiler to do the Hoare propagation and seeing if it connects, at a semantic level that would need to be done early on in a compiler. Given such information, depending on build modes, a compiler can just remove all checks in that function, as there's no way they don't hold. Will never be able to do all code - but if it can do 95% of the code, I'll happily review or rewrite the remaining 5%. Think of it like a borrow checker for the
> guarantees
> > that brings, except functional safety (and whatever memory safety was expressed in contracts).
> >
>
> I implemented an Ownership class borrow checker with a few lines of code using compile_assert(), at compile-time.
>
> Sir Tony Hoare gave a good presentation, may I ask if you have seen this one?
> The 1980 ACM Turing Award Lecture
> The Emperor's Old Clothes
>
> Tony Hoare wrote about PL/1 and ADA, how they got bigger, more complicated. Tony Hoare spoke about simplification of programming languages, taking a subset when referring to ALGOL, ADA and other projects from his career.
>
>
> I'm very much on board with restricting C++ in ways that allow the inner core to get out and be a future language - see also P3716 (subsetting), P4314 (on activating a profile) and at least 10 other papers in the past three years all targeted at having a future C++ that contains less features you're going to find, and more constructs that allow you to write code safely. The old adage - make it easy to use and hard to misuse - is the one where we have to provide the tools so that our users can implement it. They need ways to check that what people pass in is actually correct, that the intermediate results make sense, that the return values comply with what the function promises, that users don't use overly-powerful constructs or outdated strategies like reinterpret_cast and strncpy in any new code, so that we will end up with a new environment where functions are always called in contract, where outmoded and outdated constructs are not usable in new code, and where we can move
> towards compile-time proving as much as possible. In a way, profiles *is* compile-time proving that a given guarantee holds, not actually too dissimilar in spirit from compile-time proving contracts, just with a wider scope.
>
The difficulty (as I see it), by adding P2900 it becomes far more complicated for your P3716 subset proposal. It then it uses up a lot of time to create a subset. Often things are so intertwined together that it is not possible to take a subset, and all the header files are modified to have C++ Contracts specified.
Re the adage, when misuse is detected at compile-time, the programmer can make the fix so there isn't accidental misuse. Because P2900 has 4 runtime modes, the issues may not be identified at compile-time directly.
>
>
> I'll share a quote:
>
> "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies."
>
>
> It is one of my favorites. So much software, especially today, is being built by adding much more code that eventually it'll kinda run, but nobody has any idea what goes where. I prefer his second option; make software that cleanly separates responsibilities such that it's obviously correct.
>
> > But let's first see what happens with the C++26 DIS. If you want to form an opinion on how well it works, try it out - godbolt, local install - and form your own opinion. And if you'd like it to have more features maybe consider not voting against for that reason. That's not going to get you more features - it's only going to cause more turbulence and delay.
> >
>
> Tony Hoare was keen on subsets, simple features, I feel similar, my preference I rather it was far smaller and at compile-time, without any runtime behaviour. A contract is a compile-time proof obligation, it should not have runtime behaviour. Tony Hoare suggested to resist features whose complexity exceeds our ability to understand their consequences. ie my objection is not against Hoare Logic Contracts in C++; it's an objection to making the technological mechanics of expressing Contracts a runtime model.
>
> May I ask your viewpoint - would you consider if the design of C++ Contracts were simpler, compile-time only, without any runtime behaviour/callbacks would that be more useful for programmers?
>
>
> If it only did compile-time checks, it would be unsuitable for 95%+ of them. For the remaining 5% it'd be better, if only by virtue of being simpler.
Could you share some examples of some of those 95%+ checks that can't be compile_assert at compile-time please.
>
> P2900 allows it to be proven at compile time (just under as-if rule), see above. It allows it to spill to runtime. It has defined mechanisms to change from "enforce" to some other semantic, and the predefined ones that we know people use now and will want to use, even if you should never want to use them.
>
That "spill to runtime" is what compile_assert() specifically avoids.
Constraints silently moving to runtime checks is a Functional Safety concern, as "enforce" they then make a callback. And then what does a callback do when an array subscript is violated in a crucial image decoder?
At runtime the decoder cannot be fixed - probably the programmer then needs to spend time developing, and testing a mechanism to shutdown the module and retry?
But when it is restarted, the image decoder will again suffer the same array subscript error, and call the handler again. Imagine it was compile-time only, the programmer would have fixed it - there would be no issue, and no time lost writing a recovery mechanism.
compile_assert() is a significant developer time-saver, because all these bugs never get into production code. There's no coredump or log file, because the buggy software never got to run in a car, or airplane. For businesses the capability of compile_assert() would avoid them losing money, there are less product recalls, and less customers complaining their car is back in the garage, or needing a software update. Businesses like to avoid losing money. Microsoft said 70%+ of bugs are due to C style memory issues, compile_assert can go towards preventing a whole bunch of these if used.
Do you have experience working in functional safety, safety critical software?
I saw GCC sets the evaluation semantic per file, rather than per constraint. -fcontract-evaluation-semantic=enforce which is then complicated, programmers need to set up each file differently, and what if they want some of the different four modes in C++ code in the same file.
It doesn't sound straight-forward, it sounds so complicated that there are no obvious deficiencies, as Tony Hoare might say, if he was still with us. P2900 doesn't make things simple, it has four different modes, it doesn't have the most useful mode.
> ---
>
> With regards to a comment Ville made, apparently there has been a Windows-available build of GCC for a while now; I could find four flavors of a GCC build that runs contracts, and a number of people that use Windows that found that they were already using a contracts-supporting compiler. So that has existed, even for Windows users that want Windows-executable outputting compilers, for a few months. I didn't respond earlier because I haven't used it in years and have no idea on what state the platform is in.
>
> Best regards,
> Peter Bindels
Best regards
Jonathan
> Hi Jonathan,
>
> On Tue, Aug 18, 2026 at 11:30 PM Jonathan Grant <jgrantonline_at_[hidden] <mailto:jgrantonline_at_[hidden]>> wrote:
>
> > compile_assert, if I understand it correctly, is identical to contracts in P2900 when set up to have a C++ library that does not implement its violation handler function. Your program will link if and only if it could be proven during compilation. That already works like that - in fact, I at first didn't notice I had forgotten to switch over to my experimental libc++ until it failed to link after adding a few contracts. The first few in the places they were called were always true and didn't emit a symbol to link to in the first place.
> >
>
> compile_assert() is eloquent, just a few lines of code, it uses the compiler's internal knowledge and exposes it to the programmer, compile_assert isn't present in any compiled code. The sample works in GCC since version 4.5.3 (2011). The Linux Kernel has had similar for over a decade. So my proposal would standardize existing use.
>
> Matt Borland's SafeNumbers uses compile_assert for Compile Time Pre-Condition checks
> https://develop.safe-numbers.cpp.al/compile_time_checks.html <https://develop.safe-numbers.cpp.al/compile_time_checks.html>
>
> I've read P2900 C++ Contracts and it's very different. P2900 is a very large specification and at runtime.
>
> It's a functional safety concern to have runtime behaviour in callbacks, and ignore. observe - continuing means the issue is missed, enforce - very difficult to recover from such a callback - far better to identify such bugs at compile-time. quick-enforce, is just std::terminate()?
>
> On top of the simple statement form of compile_assert() it's possible to implement more advanced Rust style ownership models, optionality etc. P2900 does look very large for what could can be achieved at compile-time in a few lines. Compile-time Contracts I put in one of the testsuite files was 3 lines of code on top of compile_assert().
>
> Maybe with your knowledge and experience of P2900 C++ Contracts you'd like to see the compile_assert example of contracts? It's here on godbolt, see it find the bugs at compile time on lines 78 and 79.
>
> https://godbolt.org/z/9P731ozzz <https://godbolt.org/z/9P731ozzz>
>
>
> https://godbolt.org/z/PTMbMY1MW <https://godbolt.org/z/PTMbMY1MW> is the same in P2900, on the stock GCC 16.1 that you also used. I made a custom violation handler that calls a nonexistent function called "failed to prove" if the compiler fails to prove them. It behaves the same as your example, and similarly relies on the optimizer to accomplish this. P2900 has different ways to be usable, and this is one of them. It's not one that I think most people will want to use, because of fragility, but it definitely works. This is also the approach I described in the previous message, see above. The contract violation handler is defined inline to make the compiler not output a copy if it's not used; otherwise it functions as described.
I think you've shared this before, I recall speaking on this list a few months ago. I see missing symbol error in the P2900 example, which isn't as good as compile_assert() achieves, and compile_assert works in GCC since version 5.
/tmp/cchKdbjo.o: in function `handle_contract_violation(std::contracts::contract_violation const&)':
<source>:86:(.text.startup+0x72): undefined reference to `failed_to_prove()'
Missing symbol is the fallback method I use for MSVC support in compile_assert().
Can you see a use-case for P2900 runtime callbacks?
It looks like P2900 doesn't offer advantages over compile_assert() in the detection of the issues, it doesn't show file and line like compile_assert does. Now you have tried out compile_assert, you can see it is a a useful direction? It's elegantly simple.
>
> For a targeted embedded target this is probably usable. For any general use it is not.
>
>
> > With regards to proving things at compile time, the current definition of contracts is enough for simple assertions. Anything that is too complicated (lamdbas, usually) or that passes through an opaque interface that the compiler cannot see into, cannot be optimized. In particular, a sequence f(g(x)) where both g(x) has a postcondition r:p(rv) and f(r) has a precondition p(r), cannot forward the result of a postcondition on g(x) to f, as there is no way to explain that evaluating p with the same argument twice will do the same thing twice. For repeated checks on a precondition we have taken that allowance into the standard, but for this specific situation we'd need something like [[reproducible]] or [[unsequenced]] as in C.
> >
>
> Do you mean though abstract base classes with virtual functions?
>
> compile_assert works through APIs, but I have not tried opaque interfaces. It might work.
>
>
> No, this is for general function contracts. Compilers cannot in general look into functions unless they are available to the compiler to use (without runtime substitutability, see also gcc bugs) or are sufficiently clear from their declaration (ie, reproducible, unsequenced, return-type constrained or some such).
>
Maybe you can give an example of a function contract with compile_assert() checking it?
I have some multi-file compile_assert examples, and LTO you could try out for those use-cases.
> > Beyond that, I know that multiple different groups of people are looking into what specifically we can do with contracts as specified, and what we'd need to change or add. So far the results seem to be that it works well enough, but that with minor tweaks we can make it more powerful. A hypothetical [[mustprove]] attribute could exist in a compiler, requesting it to fail the build if it cannot prove a functions' calls' pre-contracts, and its postcontract, based on its own pre-contracts and its calls' postcontracts. Basically, asking the compiler to do the Hoare propagation and seeing if it connects, at a semantic level that would need to be done early on in a compiler. Given such information, depending on build modes, a compiler can just remove all checks in that function, as there's no way they don't hold. Will never be able to do all code - but if it can do 95% of the code, I'll happily review or rewrite the remaining 5%. Think of it like a borrow checker for the
> guarantees
> > that brings, except functional safety (and whatever memory safety was expressed in contracts).
> >
>
> I implemented an Ownership class borrow checker with a few lines of code using compile_assert(), at compile-time.
>
> Sir Tony Hoare gave a good presentation, may I ask if you have seen this one?
> The 1980 ACM Turing Award Lecture
> The Emperor's Old Clothes
>
> Tony Hoare wrote about PL/1 and ADA, how they got bigger, more complicated. Tony Hoare spoke about simplification of programming languages, taking a subset when referring to ALGOL, ADA and other projects from his career.
>
>
> I'm very much on board with restricting C++ in ways that allow the inner core to get out and be a future language - see also P3716 (subsetting), P4314 (on activating a profile) and at least 10 other papers in the past three years all targeted at having a future C++ that contains less features you're going to find, and more constructs that allow you to write code safely. The old adage - make it easy to use and hard to misuse - is the one where we have to provide the tools so that our users can implement it. They need ways to check that what people pass in is actually correct, that the intermediate results make sense, that the return values comply with what the function promises, that users don't use overly-powerful constructs or outdated strategies like reinterpret_cast and strncpy in any new code, so that we will end up with a new environment where functions are always called in contract, where outmoded and outdated constructs are not usable in new code, and where we can move
> towards compile-time proving as much as possible. In a way, profiles *is* compile-time proving that a given guarantee holds, not actually too dissimilar in spirit from compile-time proving contracts, just with a wider scope.
>
The difficulty (as I see it), by adding P2900 it becomes far more complicated for your P3716 subset proposal. It then it uses up a lot of time to create a subset. Often things are so intertwined together that it is not possible to take a subset, and all the header files are modified to have C++ Contracts specified.
Re the adage, when misuse is detected at compile-time, the programmer can make the fix so there isn't accidental misuse. Because P2900 has 4 runtime modes, the issues may not be identified at compile-time directly.
>
>
> I'll share a quote:
>
> "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies."
>
>
> It is one of my favorites. So much software, especially today, is being built by adding much more code that eventually it'll kinda run, but nobody has any idea what goes where. I prefer his second option; make software that cleanly separates responsibilities such that it's obviously correct.
>
> > But let's first see what happens with the C++26 DIS. If you want to form an opinion on how well it works, try it out - godbolt, local install - and form your own opinion. And if you'd like it to have more features maybe consider not voting against for that reason. That's not going to get you more features - it's only going to cause more turbulence and delay.
> >
>
> Tony Hoare was keen on subsets, simple features, I feel similar, my preference I rather it was far smaller and at compile-time, without any runtime behaviour. A contract is a compile-time proof obligation, it should not have runtime behaviour. Tony Hoare suggested to resist features whose complexity exceeds our ability to understand their consequences. ie my objection is not against Hoare Logic Contracts in C++; it's an objection to making the technological mechanics of expressing Contracts a runtime model.
>
> May I ask your viewpoint - would you consider if the design of C++ Contracts were simpler, compile-time only, without any runtime behaviour/callbacks would that be more useful for programmers?
>
>
> If it only did compile-time checks, it would be unsuitable for 95%+ of them. For the remaining 5% it'd be better, if only by virtue of being simpler.
Could you share some examples of some of those 95%+ checks that can't be compile_assert at compile-time please.
>
> P2900 allows it to be proven at compile time (just under as-if rule), see above. It allows it to spill to runtime. It has defined mechanisms to change from "enforce" to some other semantic, and the predefined ones that we know people use now and will want to use, even if you should never want to use them.
>
That "spill to runtime" is what compile_assert() specifically avoids.
Constraints silently moving to runtime checks is a Functional Safety concern, as "enforce" they then make a callback. And then what does a callback do when an array subscript is violated in a crucial image decoder?
At runtime the decoder cannot be fixed - probably the programmer then needs to spend time developing, and testing a mechanism to shutdown the module and retry?
But when it is restarted, the image decoder will again suffer the same array subscript error, and call the handler again. Imagine it was compile-time only, the programmer would have fixed it - there would be no issue, and no time lost writing a recovery mechanism.
compile_assert() is a significant developer time-saver, because all these bugs never get into production code. There's no coredump or log file, because the buggy software never got to run in a car, or airplane. For businesses the capability of compile_assert() would avoid them losing money, there are less product recalls, and less customers complaining their car is back in the garage, or needing a software update. Businesses like to avoid losing money. Microsoft said 70%+ of bugs are due to C style memory issues, compile_assert can go towards preventing a whole bunch of these if used.
Do you have experience working in functional safety, safety critical software?
I saw GCC sets the evaluation semantic per file, rather than per constraint. -fcontract-evaluation-semantic=enforce which is then complicated, programmers need to set up each file differently, and what if they want some of the different four modes in C++ code in the same file.
It doesn't sound straight-forward, it sounds so complicated that there are no obvious deficiencies, as Tony Hoare might say, if he was still with us. P2900 doesn't make things simple, it has four different modes, it doesn't have the most useful mode.
> ---
>
> With regards to a comment Ville made, apparently there has been a Windows-available build of GCC for a while now; I could find four flavors of a GCC build that runs contracts, and a number of people that use Windows that found that they were already using a contracts-supporting compiler. So that has existed, even for Windows users that want Windows-executable outputting compilers, for a few months. I didn't respond earlier because I haven't used it in years and have no idea on what state the platform is in.
>
> Best regards,
> Peter Bindels
Best regards
Jonathan
Received on 2026-08-18 23:37:14
