Skip to content

Commit 447a245

Browse files
committed
Allow various type erasure patterns in transmute_undefined_repr
1 parent 01732b6 commit 447a245

File tree

6 files changed

+96
-74
lines changed

6 files changed

+96
-74
lines changed

clippy_lints/src/casts/cast_ptr_alignment.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_utils::diagnostics::span_lint;
22
use clippy_utils::is_hir_ty_cfg_dependant;
3+
use clippy_utils::ty::is_c_void;
34
use if_chain::if_chain;
45
use rustc_hir::{Expr, ExprKind, GenericArg};
56
use rustc_lint::LateContext;
67
use rustc_middle::ty::layout::LayoutOf;
78
use rustc_middle::ty::{self, Ty};
8-
use rustc_span::symbol::sym;
99

1010
use super::CAST_PTR_ALIGNMENT;
1111

@@ -62,19 +62,3 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
6262
}
6363
}
6464
}
65-
66-
/// Check if the given type is either `core::ffi::c_void` or
67-
/// one of the platform specific `libc::<platform>::c_void` of libc.
68-
fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
69-
if let ty::Adt(adt, _) = ty.kind() {
70-
let names = cx.get_def_path(adt.did);
71-
72-
if names.is_empty() {
73-
return false;
74-
}
75-
if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
76-
return true;
77-
}
78-
}
79-
false
80-
}

clippy_lints/src/transmute/transmute_undefined_repr.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::TRANSMUTE_UNDEFINED_REPR;
22
use clippy_utils::diagnostics::span_lint_and_then;
3+
use clippy_utils::ty::is_c_void;
34
use rustc_hir::Expr;
45
use rustc_lint::LateContext;
56
use rustc_middle::ty::subst::{GenericArg, Subst};
@@ -100,7 +101,8 @@ pub(super) fn check<'tcx>(
100101
from_ty: from_sub_ty,
101102
to_ty: to_sub_ty,
102103
} => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
103-
(ReducedTy::IntArray, _) | (_, ReducedTy::IntArray) => return false,
104+
(ReducedTy::IntArray | ReducedTy::TypeErasure, _)
105+
| (_, ReducedTy::IntArray | ReducedTy::TypeErasure) => return false,
104106
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
105107
span_lint_and_then(
106108
cx,
@@ -228,8 +230,10 @@ fn reduce_refs<'tcx>(
228230
}
229231

230232
enum ReducedTy<'tcx> {
231-
/// The type is a struct containing either zero sized fields, or multiple sized fields with a
232-
/// defined order.
233+
/// The type can be used for type erasure.
234+
TypeErasure,
235+
/// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
236+
/// sized fields with a defined order.
233237
OrderedFields(Ty<'tcx>),
234238
/// The type is a struct containing multiple non-zero sized fields with no defined order.
235239
UnorderedFields(Ty<'tcx>),
@@ -252,6 +256,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
252256
ty = sub_ty;
253257
continue;
254258
},
259+
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
255260
ty::Tuple(args) => {
256261
let mut iter = args.iter().map(GenericArg::expect_ty);
257262
let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, ty)) else {
@@ -270,7 +275,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
270275
.iter()
271276
.map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
272277
let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, ty)) else {
273-
return ReducedTy::OrderedFields(ty);
278+
return ReducedTy::TypeErasure;
274279
};
275280
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
276281
ty = sized_ty;
@@ -282,6 +287,10 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
282287
ReducedTy::UnorderedFields(ty)
283288
}
284289
},
290+
ty::Adt(def, _) if def.is_enum() && (def.variants.is_empty() || is_c_void(cx, ty)) => {
291+
ReducedTy::TypeErasure
292+
},
293+
ty::Foreign(_) => ReducedTy::TypeErasure,
285294
ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
286295
ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
287296
_ => ReducedTy::Other(ty),

clippy_utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(box_patterns)]
22
#![feature(control_flow_enum)]
33
#![feature(let_else)]
4+
#![feature(let_chains)]
45
#![feature(once_cell)]
56
#![feature(rustc_private)]
67
#![recursion_limit = "512"]

clippy_utils/src/ty.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,17 @@ pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -
572572
},
573573
}
574574
}
575+
576+
/// Check if the given type is either `core::ffi::c_void`, `std::os::raw::c_void`, or one of the
577+
/// platform specific `libc::<platform>::c_void` types in libc.
578+
pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
579+
if let ty::Adt(adt, _) = ty.kind()
580+
&& let &[krate, .., name] = &*cx.get_def_path(adt.did)
581+
&& let sym::libc | sym::core | sym::std = krate
582+
&& name.as_str() == "c_void"
583+
{
584+
true
585+
} else {
586+
false
587+
}
588+
}

tests/ui/transmute_undefined_repr.rs

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

4+
use core::ffi::c_void;
5+
use core::mem::transmute;
6+
47
fn value<T>() -> T {
58
unimplemented!()
69
}
@@ -14,49 +17,60 @@ struct Ty2C<T, U>(T, U);
1417

1518
fn main() {
1619
unsafe {
17-
let _: () = core::mem::transmute(value::<Empty>());
18-
let _: Empty = core::mem::transmute(value::<()>());
20+
let _: () = transmute(value::<Empty>());
21+
let _: Empty = transmute(value::<()>());
1922

20-
let _: Ty<u32> = core::mem::transmute(value::<u32>());
21-
let _: Ty<u32> = core::mem::transmute(value::<u32>());
23+
let _: Ty<u32> = transmute(value::<u32>());
24+
let _: Ty<u32> = transmute(value::<u32>());
2225

23-
let _: Ty2C<u32, i32> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
24-
let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
26+
let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
27+
let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
2528

26-
let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Ok, Ty2 types are the same
27-
let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Ok, Ty2 types are the same
29+
let _: Ty2<u32, i32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Ok, Ty2 types are the same
30+
let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, i32>>()); // Ok, Ty2 types are the same
2831

29-
let _: Ty2<u32, f32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
30-
let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
32+
let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
33+
let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
3134

32-
let _: Ty<&()> = core::mem::transmute(value::<&()>());
33-
let _: &() = core::mem::transmute(value::<Ty<&()>>());
35+
let _: Ty<&()> = transmute(value::<&()>());
36+
let _: &() = transmute(value::<Ty<&()>>());
3437

35-
let _: &Ty2<u32, f32> = core::mem::transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
36-
let _: Ty<&Ty2<u32, i32>> = core::mem::transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
38+
let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
39+
let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
3740

38-
let _: Ty<usize> = core::mem::transmute(value::<&Ty2<u32, i32>>()); // Ok, pointer to usize conversion
39-
let _: &Ty2<u32, i32> = core::mem::transmute(value::<Ty<usize>>()); // Ok, pointer to usize conversion
41+
let _: Ty<usize> = transmute(value::<&Ty2<u32, i32>>()); // Ok, pointer to usize conversion
42+
let _: &Ty2<u32, i32> = transmute(value::<Ty<usize>>()); // Ok, pointer to usize conversion
4043

41-
let _: Ty<[u8; 8]> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Ok, transmute to byte array
42-
let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty<[u8; 8]>>()); // Ok, transmute from byte array
44+
let _: Ty<[u8; 8]> = transmute(value::<Ty2<u32, i32>>()); // Ok, transmute to byte array
45+
let _: Ty2<u32, i32> = transmute(value::<Ty<[u8; 8]>>()); // Ok, transmute from byte array
4346

4447
// issue #8417
45-
let _: Ty2C<Ty2<u32, i32>, ()> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Ok, Ty2 types are the same
46-
let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty2C<Ty2<u32, i32>, ()>>()); // Ok, Ty2 types are the same
48+
let _: Ty2C<Ty2<u32, i32>, ()> = transmute(value::<Ty2<u32, i32>>()); // Ok, Ty2 types are the same
49+
let _: Ty2<u32, i32> = transmute(value::<Ty2C<Ty2<u32, i32>, ()>>()); // Ok, Ty2 types are the same
50+
51+
let _: &'static mut Ty2<u32, u32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Ok, Ty2 types are the same
52+
let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, u32>>()); // Ok, Ty2 types are the same
53+
let _: *mut Ty2<u32, u32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Ok, Ty2 types are the same
54+
let _: Box<Ty2<u32, u32>> = transmute(value::<*mut Ty2<u32, u32>>()); // Ok, Ty2 types are the same
55+
56+
let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
57+
let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
4758

48-
// Ty2 types are the same
49-
let _: &'static mut Ty2<u32, u32> = core::mem::transmute(value::<Box<Ty2<u32, u32>>>()); // Ok
50-
// Ty2 types are the same
51-
let _: Box<Ty2<u32, u32>> = core::mem::transmute(value::<&'static mut Ty2<u32, u32>>()); // Ok
52-
let _: *mut Ty2<u32, u32> = core::mem::transmute(value::<Box<Ty2<u32, u32>>>()); // Ok, Ty2 types are the same
53-
let _: Box<Ty2<u32, u32>> = core::mem::transmute(value::<*mut Ty2<u32, u32>>()); // Ok, Ty2 types are the same
59+
let _: *const () = transmute(value::<Ty<&Ty2<u32, f32>>>()); // Ok, type erasure
60+
let _: Ty<&Ty2<u32, f32>> = transmute(value::<*const ()>()); // Ok, reverse type erasure
5461

55-
// Different Ty2 instances
56-
let _: &'static mut Ty2<u32, f32> = core::mem::transmute(value::<Box<Ty2<u32, u32>>>()); // Lint
57-
// Different Ty2 instances
58-
let _: Box<Ty2<u32, u32>> = core::mem::transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint
62+
let _: *const c_void = transmute(value::<Ty<&Ty2<u32, f32>>>()); // Ok, type erasure
63+
let _: Ty<&Ty2<u32, f32>> = transmute(value::<*const c_void>()); // Ok, reverse type erasure
5964

65+
enum Erase {}
66+
let _: *const Erase = transmute(value::<Ty<&Ty2<u32, f32>>>()); // Ok, type erasure
67+
let _: Ty<&Ty2<u32, f32>> = transmute(value::<*const Erase>()); // Ok, reverse type erasure
6068

69+
struct Erase2(
70+
[u8; 0],
71+
core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
72+
);
73+
let _: *const Erase2 = transmute(value::<Ty<&Ty2<u32, f32>>>()); // Ok, type erasure
74+
let _: Ty<&Ty2<u32, f32>> = transmute(value::<*const Erase2>()); // Ok, reverse type erasure
6175
}
6276
}

tests/ui/transmute_undefined_repr.stderr

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,62 @@
11
error: transmute from `Ty2<u32, i32>` which has an undefined layout
2-
--> $DIR/transmute_undefined_repr.rs:23:33
2+
--> $DIR/transmute_undefined_repr.rs:26:33
33
|
4-
LL | let _: Ty2C<u32, i32> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:24:32
10+
--> $DIR/transmute_undefined_repr.rs:27:32
1111
|
12-
LL | let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:29:32
16+
--> $DIR/transmute_undefined_repr.rs:32:32
1717
|
18-
LL | let _: Ty2<u32, f32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
19-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:30:36
24+
--> $DIR/transmute_undefined_repr.rs:33:36
2525
|
26-
LL | let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
27-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:35:33
32+
--> $DIR/transmute_undefined_repr.rs:38:33
3333
|
34-
LL | let _: &Ty2<u32, f32> = core::mem::transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
35-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:36:37
40+
--> $DIR/transmute_undefined_repr.rs:39:37
4141
|
42-
LL | let _: Ty<&Ty2<u32, i32>> = core::mem::transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
43-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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
4848
--> $DIR/transmute_undefined_repr.rs:56:45
4949
|
50-
LL | let _: &'static mut Ty2<u32, f32> = core::mem::transmute(value::<Box<Ty2<u32, u32>>>()); // Lint
51-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:58:37
56+
--> $DIR/transmute_undefined_repr.rs:57:37
5757
|
58-
LL | let _: Box<Ty2<u32, u32>> = core::mem::transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint
59-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
58+
LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6060
|
6161
= note: two instances of the same generic type (`Ty2`) may have different layouts
6262

0 commit comments

Comments
 (0)