Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't lint transmute_undefined_repr when changing the type of generic params #8553

Merged
merged 1 commit into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions clippy_lints/src/transmute/transmute_undefined_repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand All @@ -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));
}
}
},
Expand Down Expand Up @@ -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,
},
}
}
Expand Down Expand Up @@ -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>),
}
Expand Down Expand Up @@ -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),
};
}
Expand Down Expand Up @@ -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
}
32 changes: 32 additions & 0 deletions tests/ui/transmute_undefined_repr.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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
}
}
34 changes: 25 additions & 9 deletions tests/ui/transmute_undefined_repr.stderr
Original file line number Diff line number Diff line change
@@ -1,64 +1,80 @@
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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