https://gcc.gnu.org/g:6242294eb326ec926bd0520b8fc01cd778d0a802
commit r17-2258-g6242294eb326ec926bd0520b8fc01cd778d0a802 Author: Enes Cevik <[email protected]> Date: Mon Jun 29 10:34:58 2026 +0300 gccrs: backend: Fix incorrect impl block selection During vtable generation in `compute_address_for_trait_item`, the compiler was picking the first `impl` block that satisfied the trait predicate, without verifying if the `impl` block actually belonged to the target receiver type. This caused dynamic dispatch to call the wrong methods when multiple types implemented the same trait in the same scope. This patch adds a comparison between the impl block's resolved type and the `receiver` type to ensure we compute the address of the correct associated function. gcc/rust/ChangeLog: * backend/rust-compile.cc (HIRCompileBase::compute_address_for_trait_item): Ensure the impl block type matches the receiver type. gcc/testsuite/ChangeLog: * rust/execute/trait-multi-impl.rs: New test. * rust/execute/trait-multi-impl-generic.rs: New test. * rust/execute/trait-multi-impl-generic2.rs: New test. Signed-off-by: Enes Cevik <[email protected]> Diff: --- gcc/rust/backend/rust-compile.cc | 9 +++ .../rust/execute/trait-multi-impl-generic.rs | 46 +++++++++++++++ .../rust/execute/trait-multi-impl-generic2.rs | 69 ++++++++++++++++++++++ gcc/testsuite/rust/execute/trait-multi-impl.rs | 51 ++++++++++++++++ 4 files changed, 175 insertions(+) diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index c2ef00b8bf95..b57ba966ffd0 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -314,6 +314,15 @@ HIRCompileBase::compute_address_for_trait_item ( rust_assert (ok); + TyTy::BaseType *mut_receiver = const_cast<TyTy::BaseType *> (receiver); + bool receiver_matches = Resolver::types_compatable ( + TyTy::TyWithLocation (self, self->get_locus ()), + TyTy::TyWithLocation (mut_receiver, mut_receiver->get_locus ()), + UNDEF_LOCATION, false); + + if (!receiver_matches) + continue; + // Look through the relevant bounds on our type, and find which one our // impl block satisfies TyTy::TypeBoundPredicate *self_bound = nullptr; diff --git a/gcc/testsuite/rust/execute/trait-multi-impl-generic.rs b/gcc/testsuite/rust/execute/trait-multi-impl-generic.rs new file mode 100644 index 000000000000..7be5eb29b192 --- /dev/null +++ b/gcc/testsuite/rust/execute/trait-multi-impl-generic.rs @@ -0,0 +1,46 @@ +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +trait TraitA { + fn do_a(&self) -> i32; +} + +pub struct Container<T> { + pub val: i32, + pub _marker: T, +} + +impl TraitA for Container<i32> { + fn do_a(&self) -> i32 { + self.val * 10 + } +} + +impl TraitA for Container<u32> { + fn do_a(&self) -> i32 { + self.val * 20 + } +} + +fn main() -> i32 { + let a = Container { + val: 10, + _marker: 0_i32, + }; + let b = Container { + 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 { + 0 + } else { + 1 + } +} diff --git a/gcc/testsuite/rust/execute/trait-multi-impl-generic2.rs b/gcc/testsuite/rust/execute/trait-multi-impl-generic2.rs new file mode 100644 index 000000000000..2b42668f3468 --- /dev/null +++ b/gcc/testsuite/rust/execute/trait-multi-impl-generic2.rs @@ -0,0 +1,69 @@ +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +trait TraitA { + fn do_a(&self) -> i32; +} + +mod mod_a { + use super::TraitA; + + pub struct StructX<T> { + pub val: i32, + _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, + _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() -> i32 { + 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 { + 0 + } else { + 1 + } +} diff --git a/gcc/testsuite/rust/execute/trait-multi-impl.rs b/gcc/testsuite/rust/execute/trait-multi-impl.rs new file mode 100644 index 000000000000..cd507c0d7c89 --- /dev/null +++ b/gcc/testsuite/rust/execute/trait-multi-impl.rs @@ -0,0 +1,51 @@ +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +trait TraitA { + fn do_a(&self) -> i32; +} + +mod mod_a { + use super::TraitA; + + pub struct StructX { + pub val: i32, + } + + impl TraitA for StructX { + fn do_a(&self) -> i32 { + self.val * 10 + } + } +} + +mod mod_b { + use super::TraitA; + + pub struct StructX { + pub val: i32, + } + + impl TraitA for StructX { + fn do_a(&self) -> i32 { + self.val * 20 + } + } +} + +fn main() -> i32 { + let a = mod_a::StructX { val: 10 }; + let b = mod_b::StructX { val: 20 }; + + 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 { + 0 + } else { + 1 + } +}
