[gccrs COMMIT 1/2] lang: Add DST support to box and improve box dispatch
gerris.rs@gmail.com
gerris.rs@gmail.com
Sun Aug 16 01:07:51 GMT 2026
From: Enes Cevik <enes@nsvke.com>
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 <enes@nsvke.com>
---
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
More information about the Gcc-rust
mailing list