From: Enes Cevik <[email protected]>
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]>
---
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(-)
create mode 100644 gcc/testsuite/rust/execute/box-dispatch-from-dyn.rs
diff --git a/gcc/rust/backend/rust-compile-expr.cc
b/gcc/rust/backend/rust-compile-expr.cc
index be092070b99..3229dea3646 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 145727d29fd..d1095d55363 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 3be15a805fc..00dc02b3c30 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 8cadfd0c227..61b4f64da25 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 00000000000..90b43b2f2ec
--- /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
+ }
+}
--
2.50.1