[gccrs COMMIT 1/2] lang: Add DST support to box and improve box dispatch

[email protected]
Newsgroups gmane.comp.gcc.rust,gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Enes Cevik <[email protected]>

This patch introduces DST support for box, allowing it to correctly
handle unsized types.

It also implements the auto-deref mechanism for box. This ensures that
method dispatch, indexing, and tuple field access work correctly.

gcc/rust/ChangeLog:

	* backend/rust-compile-expr.cc (compile_box): Remove DST guard.
	(build_box_inner_ptr): Add fat pointer control.
	(CompileExpr::visit): Add auto-deref for box.
	(HIRCompileBase::resolve_deref_adjustment): Return fat or thin
	pointer.
	* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit):
	Add auto-deref for box.
	* typecheck/rust-tyty.cc (ADTType::is_box): New function.
	* typecheck/rust-tyty.h (class BaseType): New declaration.

gcc/testsuite/ChangeLog:

	* rust/execute/box-dispatch-1.rs: New test.
	* rust/execute/box-dispatch-2.rs: New test.
	* rust/execute/unsized-adt-size.rs: Format 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/c8230e04f08742c916e9248bc4357b4e4b686581

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         | 62 +++++++++------
 .../typecheck/rust-hir-type-check-expr.cc     | 11 +++
 gcc/rust/typecheck/rust-tyty.cc               |  9 +++
 gcc/rust/typecheck/rust-tyty.h                |  3 +
 gcc/testsuite/rust/execute/box-dispatch-1.rs  | 47 ++++++++++++
 gcc/testsuite/rust/execute/box-dispatch-2.rs  | 76 +++++++++++++++++++
 .../rust/execute/unsized-adt-size.rs          | 13 ++--
 7 files changed, 190 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/rust/execute/box-dispatch-1.rs
 create mode 100644 gcc/testsuite/rust/execute/box-dispatch-2.rs

diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 12369f583..be092070b 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -101,12 +101,6 @@ compile_box (Context *ctx, TyTy::BaseType *box_tyty, TyTy::BaseType *inner_tyty,
 {
   tree inner_type_tree = TyTyResolveCompile::compile (ctx, inner_tyty);
 
-  if (!COMPLETE_TYPE_P (inner_type_tree))
-    {
-      rust_sorry_at (locus,
-		     "dynamically sized types in boxes are not supported yet");
-      return error_mark_node;
-    }
   tree size_tree = TYPE_SIZE_UNIT (inner_type_tree);
   tree align_tree
     = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (inner_type_tree));
@@ -145,6 +139,9 @@ build_box_inner_ptr (tree main_expr, location_t locus)
   // custom allocator is placed as the first field in the RECORD_TYPE.
   while (TREE_CODE (TREE_TYPE (main_expr)) == RECORD_TYPE)
     {
+      if (RS_DST_FLAG_P (TREE_TYPE (main_expr)))
+	break;
+
       tree first_field = TYPE_FIELDS (TREE_TYPE (main_expr));
       if (first_field == NULL_TREE)
 	break;
@@ -187,6 +184,13 @@ CompileExpr::visit (HIR::TupleIndexExpr &expr)
       tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
       receiver_ref = indirect;
     }
+  else if (auto inner_expr_ty = TyTy::try_get_box_inner_type (tuple_expr_ty))
+    {
+      rust_assert (inner_expr_ty.value ()->get_kind ()
+		   == TyTy::TypeKind::TUPLE);
+      receiver_ref = build_box_inner_ptr (receiver_ref, expr.get_locus ());
+      receiver_ref = indirect_expression (receiver_ref, expr.get_locus ());
+    }
 
   translated
     = Backend::struct_field_expression (receiver_ref, index, expr.get_locus ());
@@ -1781,6 +1785,21 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
     expr.get_receiver ().get_mappings ().get_hirid (), &receiver);
   rust_assert (ok);
 
+  // lookup the autoderef mappings
+  HirId autoderef_mappings_id
+    = expr.get_receiver ().get_mappings ().get_hirid ();
+  std::vector<Resolver::Adjustment> *adjustments = nullptr;
+  ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
+						     &adjustments);
+  rust_assert (ok);
+
+  // apply adjustments for the fn call
+  self = resolve_adjustments (*adjustments, self,
+			      expr.get_receiver ().get_locus ());
+
+  if (adjustments != nullptr && !adjustments->empty ())
+    receiver = adjustments->back ().get_expected ();
+
   bool is_dyn_dispatch
     = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
@@ -1804,18 +1823,6 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
     // lookup compiled functions since it may have already been compiled
     fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
 
-  // lookup the autoderef mappings
-  HirId autoderef_mappings_id
-    = expr.get_receiver ().get_mappings ().get_hirid ();
-  std::vector<Resolver::Adjustment> *adjustments = nullptr;
-  ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
-						     &adjustments);
-  rust_assert (ok);
-
-  // apply adjustments for the fn call
-  self = resolve_adjustments (*adjustments, self,
-			      expr.get_receiver ().get_locus ());
-
   std::vector<tree> args;
   args.push_back (self); // adjusted self
 
@@ -2501,12 +2508,14 @@ HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
 	       || adjustment.is_deref_mut_adjustment ());
   if (!adjustment.has_operator_overload ())
     {
-      TyTy::BaseType *receiver = adjustment.get_actual ();
-      if (TyTy::try_get_box_inner_type (receiver))
+      if (TyTy::try_get_box_inner_type (adjustment.get_actual ()))
 	{
-	  tree receiver_ref = expression;
-	  receiver_ref = build_box_inner_ptr (receiver_ref, locus);
-	  return indirect_expression (receiver_ref, locus);
+	  expression = build_box_inner_ptr (expression, locus);
+	  if (TREE_CODE (TREE_TYPE (expression)) == POINTER_TYPE
+	      || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE)
+	    expression = indirect_expression (expression, locus);
+	  return expression;
+	  ;
 	}
       rust_assert (false);
     }
@@ -2931,6 +2940,13 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr)
       array_reference
 	= indirect_expression (array_reference, expr.get_locus ());
     }
+  else if (TyTy::try_get_box_inner_type (array_expr_ty))
+    {
+      array_reference
+	= build_box_inner_ptr (array_reference, expr.get_locus ());
+      array_reference
+	= indirect_expression (array_reference, expr.get_locus ());
+    }
 
   translated = Backend::array_index_expression (array_reference, index,
 						expr.get_locus ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 41d71ccfd..fd9d1f953 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -95,6 +95,12 @@ TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
       return;
     }
 
+  // Box<T> autoderef
+  if (auto resolved_base = TyTy::try_get_box_inner_type (resolved))
+    {
+      resolved = *resolved_base;
+    }
+
   // FIXME does this require autoderef here?
   if (resolved->get_kind () == TyTy::TypeKind::REF)
     {
@@ -1087,6 +1093,11 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
       if (base->get_kind () == TyTy::TypeKind::ARRAY)
 	direct_array_expr_ty = base;
     }
+  // Box<T> autoderef
+  else if (auto base = TyTy::try_get_box_inner_type (direct_array_expr_ty))
+    {
+      direct_array_expr_ty = *base;
+    }
 
   TyTy::BaseType *size_ty;
   bool ok = context->lookup_builtin ("usize", &size_ty);
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index f77d796d1..ad487208c 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -2186,6 +2186,15 @@ ADTType::is_unsized () const
   return last_field_type->is_unsized ();
 }
 
+bool
+ADTType::is_box () const
+{
+  if (auto owned_box = mappings.lookup_lang_item (LangItem::Kind::OWNED_BOX))
+    if (get_id () == owned_box)
+      return true;
+  return false;
+}
+
 // TupleType
 
 TupleType::TupleType (HirId ref, location_t locus, std::vector<TyVar> fields,
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index c51bb359a..3d910212a 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -363,6 +363,8 @@ public:
   // is_unsized returns true if the type is a DST
   virtual bool is_unsized () const { return false; }
 
+  virtual bool is_box () const { return false; }
+
 protected:
   BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
 	    std::set<HirId> refs = std::set<HirId> ());
@@ -1046,6 +1048,7 @@ public:
 
   bool contains_unsafe_cell () const override;
   virtual bool is_unsized () const override;
+  virtual bool is_box () const override;
 
 private:
   DefId id;
diff --git a/gcc/testsuite/rust/execute/box-dispatch-1.rs b/gcc/testsuite/rust/execute/box-dispatch-1.rs
new file mode 100644
index 000000000..50e05ec43
--- /dev/null
+++ b/gcc/testsuite/rust/execute/box-dispatch-1.rs
@@ -0,0 +1,47 @@
+#![feature(no_core, lang_items, box_syntax)]
+#![no_core]
+
+extern "C" {
+    fn malloc(size: usize) -> *mut u8;
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+#[lang = "exchange_malloc"]
+pub unsafe fn exchange_malloc(size: usize, _align: usize) -> *mut u8 {
+    malloc(size)
+}
+
+impl<T> Box<T> {
+    pub fn new(x: T) -> Box<T> {
+        box x
+    }
+}
+
+pub trait Animal {
+    fn speak(&self) -> i32;
+}
+
+pub struct Dog {
+    pub code: i32,
+}
+
+impl Animal for Dog {
+    fn speak(&self) -> i32 {
+        self.code
+    }
+}
+
+fn main() -> i32 {
+    let dog1 = Dog { code: 111 };
+
+    let animal_ref: &dyn Animal = &dog1;
+
+    let box_of_ref: Box<&dyn Animal> = Box::new(animal_ref);
+
+    box_of_ref.speak() - 111
+}
diff --git a/gcc/testsuite/rust/execute/box-dispatch-2.rs b/gcc/testsuite/rust/execute/box-dispatch-2.rs
new file mode 100644
index 000000000..0d962778d
--- /dev/null
+++ b/gcc/testsuite/rust/execute/box-dispatch-2.rs
@@ -0,0 +1,76 @@
+#![feature(no_core, lang_items, box_syntax, intrinsics)]
+#![no_core]
+
+extern "C" {
+    fn malloc(size: usize) -> *mut u8;
+}
+
+extern "rust-intrinsic" {
+    fn offset<T>(dst: *const T, offset: isize) -> *const T;
+}
+
+#[lang = "index"]
+pub trait Index<Idx> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl Index<usize> for [i32] {
+    type Output = i32;
+
+    fn index(&self, index: usize) -> &i32 {
+        unsafe {
+            let ptr = self as *const [i32] as *const i32;
+            &*offset(ptr, index as isize)
+        }
+    }
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+#[lang = "exchange_malloc"]
+pub unsafe fn em(size: usize, _align: usize) -> *mut u8 {
+    malloc(size)
+}
+
+impl<T> Box<T> {
+    pub fn new(x: T) -> Box<T> {
+        box x
+    }
+}
+
+pub struct X { data: i32 }
+
+pub trait A {
+    fn a(&self) -> i32;
+}
+
+impl A for X {
+    fn a(&self) -> i32 {
+        self.data
+    }
+}
+pub fn main() -> i32 {
+    let x = X { data: 44 };
+    let y = X { data: 22 };
+    let z : [i32; 3] = [1, 2, 3];
+    let w : (i32, i32) = (10, 20);
+
+    let a : Box<dyn A> = Box::new(x);
+    let b : Box<X> = Box::new(y);
+    let c : Box<[i32; 3]> = Box::new(z);
+    let d : Box<(i32, i32)> = Box::new(w);
+    let e : Box<[i32]> = Box::new(z);
+
+    a.a() - 2 * b.data // 44 - 2 * 22
+    +
+    c[0] + c[1] - c[2] // 1 + 2 - 3
+    +
+    2 * d.0 - d.1 // 2 * 10 - 20
+    +
+    e[0] + e[1] - e[2] // 1 + 2 - 3
+}
diff --git a/gcc/testsuite/rust/execute/unsized-adt-size.rs b/gcc/testsuite/rust/execute/unsized-adt-size.rs
index c3210a941..aa2153c37 100644
--- a/gcc/testsuite/rust/execute/unsized-adt-size.rs
+++ b/gcc/testsuite/rust/execute/unsized-adt-size.rs
@@ -59,15 +59,12 @@ pub fn sov3(s: &TailStruct<TailStruct<[i32]>>) -> usize {
 fn main() -> i32 {
     let t = [1, 2, 3];
     let t1 = &t as &[i32];
-    let s1 : TailStruct<[i32; 3]> = TailStruct {
-        a: 10,
-        tail: t,
-    };
-    let s2_tail: TailStruct<[i32; 3]> = TailStruct {
-        a: 10,
-        tail: t,
+    let s1: TailStruct<[i32; 3]> = TailStruct { a: 10, tail: t };
+    let s2_tail: TailStruct<[i32; 3]> = TailStruct { a: 10, tail: t };
+    let s2: TailStruct<TailStruct<[i32; 3]>> = TailStruct {
+        a: 20,
+        tail: s2_tail,
     };
-    let s2 : TailStruct<TailStruct<[i32; 3]>> = TailStruct { a: 20, tail: s2_tail };
 
     let a = sov1(t1);
     let b = sov2(&s1);

base-commit: adf05734d896265d69cf64ec53bf8147556e1a77
-- 
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.