From 89625360ec4fa11bdc073a74607c7ff0f624fb96 Mon Sep 17 00:00:00 2001
From: xizheyin <xizheyin@smail.nju.edu.cn>
Date: Wed, 26 Mar 2025 11:27:52 +0800
Subject: [PATCH 1/2] Add ui test cast-array-issue-138836

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
---
 tests/ui/cast/cast-array-issue-138836.rs     |  5 +++++
 tests/ui/cast/cast-array-issue-138836.stderr | 12 ++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 tests/ui/cast/cast-array-issue-138836.rs
 create mode 100644 tests/ui/cast/cast-array-issue-138836.stderr

diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs
new file mode 100644
index 0000000000000..6fd65d5878ac9
--- /dev/null
+++ b/tests/ui/cast/cast-array-issue-138836.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let a: [u8; 3] = [1,2,3];
+    let b = &a;
+    let c = b as *const [u32; 3]; //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr
new file mode 100644
index 0000000000000..fe20d429a4989
--- /dev/null
+++ b/tests/ui/cast/cast-array-issue-138836.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/cast-array-issue-138836.rs:4:13
+   |
+LL |     let c = b as *const [u32; 3];
+   |             ^^^^^^^^^^^^^^^^^^^^ expected `[u8; 3]`, found `[u32; 3]`
+   |
+   = note: expected array `[u8; 3]`
+              found array `[u32; 3]`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.

From a34c42fefabc774af2d8b2c5a5a100c0697d2ba9 Mon Sep 17 00:00:00 2001
From: xizheyin <xizheyin@smail.nju.edu.cn>
Date: Wed, 26 Mar 2025 11:31:58 +0800
Subject: [PATCH 2/2] Expect an array when expected and acutal types are both
 arrays during cast

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
---
 compiler/rustc_hir_typeck/src/cast.rs        | 39 ++++++++++----------
 tests/ui/cast/cast-array-issue-138836.rs     |  2 +-
 tests/ui/cast/cast-array-issue-138836.stderr |  9 ++---
 tests/ui/consts/const-cast-wrong-type.rs     |  2 +-
 tests/ui/consts/const-cast-wrong-type.stderr |  6 +--
 5 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 8f5fddd19d7f6..b19d9efe2c6f5 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         m_cast: ty::TypeAndMut<'tcx>,
     ) -> Result<CastKind, CastError<'tcx>> {
         // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
-        if m_expr.mutbl >= m_cast.mutbl {
-            if let ty::Array(ety, _) = m_expr.ty.kind() {
-                // Due to the limitations of LLVM global constants,
-                // region pointers end up pointing at copies of
-                // vector elements instead of the original values.
-                // To allow raw pointers to work correctly, we
-                // need to special-case obtaining a raw pointer
-                // from a region pointer to a vector.
-
-                // Coerce to a raw pointer so that we generate RawPtr in MIR.
-                let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
-                fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
-                    .unwrap_or_else(|_| {
-                        bug!(
+        if m_expr.mutbl >= m_cast.mutbl
+            && let ty::Array(ety, _) = m_expr.ty.kind()
+            && fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
+        {
+            // Due to the limitations of LLVM global constants,
+            // region pointers end up pointing at copies of
+            // vector elements instead of the original values.
+            // To allow raw pointers to work correctly, we
+            // need to special-case obtaining a raw pointer
+            // from a region pointer to a vector.
+
+            // Coerce to a raw pointer so that we generate RawPtr in MIR.
+            let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
+            fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
+                .unwrap_or_else(|_| {
+                    bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
                         self.expr_ty,
                         array_ptr_type,
                     )
-                    });
+                });
 
-                // this will report a type mismatch if needed
-                fcx.demand_eqtype(self.span, *ety, m_cast.ty);
-                return Ok(CastKind::ArrayPtrCast);
-            }
+            // this will report a type mismatch if needed
+            fcx.demand_eqtype(self.span, *ety, m_cast.ty);
+            return Ok(CastKind::ArrayPtrCast);
         }
 
         Err(CastError::IllegalCast)
diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs
index 6fd65d5878ac9..3f8098e76fd29 100644
--- a/tests/ui/cast/cast-array-issue-138836.rs
+++ b/tests/ui/cast/cast-array-issue-138836.rs
@@ -1,5 +1,5 @@
 fn main() {
     let a: [u8; 3] = [1,2,3];
     let b = &a;
-    let c = b as *const [u32; 3]; //~ ERROR mismatched types [E0308]
+    let c = b as *const [u32; 3]; //~ ERROR casting `&[u8; 3]` as `*const [u32; 3]` is invalid
 }
diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr
index fe20d429a4989..309474c29f933 100644
--- a/tests/ui/cast/cast-array-issue-138836.stderr
+++ b/tests/ui/cast/cast-array-issue-138836.stderr
@@ -1,12 +1,9 @@
-error[E0308]: mismatched types
+error[E0606]: casting `&[u8; 3]` as `*const [u32; 3]` is invalid
   --> $DIR/cast-array-issue-138836.rs:4:13
    |
 LL |     let c = b as *const [u32; 3];
-   |             ^^^^^^^^^^^^^^^^^^^^ expected `[u8; 3]`, found `[u32; 3]`
-   |
-   = note: expected array `[u8; 3]`
-              found array `[u32; 3]`
+   |             ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/consts/const-cast-wrong-type.rs b/tests/ui/consts/const-cast-wrong-type.rs
index 6e055a2bcd340..9936a660936b0 100644
--- a/tests/ui/consts/const-cast-wrong-type.rs
+++ b/tests/ui/consts/const-cast-wrong-type.rs
@@ -1,5 +1,5 @@
 const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
-const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
+const b: *const i8 = &a as *const i8; //~ ERROR casting `&[u8; 3]` as `*const i8` is invalid
 
 fn main() {
 }
diff --git a/tests/ui/consts/const-cast-wrong-type.stderr b/tests/ui/consts/const-cast-wrong-type.stderr
index 44361f15d8a98..0730bac22354d 100644
--- a/tests/ui/consts/const-cast-wrong-type.stderr
+++ b/tests/ui/consts/const-cast-wrong-type.stderr
@@ -1,9 +1,9 @@
-error[E0308]: mismatched types
+error[E0606]: casting `&[u8; 3]` as `*const i8` is invalid
   --> $DIR/const-cast-wrong-type.rs:2:22
    |
 LL | const b: *const i8 = &a as *const i8;
-   |                      ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
+   |                      ^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0606`.