Skip to content

Commit eabd4be

Browse files
committed
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 <enes@nsvke.com>
1 parent f595502 commit eabd4be

5 files changed

Lines changed: 124 additions & 11 deletions

File tree

gcc/rust/backend/rust-compile-expr.cc

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,8 +1800,30 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
18001800
if (adjustments != nullptr && !adjustments->empty ())
18011801
receiver = adjustments->back ().get_expected ();
18021802

1803-
bool is_dyn_dispatch
1804-
= receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
1803+
enum
1804+
{
1805+
DYN,
1806+
DYN_BOX,
1807+
NOT_DYN,
1808+
} is_dyn_dispatch
1809+
= NOT_DYN;
1810+
const TyTy::DynamicObjectType *dyn = nullptr;
1811+
if (receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
1812+
{
1813+
is_dyn_dispatch = DYN;
1814+
dyn
1815+
= static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
1816+
}
1817+
else if (auto inner = TyTy::try_get_box_inner_type (receiver->get_root ()))
1818+
{
1819+
if ((*inner)->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC)
1820+
{
1821+
is_dyn_dispatch = DYN_BOX;
1822+
dyn = static_cast<const TyTy::DynamicObjectType *> (
1823+
(*inner)->get_root ());
1824+
}
1825+
}
1826+
18051827
bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
18061828
if (is_generic_receiver)
18071829
{
@@ -1810,18 +1832,22 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
18101832
}
18111833

18121834
tree fn_expr = error_mark_node;
1813-
if (is_dyn_dispatch)
1835+
if (is_dyn_dispatch == NOT_DYN)
1836+
// lookup compiled functions since it may have already been compiled
1837+
fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
1838+
else
18141839
{
1815-
const TyTy::DynamicObjectType *dyn
1816-
= static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
1817-
fn_expr
1818-
= get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_locus ());
1819-
self = get_receiver_from_dyn (dyn, receiver, fntype, self,
1840+
tree target_self
1841+
= is_dyn_dispatch == DYN
1842+
? self
1843+
: build_box_inner_ptr (self, expr.get_receiver ().get_locus ());
1844+
1845+
fn_expr = get_fn_addr_from_dyn (dyn, receiver, fntype, target_self,
1846+
expr.get_locus ());
1847+
1848+
self = get_receiver_from_dyn (dyn, receiver, fntype, target_self,
18201849
expr.get_locus ());
18211850
}
1822-
else
1823-
// lookup compiled functions since it may have already been compiled
1824-
fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
18251851

18261852
std::vector<tree> args;
18271853
args.push_back (self); // adjusted self

gcc/rust/typecheck/rust-hir-dot-operator.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ MethodResolver::try_hook (const TyTy::BaseType &r)
103103
predicate_items
104104
= get_predicate_items (segment_name, element_ty, specified_bounds);
105105
}
106+
else if (auto inner
107+
= TyTy::try_get_box_inner_type (const_cast<TyTy::BaseType *> (&r)))
108+
{
109+
const auto &specified_bounds = (*inner)->get_specified_bounds ();
110+
predicate_items
111+
= get_predicate_items (segment_name, **inner, specified_bounds);
112+
}
106113
}
107114

108115
std::vector<MethodResolver::impl_item_candidate>

gcc/rust/util/rust-lang-item.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
5757
{"RangeToInclusive", Kind::RANGE_TO_INCLUSIVE},
5858
{"range_inclusive_new", Kind::RANGE_INCLUSIVE_NEW},
5959
{"coerce_unsized", Kind::COERCE_UNSIZED},
60+
{"dispatch_from_dyn", Kind::DISPATCH_FROM_DYN},
6061
{"phantom_data", Kind::PHANTOM_DATA},
6162
{"fn", Kind::FN},
6263
{"fn_mut", Kind::FN_MUT},

gcc/rust/util/rust-lang-item.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class LangItem
8181

8282
// https://github.com/rust-lang/rust/blob/master/library/core/src/ops/unsize.rs
8383
COERCE_UNSIZED,
84+
DISPATCH_FROM_DYN,
8485

8586
// https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
8687
PHANTOM_DATA,
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![feature(no_core, lang_items, box_syntax)]
2+
#![no_core]
3+
4+
extern "C" {
5+
fn malloc(size: usize) -> *mut u8;
6+
}
7+
8+
#[lang = "sized"]
9+
pub trait Sized {}
10+
11+
#[lang = "unsize"]
12+
pub trait Unsize<T: ?Sized> {}
13+
14+
#[lang = "coerce_unsized"]
15+
pub trait CoerceUnsized<T: ?Sized> {}
16+
17+
#[lang = "dispatch_from_dyn"]
18+
pub trait DispatchFromDyn<T> {}
19+
20+
#[lang = "phantom_data"]
21+
pub struct PhantomData<T: ?Sized>;
22+
23+
#[lang = "exchange_malloc"]
24+
pub unsafe fn exchange_malloc(size: usize, _align: usize) -> *mut u8 {
25+
malloc(size)
26+
}
27+
28+
pub struct NonNull<T: ?Sized> {
29+
pub ptr: *const T,
30+
}
31+
32+
pub struct Unique<T: ?Sized> {
33+
pub pointer: NonNull<T>,
34+
pub _marker: PhantomData<T>,
35+
}
36+
37+
#[lang = "owned_box"]
38+
pub struct Box<T: ?Sized> {
39+
pub inner: Unique<T>,
40+
}
41+
42+
impl<T: ?Sized> Box<T> {
43+
pub fn new(x: T) -> Box<T> {
44+
box x
45+
}
46+
}
47+
48+
#[lang = "receiver"]
49+
pub trait Receiver {}
50+
51+
trait Animal {
52+
fn get_age(self: Box<Self>) -> i32;
53+
}
54+
55+
struct Dog {
56+
age: i32,
57+
}
58+
59+
impl Animal for Dog {
60+
fn get_age(self: Box<Self>) -> i32 {
61+
self.age
62+
}
63+
}
64+
65+
pub fn main() -> i32 {
66+
let dog = Dog { age: 42 };
67+
let _ = dog.age;
68+
69+
let coerced_box: Box<dyn Animal> = Box::new(dog);
70+
71+
let result = coerced_box.get_age();
72+
73+
if result == 42 {
74+
0
75+
} else {
76+
1
77+
}
78+
}

0 commit comments

Comments
 (0)