@@ -7,6 +7,7 @@ mod transmute_num_to_bytes;
77mod transmute_ptr_to_ptr;
88mod transmute_ptr_to_ref;
99mod transmute_ref_to_ref;
10+ mod transmute_undefined_repr;
1011mod transmutes_expressible_as_ptr_casts;
1112mod unsound_collection_transmute;
1213mod useless_transmute;
@@ -355,6 +356,30 @@ declare_clippy_lint! {
355356 "transmute between collections of layout-incompatible types"
356357}
357358
359+ declare_clippy_lint ! {
360+ /// ### What it does
361+ /// Checks for transmutes either to or from a type which does not have a defined representation.
362+ ///
363+ /// ### Why is this bad?
364+ /// The results of such a transmute are not defined.
365+ ///
366+ /// ### Example
367+ /// ```rust
368+ /// struct Foo<T>(u32, T);
369+ /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
370+ /// ```
371+ /// Use instead:
372+ /// ```rust
373+ /// #[repr(C)]
374+ /// struct Foo<T>(u32, T);
375+ /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
376+ /// ```
377+ #[ clippy:: version = "1.60.0" ]
378+ pub TRANSMUTE_UNDEFINED_REPR ,
379+ correctness,
380+ "transmute to or from a type with an undefined representation"
381+ }
382+
358383declare_lint_pass ! ( Transmute => [
359384 CROSSPOINTER_TRANSMUTE ,
360385 TRANSMUTE_PTR_TO_REF ,
@@ -369,13 +394,13 @@ declare_lint_pass!(Transmute => [
369394 TRANSMUTE_NUM_TO_BYTES ,
370395 UNSOUND_COLLECTION_TRANSMUTE ,
371396 TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS ,
397+ TRANSMUTE_UNDEFINED_REPR ,
372398] ) ;
373399
374400impl < ' tcx > LateLintPass < ' tcx > for Transmute {
375- #[ allow( clippy:: similar_names, clippy:: too_many_lines) ]
376401 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > ) {
377402 if_chain ! {
378- if let ExprKind :: Call ( path_expr, args ) = e. kind;
403+ if let ExprKind :: Call ( path_expr, [ arg ] ) = e. kind;
379404 if let ExprKind :: Path ( ref qpath) = path_expr. kind;
380405 if let Some ( def_id) = cx. qpath_res( qpath, path_expr. hir_id) . opt_def_id( ) ;
381406 if cx. tcx. is_diagnostic_item( sym:: transmute, def_id) ;
@@ -385,28 +410,31 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
385410 // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
386411 let const_context = in_constant( cx, e. hir_id) ;
387412
388- let from_ty = cx. typeck_results( ) . expr_ty( & args [ 0 ] ) ;
413+ let from_ty = cx. typeck_results( ) . expr_ty( arg ) ;
389414 let to_ty = cx. typeck_results( ) . expr_ty( e) ;
390415
391416 // If useless_transmute is triggered, the other lints can be skipped.
392- if useless_transmute:: check( cx, e, from_ty, to_ty, args ) {
417+ if useless_transmute:: check( cx, e, from_ty, to_ty, arg ) {
393418 return ;
394419 }
395420
396- let mut linted = wrong_transmute:: check( cx, e, from_ty, to_ty) ;
397- linted |= crosspointer_transmute:: check( cx, e, from_ty, to_ty) ;
398- linted |= transmute_ptr_to_ref:: check( cx, e, from_ty, to_ty, args, qpath) ;
399- linted |= transmute_int_to_char:: check( cx, e, from_ty, to_ty, args) ;
400- linted |= transmute_ref_to_ref:: check( cx, e, from_ty, to_ty, args, const_context) ;
401- linted |= transmute_ptr_to_ptr:: check( cx, e, from_ty, to_ty, args) ;
402- linted |= transmute_int_to_bool:: check( cx, e, from_ty, to_ty, args) ;
403- linted |= transmute_int_to_float:: check( cx, e, from_ty, to_ty, args, const_context) ;
404- linted |= transmute_float_to_int:: check( cx, e, from_ty, to_ty, args, const_context) ;
405- linted |= transmute_num_to_bytes:: check( cx, e, from_ty, to_ty, args, const_context) ;
406- linted |= unsound_collection_transmute:: check( cx, e, from_ty, to_ty) ;
421+ let linted = wrong_transmute:: check( cx, e, from_ty, to_ty)
422+ | crosspointer_transmute:: check( cx, e, from_ty, to_ty)
423+ | transmute_ptr_to_ref:: check( cx, e, from_ty, to_ty, arg, qpath)
424+ | transmute_int_to_char:: check( cx, e, from_ty, to_ty, arg)
425+ | transmute_ref_to_ref:: check( cx, e, from_ty, to_ty, arg, const_context)
426+ | transmute_ptr_to_ptr:: check( cx, e, from_ty, to_ty, arg)
427+ | transmute_int_to_bool:: check( cx, e, from_ty, to_ty, arg)
428+ | transmute_int_to_float:: check( cx, e, from_ty, to_ty, arg, const_context)
429+ | transmute_float_to_int:: check( cx, e, from_ty, to_ty, arg, const_context)
430+ | transmute_num_to_bytes:: check( cx, e, from_ty, to_ty, arg, const_context)
431+ | (
432+ unsound_collection_transmute:: check( cx, e, from_ty, to_ty)
433+ || transmute_undefined_repr:: check( cx, e, from_ty, to_ty)
434+ ) ;
407435
408436 if !linted {
409- transmutes_expressible_as_ptr_casts:: check( cx, e, from_ty, to_ty, args ) ;
437+ transmutes_expressible_as_ptr_casts:: check( cx, e, from_ty, to_ty, arg ) ;
410438 }
411439 }
412440 }
0 commit comments