Document: P3874R1
Authors: Jon Bauman, Timur Doumler, Nevin Liber, Ryan McDougall, Pablo Halpern, Jeff Garland, Jonathan Müller
Date: 2026-02-23
Audience: EWG
This is the paper that asks the uncomfortable question out loud: should C++ formally commit to becoming a memory-safe language? Not “safer” — safe, with a definition. The authors propose that a memory-safe language must contain a syntactically explicit, compiler-enforced subset that is systematically free of all undefined behavior. Not reduced-by-profiles, not hardened-at-runtime — systematically free, as in: if you’re in the safe subset, you cannot trigger UB without an explicit unsafe escape hatch.
The Rust comparison is right there in the paper. Sean Baxter’s Circle compiler is cited as the existence proof that this architecture is implementable for C++ — safe/unsafe regions, borrow checking, lifetime annotations. Lifetime safety is identified as the hardest remaining problem. The paper explicitly says profiles (P3081) and contracts (P2900) don’t meet the bar — they reduce UB incidence but cannot eliminate it systematically.
This is not a proposal for a specific feature. It is asking EWG whether C++ should commit to this direction at all. Which means the real audience is everyone who has an opinion about what C++ should become — which on r/cpp is everyone.
committee gonna committee, but at least this time they are committing to the direction of committing to maybe doing something about the thing that everyone else solved five years ago
they already solved it, it’s called Rust
thanks, you are the 400th person to say this in a WG21 paper thread today
in fairness, the 400th time isn’t wrong either
🫱
The key question this paper does not answer: what percentage of real C++ can actually live in the safe subset without
unsafeannotations?For the code I work with daily — embedded, bare-metal Cortex-M — the answer is not encouraging. Things that need
unsafein any reasonable model:volatilewith hardware-facing memoryFor a typical firmware image I ship, maybe 6–10% of the code could plausibly live in a safe subset. The paper uses Rust as the existence proof, but Rust’s safe/unsafe ratio only looks good because Rust has a decade of safe abstractions:
Vec,Arc,Mutex,Pin. C++ hasstd::vector, which itself would need to be redesigned to expose a safe interface under borrow checking — andstd::mutex, which makes no lifetime promises a borrow checker could verify.This is the gap between “the model is sound” and “the model is useful.” Circle proves the borrow-checker model can work for C++. It does not prove that 80% of production C++ could be in the safe zone.
I am not saying don’t do this. I am saying the paper needs to engage with the coverage question or it is not telling us anything we can act on.
this is the comment. the rest of the thread is noise.
The Rust answer to this is worth engaging with: safe Rust is not supposed to replace all unsafe C++ patterns immediately. The model is that you encapsulate the unsafe invariants behind safe abstractions.
Vecis unsafe internally and safe externally — that’s the whole point.The embedded situation is genuinely harder because you often have no clean boundary between “safe logic” and “hardware interface” — they are interwoven. But Rust has made real inroads in embedded precisely by building safe HAL layers (
embedded-hal,cortex-m) that encapsulate the unsafe register access behind sound APIs. A C++ equivalent would require the same investment.The question is not “what percentage of today’s C++ is already safe”. It is “what percentage could be safe if we built standard library primitives that expose sound interfaces.” That is a very different number.
I work on a compiler. I want to believe the “build safe abstractions over unsafe internals” argument, but there is a structural problem: C++ has 45 years of libraries with no soundness discipline. Every
std::type that needs to expose a safe interface requires audit and likely redesign.std::spanis a great example — it is trivially constructable with a dangling pointer right now. A borrow-checkedstd::spanis a different API with different construction rules.I ran Circle on a moderately complex codebase — standard library containers, some templates, a few custom allocators. About 40% of the code needed
unsafeannotations or failed to compile in safe mode entirely. Some of that is fixable with better library design. A lot of it is fundamental: you cannot makeplacement newsafe, you cannot makereinterpret_castsafe, and they appear in more places than you would expect.The paper is asking EWG to commit to a direction. Fine. But directions cost nothing. The real commitment is in the subsequent papers that say “here is what safe
std::vectorlooks like, and here is what your existing code that callsvec.data()now needs to do.” Those papers are going to be brutal.Yes, and that is fine? The whole premise of the paper is that there will be a new safe subset with new APIs. Nobody said
std::spangets magically retrofitted. The migration story is: new safe APIs coexist with old ones, code in the safe subset uses the safe APIs, unsafe code uses the old ones.The 40% number from your Circle experiment is interesting — do you know if that’s 40% of lines or 40% of translation units? If it’s 40% of lines but 5% of TUs, all clustered in allocator and container internals, that is actually a reasonable outcome. The unsafe surface is isolated and auditable.
The paper explicitly does not ask anyone to convert existing code. It is asking EWG to commit to developing language features that make a safe subset viable. The existing code stays unsafe by default. That is the whole point of the superset architecture.
Fair point on TU concentration — I did not measure that carefully. You are probably right that the unsafe surface concentrates in container/allocator code if you do it properly.
My real concern is timeline and fragmentation. We are talking about a safe language variant shipping in C++35 at the absolute earliest, ergonomic parity with Rust maybe C++38. During that window, every C++ shop that needs to answer the “is your code memory-safe” question on a government contract has to pick between: Rust now, profiles-plus-hardening now (imperfect but available), or wait a decade for the C++ safe subset.
A direction commitment creates a third option that is theoretically superior but not available for ten years. I am worried that paradoxically accelerates Rust adoption — C++ says “we’re working on it,” procurement officers pick Rust because “working on it” does not satisfy a compliance checkbox.
That is actually the best argument against this paper and you buried it in turn four.
I do not have a clean rebuttal. If the direction commitment delays real-world adoption of safe C++ by a decade while positioning C++ as “we’re working on it,” that is a genuine strategic error. You want C++ to either be safe now via profiles, or admit it cannot be and fund migration.
I still think the paper is right that profiles are not systematically safe. But “systematically safe in 2035” may be worse than “heuristically safe in 2026.”
Editing my earlier position: the direction commitment makes sense if the committee also accelerates profiles work as a short-term bridge. If the commitment replaces profiles investment, I agree with you.
just use Rust lol
yes, I will simply rewrite the AUTOSAR stack
and the DO-178C certified flight software
and convince the certification authorities that Rust’s MISRA compliance story is settled (it is not, as of the time of this writing)
This is the sentence the whole paper turns on. The word “systematically” in the proposed definition is doing enormous work. If “systematic” means “a formal proof guarantee,” then profiles fail on principle even if they achieve 99.9% coverage. If it means “practical elimination of the dangerous cases,” then profiles might succeed.
The paper is right that there is a categorical difference between the two. It is less right that the categorical difference matters for every threat model. For a government contractor asking “are you using a memory-safe language,” the categorical distinction is everything — checkbox compliance. For a security researcher asking “can an attacker exploit this binary,” what matters is whether the exploitable paths are closed, not whether the language model is formally clean.
The paper is arguing for the checkbox. That is a legitimate position. But it should say so explicitly rather than framing profiles as categorically insufficient for safety when they may be practically sufficient for security. Those are not the same word.
saving this comment for the next time someone asks me why profiles aren’t enough
The safety vs. security distinction is doing real work here and the paper elides it. The CISA/NSA mandate language is about security (exploitability), but the paper’s definition is about safety (formal UB freedom). They are not the same bar.
A language where profiles eliminate 99.8% of exploitable memory bugs is arguably sufficient for the government mandate. A language where safe code can still trigger UB on the 0.2% edge case fails the paper’s formal definition. Whether that gap matters depends on whether you are trying to satisfy a compliance checkbox or trying to enable formal verification.
wait, the paper actually addresses the safety/security distinction? I only read the abstract and skimmed the motivation section, like god intended
It does not make the distinction explicitly — that is the critique. The paper uses “safety” and “security” somewhat interchangeably when citing government mandates, then pivots to a formal language-theoretic definition of safety. The conflation is doing work in the argument.
The NSA, CISA, ONCD, and various European cybersecurity agencies all issued guidance telling us to use memory-safe languages. C++’s response is a direction paper asking if it should try to become one. The Rust Foundation responded by forming a safety-critical consortium and landing Rust in the Linux kernel. I am sure this is fine.
to be fair, asking “should we do this” before doing it is an improvement over previous WG21 practice of doing it for 15 years and then asking
this is the most accurate description of the networking/executors/coroutines situation I have ever read
I have been using Circle (Sean Baxter’s safe C++ superset) seriously for about eight months. The borrow checker works. It catches use-after-free and dangling references at compile time that Valgrind finds at runtime. The ergonomics differ from Rust’s borrow checker in interesting ways — Circle is more permissive on some patterns Rust rejects conservatively, stricter on others.
The paper cites Circle as the existence proof. Fair. What the paper cannot answer is whether Clang, GCC, and MSVC will implement the same borrow-checking model. Sean Baxter is one person. The C++ compiler infrastructure is three independent codebases with competing ABI constraints and different organizations with different priorities.
“Circle does it” is necessary but not sufficient as a feasibility argument. The paper needs an implementation commitment from at least one major vendor, not just a prototype fork.
This. The paper’s feasibility argument would be substantially stronger with even one sentence from a Clang or GCC maintainer saying “we believe this is implementable in our codebase.” Without that, “Circle proves it” is closer to “one person’s graduate project proves it,” which is a different claim.
Reminder: the paper authors and WG21 members read these threads. Technical disagreements are welcome. “Just use Rust” as your complete argument is not. Keep it civil.
The irony the paper skips: Rust’s borrow checker itself has known limitations that active research is still trying to fix. The Polonius project (next-generation borrow checker) has been “almost ready” since roughly 2018. Group borrowing is an open research problem. Non-lexical lifetime edge cases still reject valid programs. C++ is proposing to standardize on a model that Rust is still iterating on.
None of that is disqualifying — you pick the best available model and iterate. But the paper presents the Rust model as settled, which it is not.
Polonius has been “almost ready” since 2018, so C++ borrow checking is in good company
[removed by moderator]
what did they say?
something about Rust developers not understanding systems programming. the usual.
“new language features requiring per-function borrow analysis”
laughs in 45-minute build times
borrow checking is actually a dataflow pass, it’s not particularly expensive compared to template instantiation
tell that to my seven-level recursive template instantiation that is currently borrow-checking itself into the void
if we eliminate all UB then half my job as a compiler optimizer disappears. I am contractually obligated to oppose this paper.
the only genuine conflict of interest disclosed in this thread
can we please get networking in the standard before we redesign the entire safety model
executors have entered the chat
[deleted]
wait does this mean my existing code stops compiling? I have 600kloc of C++11 that I cannot touch for contractual reasons
No. The paper explicitly proposes a superset model: existing C++ is
unsafeby default and compiles unchanged. Newsaferegions are opt-in. Your 600kloc is fine; it simply cannot make formal safety guarantees. This is the whole point of the superset architecture — Circle already validates that existing C++ code compiles as-is under the model, it just sits in the unsafe zone.“compiles unchanged” assumes no ABI implications from whatever the safe-subset annotations require, which is optimistic given WG21’s track record with ABI — but yes the design goal is backward compatibility
One thing I want to add to my earlier comment: I re-read section 4 on the phased strategy and the paper is more honest about the long timeline than I initially gave it credit for. It explicitly calls out lifetime safety as requiring “significant new language features” and does not pretend that C++26 or even C++29 addresses it. The ask is genuinely just “should EWG commit to the direction” — not “sign off on a feature.”
That changes my read a bit. I can support a direction commitment as long as profiles work (P3081) continues in parallel as the near-term bridge. What I do not want is for this direction paper to be used as a reason to deprioritize profiles on the grounds that “we’re doing the real thing instead.”
Promoted — 10x your C++ productivity with AI-powered refactoring! Visit cpplearnahz.io
report and move on
The tell that this paper is serious is the author list. Timur Doumler, Nevin Liber, Pablo Halpern — these are not people who write directional papers on a whim. When that group puts their names on “should we do X,” the implicit message is “we have already thought hard about whether X is achievable and we believe it is.”
The paper is not the proposal. The paper is the canary poll. EWG answers yes, the proposals follow. Worth reading the author list before dismissing it as wishful thinking.
the implicit message is also “we are willing to do the work,” which matters even more than the belief that it’s achievable
CppCon 2026 — Aurora, CO. Early bird ends May 15. The conference for the C++ community.
CLion — the C++ IDE that understands your templates. Free 30-day trial.