[gccrs COMMIT 3/6] typecheck: Add ADT to ADT unsize coercion support

gerris.rs@gmail.com gerris.rs@gmail.com
Sat Aug 15 21:42:14 GMT 2026


From: Enes Cevik <enes@nsvke.com>

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 <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/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



More information about the Gcc-rust mailing list