interesting story
as an aside, I think the original code, with the if statement, was clearer and would be easier to debug, etc, even if it was a bit longer
This feels like it should have been a warning rather than an optimization in the first place. In my opinion, dead code elimination should only be done during link time optimization where it can be proven that branches are not taken given the whole program information. If there is an unused assignment regardless of the branch, the compiler could emit a warning so the user can do their own dead code elimination, or choose to suppress/ignore the warning. The worst thing a compiler can do is silently incorrectly apply an optimization.
Of course, I also feel this way about the vast majority of optimizations. If the compiler can optimize a piece of code, it can also show the user what it thinks the optimal code would be so that they can rewrite it themselves, if they so choose. This both prevents these kinds of miscompiles and prevents compilation times from exploding because the compiler doesn't need to do much work, it primarily just translates the human readable code into machine code.
Especially interesting because (as one of the compiler team members noted on Zulip) this is a miscompilation relatively easy to stumble into in safe code (yikes). Looks like the cause was a late pass in MIR optimization pipeline — I would think these are carefully vetted for soundness so am surprised that this slipped in there.
It's a good story, it takes a bit of courage to post a compiler issue - so well done. As an aside note - I abs love the lefthand progress color indicator on your blog!
If the author is here, typo in the second paragraph: "eariler", should probably be "earlier".
I was experimenting with an early, early version of the Java SDK, v1.0.1, about 30 years ago. I was trying to build a calendar using a GridBagLayout, and all the date squares got scrambled and drew on top of each other. I posted to mailing lists and USENET, asking what exactly I was doing wrong, since—recalling the first rule of compiler bugs, to wit, "it's probably not a compiler bug"—while I thought I was "holding it correctly" (i.e., using the APIs in the manner recommended by the documentation), I was willing to concede that I was missing something important.
Turns out it was a bug in the Java runtime, one that was fixed in v1.0.3.
I started programming at ~8 and as a kid you often are sure the compiler is wrong, and it never is. (maybe once, have a vague memory of it)
Then years later I started playing with Nim when it was still in beta, I think I found 3 compiler bugs in a few weeks! Reported them all, all got fixed!
And then a few years later found a bug in LLVM, doing weird stuff with Rust and SIMD intrinsics. Was difficult to even communicate what was going wrong but did get it reported and confirmed eventually!
> The issue was labeled p-critical and i-miscompile, out of +61K rust issues there only 7 (including this one) that are both p-critical and i-miscompile, to me those are the most dangerous kind of bugs a compiler can have, given that they violate the contract between the programmer and the language. They show that not every safe code you write is safe. And also more generally there are only 247 p-critical issues to begin with.
I don't mean this in a snarky way or the like... and I guess the fact there are so few of these are a good indicator that the current processes are working decently well... but I would be very curious on a post-mortem from maintainers on how this bug got through. Miscompiles feel like the scariest sort of thing.
Maybe the deep and dark secret is simply that compiler optimizations are just extremely prone to mistakes and we all are just lucky enough that most messed up optimizations will break _something somewhere_ early enough to not get merged.