From: Enes Cevik <[email protected]>

This patch enables fundamental array-to-slice (`[T; N]` to `[T]`)
unsized coercions. Previously, the compiler only handled `dyn Trait`
unsized coercions and immediately rejected array-to-slice conversions.
Now, the compiler correctly identifies valid array-to-slice coercions
and generates the appropriate `Adjustment::UNSIZE` tags.

gcc/rust/ChangeLog:

        * typecheck/rust-coercion.cc
        (TypeCoercionRules::coerce_unsized): Add array-to-slice coercion
        support.

gcc/testsuite/ChangeLog:

        * rust/compile/coercion.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/19b40258edd45bdeef85a5d5289baae358057156

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/typecheck/rust-coercion.cc    | 72 ++++++++++++++++++++++++++
 gcc/testsuite/rust/compile/coercion.rs | 39 ++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 gcc/testsuite/rust/compile/coercion.rs

diff --git a/gcc/rust/typecheck/rust-coercion.cc 
b/gcc/rust/typecheck/rust-coercion.cc
index 954065ee6..a423449ba 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -322,6 +322,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
              source->debug_str ().c_str (), target->debug_str ().c_str ());
 
   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;
 
@@ -377,6 +378,30 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
       needs_reborrow = true;
       expected_mutability = to_mutbl;
 
+      adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
+                               source_ref, ty_a);
+    }
+  else if (source_is_ptr && target_is_ptr)
+    {
+      TyTy::PointerType *source_ref = static_cast<TyTy::PointerType *> 
(source);
+      TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> 
(target);
+
+      Mutability from_mutbl = source_ref->mutability ();
+      Mutability to_mutbl = target_ref->mutability ();
+      if (!coerceable_mutability (from_mutbl, to_mutbl))
+       {
+         location_t lhs = mappings.lookup_location (source->get_ref ());
+         location_t rhs = mappings.lookup_location (target->get_ref ());
+         mismatched_mutability_error (locus, lhs, rhs);
+         return tl::unexpected<CoerceUnsizedError> (
+           CoerceUnsizedError::Unsafe);
+       }
+
+      ty_a = source_ref->get_base ();
+      ty_b = target_ref->get_base ();
+      needs_reborrow = true;
+      expected_mutability = to_mutbl;
+
       adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
                                source_ref, ty_a);
     }
@@ -393,6 +418,9 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
   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;
+
   if (expect_dyn && need_unsize)
     {
       bool bounds_compatible = b->bounds_compatible (*a, locus, false);
@@ -420,6 +448,50 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
          adjustments.emplace_back (borrow_type, result, reborrow);
          result = reborrow;
        }
+      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 (!array_element->is_equal (*slice_element))
+       {
+         adjustments.clear ();
+         return tl::unexpected<CoerceUnsizedError> (
+           CoerceUnsizedError::Regular);
+       }
+      TyTy::BaseType *result = b->clone ();
+
+      adjustments.emplace_back (Adjustment::UNSIZE, a, result);
+
+      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;
+       }
 
       return CoercionResult{adjustments, result};
     }
diff --git a/gcc/testsuite/rust/compile/coercion.rs 
b/gcc/testsuite/rust/compile/coercion.rs
new file mode 100644
index 000000000..30adbd266
--- /dev/null
+++ b/gcc/testsuite/rust/compile/coercion.rs
@@ -0,0 +1,39 @@
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+fn main() {
+    let arr: [i32; 4] = [1, 2, 3, 4];
+    let mut arr_mut: [i32; 4] = [1, 2, 3, 4];
+
+    // 1. &mut T -> &mut U
+    let _mut_to_mut: &mut [i32] = &mut arr_mut;
+    
+    // 2. &mut T -> &U
+    let _mut_to_ref: &[i32] = &mut arr_mut;
+    
+    // 3. &mut T -> *mut U
+    let _mut_to_ptr_mut: *mut [i32] = &mut arr_mut;
+    
+    // 4. &mut T -> *const U
+    let _mut_to_ptr_const: *const [i32] = &mut arr_mut;
+
+    // 5. &T -> &U
+    let _ref_to_ref: &[i32] = &arr;
+    
+    // 6. &T -> *const U
+    let _ref_to_ptr_const: *const [i32] = &arr;
+
+    // 7. *mut T -> *mut U
+    let raw_mut: *mut [i32; 4] = &mut arr_mut;
+    let _ptr_mut_to_ptr_mut: *mut [i32] = raw_mut;
+
+    // 8. *mut T -> *const U
+    let _ptr_mut_to_ptr_const: *const [i32] = raw_mut;
+
+    // 9. *const T -> *const U
+    let raw_const: *const [i32; 4] = &arr;
+    let _ptr_const_to_ptr_const: *const [i32] = raw_const;
+}
-- 
2.54.0

Reply via email to