https://gcc.gnu.org/g:8965fd1299643bf968a959e07d6cd400d34199e7

commit r17-4117-g8965fd1299643bf968a959e07d6cd400d34199e7
Author: Enes Cevik <[email protected]>
Date:   Mon Aug 10 11:09:22 2026 +0300

    gccrs: lang: Add dispatch_from_dyn for Box
    
    This patch implements the 'dispatch_from_dyn' lang item specifically for
    'Box'. While there are other smart pointers and types that require this
    lang item for dynamic dispatch, they are omitted in this patch as they
    are not yet fully supported by the compiler.
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-expr.cc (CompileExpr::visit): Handle Box
            receivers correctly during dynamic dispatch.
            * typecheck/rust-hir-dot-operator.cc (MethodResolver::try_hook):
            Extract the inner type of a Box to resolve trait methods.
            * util/rust-lang-item.cc (Rust::LangItem::lang_items): Register
            dispatch_from_dyn to the BiMap.
            * util/rust-lang-item.h (class LangItem): Add DISPATCH_FROM_DYN
            to the Kind enum.
    
    gcc/testsuite/ChangeLog:
    
            * rust/execute/box-dispatch-from-dyn.rs: New test.
    
    Signed-off-by: Enes Cevik <[email protected]>

Diff:
---
 gcc/rust/backend/rust-compile-expr.cc              | 48 ++++++++++---
 gcc/rust/typecheck/rust-hir-dot-operator.cc        |  7 ++
 gcc/rust/util/rust-lang-item.cc                    |  1 +
 gcc/rust/util/rust-lang-item.h                     |  1 +
 .../rust/execute/box-dispatch-from-dyn.rs          | 78 ++++++++++++++++++++++
 5 files changed, 124 insertions(+), 11 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index be092070b990..3229dea3646d 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -1800,8 +1800,30 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
   if (adjustments != nullptr && !adjustments->empty ())
     receiver = adjustments->back ().get_expected ();
 
-  bool is_dyn_dispatch
-    = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
+  enum
+  {
+    DYN,
+    DYN_BOX,
+    NOT_DYN,
+  } is_dyn_dispatch
+    = NOT_DYN;
+  const TyTy::DynamicObjectType *dyn = nullptr;
+  if (receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
+    {
+      is_dyn_dispatch = DYN;
+      dyn
+       = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
+    }
+  else if (auto inner = TyTy::try_get_box_inner_type (receiver->get_root ()))
+    {
+      if ((*inner)->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
+       {
+         is_dyn_dispatch = DYN_BOX;
+         dyn = static_cast<const TyTy::DynamicObjectType *> (
+           (*inner)->get_root ());
+       }
+    }
+
   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
   if (is_generic_receiver)
     {
@@ -1810,18 +1832,22 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
     }
 
   tree fn_expr = error_mark_node;
-  if (is_dyn_dispatch)
+  if (is_dyn_dispatch == NOT_DYN)
+    // lookup compiled functions since it may have already been compiled
+    fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
+  else
     {
-      const TyTy::DynamicObjectType *dyn
-       = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
-      fn_expr
-       = get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_locus ());
-      self = get_receiver_from_dyn (dyn, receiver, fntype, self,
+      tree target_self
+       = is_dyn_dispatch == DYN
+           ? self
+           : build_box_inner_ptr (self, expr.get_receiver ().get_locus ());
+
+      fn_expr = get_fn_addr_from_dyn (dyn, receiver, fntype, target_self,
+                                     expr.get_locus ());
+
+      self = get_receiver_from_dyn (dyn, receiver, fntype, target_self,
                                    expr.get_locus ());
     }
-  else
-    // lookup compiled functions since it may have already been compiled
-    fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
 
   std::vector<tree> args;
   args.push_back (self); // adjusted self
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc 
b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 145727d29fd0..d1095d553630 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -103,6 +103,13 @@ MethodResolver::try_hook (const TyTy::BaseType &r)
       predicate_items
        = get_predicate_items (segment_name, element_ty, specified_bounds);
     }
+  else if (auto inner
+          = TyTy::try_get_box_inner_type (const_cast<TyTy::BaseType *> (&r)))
+    {
+      const auto &specified_bounds = (*inner)->get_specified_bounds ();
+      predicate_items
+       = get_predicate_items (segment_name, **inner, specified_bounds);
+    }
 }
 
 std::vector<MethodResolver::impl_item_candidate>
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index 3be15a805fcc..00dc02b3c301 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -57,6 +57,7 @@ const BiMap<std::string, LangItem::Kind> 
Rust::LangItem::lang_items = {{
   {"RangeToInclusive", Kind::RANGE_TO_INCLUSIVE},
   {"range_inclusive_new", Kind::RANGE_INCLUSIVE_NEW},
   {"coerce_unsized", Kind::COERCE_UNSIZED},
+  {"dispatch_from_dyn", Kind::DISPATCH_FROM_DYN},
   {"phantom_data", Kind::PHANTOM_DATA},
   {"fn", Kind::FN},
   {"fn_mut", Kind::FN_MUT},
diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h
index 8cadfd0c227e..61b4f64da251 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -81,6 +81,7 @@ public:
 
     // 
https://github.com/rust-lang/rust/blob/master/library/core/src/ops/unsize.rs
     COERCE_UNSIZED,
+    DISPATCH_FROM_DYN,
 
     // https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
     PHANTOM_DATA,
diff --git a/gcc/testsuite/rust/execute/box-dispatch-from-dyn.rs 
b/gcc/testsuite/rust/execute/box-dispatch-from-dyn.rs
new file mode 100644
index 000000000000..90b43b2f2ec3
--- /dev/null
+++ b/gcc/testsuite/rust/execute/box-dispatch-from-dyn.rs
@@ -0,0 +1,78 @@
+#![feature(no_core, lang_items, box_syntax)]
+#![no_core]
+
+extern "C" {
+    fn malloc(size: usize) -> *mut u8;
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+#[lang = "exchange_malloc"]
+pub unsafe fn exchange_malloc(size: usize, _align: usize) -> *mut u8 {
+    malloc(size)
+}
+
+pub struct NonNull<T: ?Sized> {
+    pub ptr: *const T,
+}
+
+pub struct Unique<T: ?Sized> {
+    pub pointer: NonNull<T>,
+    pub _marker: PhantomData<T>,
+}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized> {
+    pub inner: Unique<T>,
+}
+
+impl<T: ?Sized> Box<T> {
+    pub fn new(x: T) -> Box<T> {
+        box x
+    }
+}
+
+#[lang = "receiver"]
+pub trait Receiver {}
+
+trait Animal {
+    fn get_age(self: Box<Self>) -> i32;
+}
+
+struct Dog {
+    age: i32,
+}
+
+impl Animal for Dog {
+    fn get_age(self: Box<Self>) -> i32 {
+        self.age
+    }
+}
+
+pub fn main() -> i32 {
+    let dog = Dog { age: 42 };
+    let _ = dog.age;
+
+    let coerced_box: Box<dyn Animal> = Box::new(dog);
+
+    let result = coerced_box.get_age();
+
+    if result == 42 {
+        0
+    } else {
+        1
+    }
+}

Reply via email to