https://gcc.gnu.org/g:ca2ff45ff6dda8444bdd993bce955baceebb18a6
commit r17-4116-gca2ff45ff6dda8444bdd993bce955baceebb18a6 Author: Enes Cevik <[email protected]> Date: Wed Aug 5 11:56:58 2026 +0300 gccrs: lang: Add DST support to box and improve box dispatch 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]> Diff: --- gcc/rust/backend/rust-compile-expr.cc | 62 +++++++++++++-------- gcc/rust/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 ++++++++++++++++++++++++++ gcc/testsuite/rust/execute/unsized-adt-size.rs | 13 ++--- 7 files changed, 190 insertions(+), 31 deletions(-) diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 12369f583430..be092070b990 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 41d71ccfda27..fd9d1f95399c 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 f77d796d1f60..ad487208ce4a 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 c51bb359aadd..3d910212ab76 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 000000000000..50e05ec43a98 --- /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 000000000000..0d962778d9fc --- /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 c3210a941381..aa2153c3794e 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);
