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