Skip to content

Commit 2b0e730

Browse files
committed
Auto merge of rust-lang#8547 - Jarcho:transmute_8501, r=flip1995
More `transmute_undefined_repr` fixes fixes: rust-lang#8498 fixes: rust-lang#8501 fixes: rust-lang#8503 changelog: Allow `transumte_undefined_repr` between fat pointers and `(usize, usize)` changelog: Allow `transumte_undefined_repr` when one side is a union changelog: Fix `transumte_undefined_repr` on tuples with one non-zero-sized type.
2 parents d6a3fbf + 47c9ed6 commit 2b0e730

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

clippy_lints/src/transmute/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
415415
// And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
416416
let const_context = in_constant(cx, e.hir_id);
417417

418-
let from_ty = cx.typeck_results().expr_ty(arg);
418+
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
419+
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
419420
let to_ty = cx.typeck_results().expr_ty(e);
420421

421422
// If useless_transmute is triggered, the other lints can be skipped.

clippy_lints/src/transmute/transmute_undefined_repr.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void;
44
use rustc_hir::Expr;
55
use rustc_lint::LateContext;
66
use rustc_middle::ty::subst::Subst;
7-
use rustc_middle::ty::{self, Ty, TypeAndMut};
7+
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
88
use rustc_span::Span;
99

1010
#[allow(clippy::too_many_lines)]
@@ -23,7 +23,8 @@ pub(super) fn check<'tcx>(
2323
unsized_ty,
2424
to_ty: to_sub_ty,
2525
} => match reduce_ty(cx, to_sub_ty) {
26-
ReducedTy::IntArray | ReducedTy::TypeErasure => break,
26+
ReducedTy::TypeErasure => break,
27+
ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
2728
ReducedTy::Ref(to_sub_ty) => {
2829
from_ty = unsized_ty;
2930
to_ty = to_sub_ty;
@@ -48,7 +49,8 @@ pub(super) fn check<'tcx>(
4849
unsized_ty,
4950
from_ty: from_sub_ty,
5051
} => match reduce_ty(cx, from_sub_ty) {
51-
ReducedTy::IntArray | ReducedTy::TypeErasure => break,
52+
ReducedTy::TypeErasure => break,
53+
ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
5254
ReducedTy::Ref(from_sub_ty) => {
5355
from_ty = from_sub_ty;
5456
to_ty = unsized_ty;
@@ -123,8 +125,7 @@ pub(super) fn check<'tcx>(
123125
from_ty: from_sub_ty,
124126
to_ty: to_sub_ty,
125127
} => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
126-
(ReducedTy::IntArray | ReducedTy::TypeErasure, _)
127-
| (_, ReducedTy::IntArray | ReducedTy::TypeErasure) => return false,
128+
(ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
128129
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
129130
span_lint_and_then(
130131
cx,
@@ -263,9 +264,6 @@ enum ReducedTy<'tcx> {
263264
UnorderedFields(Ty<'tcx>),
264265
/// The type is a reference to the contained type.
265266
Ref(Ty<'tcx>),
266-
/// The type is an array of a primitive integer type. These can be used as storage for a value
267-
/// of another type.
268-
IntArray,
269267
/// Any other type.
270268
Other(Ty<'tcx>),
271269
}
@@ -275,17 +273,18 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
275273
loop {
276274
ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
277275
return match *ty.kind() {
278-
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::IntArray,
276+
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure,
279277
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
280278
ty = sub_ty;
281279
continue;
282280
},
283281
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
284282
ty::Tuple(args) => {
285-
let Some(sized_ty) = args.iter().find(|&ty| !is_zero_sized_ty(cx, ty)) else {
283+
let mut iter = args.iter();
284+
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
286285
return ReducedTy::OrderedFields(ty);
287286
};
288-
if args.iter().all(|ty| is_zero_sized_ty(cx, ty)) {
287+
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
289288
ty = sized_ty;
290289
continue;
291290
}
@@ -313,6 +312,8 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
313312
ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
314313
ReducedTy::TypeErasure
315314
},
315+
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
316+
ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure,
316317
ty::Foreign(_) => ReducedTy::TypeErasure,
317318
ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
318319
ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
@@ -332,3 +333,14 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
332333
}
333334
}
334335
}
336+
337+
fn is_size_pair(ty: Ty<'_>) -> bool {
338+
if let ty::Tuple(tys) = *ty.kind()
339+
&& let [ty1, ty2] = &**tys
340+
{
341+
matches!(ty1.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
342+
&& matches!(ty2.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
343+
} else {
344+
false
345+
}
346+
}

tests/ui/transmute_undefined_repr.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)]
33

44
use core::ffi::c_void;
5-
use core::mem::{size_of, transmute};
5+
use core::mem::{size_of, transmute, MaybeUninit};
66

77
fn value<T>() -> T {
88
unimplemented!()
@@ -87,5 +87,26 @@ fn main() {
8787

8888
let _: *const [u8] = transmute(value::<Box<[u8]>>()); // Ok
8989
let _: Box<[u8]> = transmute(value::<*mut [u8]>()); // Ok
90+
91+
let _: Ty2<u32, u32> = transmute(value::<(Ty2<u32, u32>,)>()); // Ok
92+
let _: (Ty2<u32, u32>,) = transmute(value::<Ty2<u32, u32>>()); // Ok
93+
94+
let _: Ty2<u32, u32> = transmute(value::<(Ty2<u32, u32>, ())>()); // Ok
95+
let _: (Ty2<u32, u32>, ()) = transmute(value::<Ty2<u32, u32>>()); // Ok
96+
97+
let _: Ty2<u32, u32> = transmute(value::<((), Ty2<u32, u32>)>()); // Ok
98+
let _: ((), Ty2<u32, u32>) = transmute(value::<Ty2<u32, u32>>()); // Ok
99+
100+
let _: (usize, usize) = transmute(value::<&[u8]>()); // Ok
101+
let _: &[u8] = transmute(value::<(usize, usize)>()); // Ok
102+
103+
trait Trait {}
104+
let _: (isize, isize) = transmute(value::<&dyn Trait>()); // Ok
105+
let _: &dyn Trait = transmute(value::<(isize, isize)>()); // Ok
106+
107+
let _: MaybeUninit<Ty2<u32, u32>> = transmute(value::<Ty2<u32, u32>>()); // Ok
108+
let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
109+
110+
let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
90111
}
91112
}

tests/ui/transmutes_expressible_as_ptr_casts.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ error: transmute from a reference to a pointer
3434
LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) };
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]`
3636

37-
error: transmute from `fn(usize) -> u8 {main::foo}` to `*const usize` which could be expressed as a pointer cast instead
37+
error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead
3838
--> $DIR/transmutes_expressible_as_ptr_casts.rs:48:41
3939
|
4040
LL | let _usize_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, *const usize>(foo) };
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize`
4242

43-
error: transmute from `fn(usize) -> u8 {main::foo}` to `usize` which could be expressed as a pointer cast instead
43+
error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead
4444
--> $DIR/transmutes_expressible_as_ptr_casts.rs:52:49
4545
|
4646
LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };

0 commit comments

Comments
 (0)