Fair enough. I didn’t mean to push Rust, which is why I removed the last statement from my original comment. I was really just trying to make an observation that devirtualisation isnt something I need to think about in Rust (you could make an argument that dynamic should be the default and C++ got it right, and it would be an interesting, but different, discussion). I thought that was interesting, as a language design enthusiast.
In the OP, there are ten test cases. Some devirtualise. One only on clang, another only on GCC. In Rust, polymorphism is always "devirtualised" unless I say "no, actually, make this dyn", and in many cases, that's actually perfectly fine. It feels like the rational default, you only pay for the dynamic support when you need it. I don't dislike C++, but sometimes it gets exhausting having to remember all the situations where the compiler might do this or that, or I have to write far more complex code via templates or other techniques to get the behavior I want (sure, its been made easier with recent C++ versions, I admit I'm still on C++20 and even then not all of it; originally because compiler support was patchy, now because I just haven't used C++ as much lately). Its that difference that I thought was interesting.