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
+    }
+}

Reply via email to