about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/transmute/transmute_undefined_repr.rs66
-rw-r--r--tests/ui/transmute_undefined_repr.rs16
2 files changed, 50 insertions, 32 deletions
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 74bdace408c..2630bc4e9ab 100644
--- a/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -19,33 +19,39 @@ pub(super) fn check<'tcx>(
 
     while from_ty != to_ty {
         match reduce_refs(cx, e.span, from_ty, to_ty) {
-            ReducedTys::FromFatPtr { unsized_ty, .. } => {
-                span_lint_and_then(
-                    cx,
-                    TRANSMUTE_UNDEFINED_REPR,
-                    e.span,
-                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                    |diag| {
-                        if from_ty_orig.peel_refs() != unsized_ty {
-                            diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                        }
-                    },
-                );
-                return true;
+            ReducedTys::FromFatPtr { unsized_ty, to_ty } => match reduce_ty(cx, to_ty) {
+                ReducedTy::IntArray | ReducedTy::TypeErasure => break,
+                _ => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                        |diag| {
+                            if from_ty_orig.peel_refs() != unsized_ty {
+                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
             },
-            ReducedTys::ToFatPtr { unsized_ty, .. } => {
-                span_lint_and_then(
-                    cx,
-                    TRANSMUTE_UNDEFINED_REPR,
-                    e.span,
-                    &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
-                    |diag| {
-                        if to_ty_orig.peel_refs() != unsized_ty {
-                            diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                        }
-                    },
-                );
-                return true;
+            ReducedTys::ToFatPtr { unsized_ty, from_ty } => match reduce_ty(cx, from_ty) {
+                ReducedTy::IntArray | ReducedTy::TypeErasure => break,
+                _ => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
+                        |diag| {
+                            if to_ty_orig.peel_refs() != unsized_ty {
+                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
             },
             ReducedTys::ToPtr {
                 from_ty: from_sub_ty,
@@ -184,8 +190,8 @@ pub(super) fn check<'tcx>(
 }
 
 enum ReducedTys<'tcx> {
-    FromFatPtr { unsized_ty: Ty<'tcx> },
-    ToFatPtr { unsized_ty: Ty<'tcx> },
+    FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+    ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> },
     ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
     FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
     Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
@@ -211,12 +217,12 @@ fn reduce_refs<'tcx>(
             (ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }), _)
                 if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
             {
-                ReducedTys::FromFatPtr { unsized_ty }
+                ReducedTys::FromFatPtr { unsized_ty, to_ty }
             },
             (_, ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }))
                 if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
             {
-                ReducedTys::ToFatPtr { unsized_ty }
+                ReducedTys::ToFatPtr { unsized_ty, from_ty }
             },
             (ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. }), _) => {
                 ReducedTys::FromPtr { from_ty, to_ty }
diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs
index c1ee0d98a92..84dd1ada8c3 100644
--- a/tests/ui/transmute_undefined_repr.rs
+++ b/tests/ui/transmute_undefined_repr.rs
@@ -1,8 +1,8 @@
 #![warn(clippy::transmute_undefined_repr)]
-#![allow(clippy::unit_arg)]
+#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)]
 
 use core::ffi::c_void;
-use core::mem::transmute;
+use core::mem::{size_of, transmute};
 
 fn value<T>() -> T {
     unimplemented!()
@@ -72,5 +72,17 @@ fn main() {
         );
         let _: *const Erase2 = transmute(value::<Ty<&Ty2<u32, f32>>>()); // Ok, type erasure
         let _: Ty<&Ty2<u32, f32>> = transmute(value::<*const Erase2>()); // Ok, reverse type erasure
+
+        let _: *const () = transmute(value::<&&[u8]>()); // Ok, type erasure
+        let _: &&[u8] = transmute(value::<*const ()>()); // Ok, reverse type erasure
+
+        let _: *mut c_void = transmute(value::<&mut &[u8]>()); // Ok, type erasure
+        let _: &mut &[u8] = transmute(value::<*mut c_void>()); // Ok, reverse type erasure
+
+        let _: [u8; size_of::<&[u8]>()] = transmute(value::<&[u8]>()); // Ok, transmute to byte array
+        let _: &[u8] = transmute(value::<[u8; size_of::<&[u8]>()]>()); // Ok, transmute from byte array
+
+        let _: [usize; 2] = transmute(value::<&[u8]>()); // Ok, transmute to int array
+        let _: &[u8] = transmute(value::<[usize; 2]>()); // Ok, transmute from int array
     }
 }