Skip to content

Commit 65e5cd0

Browse files
committed
Auto merge of rust-lang#8553 - Jarcho:transmute_undefined_8499, r=llogiq
Don't lint `transmute_undefined_repr` when changing the type of generic params Partially fixes rust-lang#8499 changelog: Don't lint `transmute_undefined_repr` when changing the type of generic params
2 parents d23ddab + 8e5208c commit 65e5cd0

File tree

3 files changed

+102
-28
lines changed

3 files changed

+102
-28
lines changed

clippy_lints/src/transmute/transmute_undefined_repr.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::ty::is_c_void;
44
use rustc_hir::Expr;
55
use rustc_lint::LateContext;
6-
use rustc_middle::ty::subst::Subst;
6+
use rustc_middle::ty::subst::{Subst, SubstsRef};
77
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
88
use rustc_span::Span;
99

@@ -127,6 +127,17 @@ pub(super) fn check<'tcx>(
127127
} => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
128128
(ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
129129
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
130+
let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
131+
= (from_ty.kind(), to_ty.kind())
132+
&& from_def == to_def
133+
{
134+
if same_except_params(from_subs, to_subs) {
135+
return false;
136+
}
137+
Some(from_def.did())
138+
} else {
139+
None
140+
};
130141
span_lint_and_then(
131142
cx,
132143
TRANSMUTE_UNDEFINED_REPR,
@@ -136,21 +147,17 @@ pub(super) fn check<'tcx>(
136147
from_ty_orig, to_ty_orig
137148
),
138149
|diag| {
139-
if_chain! {
140-
if let (Some(from_def), Some(to_def)) = (from_ty.ty_adt_def(), to_ty.ty_adt_def());
141-
if from_def == to_def;
142-
then {
143-
diag.note(&format!(
144-
"two instances of the same generic type (`{}`) may have different layouts",
145-
cx.tcx.item_name(from_def.did())
146-
));
147-
} else {
148-
if from_ty_orig.peel_refs() != from_ty {
149-
diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
150-
}
151-
if to_ty_orig.peel_refs() != to_ty {
152-
diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
153-
}
150+
if let Some(same_adt_did) = same_adt_did {
151+
diag.note(&format!(
152+
"two instances of the same generic type (`{}`) may have different layouts",
153+
cx.tcx.item_name(same_adt_did)
154+
));
155+
} else {
156+
if from_ty_orig.peel_refs() != from_ty {
157+
diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
158+
}
159+
if to_ty_orig.peel_refs() != to_ty {
160+
diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
154161
}
155162
}
156163
},
@@ -197,10 +204,13 @@ pub(super) fn check<'tcx>(
197204
continue;
198205
},
199206
(
200-
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_),
201-
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_),
207+
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
208+
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
202209
)
203-
| (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => break,
210+
| (
211+
ReducedTy::UnorderedFields(_) | ReducedTy::Param,
212+
ReducedTy::UnorderedFields(_) | ReducedTy::Param,
213+
) => break,
204214
},
205215
}
206216
}
@@ -264,6 +274,8 @@ enum ReducedTy<'tcx> {
264274
UnorderedFields(Ty<'tcx>),
265275
/// The type is a reference to the contained type.
266276
Ref(Ty<'tcx>),
277+
/// The type is a generic parameter.
278+
Param,
267279
/// Any other type.
268280
Other(Ty<'tcx>),
269281
}
@@ -317,6 +329,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
317329
ty::Foreign(_) => ReducedTy::TypeErasure,
318330
ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
319331
ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
332+
ty::Param(_) => ReducedTy::Param,
320333
_ => ReducedTy::Other(ty),
321334
};
322335
}
@@ -344,3 +357,16 @@ fn is_size_pair(ty: Ty<'_>) -> bool {
344357
false
345358
}
346359
}
360+
361+
fn same_except_params(subs1: SubstsRef<'_>, subs2: SubstsRef<'_>) -> bool {
362+
// TODO: check const parameters as well. Currently this will consider `Array<5>` the same as
363+
// `Array<6>`
364+
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
365+
match (ty1.kind(), ty2.kind()) {
366+
(ty::Param(_), _) | (_, ty::Param(_)) => (),
367+
(ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
368+
_ => return false,
369+
}
370+
}
371+
true
372+
}

tests/ui/transmute_undefined_repr.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(clippy::transmute_undefined_repr)]
22
#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)]
33

4+
use core::any::TypeId;
45
use core::ffi::c_void;
56
use core::mem::{size_of, transmute, MaybeUninit};
67

@@ -110,3 +111,34 @@ fn main() {
110111
let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
111112
}
112113
}
114+
115+
fn _with_generics<T: 'static, U: 'static>() {
116+
if TypeId::of::<T>() != TypeId::of::<u32>() || TypeId::of::<T>() != TypeId::of::<U>() {
117+
return;
118+
}
119+
unsafe {
120+
let _: &u32 = transmute(value::<&T>()); // Ok
121+
let _: &T = transmute(value::<&u32>()); // Ok
122+
123+
let _: Vec<U> = transmute(value::<Vec<T>>()); // Ok
124+
let _: Vec<T> = transmute(value::<Vec<U>>()); // Ok
125+
126+
let _: Ty<&u32> = transmute(value::<&T>()); // Ok
127+
let _: Ty<&T> = transmute(value::<&u32>()); // Ok
128+
129+
let _: Vec<u32> = transmute(value::<Vec<T>>()); // Ok
130+
let _: Vec<T> = transmute(value::<Vec<u32>>()); // Ok
131+
132+
let _: &Ty2<u32, u32> = transmute(value::<&Ty2<T, U>>()); // Ok
133+
let _: &Ty2<T, U> = transmute(value::<&Ty2<u32, u32>>()); // Ok
134+
135+
let _: Vec<Vec<u32>> = transmute(value::<Vec<Vec<T>>>()); // Ok
136+
let _: Vec<Vec<T>> = transmute(value::<Vec<Vec<u32>>>()); // Ok
137+
138+
let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
139+
let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
140+
141+
let _: *const u32 = transmute(value::<Box<T>>()); // Ok
142+
let _: Box<T> = transmute(value::<*const u32>()); // Ok
143+
}
144+
}
Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,80 @@
11
error: transmute from `Ty2<u32, i32>` which has an undefined layout
2-
--> $DIR/transmute_undefined_repr.rs:26:33
2+
--> $DIR/transmute_undefined_repr.rs:27:33
33
|
44
LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::transmute-undefined-repr` implied by `-D warnings`
88

99
error: transmute into `Ty2<u32, i32>` which has an undefined layout
10-
--> $DIR/transmute_undefined_repr.rs:27:32
10+
--> $DIR/transmute_undefined_repr.rs:28:32
1111
|
1212
LL | let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
16-
--> $DIR/transmute_undefined_repr.rs:32:32
16+
--> $DIR/transmute_undefined_repr.rs:33:32
1717
|
1818
LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020
|
2121
= note: two instances of the same generic type (`Ty2`) may have different layouts
2222

2323
error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
24-
--> $DIR/transmute_undefined_repr.rs:33:36
24+
--> $DIR/transmute_undefined_repr.rs:34:36
2525
|
2626
LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
2727
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2828
|
2929
= note: two instances of the same generic type (`Ty2`) may have different layouts
3030

3131
error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout
32-
--> $DIR/transmute_undefined_repr.rs:38:33
32+
--> $DIR/transmute_undefined_repr.rs:39:33
3333
|
3434
LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3636
|
3737
= note: two instances of the same generic type (`Ty2`) may have different layouts
3838

3939
error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout
40-
--> $DIR/transmute_undefined_repr.rs:39:37
40+
--> $DIR/transmute_undefined_repr.rs:40:37
4141
|
4242
LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
4343
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4444
|
4545
= note: two instances of the same generic type (`Ty2`) may have different layouts
4646

4747
error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout
48-
--> $DIR/transmute_undefined_repr.rs:56:45
48+
--> $DIR/transmute_undefined_repr.rs:57:45
4949
|
5050
LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
5151
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5252
|
5353
= note: two instances of the same generic type (`Ty2`) may have different layouts
5454

5555
error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout
56-
--> $DIR/transmute_undefined_repr.rs:57:37
56+
--> $DIR/transmute_undefined_repr.rs:58:37
5757
|
5858
LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
5959
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6060
|
6161
= note: two instances of the same generic type (`Ty2`) may have different layouts
6262

63-
error: aborting due to 8 previous errors
63+
error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
64+
--> $DIR/transmute_undefined_repr.rs:138:35
65+
|
66+
LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
|
69+
= note: two instances of the same generic type (`Vec`) may have different layouts
70+
71+
error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
72+
--> $DIR/transmute_undefined_repr.rs:139:35
73+
|
74+
LL | let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76+
|
77+
= note: two instances of the same generic type (`Vec`) may have different layouts
78+
79+
error: aborting due to 10 previous errors
6480

0 commit comments

Comments
 (0)