C++26 Makes Trivial Infinite Loops Well-Defined, Ending Decades of Undefined Behavior
C++26: Trivial infinite loops are no longer undefined behaviour
Before C++26, a trivial infinite loop like `while (true);` was undefined behavior, allowing compilers to optimize it away. C++26's P2809R3 fixes this by defining such loops as well-defined and replacing their body with `std::this_thread::yield()`. This change, also accepted as a defect report, addresses a long-standing divergence from C and prevents dangerous optimizations in embedded and security-critical code.
In Clang, this prints “Hello world!”. The compiler removes the infinite loop, main falls through, and the linker-placed unreachable() function executes.
- wahern
> When both conditions are met, the loop body is replaced with a call to std::this_thread::yield(). This gives execution of the loop the forward-progress semantics it previously lacked.
That's the epitome of the hidden code downside that Linus and many others dislike about C++. For constructors and destructors it's somewhat unavoidable and not so random, though Rust does better at limiting the blast radius of non-local code, at least in the drop case.
If they didn't want to adopt the C11 rule, the C++ committee should've explored a rule that required the compiler to emit a diagnostic or error for trivial loops (whether as defined by C11 or otherwise), requiring the programmer to explicitly insert ::yield or similar. No hidden code, and less opportunity for the compiler to do surprising things.
The C committee has been rigorously enumerating UB cases in the standard and addressing each case in turn, often by requiring a diagnostic, error, or by turning it into implemention defined behavior. But inserting code like that would be unthinkable.
- JoshTriplett
> When both conditions are met, the loop body is replaced with a call to std::this_thread::yield().
Insert screaming here.
An infinite loop, with no library calls whatsoever, gets a system call inserted. That's a horrible surprise waiting to happen.
The entire concept of the "forward progress guarantee" is broken. An infinite loop should compile to an infinite loop. Nothing more, nothing less.
- Dwedit
"This is not simply a common pattern on bare metal — it was also undefined behaviour in C++."
Not just X (em dash) but also Y.
- omoikane
> The loop must be a trivially empty iteration statement -- meaning its body is literally empty
This seems to say that the loop body can not be "continue". Indeed, I just tried -std=c++26 with ";" and got an infinite loop as promised, but "continue" restores the undefined behavior:
- "while(true);" -> https://godbolt.org/z/T65o51crx
- "while(true) continue;" -> https://godbolt.org/z/Pj9raEcnP
This is unfortunate since I know of one style guide that prefers "continue" over single semicolons. I guess all those code will be doing "while(true) {}" from now on.
https://google.github.io/styleguide/cppguide.html#Formatting...
- ameliaquining
The article, most unfortunately, doesn't explain why anyone would want infinite loops to be UB in the first place. I found this explanation: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
- kazinator
[delayed]
- paparulo329
The mere concept of undefined behavior is hilarious to me. "Oh this part? No we can't and won't even try figuring out what doing that does, this page intentionally left blank; yes we are a very serious whole ass standards body thanks for asking"
- peterus
There are valid use cases for the infinite while(1) loop in microcontroller programming (contrary to popular belief it seems). Autogenerated HAL code for the stm32 uses it for error handlers, and they support C++ so I am surprised this was UB.
I only use it for error handling and of course it is a bad idea to use this to wait/stall in power sensitive applications, in that case use wake from interrupt.
As an aside, I like to include a software breakpoint in my error handlers. It makes debugging easier without wasting a hardware breakpoint (which are physically limited by the microcontroller):
__BKPT();
while (1)
;