[gccrs COMMIT 4/6] backend: Add DST ADT support
[email protected] Sat, 15 Aug 2026 21:42:15 +0000
Newsgroups
gmane.comp.gcc.rust,gmane.comp.gcc.patches
Message-ID
<[email protected] >
From: Enes Cevik <[email protected] >
This patch introduces support for Dynamically Sized Types (DST) within
Algebraic Data Types (ADTs). Previously, the compiler embedded DST
fields directly into the ADT memory layout, even for ADTs following
unsize coercion rules. With this update, the compiler correctly
identifies unsized ADTs, preserves their static layout by avoiding
direct embedding, and appropriately generates fat pointers (containing
the data pointer and metadata) for references to these ADTs.
gcc/rust/ChangeLog:
* backend/rust-compile-expr.cc (CompileExpr::visit): Add
indirect field access for DST's and new borrow approach for fat
pointers.
(resolve_unsized_adt_adjustment): Correct GIMPLE generation for
nested unsized ADTs.
* backend/rust-compile-type.cc (TyTyResolveCompile::visit): Add
DST ADT support.
(TyTyResolveCompile::create_dyn_adt_record): New function.
* backend/rust-compile-type.h (create_dyn_adt_record): New
declaration.
* backend/rust-intrinsic-handlers.cc (get_inner_dst): New
function.
(size_of_val_handler): Add DST ADT support.
(min_align_of_val_handler): Likewise.
* typecheck/rust-coercion.cc
(TypeCoercionRules::coerce_unsized_adt): Skip zero-sized fields
during coercion.
* backend/rust-compile.cc (HIRCompileBase::coerce_to_dyn_object):
Remove unnecessary ref wrapping.
* typecheck/rust-tyty.cc (ADTType::is_unsized): New function.
(ReferenceType::is_dyn_object): Add DST ADT support.
(ReferenceType::is_dyn_adt_type): New function.
(PointerType::is_dyn_object): Add DST ADT support.
(PointerType::is_dyn_adt_type): New function.
* typecheck/rust-tyty.h (is_unsized): New declaration.
gcc/testsuite/ChangeLog:
* rust/execute/unsized-adt-nested-coercion.rs: New test.
* rust/execute/unsized-adt-size.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/53122e37bdaae8617583c7aa4feb48f24fe63887
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/4722
gcc/rust/backend/rust-compile-expr.cc | 285 +++++++++++++-----
gcc/rust/backend/rust-compile-type.cc | 115 +++++++
gcc/rust/backend/rust-compile-type.h | 1 +
gcc/rust/backend/rust-compile.cc | 8 +-
gcc/rust/backend/rust-intrinsic-handlers.cc | 78 +++--
gcc/rust/typecheck/rust-coercion.cc | 15 +-
gcc/rust/typecheck/rust-tyty.cc | 57 +++-
gcc/rust/typecheck/rust-tyty.h | 11 +
.../execute/unsized-adt-nested-coercion.rs | 75 +++++
.../rust/execute/unsized-adt-size.rs | 98 ++++++
10 files changed, 641 insertions(+), 102 deletions(-)
create mode 100644 gcc/testsuite/rust/execute/unsized-adt-nested-coercion.rs
create mode 100644 gcc/testsuite/rust/execute/unsized-adt-size.rs
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 574099672..12369f583 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -915,6 +915,15 @@ CompileExpr::visit (HIR::FieldAccessExpr &expr)
}
else
{
+ if (RS_DST_FLAG_P (TREE_TYPE (receiver_ref)))
+ {
+ tree data_ptr_field = TYPE_FIELDS (TREE_TYPE (receiver_ref));
+ tree data_ptr_expr
+ = build3_loc (expr.get_locus (), COMPONENT_REF,
+ TREE_TYPE (data_ptr_field), receiver_ref,
+ data_ptr_field, NULL_TREE);
+ receiver_ref = data_ptr_expr;
+ }
tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;
}
@@ -1197,6 +1206,49 @@ CompileExpr::visit (HIR::BorrowExpr &expr)
return;
tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
+
+ bool is_fat_ptr
+ = tyty->is<TyTy::ReferenceType> ()
+ ? tyty->as<TyTy::ReferenceType> ()->get_base ()->is_unsized ()
+ : tyty->is<TyTy::PointerType> ()
+ ? tyty->as<TyTy::PointerType> ()->get_base ()->is_unsized ()
+ : false;
+
+ if (is_fat_ptr)
+ {
+ tree data_ptr
+ = address_expression (main_expr, expr.get_locus (), NULL_TREE);
+ tree meta = error_mark_node;
+ if (TREE_CODE (main_expr) == COMPONENT_REF)
+ {
+ tree indirect = TREE_OPERAND (main_expr, 0);
+ if (TREE_CODE (indirect) == INDIRECT_REF)
+ {
+ tree data_ptr_expr = TREE_OPERAND (indirect, 0);
+ if (TREE_CODE (data_ptr_expr) == COMPONENT_REF)
+ {
+ tree fat_ptr = TREE_OPERAND (data_ptr_expr, 0);
+ if (RS_DST_FLAG_P (TREE_TYPE (fat_ptr)))
+ {
+ tree meta_field
+ = DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (fat_ptr)));
+ meta = build3_loc (expr.get_locus (), COMPONENT_REF,
+ TREE_TYPE (meta_field), fat_ptr,
+ meta_field, NULL_TREE);
+ }
+ }
+ }
+ }
+ if (meta != error_mark_node)
+ {
+ std::vector<tree> constructor_elements = {data_ptr, meta};
+ translated = Backend::constructor_expression (expected_type, false,
+ constructor_elements,
+ -1, expr.get_locus ());
+ return;
+ }
+ }
+
translated = address_expression (main_expr, expr.get_locus (), expected_type);
}
@@ -2549,10 +2601,6 @@ HIRCompileBase::resolve_unsized_adt_adjustment (
/*
* FIXME: This method is implemented as a temporary workaround to enable the
* compilation of intra-ADT conversions for the `coerce_unsized` lang item.
- * Currently, it generates incorrect GIMPLE, though it allows the compilation
- * to succeed. Execution tests relying on this will exhibit undefined behavior
- * at runtime. This must be revisited and properly refactored once the DST
- * memory layout is fully supported.
*/
auto source_adt
@@ -2560,85 +2608,182 @@ HIRCompileBase::resolve_unsized_adt_adjustment (
auto target_adt
= static_cast<const TyTy::ADTType *> (adjustment.get_expected ());
- auto s_variant = source_adt->get_variants ().front ();
- auto t_variant = target_adt->get_variants ().front ();
-
- std::vector<tree> constructor_elements;
+ if (target_adt->is_unsized ())
+ {
+ TyTy::TyVar t_tyvar = TyTy::TyVar::get_implicit_infer_var (locus);
+ TyTy::BaseType *cloned_target = target_adt->clone ();
+ cloned_target->set_ref (t_tyvar.get_ref ());
+ Analysis::NodeMapping pseudo_mapping (
+ ctx->get_mappings ().get_current_crate (), 0, t_tyvar.get_ref (), 0);
+ ctx->get_tyctx ()->insert_type (pseudo_mapping, cloned_target);
+
+ const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
+ t_tyvar, Mutability::Imm);
+
+ tree fat_pointer = TyTyResolveCompile::compile (ctx, &r);
+ rust_assert (fat_pointer != error_mark_node);
+ tree data_ptr = address_expression (expression, locus);
+
+ size_t tail_idx = source_adt->get_variants ().front ()->num_fields () - 1;
+ tree tail_expr
+ = Backend::struct_field_expression (expression, tail_idx, locus);
+
+ auto s_tail_ty = source_adt->get_variants ()
+ .front ()
+ ->get_field_at_index (tail_idx)
+ ->get_field_type ();
+ auto t_tail_ty = target_adt->get_variants ()
+ .front ()
+ ->get_field_at_index (tail_idx)
+ ->get_field_type ();
+
+ Resolver::Adjustment tail_adj (
+ Resolver::Adjustment::AdjustmentType::UNSIZE, s_tail_ty, t_tail_ty);
+ tree inner_fat_ptr
+ = resolve_unsized_adjustment (tail_adj, tail_expr, locus);
+ rust_assert (inner_fat_ptr != error_mark_node);
+ tree meta = error_mark_node;
+ if (TREE_CODE (inner_fat_ptr) == CONSTRUCTOR)
+ {
+ unsigned HOST_WIDE_INT ix;
+ tree field ATTRIBUTE_UNUSED, val;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (inner_fat_ptr), ix, field,
+ val)
+ if (ix == 1)
+ {
+ meta = val;
+ break;
+ }
+ }
+ else
+ {
+ tree meta_field_decl
+ = DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (inner_fat_ptr)));
+ meta = fold_build3_loc (locus, COMPONENT_REF,
+ TREE_TYPE (meta_field_decl), inner_fat_ptr,
+ meta_field_decl, NULL_TREE);
+ }
- for (size_t i = 0; i < s_variant->num_fields (); i++)
+ std::vector<tree> constructor_elements = {data_ptr, meta};
+ tree result
+ = Backend::constructor_expression (fat_pointer, false,
+ constructor_elements, -1, locus);
+ rust_assert (result != error_mark_node);
+ RS_DST_FLAG (TREE_TYPE (result)) = 1;
+ return result;
+ }
+ else
{
- auto s_field_ty = s_variant->get_field_at_index (i)
- ->get_field_type ()
- ->monomorphized_clone ();
- auto t_field_ty = t_variant->get_field_at_index (i)
- ->get_field_type ()
- ->monomorphized_clone ();
+ tree target = TyTyResolveCompile::compile (ctx, target_adt);
+ size_t coerce_idx = -1;
+ auto s_variant = source_adt->get_variants ().front ();
+ auto t_variant = target_adt->get_variants ().front ();
- tree field_expr = Backend::struct_field_expression (expression, i, locus);
- if (s_field_ty->is_equal (*t_field_ty))
- constructor_elements.push_back (field_expr);
- else
+ for (size_t idx = 0; idx < s_variant->num_fields (); idx++)
{
- bool is_ptr = s_field_ty->get_kind () == TyTy::TypeKind::POINTER;
- bool is_ref = s_field_ty->get_kind () == TyTy::TypeKind::REF;
-
- if (is_ptr || is_ref)
+ auto s_field_ty
+ = s_variant->get_field_at_index (idx)->get_field_type ();
+ auto t_field_ty
+ = t_variant->get_field_at_index (idx)->get_field_type ();
+ if (!s_field_ty->is_equal (*t_field_ty))
{
- TyTy::BaseType *s_base = nullptr;
- TyTy::BaseType *t_base = nullptr;
- Resolver::Adjustment::AdjustmentType ref_adj_type
- = Resolver::Adjustment::AdjustmentType::IMM_REF;
-
- if (is_ptr)
+ bool is_phantom = false;
+ if (s_field_ty->is<TyTy::ADTType> ())
+ if (auto phantom_data
+ = Analysis::Mappings::get ().lookup_lang_item (
+ LangItem::Kind::PHANTOM_DATA))
+ if (s_field_ty->as<TyTy::ADTType> ()->get_id ()
+ == phantom_data)
+ is_phantom = true;
+
+ if (!is_phantom)
{
- auto s_ptr
- = static_cast<const TyTy::PointerType *> (s_field_ty);
- auto t_ptr
- = static_cast<const TyTy::PointerType *> (t_field_ty);
- s_base = s_ptr->get_base ();
- t_base = t_ptr->get_base ();
- if (t_ptr->mutability () == Mutability::Mut)
- ref_adj_type
- = Resolver::Adjustment::AdjustmentType::MUT_REF;
+ coerce_idx = idx;
+ break;
}
- else
- {
- auto s_ref
- = static_cast<const TyTy::ReferenceType *> (s_field_ty);
- auto t_ref
- = static_cast<const TyTy::ReferenceType *> (t_field_ty);
- s_base = s_ref->get_base ();
- t_base = t_ref->get_base ();
- if (t_ref->mutability () == Mutability::Mut)
- ref_adj_type
- = Resolver::Adjustment::AdjustmentType::MUT_REF;
- }
- std::vector<Resolver::Adjustment> inner_adjs;
- inner_adjs.push_back (Resolver::Adjustment (
- Resolver::Adjustment::AdjustmentType::INDIRECTION, s_field_ty,
- s_base));
- inner_adjs.push_back (Resolver::Adjustment (
- Resolver::Adjustment::AdjustmentType::UNSIZE, s_base, t_base));
- inner_adjs.push_back (
- Resolver::Adjustment (ref_adj_type, t_base, t_field_ty));
-
- tree coerced_ptr
- = resolve_adjustments (inner_adjs, field_expr, locus);
- constructor_elements.push_back (coerced_ptr);
+ }
+ }
+ rust_assert (coerce_idx != (size_t) -1);
+ std::vector<tree> constructor_elements;
+ for (size_t i = 0; i < s_variant->num_fields (); i++)
+ {
+ tree field_expr
+ = Backend::struct_field_expression (expression, i, locus);
+
+ if (i != coerce_idx)
+ {
+ constructor_elements.push_back (field_expr);
}
else
{
- Resolver::Adjustment inner_adj (adjustment.get_type (),
- s_field_ty, t_field_ty);
- tree unsized_inner_expr
- = resolve_unsized_adjustment (inner_adj, field_expr, locus);
- constructor_elements.push_back (unsized_inner_expr);
+ auto s_coerce_ty
+ = s_variant->get_field_at_index (i)->get_field_type ();
+ auto t_coerce_ty
+ = t_variant->get_field_at_index (i)->get_field_type ();
+
+ Resolver::Adjustment adj (adjustment.get_type (), s_coerce_ty,
+ t_coerce_ty);
+ tree coerced_inner_expr = error_mark_node;
+
+ if (t_coerce_ty->get_kind () == TyTy::TypeKind::SLICE
+ || t_coerce_ty->get_kind () == TyTy::TypeKind::STR)
+ coerced_inner_expr
+ = resolve_unsized_slice_adjustment (adj, field_expr, locus);
+ else if (t_coerce_ty->get_kind () == TyTy::TypeKind::DYNAMIC)
+ coerced_inner_expr
+ = resolve_unsized_dyn_adjustment (adj, field_expr, locus);
+ else if (t_coerce_ty->get_kind () == TyTy::TypeKind::ADT)
+ coerced_inner_expr
+ = resolve_unsized_adt_adjustment (adj, field_expr, locus);
+ else if (t_coerce_ty->get_kind () == TyTy::TypeKind::POINTER
+ || t_coerce_ty->get_kind () == TyTy::TypeKind::REF)
+ {
+ bool is_ptr
+ = t_coerce_ty->get_kind () == TyTy::TypeKind::POINTER;
+
+ TyTy::BaseType *s_base
+ = is_ptr ? s_coerce_ty->as<TyTy::PointerType> ()
+ ->get_base ()
+ ->monomorphized_clone ()
+ : s_coerce_ty->as<TyTy::ReferenceType> ()
+ ->get_base ()
+ ->monomorphized_clone ();
+ TyTy::BaseType *t_base
+ = is_ptr ? t_coerce_ty->as<TyTy::PointerType> ()
+ ->get_base ()
+ ->monomorphized_clone ()
+ : t_coerce_ty->as<TyTy::ReferenceType> ()
+ ->get_base ()
+ ->monomorphized_clone ();
+
+ Resolver::Adjustment::AdjustmentType ref_adj_type
+ = Resolver::Adjustment::AdjustmentType::IMM_REF;
+
+ std::vector<Resolver::Adjustment> inner_adjs;
+ inner_adjs.push_back (Resolver::Adjustment (
+ Resolver::Adjustment::AdjustmentType::INDIRECTION,
+ s_coerce_ty, s_base));
+ inner_adjs.push_back (Resolver::Adjustment (
+ Resolver::Adjustment::AdjustmentType::UNSIZE, s_base,
+ t_base));
+ inner_adjs.push_back (
+ Resolver::Adjustment (ref_adj_type, t_base, t_coerce_ty));
+
+ coerced_inner_expr
+ = resolve_adjustments (inner_adjs, field_expr, locus);
+ }
+ else
+ rust_unreachable ();
+
+ constructor_elements.push_back (coerced_inner_expr);
}
}
+
+ return Backend::constructor_expression (target, false,
+ constructor_elements, -1, locus);
}
- tree target_type_tree = TyTyResolveCompile::compile (ctx, target_adt);
- return Backend::constructor_expression (target_type_tree, false,
- constructor_elements, -1, locus);
+
+ return error_mark_node;
}
tree
diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc
index eed8fd734..c3fb34260 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -353,6 +353,40 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
type.get_ty_ref ()));
}
+ if (!type.is_union () && variant.num_fields () > 0)
+ {
+ const TyTy::StructFieldType *tail_field
+ = variant.get_field_at_index (variant.num_fields () - 1);
+ TyTy::BaseType *tail_ty = tail_field->get_field_type ();
+
+ if (tail_ty->is_unsized ())
+ {
+ tree raw_dst_type = error_mark_node;
+
+ if (tail_ty->get_kind () == TyTy::TypeKind::SLICE)
+ {
+ auto slice = static_cast<TyTy::SliceType *> (tail_ty);
+ tree elem_type
+ = TyTyResolveCompile::compile (ctx,
+ slice->get_element_type ());
+ raw_dst_type = build_array_type (elem_type, NULL_TREE);
+ }
+ else if (tail_ty->get_kind () == TyTy::TypeKind::DYNAMIC)
+ {
+ raw_dst_type = make_node (RECORD_TYPE);
+ TYPE_SIZE (raw_dst_type) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (raw_dst_type) = size_zero_node;
+ layout_type (raw_dst_type);
+ }
+ else
+ {
+ raw_dst_type = fields.back ().type;
+ }
+ fields.pop_back ();
+ fields.emplace_back (tail_field->get_name (), raw_dst_type,
+ type.get_locus ());
+ }
+ }
type_record = type.is_union () ? Backend::union_type (fields, false)
: Backend::struct_type (fields, false);
}
@@ -742,6 +776,16 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
return;
}
+ else if (type.is_dyn_adt_type (&adt))
+ {
+ tree type_record = create_dyn_adt_record (*adt);
+ std::string dyn_str_type_str
+ = std::string (type.is_mutable () ? "&mut" : "& ") + adt->get_name ();
+
+ translated = Backend::named_type (dyn_str_type_str, type_record,
+ adt->get_locus ());
+ return;
+ }
// Check for CStr, create a specific record for it
else if (type.is_dyn_cstr_type (&adt))
{
@@ -794,6 +838,7 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type)
const TyTy::SliceType *slice = nullptr;
const TyTy::StrType *str = nullptr;
const TyTy::DynamicObjectType *dyn = nullptr;
+ const TyTy::ADTType *adt = nullptr;
if (type.is_dyn_slice_type (&slice))
{
tree type_record = create_slice_type_record (*slice);
@@ -829,6 +874,17 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type)
return;
}
+ else if (type.is_dyn_adt_type (&adt))
+ {
+ tree type_record = create_dyn_adt_record (*adt);
+ std::string dyn_str_type_str
+ = std::string (type.is_mutable () ? "*mut" : "*const ")
+ + adt->get_name ();
+
+ translated = Backend::named_type (dyn_str_type_str, type_record,
+ adt->get_locus ());
+ return;
+ }
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
@@ -963,5 +1019,64 @@ TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type)
return record;
}
+tree
+TyTyResolveCompile::create_dyn_adt_record (const TyTy::ADTType &type)
+{
+ location_t locus = type.get_locus ();
+
+ tree adt_record = TyTyResolveCompile::compile (ctx, &type);
+ tree data_field_ty = build_pointer_type (adt_record);
+ Backend::typed_identifier data_field ("data", data_field_ty, locus);
+
+ rust_assert (type.number_of_variants () > 0);
+ TyTy::VariantDef &variant = *type.get_variants ().front ();
+ rust_assert (variant.num_fields () > 0);
+
+ const TyTy::BaseType *tail_field
+ = variant.get_field_at_index (variant.num_fields () - 1)->get_field_type ();
+
+ tree meta_field_ty = error_mark_node;
+ std::string meta = "meta";
+
+ if (tail_field->get_kind () == TyTy::TypeKind::SLICE
+ || tail_field->get_kind () == TyTy::TypeKind::STR)
+ {
+ TyTy::BaseType *usize = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
+ rust_assert (ok);
+ meta_field_ty = TyTyResolveCompile::compile (ctx, usize);
+ meta = "len";
+ }
+ else if (tail_field->get_kind () == TyTy::TypeKind::DYNAMIC)
+ {
+ const TyTy::DynamicObjectType *dyn
+ = static_cast<const TyTy::DynamicObjectType *> (tail_field);
+ tree dyn_record = create_dyn_obj_record (*dyn);
+ tree vtable_field = DECL_CHAIN (TYPE_FIELDS (dyn_record));
+ meta_field_ty = TREE_TYPE (vtable_field);
+ meta = "vtable";
+ }
+ else if (tail_field->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *inner_adt
+ = static_cast<const TyTy::ADTType *> (tail_field);
+ tree inner_fat_ptr = create_dyn_adt_record (*inner_adt);
+ tree inner_meta_field = DECL_CHAIN (TYPE_FIELDS (inner_fat_ptr));
+ meta_field_ty = TREE_TYPE (inner_meta_field);
+ tree name_ident = DECL_NAME (inner_meta_field);
+ if (name_ident != NULL_TREE)
+ meta = IDENTIFIER_POINTER (name_ident);
+ }
+ else
+ rust_unreachable ();
+
+ Backend::typed_identifier meta_field (meta, meta_field_ty, locus);
+ tree record = Backend::struct_type ({data_field, meta_field});
+ RS_DST_FLAG (record) = 1;
+ TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
+
+ return record;
+}
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h
index 480206fa9..95fc845ed 100644
--- a/gcc/rust/backend/rust-compile-type.h
+++ b/gcc/rust/backend/rust-compile-type.h
@@ -69,6 +69,7 @@ protected:
tree create_slice_type_record (const TyTy::SliceType &type);
tree create_str_type_record (const TyTy::StrType &type);
tree create_dyn_obj_record (const TyTy::DynamicObjectType &type);
+ tree create_dyn_adt_record (const TyTy::ADTType &type);
tree get_implicit_enumeral_node_type (TyTy::BaseType *repr);
private:
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index b57ba966f..0f9a67176 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -64,7 +64,7 @@ HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval,
bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
if (ok)
{
- rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
+ rvalue = resolve_adjustments (*adjustments, rvalue, rvalue_locus);
}
return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
@@ -188,11 +188,7 @@ HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
const TyTy::DynamicObjectType *ty,
location_t locus)
{
- // DST's get wrapped in a pseudo reference that doesnt exist...
- const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
- TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
-
- tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
+ tree dynamic_object = TyTyResolveCompile::compile (ctx, ty);
tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
tree vtableptr_field = DECL_CHAIN (dynamic_object_fields);
rust_assert (TREE_CODE (TREE_TYPE (vtableptr_field)) == POINTER_TYPE);
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 6069898da..127d0642e 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -184,6 +184,19 @@ finalize_intrinsic_block (Context *ctx, tree fndecl)
maybe_save_constexpr_fundef (fndecl);
}
+static TyTy::BaseType *
+get_inner_dst (TyTy::BaseType *type)
+{
+ TyTy::BaseType *curr = type;
+ while (curr->get_kind () == TyTy::TypeKind::ADT)
+ {
+ auto variant = curr->as<TyTy::ADTType> ()->get_variants ().front ();
+ curr = variant->get_field_at_index (variant->num_fields () - 1)
+ ->get_field_type ();
+ }
+ return curr;
+}
+
namespace inner {
static std::string
@@ -1645,23 +1658,26 @@ size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
// BUILTIN size_of FN BODY BEGIN
tree size_expr = NULL_TREE;
- if (RS_DST_FLAG_P (template_parameter_type))
+
+ tree param = Backend::var_expression (__param, UNDEF_LOCATION);
+ tree param_ty = TREE_TYPE (param);
+ if (RS_DST_FLAG_P (param_ty))
{
- tree param = Backend::var_expression (__param, UNDEF_LOCATION);
- tree param_ty = TREE_TYPE (param);
tree data_field = TYPE_FIELDS (param_ty);
tree meta_field = DECL_CHAIN (data_field);
tree meta_field_expr
= build3_loc (locus, COMPONENT_REF, TREE_TYPE (meta_field), param,
meta_field, NULL_TREE);
- if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE
- || resolved_tyty->get_kind () == TyTy::TypeKind::STR)
+ TyTy::BaseType *inner_dst = get_inner_dst (resolved_tyty);
+ tree tail_size_expr = NULL_TREE;
+ if (inner_dst->get_kind () == TyTy::TypeKind::SLICE
+ || inner_dst->get_kind () == TyTy::TypeKind::STR)
{
tree elem_type = NULL_TREE;
- if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE)
+ if (inner_dst->get_kind () == TyTy::TypeKind::SLICE)
{
- auto slice_tyty = static_cast<TyTy::SliceType *> (resolved_tyty);
+ auto slice_tyty = static_cast<TyTy::SliceType *> (inner_dst);
elem_type
= TyTyResolveCompile::compile (ctx,
slice_tyty->get_element_type ());
@@ -1670,13 +1686,13 @@ size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
elem_type = char_type_node;
tree elem_size = TYPE_SIZE_UNIT (elem_type);
- size_expr
+ tail_size_expr
= build2_loc (locus, MULT_EXPR, size_type_node,
fold_convert_loc (locus, size_type_node,
meta_field_expr),
fold_convert_loc (locus, size_type_node, elem_size));
}
- else if (resolved_tyty->get_kind () == TyTy::TypeKind::DYNAMIC)
+ else if (inner_dst->get_kind () == TyTy::TypeKind::DYNAMIC)
{
tree vtable_ptr_ty = TREE_TYPE (meta_field_expr);
tree vtable_ty = TREE_TYPE (vtable_ptr_ty);
@@ -1688,7 +1704,7 @@ size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
tree vtable_field_size = DECL_CHAIN (vtable_field_0);
rust_assert (vtable_field_size != NULL_TREE);
- size_expr
+ tail_size_expr
= build3_loc (locus, COMPONENT_REF, TREE_TYPE (vtable_field_size),
vtable_ref, vtable_field_size, NULL_TREE);
}
@@ -1696,6 +1712,14 @@ size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
{
rust_unreachable ();
}
+ if (resolved_tyty->get_kind () == TyTy::TypeKind::ADT)
+ size_expr = build2_loc (locus, PLUS_EXPR, size_type_node,
+ fold_convert_loc (locus, size_type_node,
+ TYPE_SIZE_UNIT (
+ template_parameter_type)),
+ tail_size_expr);
+ else
+ size_expr = tail_size_expr;
}
else
size_expr = TYPE_SIZE_UNIT (template_parameter_type);
@@ -1786,23 +1810,26 @@ min_align_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
// BUILTIN size_of FN BODY BEGIN
tree align_expr = NULL_TREE;
- if (RS_DST_FLAG_P (template_parameter_type))
+ tree param = Backend::var_expression (__param, UNDEF_LOCATION);
+ tree param_ty = TREE_TYPE (param);
+ if (RS_DST_FLAG_P (param_ty))
{
- tree param = Backend::var_expression (__param, UNDEF_LOCATION);
- tree param_ty = TREE_TYPE (param);
tree data_field = TYPE_FIELDS (param_ty);
tree meta_field = DECL_CHAIN (data_field);
tree meta_field_expr
= build3_loc (locus, COMPONENT_REF, TREE_TYPE (meta_field), param,
meta_field, NULL_TREE);
- if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE
- || resolved_tyty->get_kind () == TyTy::TypeKind::STR)
+ TyTy::BaseType *inner_dst = get_inner_dst (resolved_tyty);
+ tree tail_align_expr = NULL_TREE;
+
+ if (inner_dst->get_kind () == TyTy::TypeKind::SLICE
+ || inner_dst->get_kind () == TyTy::TypeKind::STR)
{
tree elem_type = NULL_TREE;
- if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE)
+ if (inner_dst->get_kind () == TyTy::TypeKind::SLICE)
{
- auto slice_tyty = static_cast<TyTy::SliceType *> (resolved_tyty);
+ auto slice_tyty = static_cast<TyTy::SliceType *> (inner_dst);
elem_type
= TyTyResolveCompile::compile (ctx,
slice_tyty->get_element_type ());
@@ -1810,10 +1837,10 @@ min_align_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
else
elem_type = char_type_node;
- align_expr
+ tail_align_expr
= build_int_cst (size_type_node, TYPE_ALIGN_UNIT (elem_type));
}
- else if (resolved_tyty->get_kind () == TyTy::TypeKind::DYNAMIC)
+ else if (inner_dst->get_kind () == TyTy::TypeKind::DYNAMIC)
{
tree vtable_ptr_ty = TREE_TYPE (meta_field_expr);
tree vtable_ty = TREE_TYPE (vtable_ptr_ty);
@@ -1826,7 +1853,7 @@ min_align_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
tree vtable_field_align = DECL_CHAIN (vtable_field_1);
rust_assert (vtable_field_align != NULL_TREE);
- align_expr
+ tail_align_expr
= build3_loc (locus, COMPONENT_REF, TREE_TYPE (vtable_field_align),
vtable_ref, vtable_field_align, NULL_TREE);
}
@@ -1834,6 +1861,17 @@ min_align_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
{
rust_unreachable ();
}
+
+ if (resolved_tyty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ tree base_align_expr
+ = build_int_cst (size_type_node,
+ TYPE_ALIGN_UNIT (template_parameter_type));
+ align_expr = build2_loc (locus, MAX_EXPR, size_type_node,
+ base_align_expr, tail_align_expr);
+ }
+ else
+ align_expr = tail_align_expr;
}
else
align_expr = build_int_cst (size_type_node,
diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc
index fab689c24..4df9934d8 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -18,6 +18,7 @@
#include "rust-coercion.h"
#include "rust-type-util.h"
+#include "rust-tyty.h"
namespace Rust {
namespace Resolver {
@@ -313,6 +314,7 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
// &[T; n] or &mut [T; n] -> &[T]
// or &mut [T; n] -> &mut [T]
// or &Concrete -> &Trait, etc.
+// https://doc.rust-lang.org/stable/reference/type-coercions.html
tl::expected<TypeCoercionRules::CoercionResult,
TypeCoercionRules::CoerceUnsizedError>
TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
@@ -336,7 +338,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
auto b = setup->ty_b;
tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result
- = tl::unexpected (CoerceUnsizedError::Regular);
+ = tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
@@ -546,11 +548,16 @@ TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
? t_field_raw
: t_field_raw->monomorphized_clone ();
- if (s_field->is_zero_sized () && t_field->is_zero_sized ())
- continue;
-
+ // https://doc.rust-lang.org/reference/dynamically-sized-types.html
if (!s_field->is_equal (*t_field))
{
+ if (s_field->is<TyTy::ADTType> () && t_field->is<TyTy::ADTType> ())
+ if (auto phantom_data
+ = mappings.lookup_lang_item (LangItem::Kind::PHANTOM_DATA))
+ if (s_field->as<TyTy::ADTType> ()->get_id () == phantom_data
+ && t_field->as<TyTy::ADTType> ()->get_id () == phantom_data)
+ continue;
+
differing_source_field = s_field;
differing_target_field = t_field;
diff_count++;
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 72b2f9d7a..f77d796d1 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -2169,6 +2169,23 @@ ADTType::contains_unsafe_cell () const
return false;
}
+bool
+ADTType::is_unsized () const
+{
+ if (is_enum () || is_union () || number_of_variants () == 0)
+ return false;
+
+ auto &variant = get_variants ().front ();
+ if (variant->num_fields () == 0)
+ return false;
+
+ const TyTy::BaseType *last_field_type
+ = variant->get_field_at_index (variant->num_fields () - 1)
+ ->get_field_type ();
+
+ return last_field_type->is_unsized ();
+}
+
// TupleType
TupleType::TupleType (HirId ref, location_t locus, std::vector<TyVar> fields,
@@ -3317,7 +3334,7 @@ bool
ReferenceType::is_dyn_object () const
{
return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ()
- || is_dyn_cstr_type ();
+ || is_dyn_adt_type () || is_dyn_cstr_type ();
}
static const TyTy::BaseType *
@@ -3379,6 +3396,24 @@ ReferenceType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const
return true;
}
+bool
+ReferenceType::is_dyn_adt_type (const TyTy::ADTType **adt) const
+{
+ const TyTy::BaseType *element = destructure_through_projections (get_base ());
+
+ if (element->get_kind () != TyTy::TypeKind::ADT)
+ return false;
+
+ const TyTy::ADTType *adt_ty = static_cast<const TyTy::ADTType *> (element);
+
+ if (!adt_ty->is_unsized ())
+ return false;
+ if (adt != nullptr)
+ *adt = adt_ty;
+
+ return true;
+}
+
bool
ReferenceType::is_dyn_cstr_type (const TyTy::ADTType **adt) const
{
@@ -3513,7 +3548,8 @@ PointerType::is_const () const
bool
PointerType::is_dyn_object () const
{
- return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ();
+ return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ()
+ || is_dyn_adt_type ();
}
bool
@@ -3555,6 +3591,23 @@ PointerType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const
return true;
}
+bool
+PointerType::is_dyn_adt_type (const TyTy::ADTType **adt) const
+{
+ const TyTy::BaseType *element = destructure_through_projections (get_base ());
+ if (element->get_kind () != TyTy::TypeKind::ADT)
+ return false;
+
+ const TyTy::ADTType *adt_ty = static_cast<const TyTy::ADTType *> (element);
+
+ if (!adt_ty->is_unsized ())
+ return false;
+ if (adt != nullptr)
+ *adt = adt_ty;
+
+ return true;
+}
+
void
PointerType::accept_vis (TyVisitor &vis)
{
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index ecb2b3e24..c51bb359a 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -360,6 +360,9 @@ public:
virtual bool contains_unsafe_cell () const { return false; }
+ // is_unsized returns true if the type is a DST
+ virtual bool is_unsized () const { return false; }
+
protected:
BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::set<HirId> refs = std::set<HirId> ());
@@ -1042,6 +1045,7 @@ public:
handle_substitions (SubstitutionArgumentMappings &mappings) override final;
bool contains_unsafe_cell () const override;
+ virtual bool is_unsized () const override;
private:
DefId id;
@@ -1446,6 +1450,7 @@ public:
SliceType *handle_substitions (SubstitutionArgumentMappings &mappings);
bool contains_unsafe_cell () const override;
+ virtual bool is_unsized () const override { return true; }
private:
TyVar element_type;
@@ -1643,6 +1648,8 @@ public:
bool is_equal (const BaseType &other) const override;
BaseType *clone () const final override;
+
+ virtual bool is_unsized () const override { return true; }
};
class DynamicObjectType : public BaseType
@@ -1673,6 +1680,8 @@ public:
const std::vector<
std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
get_object_items () const;
+
+ virtual bool is_unsized () const override { return true; }
};
class ReferenceType : public BaseType
@@ -1713,6 +1722,7 @@ public:
bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const;
bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const;
bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const;
+ bool is_dyn_adt_type (const TyTy::ADTType **adt = nullptr) const;
bool is_dyn_cstr_type (const TyTy::ADTType **adt = nullptr) const;
private:
@@ -1753,6 +1763,7 @@ public:
bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const;
bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const;
bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const;
+ bool is_dyn_adt_type (const TyTy::ADTType **adt = nullptr) const;
private:
TyVar base;
diff --git a/gcc/testsuite/rust/execute/unsized-adt-nested-coercion.rs b/gcc/testsuite/rust/execute/unsized-adt-nested-coercion.rs
new file mode 100644
index 000000000..6cd73ef43
--- /dev/null
+++ b/gcc/testsuite/rust/execute/unsized-adt-nested-coercion.rs
@@ -0,0 +1,75 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {
+ // Due to our current architecture, coercion rules are hardcoded;
+ // therefore, this lang item is currently non-functional.
+}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+pub struct NonNull<T: ?Sized> {
+ pub ptr: *const T,
+}
+
+pub struct Unique<T: ?Sized> {
+ pub pointer: NonNull<T>,
+ pub _marker: PhantomData<T>,
+}
+
+pub struct MyBox<T: ?Sized> {
+ pub inner: Unique<T>,
+}
+
+pub struct TailStruct<T: ?Sized> {
+ pub header: usize,
+ pub data: T,
+}
+
+fn do_coercion(tail_ptr: *const TailStruct<[i32; 3]>) -> MyBox<TailStruct<[i32]>> {
+ let non_null = NonNull::<TailStruct<[i32; 3]>> { ptr: tail_ptr };
+ let unique = Unique::<TailStruct<[i32; 3]>> {
+ pointer: non_null,
+ _marker: PhantomData::<TailStruct<[i32; 3]>>,
+ };
+ let my_box = MyBox::<TailStruct<[i32; 3]>> { inner: unique };
+
+ let my_box_slice: MyBox<TailStruct<[i32]>> = my_box;
+ my_box_slice
+}
+
+fn clobber_stack() {
+ let mut _dummy: [usize; 10] = [0xDEADBEEF; 10];
+}
+
+pub fn main() -> i32 {
+ let tail: TailStruct<[i32; 3]> = TailStruct {
+ header: 42,
+ data: [1, 2, 3],
+ };
+ let tail_ptr: *const TailStruct<[i32; 3]> = &tail;
+
+ let coerced_box = do_coercion(tail_ptr);
+
+ clobber_stack();
+
+ unsafe {
+ let fat_ptr: *const TailStruct<[i32]> = coerced_box.inner.pointer.ptr;
+
+ let thin_ptr = fat_ptr as *const usize;
+
+ if *thin_ptr == 42 {
+ 0
+ } else {
+ *thin_ptr as i32
+ }
+ }
+}
diff --git a/gcc/testsuite/rust/execute/unsized-adt-size.rs b/gcc/testsuite/rust/execute/unsized-adt-size.rs
new file mode 100644
index 000000000..c3210a941
--- /dev/null
+++ b/gcc/testsuite/rust/execute/unsized-adt-size.rs
@@ -0,0 +1,98 @@
+// { dg-require-effective-target lp64 }
+#![feature(no_core, lang_items, intrinsics)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {
+ // Due to our current architecture, coercion rules are hardcoded;
+ // therefore, this lang item is currently non-functional.
+}
+
+extern "rust-intrinsic" {
+ fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+}
+
+pub struct TailStruct<T: ?Sized> {
+ pub a: i32,
+ pub tail: T,
+}
+
+pub fn _coerce(s: &TailStruct<[i32; 3]>) -> &TailStruct<[i32]> {
+ s as &TailStruct<[i32]>
+}
+
+pub trait MyTrait {
+ fn dummy(&self) -> i32;
+}
+
+impl MyTrait for i64 {
+ fn dummy(&self) -> i32 {
+ 0
+ }
+}
+
+impl MyTrait for [i32; 3] {
+ fn dummy(&self) -> i32 {
+ 0
+ }
+}
+
+pub fn sovt(s: &TailStruct<dyn MyTrait>) -> usize {
+ unsafe { size_of_val(s as *const TailStruct<dyn MyTrait>) }
+}
+
+pub fn sov1(s: &[i32]) -> usize {
+ unsafe { size_of_val(s as *const [i32]) }
+}
+
+pub fn sov2(s: &TailStruct<[i32]>) -> usize {
+ unsafe { size_of_val(s as *const TailStruct<[i32]>) }
+}
+
+pub fn sov3(s: &TailStruct<TailStruct<[i32]>>) -> usize {
+ unsafe { size_of_val(s as *const TailStruct<TailStruct<[i32]>>) }
+}
+
+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 s2 : TailStruct<TailStruct<[i32; 3]>> = TailStruct { a: 20, tail: s2_tail };
+
+ let a = sov1(t1);
+ let b = sov2(&s1);
+ let c = sov3(&s2);
+ let d = sov1(&s1.tail);
+ let e = sov2(&s2.tail);
+
+ let s3 = TailStruct {
+ a: 10,
+ tail: 10_i64,
+ };
+ let s4 = TailStruct { a: 20, tail: t };
+
+ let r1: &TailStruct<dyn MyTrait> = &s3;
+ let r2: &TailStruct<dyn MyTrait> = &s4;
+
+ let f = sovt(r1);
+ let g = sovt(r2);
+
+ let slice_ok = a == 12 && b == 16 && c == 20 && d == a && e == b;
+ let trait_ok = f == 12 && g == 16;
+
+ if slice_ok && trait_ok {
+ 0
+ } else {
+ 1
+ }
+}
--
2.54.0