Balloting has completed for C++26. Unfortunately it was Disapproved
39 points by mond
39 points by mond
tl;dr: it looks like C++ 26 got turned down by the national bodies (afaik unprecedented)
From looking around, it seems this was due to controversy regarding contracts? It almost seems like a political split going on there, with some people blaming the standards bodies and others blaming WG21 but all with somewhat fuzzy reasons. I'm curious if anyone has some info on the disagreements who isn't actually deep enough in this to have taken a side already?
EDIT: Okay wow, so there's P4334r0 which complains about contracts, a now-archived petition encouraging the DIS vote to fail, and P4433r0 (confusing numbering, much?) which argues that P4334r0 and the petition are incorrect. There's a lotta history here, huh...
My understanding is that Bjarne has been going around trying to prevent contracts from going in. I think he's right on this one (even though I otherwise largely disagree with him wrt profiles), but it's very hard for me to tell whether blocking the standard with the national bodies is remotely worth it or proportional.
No clue what happens next! I assume the ideal would be that contracts get thrown out, then they redo the vote and the standard passes, and hopefully this happens relatively quickly? Worst case would be that there'll be no C++26?
No clue what happens next!
It’s complicated and I don’t fully understand it. Apparently individual member bodies can ratify and publish it, so what happens if ANSI ratifies it but ISO doesn’t? There’s now a C++26 but it isn’t an ISO standard. Fun times. If there is no ratified ISO standard, the current draft remains the working draft, so the next ISO standard will be based on it. There’s no process for accepting the standard with contracts removed.
I am one of the people strongly objected to contracts and regard it as a disaster for the language, but I gave up engaging (and did not vote in my national body vote) because I lost faith in the process as something able to produce a good outcome. My engagement is now very narrowly focused on trying to make sure that we have sensible definitions of pointer behaviour.
It’s complicated and I don’t fully understand it. Apparently individual member bodies can ratify and publish it, so what happens if ANSI ratifies it but ISO doesn’t? There’s now a C++26 but it isn’t an ISO standard. Fun times. If there is no ratified ISO standard, the current draft remains the working draft, so the next ISO standard will be based on it. There’s no process for accepting the standard with contracts removed.
My current guess (based on nothing) is that the draft will be sent back to WG21, has a chance to be amended (either removing or affirming contracts), and will then get another vote by the national bodies. Do you think that's likely?
My engagement is now very narrowly focused on trying to make sure that we have sensible definitions of pointer behaviour.
Probably unrelated to this discussion, but I'd be interested to hear what you're working on here. Is this a pointer provenance thing? Is it about ensuring CHERI compatibility? I didn't know there's any "open discussions" on pointer behavior in C++, I figured most of this would be completely set in stone.
Probably unrelated to this discussion, but I'd be interested to hear what you're working on here. Is this a pointer provenance thing? Is it about ensuring CHERI compatibility? I didn't know there's any "open discussions" on pointer behavior in C++, I figured most of this would be completely set in stone.
The core model is fairly uncontentious but there are other things like the semantics of intprt_t. In C, it remains optional. C++ has made it mandatory but with implementation-defined semantics. I’m working (though haven’t updated the paper for a bit) on codifying the semantics to permit both what CHERI does and a slightly more lenient model.
In particular, there are some simple things people expect. If you cast a pointer to an intprt_t and add N, then cast back, the result should be the same as if you’d cast to char*. This is not guaranteed by C or C++ but it’s such an obvious ‘of course it works that way’ thing that an implementation that didn’t preserve that property would not work for most non-trivial codebases. And, since compilers have to be able to do the right thing for char*, all implementations can do that.
Other arithmetic also needs to be defined in similar terms. In the CHERI C/C++ work, we found that the most common use of intprt_t was to align pointers up and down. That use requires masking the low bits. Again, that should be defined because it’s currently 100% implementation-defined but people assume it works (we had to make it work with CHERI C/C++ because the other option was break everything).
Beyond that, I want some feature-test macros that define whether arithmetic that takes the address to another object is defined. It doesn’t work in CHERI, but it is expected to in some low-level systems code (e.g. CPU-local storage in the FreeBSD kernel), so there needs to be a way for software to say ‘I assume this works, static assert fail if it doesn’t on thei target’.
My understanding is that Bjarne has been going around trying to prevent contracts from going in. I think he's right on this one (even though I otherwise largely disagree with him wrt profiles), but it's very hard for me to tell whether blocking the standard with the national bodies is remotely worth it or proportional.
Oh wow, yes that seems quite severe. Looking more through some of these papers, I get some of the complaints for sure (mostly that relying on them for UB checks but then letting you turn them off is going to be a mess), but some of this wording seems like contracts are solely destructive. To be frank, the standards committees have been adding dysfunctional features for a long time, and sometimes they even later get fixed, so... I'm not sure if rounding up the international standards bodies here is a proportional action.
If Stroustrup is leading the fight against it, this does kinda seem more like a political fight, where some people who oppose it don't really want to be overridden on anything (and, perhaps, some in support wishing for the opposite).
There are multiple papers and afaik talks on "why contracts are bad" , I'd look them up for references. Afaik a lot of stuff about the one definition rule, and "how do you selectively enable or disable contracts" etc. I'd look them up for references if you want to dive deeper.
That said, afaik there was "strong consensus" to get contracts in by the standard bodies.
I have not fully kept up on the current technical statusof the draft but Bjarne being actively involved (and against contracts) is afaik confirmed.
I would be very interested to watch those talks on why contracts are bad. Do you remember a name, the speaker, the conference or anything else which could be used to find them?
It’s hard to write a good critique of contracts because the spec is incredibly complex, most of it is implementation defined, and whenever you criticise one bit the advocates tell you that this is an implementation-defined choice and implementations can do the other thing. Then, in the next conversation they say the same thing but about something where both choices cannot exist in the same implementation (and then we’re told that people aren’t acting in good faith when criticising contracts, which is when I give up on the process).
This is really my biggest complaint about it. It isn’t a spec, it’s an enumeration of a large space of possible features, many of which are mutually incompatible.
This leads onto the next issue. For safety and security, the most important thing is source-level and local reasoning. If someone needs to sign off on some component meeting some requirements, the less of the global system they need to understand, the better. For contracts, the semantics may change based on implementation-defined external behaviour. They may differ depending on how some other compilation unit in the system was compiled. They may change based on later static and dynamic linker options (note: the C++ standard still pretends dynamic linking isn’t a thing, which it should really get over).
It also comes with non-composable abstractions. There is a global handler for contract violation handlers. I thought we learned from std::set_unexpected that this was a terrible idea. There is a promise from the contracts people that this will be changed in the future but no word on how that will be done in a way that avoids breaking code that deployed contracts and has then built the assumption that their handler has global visibility of failures into their assurance model for auditing, for example.
There are a bunch of related issues like this. Every modern assertions framework provides mechanisms for fine-grained control. The one in CHERIoT RTOS, for example, which is intentionally simple because it runs on embedded systems, lets you turn on and off both the verbosity of reporting and whether the checks occur at a per-subsystem granularity (which may be multiple toggles in a single file). It also has a notion of checks that will always happen but will trap on failure if the verbosity is turned off, versus ones where the check is skipped. Adding that requires a load of new syntax in places where contracts have already define syntax.
And defining new syntax at this stage is problematic. Contracts define new syntax and new semantics. There’s no effort made to ensure that the new semantics are reusable. For example, contracts introduce a notion that you can have two versions of a function that have different run-time behaviours. This is defined to not be an ODR violation, but its implementation defined what actually happens. This is a thing that would be generally useful (and would actually make C assert work in C++ headers) if the semantics were properly specified, but they weren’t. Similarly, pre- and post-conditions provide a mechanism for defining code that runs before or after a function. Python calls these decorators and they’re a very flexible and generic mechanism. Contracts define a specific kind of decorator with tightly coupled semantics.
We have no real data to support the idea that this syntax is the right one. For example, if I’m designing a clean and regular API then I probably want to apply the same contracts in a bunch of places. We already have compiler support for a bunch of ad-hoc contracts such as non-null, but these can’t use the contracts mechanism because they’re parameter attributes not function preconditions. By defining the pre- and post-condition syntax tightly coupled with the semantics, we don’t get to explore that design space. If we’d started with a permitted way of doing ODR violation and a way of writing function decorators, we could have had a standard-library (or other library!) implementation of contracts, seen how people use, it and then added special-case syntax for the most common operations. Instead, jumping to syntax with implementation-defined semantics means that we can’t do any of that.
There were claims made during the process that Microsoft had found contracts in C++ made their static analysis tooling faster. Except Microsoft never actually implemented contracts internally and the design allows contracts to call functions defined in other compilation units (and even other libraries) so this is not only incorrect with respect to what did happen, it’s also misleading about what could happen, unless you constrain your use of contracts to a tool-defined subset.
The static analysis side is quite sad. Verus in Rust uses pre- and post-conditions and is amazing. It uses a restricted subset of the language, adds the ability to carry ghost state, and lets you formally verify properties that go way beyond the Rust type system. This is explicitly out of scope for C++ contracts. They allow arbitrary C++, including calls to extern symbols, so can’t be used with a proof engine unless you explicitly define your own subset (at which point, anyone else writing contracts in a component that you use can break your code).
Which leads onto a core issue: what are contracts for? If they’re not for formal verification (where they are phenomenally useful and let you decompose proofs into tractable local properties that you can build on up and down the call stack), they’re Eiffel-style dynamic checks. And that’s a ‘90s programming style that I hoped we’d moved away from. The ‘parse don’t verify’ and ‘make invalid states unrepresentable’ shift was great for quality. C++ leaned into this: types define invariants, you check them at construction time and can then assume them through the instance’s lifetime. Building that model as the core of the system is, to my mind, the main reason that Rust code is more likely to be correct than C code. C++ is in the middle and was slowly shifting to the Rust end. Contracts are a step back.
We should be making it easier to do things like have wrapper types that are guaranteed to have the same representation as the wrapped type, for example, and allowing consteval ghost state so type-level invariants can be passed around more easily. The contracts effort had sucked all of the air out of the room for approaches that actually solve the problems that contracts claim to address.
TL;DR: P2900 Contracts are a bad solution to the wrong problem.
Every complaint in P4334 had been brought to the committee, heard and considered, prior to voting to approve contracts in C++26. It is strange that the paper didn't acknowledge this, and the fact that you appear to believe that these complaints had not been considered is why ISO CoCs expect papers to contain relevant information like that.
It's very much a shame that a paper in this state was circulated in a way that continues to mislead readers into believing that the complaints had not already been heard and considered.
and the fact that you appear to believe that these complaints had not been considered
@refi64 never said this. They literally link to a paper which says "WG21 has carefully considered each individual concern, weighed the trade-offs involved, and ultimately decided, in each case, in favour of the specification that is now in the C++26 DIS".
P4334 is useful for people like me who are out of the loop and want to understand where the disagreements lie with contracts. Clearly there's still no consensus, and plenty of people are very unhappy with contracts in their current state, and so it's nice to have some context on why that is. Just linking to a paper (alongside other papers showing the opposite side's stance!) doesn't imply that it hasn't been "heard and considered" by the committee.
Where are you getting this claim of no consensus then? Clearly you read this paper and came to the conclusion that there was no consensus, because this paper is written in a way that makes you think that.
To cite Herb Sutter's trip report[1] from croydon, first that "lack of consensus vote" to pull contracts into C++26:
In February 2025 when we took the plenary poll to adopt contracts in the C++26 working draft (“merge it to trunk”), the vote was:
100 in favor, 14 opposed, and 12 abstaining
And in 2026 the vote to approve C++ 26, with the inclusion of contracts
the vote was non-unanimous primarily because of the sustained concerns about contracts:
114 in favor, 12 opposed, and 3 abstaining
So, what you are seeing is a paper denying the existence of consensus, where the consensus was overwhelmingly in favor, published after the committee voted to approve recommendation of C++26, but before the ISO national bodies voted essentially as to whether they should accept that recommendation.
Given you thought there was not consensus, even though there was overwhelming consensus, how do you think other groups might have read that paper?
Clearly you read this paper and came to the conclusion that there was no consensus, because this paper is written in a way that makes you think that.
I got the claim of "no consensus" from the story we're commenting on, about how the standard wasn't accepted because of concerns over contracts. Given that every prior standard passed unanimously, that feels very notable to me.
I think maybe there was a miscommunication about what I meant by "consensus". I see that there was consensus within the committee (which P4433 also notes), but contracts are clearly still extremely controversial, or else we wouldn't be having this discussion.
They're not. They really really are not.
There is a group that does not want them.
Papers like this create the appearance of controversy due to the lack of supporting context.
The absolute opacity of the actual approval process after the recommendation from the technical committee does nothing to help the appearance of controversy where none exists.
There is clearly a controversy based on how many people involved with C++ are talking about this issue. Even bjarne is talking about it. They might be wrong but it is a thing that is happening and is still unresolved.
Bjarne is one of the authors of this objection paper. You're literally saying "Even Bjarne agrees with his opinion".
Now, what do you mean "how many people involved with c++ are talking about this issue"? How many people are you seeing talking about this issue?
Yes, the disapproval you're seeing is the outcome of overwhelming consensus being drowned out by a minority opinion, and if you think "Bjarne says so, so it must be right", then you're arguing that there should not be a language committee, just whatever Bjarne thinks of and agrees with.
If that is your opinion fine, but then you're saying "development of the language depends on who is making a suggestion, not the value or technical merit of it".
That is a valid way to run a project, but the people providing technical expertise need to be aware of that as well, currently C++ is based on technical merit and consensus approval. This vote from ISO seems to go along your path of saying that technical merit and consensus aren't actually relevant to approval.
.... I'm sorry, what?
My post isn't about what shape the controversy has. You're saying that a problem that is obviously controversial is not actually a controversial. You are describing one of the textbook example shapes of a controversy (experts disagreeing with each other in public view and coming to an impasse) as an argument in response to a post that is saying that there is a controversy.
and if you think "Bjarne says so, so it must be right",
I have no idea where you got this possibility from. I specifically said "They might be wrong but it is a thing that is happening". Whether I think bjarne is right or not is immaterial and not part of what I'm saying.
Ok, in that case I apologize.
What I am having a problem is with people treating "a minority group disagrees" as something "controversial" in a way that implies that more than just that minority group disagrees.
e.g "It is controversial that the earth is more than 10000 years old".
For what it's worth, the comments on the corresponding /r/cpp thread are probably worth reading through as well for more info/context and commentary from committee members.
Contracts without neither proofs nor a strong type system make no sense, so C++ contracts are mostly useless. Compare these to Ada contracts, which are very well-designed, and can be used to prove things (e.g. no exceptions at runtime, allowing you to remove checks) given you can express side-effects. It is also distinguished between static (compile-time) and dynamic (runtime) predicates.
Who would spend all the time necessary to add contracts to a piece of C++ software? Given how deep you have to think of the code, you might as well rewrite it in another language.
Maybe it's time to stop trying to tack on features to a language that is just not made for it.