about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2022-08-03 13:16:04 -0400
committerJason Newcomb <jsnewcomb@pm.me>2022-08-03 14:41:32 -0400
commitb426bd52a167a55eee029a45b42e7c0eece1f1c0 (patch)
treec09f357ed0e9bdac7e327d6d0028800bd44e2c26
parent71777465cc71b365ca08db8afd5c25eb99bd3f08 (diff)
downloadrust-b426bd52a167a55eee029a45b42e7c0eece1f1c0.tar.gz
rust-b426bd52a167a55eee029a45b42e7c0eece1f1c0.zip
Don't lint `transmute_undefined_repr` when the the first field of a `repr(C)` type is compatible with the other type
-rw-r--r--clippy_lints/src/transmute/transmute_undefined_repr.rs29
-rw-r--r--tests/ui/transmute_undefined_repr.rs8
-rw-r--r--tests/ui/transmute_undefined_repr.stderr22
3 files changed, 44 insertions, 15 deletions
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 20b348fc14f..bf1cfb859bc 100644
--- a/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -164,9 +164,18 @@ pub(super) fn check<'tcx>(
                     );
                     return true;
                 },
+                // `Repr(C)` <-> unordered type.
+                // If the first field of the `Repr(C)` type matches then the transmute is ok
+                (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
+                | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
+                | (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
+                    from_ty = from_sub_ty;
+                    to_ty = to_sub_ty;
+                    continue;
+                },
                 (
                     ReducedTy::UnorderedFields(from_ty),
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
+                    ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
                 ) => {
                     span_lint_and_then(
                         cx,
@@ -182,7 +191,7 @@ pub(super) fn check<'tcx>(
                     return true;
                 },
                 (
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
+                    ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
                     ReducedTy::UnorderedFields(to_ty),
                 ) => {
                     span_lint_and_then(
@@ -198,14 +207,9 @@ pub(super) fn check<'tcx>(
                     );
                     return true;
                 },
-                (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
                 (
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
+                    ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
+                    ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
                 )
                 | (
                     ReducedTy::UnorderedFields(_) | ReducedTy::Param,
@@ -269,7 +273,8 @@ enum ReducedTy<'tcx> {
     TypeErasure,
     /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
     /// sized fields with a defined order.
-    OrderedFields(Ty<'tcx>),
+    /// The second value is the first non-zero sized type.
+    OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
     /// The type is a struct containing multiple non-zero sized fields with no defined order.
     UnorderedFields(Ty<'tcx>),
     /// The type is a reference to the contained type.
@@ -294,7 +299,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
             ty::Tuple(args) => {
                 let mut iter = args.iter();
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
-                    return ReducedTy::OrderedFields(ty);
+                    return ReducedTy::OrderedFields(ty, None);
                 };
                 if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
                     ty = sized_ty;
@@ -316,7 +321,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     continue;
                 }
                 if def.repr().inhibit_struct_field_reordering_opt() {
-                    ReducedTy::OrderedFields(ty)
+                    ReducedTy::OrderedFields(ty, Some(sized_ty))
                 } else {
                     ReducedTy::UnorderedFields(ty)
                 }
diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs
index ebcaa7a84cf..6df8ed8feea 100644
--- a/tests/ui/transmute_undefined_repr.rs
+++ b/tests/ui/transmute_undefined_repr.rs
@@ -109,6 +109,14 @@ fn main() {
         let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
 
         let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
+        let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
+        let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+        let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
     }
 }
 
diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr
index 28bfba6c757..8319f71a83d 100644
--- a/tests/ui/transmute_undefined_repr.stderr
+++ b/tests/ui/transmute_undefined_repr.stderr
@@ -60,8 +60,24 @@ LL |         let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32,
    |
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
+error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:118:39
+   |
+LL |         let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
+error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:119:50
+   |
+LL |         let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
 error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:138:35
+  --> $DIR/transmute_undefined_repr.rs:146:35
    |
 LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,12 +85,12 @@ LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); /
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
 error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:139:35
+  --> $DIR/transmute_undefined_repr.rs:147:35
    |
 LL |         let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors