The main reason the C version must hard-code is because C macros can't be recursive. What's Rust's excuse?
(that said, the C approach is also nice for manually accessing fields of distant base classes)
In Rust's case it is that when you say "you have IsA<Device> for all types that implement IsA<PCIDevice>" you are actually saying "you have IsA<Device> for all types, but only if they implement IsA<PCIDevice>".
When you later say "you have IsA<Device> for all types, but only if they implement IsA<I2CDevice>" the two conditions conflict.
It might be possible to avoid this issue with a different implementation but this is the simplest one that works and QEMU's hierarchy is generally shallow. If a better implementation came along, it would be a matter of search and repeat.
Though I admit that Rust also has to include the full list of base classes (https://github.com/rust-lang/rfcs/pull/1268 would fix it).