From b426bd52a167a55eee029a45b42e7c0eece1f1c0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 3 Aug 2022 13:16:04 -0400 Subject: [PATCH] Don't lint `transmute_undefined_repr` when the the first field of a `repr(C)` type is compatible with the other type --- .../src/transmute/transmute_undefined_repr.rs | 29 +++++++++++-------- tests/ui/transmute_undefined_repr.rs | 8 +++++ tests/ui/transmute_undefined_repr.stderr | 22 ++++++++++++-- 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 20b348fc14f7..bf1cfb859bc3 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>), /// 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 ebcaa7a84cfb..6df8ed8feeac 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -109,6 +109,14 @@ fn main() { let _: Ty2 = transmute(value::>>()); // Ok let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C, u32>>()); // Ok + let _: *const Ty2C, u32> = transmute(value::<*const Ty2>()); // Ok + let _: *const Ty2 = transmute(value::<*const Ty2C<(), Ty2>>()); // Ok + let _: *const Ty2C<(), Ty2> = transmute(value::<*const Ty2>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err } } diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 28bfba6c7571..8319f71a83dc 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -60,8 +60,24 @@ LL | let _: Box> = transmute(value::<&'static mut Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:118:39 + | +LL | let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + +error: transmute from `*const Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:119:50 + | +LL | let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:138:35 + --> $DIR/transmute_undefined_repr.rs:146:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,12 +85,12 @@ LL | let _: Vec> = transmute(value::>>()); / = note: two instances of the same generic type (`Vec`) may have different layouts error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:139:35 + --> $DIR/transmute_undefined_repr.rs:147:35 | LL | let _: Vec> = transmute(value::>>()); // 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