First is if you compile with `-Werror -Wall` or similar; new compiler diagnostics can result in a build failing. That's easy enough to work around.
Second, nearly any decent-sized C program has undefined behavior, and new compilers may change their handling of undefined behavior. (E.g., they may add new optimizations that detect and exploit undefined behavior that was previously benign.) See, e.g., this post by cryptologist Daniel J. Bernstein: https://groups.google.com/g/boring-crypto/c/48qa1kWignU/m/o8...
Here's one example of workarounds in ~100 packages that broke when upgrading to GCC 10: https://github.com/search?q=repo%3ANixOS%2Fnixpkgs%20fcommon...
Every language has breaking changes. The question is the frequency, not if it happens at all.
The C and C++ folks try very hard to minimize breakage, and so do the Rust folks. Rust is far closer to those two than other languages. I'm not willing to say that it's the same, because I do not know how to quantify it.
Rust 2015 can still evolve (either by language changes or by std/core changes) and packages can be broken by simply upgrading the compiler version even if they're still targeting Rust 2015. There's a whole RFC[2] on what is and isn't considered a breaking change.
[1]: https://gcc.godbolt.org/z/5jb1hMbrx
[2]: https://rust-lang.github.io/rfcs/1105-api-evolution.html
That's not what backwards compatibility means in this context. You're talking about how a compiler is backwards compatible. We're talking about the language itself, and upgrading from one versions of the language to the next.
Rust 2015 is not the same thing as C89, that is true.
> packages can be broken by simply upgrading the compiler version
This is theoretically true, but in practice, this rarely happens. Take the certainly-a-huge-mistake time issue discussed above. I actually got hit by that one, and it took me like ten minutes to even realize that it was the compiler's fault, because upgrading is generally so hassle free. The fix was also about five minutes worth of work. Yes, they should do better, but I find Rust upgrades to be the smoothest of any ecosystem I've ever dealt with, including C and C++ compilers.
> You're talking about how a compiler is backwards compatible. We're talking about the language itself, and upgrading from one versions of the language to the next.
That's part of the problem. Rust doesn't have a spec. The compiler is the spec. So I don't think we can separate the two in a meaningful way.
> So I don't think we can separate the two in a meaningful way.
I think that in that case, you'd compare like with like, upgrading both.
I do agree that gcc and clang supporting older specs with a flag is a great feature, and is something that Rust cannot do right now.
But the results of the annual survey have come out: https://blog.rust-lang.org/2025/02/13/2024-State-Of-Rust-Sur...
And 90% of users use the current stable version for development. 7.8% use a specific stable released within the past year.
These numbers are only so high because it is such a small hassle to update even large Rust codebases between releases.
So yes, in theory, breakage can happen. But that's in theory. In practice, this isn't a thing that happens very much.
Decades-old codebases tend to work because the toolchain explicitly hard-codes support for the ways they make assumptions not provided by any standard.