Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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!");
    }
}