It does mention that dealing with the pain is the only potential solve.
For example, I've been using Rust in production since just after 1.0, so about 8 years now. I maintain 10-20 libraries and tools, some with hundreds of dependencies. If I update a project with 200 dependencies that hasn't been touched in 3 years, that's 3x200 = 600 "dependency-years" worth of old code being run on a new compiler. And usually it either works flawlessly, or it can be fixed in under 5 minutes. Very occasionally I'm forced to update my code to use a new library version that requires some code changes on my end.
I've also maintained long-lived C, C++, Ruby and Python projects. Those projects tend to have far more problems with new compilers or runtimes than Rust, in my experience. Updating a large C++ program to newest version of Visual C++, for example, can be a mess.
However, Rust obviously does not support running new code on old compilers. And because stable Rust is almost always a safe upgrade, many popular libraries don't worry too much about supporting 3-year-old compilers. (This is super irritating for distros like Debian.) Which if you're working on a regulated embedded system that requires you to use a specific old compiler, well, it's a problem. Realistically, in that case you'll want to vendor and freeze all your dependencies and back-port specific security fixes as needed. If you're not allowed to update your compiler, you probably shouldn't be mass-updating your dependencies, either.
Basically, Rust got so exceptionally good at running old code on new compilers that the library ecosystem developed the habit of dropping support for old compilers too quickly for some downstream LTS maintainers. And as a library maintainer, I'm absolutely part of the problem—I don't actually care about supporting 5 year old compilers for free. On some level, I probably should, but...
That's an MSVC problem. MSVC ignored the C++ specification for decades. Now it does follow the spec. So a lot of non-standard code broke.
The transition was pretty ugly, as I'm pretty sure you've figured out. The permissive mode never gave warnings for non-standard code, so you couldn't just fix warnings as they came up. You had to do a fix the world update, which are a dickpain in large codebases. The transition was relatively fast; VS2017 introduced the standard compliant parser, and C++20 requires it.
Honestly MSVC is such a mess. I have a hunch that before this decade is out, Microsoft will just replace it with Clang a la Internet Explorer/Edge/Chromium. That's why the switch to the standard compliant parser was so rushed; they're trying to force everyone to write standard compliant code so that Clang can compile it.
I have configured cargo-deny for nearly all our projects to just ban OpenSSL from ever appearing as a dependency.
For languages with more frequent releases, that just isn't feasible. The let-else construct [0] was stabilized in 1.65 (Nov 2022), default values for const generics were stabilized in 1.59 (Feb 2022) [1], and the const evaluation timeout [2] was removed in 1.72 (Aug 2023). These are all reasonable changes, released on a reasonable timescale. However, when writing a `struct Position<const Dim: usize = 3>`, I don't check whether my library already uses language features that post-date 1.59, and I don't consider it a backwards-compatibility breakage to do so.
Incrementing the major version for a change that is source-compatible on most compiler versions (e.g. the first use of let-else in a project) just isn't justified.
[0] https://doc.rust-lang.org/rust-by-example/flow_control/let_e...
[1] https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html#const...
[2] https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html#const...