From: Enes Cevik <[email protected]>
This patch adds basic support for ADT to ADT unsized coercions. It also
refactors the main coerce_unsized function into smaller helper functions
for better readability and maintainability.
gcc/rust/ChangeLog:
* backend/rust-compile-base.h (resolve_adjustments): Fix typo.
(resolve_unsized_adt_adjustment): New declaration.
* backend/rust-compile-expr.cc (CompileExpr::visit): Fix typo.
(HIRCompileBase::resolve_unsized_adt_adjustment): New function.
(HIRCompileBase::resolve_unsized_adjustment): Use it.
(CompileExpr::generate_possible_fn_trait_call): Likewise.
(HIRCompileBase::coercion_site): Fix typo.
* typecheck/rust-coercion.cc
(TypeCoercionRules::coerce_unsized): Use helper functions.
(TypeCoercionRules::unwrap_ptrs_and_refs): New function.
(TypeCoercionRules::coerce_unsized_array_to_slice): Likewise.
(TypeCoercionRules::coerce_unsized_dyn): Likewise.
(TypeCoercionRules::coerce_unsized_adt): Liksewise.
(TypeCoercionRules::apply_reborrow_adjustment): Likewise.
* typecheck/rust-coercion.h (struct CoercionSetup): New struct.
(coerce_unsized): Add is_inner parameter.
(unwrap_ptrs_and_refs): New declaration.
(coerce_unsized_array_to_slice): Likewise.
(coerce_unsized_dyn): Likewise.
(coerce_unsized_adt): Likewise.
* util/rust-lang-item.cc (Rust::LangItem::lang_items): Add
coerce_unsized to the BiMap.
* util/rust-lang-item.h (class LangItem): Add COERCE_UNSIZED to
the Kind enum.
gcc/testsuite/ChangeLog:
* rust/compile/coercion2.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/d780d32bf97f1a0fcc2469c9b56f0404855e0446
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-base.h | 7 +-
gcc/rust/backend/rust-compile-expr.cc | 116 ++++++++++-
gcc/rust/typecheck/rust-coercion.cc | 258 +++++++++++++++++-------
gcc/rust/typecheck/rust-coercion.h | 25 ++-
gcc/rust/util/rust-lang-item.cc | 1 +
gcc/rust/util/rust-lang-item.h | 3 +
gcc/testsuite/rust/compile/coercion2.rs | 47 +++++
7 files changed, 372 insertions(+), 85 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/coercion2.rs
diff --git a/gcc/rust/backend/rust-compile-base.h
b/gcc/rust/backend/rust-compile-base.h
index d93cc3ba3..15356942d 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -76,8 +76,8 @@ protected:
const Analysis::NodeMapping &mappings,
location_t expr_locus, bool is_qualified_path);
- tree resolve_adjustements (std::vector<Resolver::Adjustment> &adjustments,
- tree expression, location_t locus);
+ tree resolve_adjustments (std::vector<Resolver::Adjustment> &adjustments,
+ tree expression, location_t locus);
tree resolve_deref_adjustment (Resolver::Adjustment &adjustment,
tree expression, location_t locus);
@@ -91,6 +91,9 @@ protected:
tree resolve_unsized_slice_adjustment (Resolver::Adjustment &adjustment,
tree expression, location_t locus);
+ tree resolve_unsized_adt_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, location_t locus);
+
tree resolve_unsized_dyn_adjustment (Resolver::Adjustment &adjustment,
tree expression, location_t locus);
diff --git a/gcc/rust/backend/rust-compile-expr.cc
b/gcc/rust/backend/rust-compile-expr.cc
index 9eac66e8b..574099672 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -504,7 +504,7 @@ CompileExpr::visit (HIR::TypeCastExpr &expr)
if (ok)
{
casted_expr
- = resolve_adjustements (*adjustments, casted_expr, expr.get_locus ());
+ = resolve_adjustments (*adjustments, casted_expr, expr.get_locus ());
}
translated
@@ -1761,8 +1761,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
rust_assert (ok);
// apply adjustments for the fn call
- self = resolve_adjustements (*adjustments, self,
- expr.get_receiver ().get_locus ());
+ self = resolve_adjustments (*adjustments, self,
+ expr.get_receiver ().get_locus ());
std::vector<tree> args;
args.push_back (self); // adjusted self
@@ -1895,7 +1895,7 @@ CompileExpr::resolve_operator_overload (
rust_assert (ok);
// apply adjustments for the fn call
- tree self = resolve_adjustements (*adjustments, lhs, lhs_expr.get_locus ());
+ tree self = resolve_adjustments (*adjustments, lhs, lhs_expr.get_locus ());
std::vector<tree> args;
args.push_back (self); // adjusted self
@@ -2398,7 +2398,7 @@ CompileExpr::array_copied_expr (location_t expr_locus,
}
tree
-HIRCompileBase::resolve_adjustements (
+HIRCompileBase::resolve_adjustments (
std::vector<Resolver::Adjustment> &adjustments, tree expression,
location_t locus)
{
@@ -2492,6 +2492,8 @@ HIRCompileBase::resolve_unsized_adjustment
(Resolver::Adjustment &adjustment,
= adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE;
bool expect_dyn
= adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC;
+ bool expect_adt
+ = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::ADT;
// assumes this is an array
tree expr_type = TREE_TYPE (expression);
@@ -2501,6 +2503,9 @@ HIRCompileBase::resolve_unsized_adjustment
(Resolver::Adjustment &adjustment,
return resolve_unsized_slice_adjustment (adjustment, expression, locus);
}
+ if (expect_adt)
+ return resolve_unsized_adt_adjustment (adjustment, expression, locus);
+
rust_assert (expect_dyn);
return resolve_unsized_dyn_adjustment (adjustment, expression, locus);
}
@@ -2537,6 +2542,105 @@ HIRCompileBase::resolve_unsized_slice_adjustment (
locus);
}
+tree
+HIRCompileBase::resolve_unsized_adt_adjustment (
+ Resolver::Adjustment &adjustment, tree expression, location_t locus)
+{
+ /*
+ * 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
+ = static_cast<const TyTy::ADTType *> (adjustment.get_actual ());
+ 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;
+
+ for (size_t i = 0; i < s_variant->num_fields (); i++)
+ {
+ 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 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
+ {
+ 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)
+ {
+ TyTy::BaseType *s_base = nullptr;
+ TyTy::BaseType *t_base = nullptr;
+ Resolver::Adjustment::AdjustmentType ref_adj_type
+ = Resolver::Adjustment::AdjustmentType::IMM_REF;
+
+ if (is_ptr)
+ {
+ 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;
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ }
+ tree target_type_tree = TyTyResolveCompile::compile (ctx, target_adt);
+ return Backend::constructor_expression (target_type_tree, false,
+ constructor_elements, -1, locus);
+}
+
tree
HIRCompileBase::resolve_unsized_dyn_adjustment (
Resolver::Adjustment &adjustment, tree expression, location_t locus)
@@ -2987,7 +3091,7 @@ CompileExpr::generate_possible_fn_trait_call
(HIR::CallExpr &expr,
rust_assert (ok);
// apply adjustments for the fn call
- tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ());
+ tree self = resolve_adjustments (*adjustments, receiver, expr.get_locus ());
// resolve the arguments
std::vector<tree> tuple_arg_vals;
diff --git a/gcc/rust/typecheck/rust-coercion.cc
b/gcc/rust/typecheck/rust-coercion.cc
index a423449ba..fab689c24 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -316,17 +316,80 @@ TypeCoercionRules::coerce_borrowed_pointer
(TyTy::BaseType *receiver,
tl::expected<TypeCoercionRules::CoercionResult,
TypeCoercionRules::CoerceUnsizedError>
TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
- TyTy::BaseType *target)
+ TyTy::BaseType *target, bool is_inner)
{
rust_debug ("coerce_unsized(source={%s}, target={%s})",
source->debug_str ().c_str (), target->debug_str ().c_str ());
+ size_t adjustments_size = adjustments.size ();
+ auto setup = unwrap_ptrs_and_refs (source, target);
+ if (!setup)
+ return tl::unexpected<CoerceUnsizedError> (setup.error ());
+
+ // FIXME
+ // there is a bunch of code to ensure something is coerce able to a dyn
+ // trait we need to support but we need to support a few more lang items for
+ // that see:
+ //
https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
+
+ auto a = setup->ty_a;
+ auto b = setup->ty_b;
+
+ tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result
+ = tl::unexpected (CoerceUnsizedError::Regular);
+
+ bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
+ bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
+
+ bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE;
+ bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY;
+
+ bool expect_adt = b->get_kind () == TyTy::TypeKind::ADT;
+ bool is_adt = a->get_kind () == TyTy::TypeKind::ADT;
+
+ if (expect_dyn && need_unsize)
+ inner_result
+ = (!setup->unwrapped_pointer && !is_inner)
+ ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
+ : coerce_unsized_dyn (a, b);
+
+ else if (expect_slice && is_array)
+ inner_result
+ = (!setup->unwrapped_pointer && !is_inner)
+ ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
+ : coerce_unsized_array_to_slice (a, b);
+
+ else if (expect_adt && is_adt)
+ inner_result = coerce_unsized_adt (a, b, setup->needs_reborrow);
+
+ if (!inner_result)
+ {
+ adjustments.erase (adjustments.begin () + adjustments_size,
+ adjustments.end ());
+ return tl::unexpected<CoerceUnsizedError> (inner_result.error ());
+ }
+
+ TyTy::BaseType *result = inner_result.value ();
+
+ if (setup->needs_reborrow)
+ result = apply_reborrow_adjustment (source, target, result,
+ setup->expected_mutability);
+
+ return CoercionResult{adjustments, result};
+}
+
+tl::expected<TypeCoercionRules::CoercionSetup,
+ TypeCoercionRules::CoerceUnsizedError>
+TypeCoercionRules::unwrap_ptrs_and_refs (TyTy::BaseType *source,
+ TyTy::BaseType *target)
+{
bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
bool source_is_ptr = source->get_kind () == TyTy::TypeKind::POINTER;
bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
bool needs_reborrow = false;
+ bool unwrapped_pointer = false;
TyTy::BaseType *ty_a = source;
TyTy::BaseType *ty_b = target;
Mutability expected_mutability = Mutability::Imm;
@@ -351,6 +414,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
ty_a = source_ref->get_base ();
ty_b = target_ref->get_base ();
needs_reborrow = true;
+ unwrapped_pointer = true;
expected_mutability = to_mutbl;
adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
@@ -376,6 +440,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
ty_a = source_ref->get_base ();
ty_b = target_ref->get_base ();
needs_reborrow = true;
+ unwrapped_pointer = true;
expected_mutability = to_mutbl;
adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
@@ -400,104 +465,145 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType
*source,
ty_a = source_ref->get_base ();
ty_b = target_ref->get_base ();
needs_reborrow = true;
+ unwrapped_pointer = true;
expected_mutability = to_mutbl;
adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
source_ref, ty_a);
}
- // FIXME
- // there is a bunch of code to ensure something is coerce able to a dyn trait
- // we need to support but we need to support a few more lang items for that
- // see:
- //
https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
+ return CoercionSetup{ty_a, ty_b, needs_reborrow, expected_mutability,
+ unwrapped_pointer};
+}
+
+tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
+TypeCoercionRules::coerce_unsized_array_to_slice (TyTy::BaseType *a,
+ TyTy::BaseType *b)
+{
+ auto array_type = static_cast<const TyTy::ArrayType *> (a);
+ auto slice_type = static_cast<const TyTy::SliceType *> (b);
- const auto a = ty_a;
- const auto b = ty_b;
+ TyTy::BaseType *array_element = array_type->get_element_type ();
+ TyTy::BaseType *slice_element = slice_type->get_element_type ();
- bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
- bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
+ if (!array_element->is_equal (*slice_element))
+ return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
- bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE;
- bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY;
+ TyTy::BaseType *result = b->clone ();
- if (expect_dyn && need_unsize)
- {
- bool bounds_compatible = b->bounds_compatible (*a, locus, false);
- if (!bounds_compatible)
- return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe);
+ adjustments.emplace_back (Adjustment::UNSIZE, a, result);
+
+ return result;
+}
+tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
+TypeCoercionRules::coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b)
+{
+ bool bounds_compatible = b->bounds_compatible (*a, locus, false);
+ if (!bounds_compatible)
+ return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe);
+
+ // return the unsize coercion
+ TyTy::BaseType *result = b->clone ();
+ // result->set_ref (a->get_ref ());
+
+ // append a dyn coercion adjustment
+ adjustments.emplace_back (Adjustment::UNSIZE, a, result);
+
+ return result;
+}
+tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
+TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
+ bool needs_reborrow)
+{
+ auto source_adt = static_cast<const TyTy::ADTType *> (a);
+ auto target_adt = static_cast<const TyTy::ADTType *> (b);
+
+ if ((!source_adt->is_struct_struct () && !source_adt->is_tuple_struct ())
+ || (!target_adt->is_struct_struct () && !target_adt->is_tuple_struct ())
+ || (source_adt->get_id () != target_adt->get_id ())
+ || (source_adt->get_variants ().front ()->num_fields ()
+ != target_adt->get_variants ().front ()->num_fields ()))
+ return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
- // return the unsize coercion
- TyTy::BaseType *result = b->clone ();
- // result->set_ref (a->get_ref ());
+ auto source_variant = source_adt->get_variants ().front ();
+ auto target_variant = target_adt->get_variants ().front ();
- // append a dyn coercion adjustment
- adjustments.emplace_back (Adjustment::UNSIZE, a, result);
+ TyTy::BaseType *differing_source_field = nullptr;
+ TyTy::BaseType *differing_target_field = nullptr;
+ size_t diff_count = 0;
+ bool is_last_field = false;
- // reborrow if needed
- if (needs_reborrow)
+ for (size_t i = 0; i < source_variant->num_fields (); i++)
+ {
+ auto s_field_raw
+ = source_variant->get_field_at_index (i)->get_field_type ();
+ auto t_field_raw
+ = target_variant->get_field_at_index (i)->get_field_type ();
+ auto s_field = s_field_raw->contains_infer ()
+ ? s_field_raw
+ : s_field_raw->monomorphized_clone ();
+ auto t_field = t_field_raw->contains_infer ()
+ ? t_field_raw
+ : t_field_raw->monomorphized_clone ();
+
+ if (s_field->is_zero_sized () && t_field->is_zero_sized ())
+ continue;
+
+ if (!s_field->is_equal (*t_field))
{
- TyTy::ReferenceType *reborrow
- = new TyTy::ReferenceType (source->get_ref (),
- TyTy::TyVar (result->get_ref ()),
- expected_mutability);
-
- Adjustment::AdjustmentType borrow_type
- = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
- : Adjustment::MUT_REF;
- adjustments.emplace_back (borrow_type, result, reborrow);
- result = reborrow;
+ differing_source_field = s_field;
+ differing_target_field = t_field;
+ diff_count++;
+ is_last_field = (i == source_variant->num_fields () - 1);
}
- return CoercionResult{adjustments, result};
}
- else if (expect_slice && is_array)
- {
- auto array_type = static_cast<const TyTy::ArrayType *> (a);
- auto slice_type = static_cast<const TyTy::SliceType *> (b);
- TyTy::BaseType *array_element = array_type->get_element_type ();
- TyTy::BaseType *slice_element = slice_type->get_element_type ();
+ if (diff_count != 1)
+ return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
- if (!array_element->is_equal (*slice_element))
- {
- adjustments.clear ();
- return tl::unexpected<CoerceUnsizedError> (
- CoerceUnsizedError::Regular);
- }
- TyTy::BaseType *result = b->clone ();
+ if (needs_reborrow && !is_last_field)
+ return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
- adjustments.emplace_back (Adjustment::UNSIZE, a, result);
+ auto adjustments_size = adjustments.size ();
+ auto inner_coercion
+ = coerce_unsized (differing_source_field, differing_target_field, true);
+ if (!inner_coercion)
+ return tl::unexpected<CoerceUnsizedError> (inner_coercion.error ());
+ adjustments.erase (adjustments.begin () + adjustments_size,
+ adjustments.end ());
- if (needs_reborrow)
- {
- TyTy::BaseType *reborrow = nullptr;
- if (target->get_kind () == TyTy::TypeKind::POINTER)
- {
- reborrow
- = new TyTy::PointerType (source->get_ref (),
- TyTy::TyVar (result->get_ref ()),
- expected_mutability);
- }
- else
- {
- reborrow
- = new TyTy::ReferenceType (source->get_ref (),
- TyTy::TyVar (result->get_ref ()),
- expected_mutability);
- }
-
- Adjustment::AdjustmentType borrow_type
- = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
- : Adjustment::MUT_REF;
- adjustments.emplace_back (borrow_type, result, reborrow);
- result = reborrow;
- }
+ TyTy::BaseType *result = b->clone ();
+ adjustments.emplace_back (Adjustment::UNSIZE, a, result);
- return CoercionResult{adjustments, result};
+ return result;
+}
+TyTy::BaseType *
+TypeCoercionRules::apply_reborrow_adjustment (TyTy::BaseType *source,
+ TyTy::BaseType *target,
+ TyTy::BaseType *result,
+ Mutability expected_mutability)
+{
+ TyTy::BaseType *reborrow = nullptr;
+
+ if (target->get_kind () == TyTy::TypeKind::POINTER)
+ {
+ reborrow = new TyTy::PointerType (source->get_ref (),
+ TyTy::TyVar (result->get_ref ()),
+ expected_mutability);
}
+ else
+ {
+ reborrow = new TyTy::ReferenceType (source->get_ref (),
+ TyTy::TyVar (result->get_ref ()),
+ expected_mutability);
+ }
+
+ Adjustment::AdjustmentType borrow_type
+ = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
+ : Adjustment::MUT_REF;
- adjustments.clear ();
- return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
+ adjustments.emplace_back (borrow_type, result, reborrow);
+ return reborrow;
}
bool
diff --git a/gcc/rust/typecheck/rust-coercion.h
b/gcc/rust/typecheck/rust-coercion.h
index d52f61051..0674cf5df 100644
--- a/gcc/rust/typecheck/rust-coercion.h
+++ b/gcc/rust/typecheck/rust-coercion.h
@@ -68,7 +68,8 @@ public:
Mutability mutability);
tl::expected<CoercionResult, CoerceUnsizedError>
- coerce_unsized (TyTy::BaseType *receiver, TyTy::BaseType *expected);
+ coerce_unsized (TyTy::BaseType *receiver, TyTy::BaseType *expected,
+ bool is_inner = false);
static bool coerceable_mutability (Mutability from_mutbl,
Mutability to_mutbl);
@@ -87,6 +88,28 @@ protected:
bool do_coercion (TyTy::BaseType *receiver);
+ struct CoercionSetup
+ {
+ TyTy::BaseType *ty_a;
+ TyTy::BaseType *ty_b;
+ bool needs_reborrow;
+ Mutability expected_mutability;
+ bool unwrapped_pointer;
+ };
+ tl::expected<CoercionSetup, CoerceUnsizedError>
+ unwrap_ptrs_and_refs (TyTy::BaseType *source, TyTy::BaseType *target);
+ tl::expected<TyTy::BaseType *, CoerceUnsizedError>
+ coerce_unsized_array_to_slice (TyTy::BaseType *a, TyTy::BaseType *b);
+ tl::expected<TyTy::BaseType *, CoerceUnsizedError>
+ coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b);
+ tl::expected<TyTy::BaseType *, CoerceUnsizedError>
+ coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
+ bool needs_reborrow);
+ TyTy::BaseType *apply_reborrow_adjustment (TyTy::BaseType *source,
+ TyTy::BaseType *target,
+ TyTy::BaseType *result,
+ Mutability expected_mutability);
+
private:
// context info
Analysis::Mappings &mappings;
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index a54b2e594..3be15a805 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -56,6 +56,7 @@ const BiMap<std::string, LangItem::Kind>
Rust::LangItem::lang_items = {{
{"RangeInclusive", Kind::RANGE_INCLUSIVE},
{"RangeToInclusive", Kind::RANGE_TO_INCLUSIVE},
{"range_inclusive_new", Kind::RANGE_INCLUSIVE_NEW},
+ {"coerce_unsized", Kind::COERCE_UNSIZED},
{"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 476752367..8cadfd0c2 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -79,6 +79,9 @@ public:
RANGE_TO_INCLUSIVE,
RANGE_INCLUSIVE_NEW,
+ //
https://github.com/rust-lang/rust/blob/master/library/core/src/ops/unsize.rs
+ COERCE_UNSIZED,
+
// https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
PHANTOM_DATA,
diff --git a/gcc/testsuite/rust/compile/coercion2.rs
b/gcc/testsuite/rust/compile/coercion2.rs
new file mode 100644
index 000000000..d852f3f04
--- /dev/null
+++ b/gcc/testsuite/rust/compile/coercion2.rs
@@ -0,0 +1,47 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {
+ // This lang item is not used for now.
+}
+
+pub struct NonNull<T: ?Sized> {
+ _ptr: *const T,
+}
+
+pub struct Unique<T: ?Sized> {
+ _pointer: NonNull<T>,
+ _marker: PhantomData<T>,
+}
+
+pub struct MyBox<T: ?Sized> {
+ _inner: Unique<T>,
+}
+
+pub struct TailStruct<T: ?Sized> {
+ _header: usize,
+ _data: T,
+}
+
+pub fn test_nested_coercions() {
+ let tail: TailStruct<[i32; 3]> = TailStruct { _header: 1, _data: [1, 2, 3]
};
+ let tail_ptr: *const TailStruct<[i32; 3]> = &tail;
+
+ 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;
+}
--
2.54.0