diff options
| author | Jason Newcomb <jsnewcomb@pm.me> | 2022-03-16 12:54:32 -0400 |
|---|---|---|
| committer | Jason Newcomb <jsnewcomb@pm.me> | 2022-03-16 12:56:23 -0400 |
| commit | 8e5208cbffd5ff43f80097d74a8802aad1d6190b (patch) | |
| tree | af7c76a74bec56cc1a0773b3bd72c60229b8f5aa | |
| parent | d23ddab82d74cf6bfd72d282254a5c19c9631ef2 (diff) | |
| download | rust-8e5208cbffd5ff43f80097d74a8802aad1d6190b.tar.gz rust-8e5208cbffd5ff43f80097d74a8802aad1d6190b.zip | |
Don't lint `transmute_undefined_repr` when changing the type of generic params
| -rw-r--r-- | clippy_lints/src/transmute/transmute_undefined_repr.rs | 64 | ||||
| -rw-r--r-- | tests/ui/transmute_undefined_repr.rs | 32 | ||||
| -rw-r--r-- | tests/ui/transmute_undefined_repr.stderr | 34 |
3 files changed, 102 insertions, 28 deletions
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 4922c40bcef..f5e21267a89 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_c_void; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy}; use rustc_span::Span; @@ -127,6 +127,17 @@ pub(super) fn check<'tcx>( } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) { (ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false, (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { + let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) + = (from_ty.kind(), to_ty.kind()) + && from_def == to_def + { + if same_except_params(from_subs, to_subs) { + return false; + } + Some(from_def.did()) + } else { + None + }; span_lint_and_then( cx, TRANSMUTE_UNDEFINED_REPR, @@ -136,21 +147,17 @@ pub(super) fn check<'tcx>( from_ty_orig, to_ty_orig ), |diag| { - if_chain! { - if let (Some(from_def), Some(to_def)) = (from_ty.ty_adt_def(), to_ty.ty_adt_def()); - if from_def == to_def; - then { - diag.note(&format!( - "two instances of the same generic type (`{}`) may have different layouts", - cx.tcx.item_name(from_def.did()) - )); - } else { - if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); - } - if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); - } + if let Some(same_adt_did) = same_adt_did { + diag.note(&format!( + "two instances of the same generic type (`{}`) may have different layouts", + cx.tcx.item_name(same_adt_did) + )); + } else { + if from_ty_orig.peel_refs() != from_ty { + diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + } + if to_ty_orig.peel_refs() != to_ty { + diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); } } }, @@ -197,10 +204,13 @@ pub(super) fn check<'tcx>( continue; }, ( - ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_), - ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_), + ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, + ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, ) - | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => break, + | ( + ReducedTy::UnorderedFields(_) | ReducedTy::Param, + ReducedTy::UnorderedFields(_) | ReducedTy::Param, + ) => break, }, } } @@ -264,6 +274,8 @@ enum ReducedTy<'tcx> { UnorderedFields(Ty<'tcx>), /// The type is a reference to the contained type. Ref(Ty<'tcx>), + /// The type is a generic parameter. + Param, /// Any other type. Other(Ty<'tcx>), } @@ -317,6 +329,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ty::Foreign(_) => ReducedTy::TypeErasure, ty::Ref(_, ty, _) => ReducedTy::Ref(ty), ty::RawPtr(ty) => ReducedTy::Ref(ty.ty), + ty::Param(_) => ReducedTy::Param, _ => ReducedTy::Other(ty), }; } @@ -344,3 +357,16 @@ fn is_size_pair(ty: Ty<'_>) -> bool { false } } + +fn same_except_params(subs1: SubstsRef<'_>, subs2: SubstsRef<'_>) -> bool { + // TODO: check const parameters as well. Currently this will consider `Array<5>` the same as + // `Array<6>` + for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) { + match (ty1.kind(), ty2.kind()) { + (ty::Param(_), _) | (_, ty::Param(_)) => (), + (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (), + _ => return false, + } + } + true +} diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index 7cc03b89fe0..b06ed4a9173 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -1,6 +1,7 @@ #![warn(clippy::transmute_undefined_repr)] #![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)] +use core::any::TypeId; use core::ffi::c_void; use core::mem::{size_of, transmute, MaybeUninit}; @@ -110,3 +111,34 @@ fn main() { let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok } } + +fn _with_generics<T: 'static, U: 'static>() { + if TypeId::of::<T>() != TypeId::of::<u32>() || TypeId::of::<T>() != TypeId::of::<U>() { + return; + } + unsafe { + let _: &u32 = transmute(value::<&T>()); // Ok + let _: &T = transmute(value::<&u32>()); // Ok + + let _: Vec<U> = transmute(value::<Vec<T>>()); // Ok + let _: Vec<T> = transmute(value::<Vec<U>>()); // Ok + + let _: Ty<&u32> = transmute(value::<&T>()); // Ok + let _: Ty<&T> = transmute(value::<&u32>()); // Ok + + let _: Vec<u32> = transmute(value::<Vec<T>>()); // Ok + let _: Vec<T> = transmute(value::<Vec<u32>>()); // Ok + + let _: &Ty2<u32, u32> = transmute(value::<&Ty2<T, U>>()); // Ok + let _: &Ty2<T, U> = transmute(value::<&Ty2<u32, u32>>()); // Ok + + let _: Vec<Vec<u32>> = transmute(value::<Vec<Vec<T>>>()); // Ok + let _: Vec<Vec<T>> = transmute(value::<Vec<Vec<u32>>>()); // Ok + + let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err + let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err + + let _: *const u32 = transmute(value::<Box<T>>()); // Ok + let _: Box<T> = transmute(value::<*const u32>()); // Ok + } +} diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 42d544fc954..28bfba6c757 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -1,5 +1,5 @@ error: transmute from `Ty2<u32, i32>` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:26:33 + --> $DIR/transmute_undefined_repr.rs:27:33 | LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lin = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings` error: transmute into `Ty2<u32, i32>` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:27:32 + --> $DIR/transmute_undefined_repr.rs:28:32 | LL | let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:32:32 + --> $DIR/transmute_undefined_repr.rs:33:32 | LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:33:36 + --> $DIR/transmute_undefined_repr.rs:34:36 | LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:38:33 + --> $DIR/transmute_undefined_repr.rs:39:33 | LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:39:37 + --> $DIR/transmute_undefined_repr.rs:40:37 | LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:56:45 + --> $DIR/transmute_undefined_repr.rs:57:45 | LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,12 +53,28 @@ LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:57:37 + --> $DIR/transmute_undefined_repr.rs:58:37 | LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Ty2`) may have different layouts -error: aborting due to 8 previous errors +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 + | +LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + | +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 |
