[gccrs COMMIT 2/2] lang: Add dispatch_from_dyn for Box

[email protected]
Newsgroups gmane.comp.gcc.rust,gmane.comp.gcc.patches
Message-ID <[email protected]>
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]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: https://github.com/Rust-GCC/gccrs/commit/d09ba8e4ece68d9c6d76ad1f49483ae46f29e0f4

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4767

 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 be092070b..3229dea36 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 145727d29..d1095d553 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 3be15a805..00dc02b3c 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 8cadfd0c2..61b4f64da 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 000000000..90b43b2f2
--- /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.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.