gccrs#4660: Fix incorrect impl block selection
Link: Rust-GCC/gccrs#4660
Note
Bug fix (issue #4600).
Objective
Fixes a bug where dynamic dispatch called the wrong methods when multiple types implemented the same trait in the same scope.
Changes Made
During vtable generation (compute_address_for_trait_item), the compiler was previously selecting the first impl block that satisfied the trait predicate, without verifying if that block actually belonged to the target receiver type.
Added a strict type comparison between the impl block’s resolved type and the actual receiver type to ensure the correct associated function address is computed for the vtable.
Why is this needed for alloc?
The alloc crate makes extensive use of dynamic dispatch (dyn Trait), especially for features like the GlobalAlloc trait. If vtable method resolution selects the wrong implementation, it leads to memory corruption or crashes at runtime.
Test Case
trait TraitA {
fn do_a(&self) -> i32;
}
mod mod_a {
use super::TraitA;
pub struct StructX<T> {
pub val: i32,
pub _marker: T,
}
impl TraitA for StructX<i32> {
fn do_a(&self) -> i32 {
self.val * 10
}
}
impl TraitA for StructX<u32> {
fn do_a(&self) -> i32 {
self.val * 1000
}
}
}
mod mod_b {
use super::TraitA;
pub struct StructX<T> {
pub val: i32,
pub _marker: T,
}
impl TraitA for StructX<u32> {
fn do_a(&self) -> i32 {
self.val * 20
}
}
impl TraitA for StructX<i32> {
fn do_a(&self) -> i32 {
self.val * 2000
}
}
}
fn main() {
let a = mod_a::StructX {
val: 10,
_marker: 0_i32,
};
let b = mod_b::StructX {
val: 20,
_marker: 0_u32,
};
let dyn_a = &a as &dyn TraitA;
let dyn_b = &b as &dyn TraitA;
if dyn_a.do_a() == 100 && dyn_b.do_a() == 400 {
println!("ok.");
} else {
println!("wrong!");
}
}