/// ```ignore
/// let ptr: *const T = core::intrinsics::transmute('x')
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRONG_TRANSMUTE,
correctness,
"transmutes that are confusing at best, undefined behaviour at worst and always useless"
/// ```rust,ignore
/// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_TRANSMUTE,
nursery,
"transmutes that have the same to and from types or could be a cast/coercion"
/// # let p: *const [i32] = &[];
/// p as *const [u16];
/// ```
+ #[clippy::version = "1.47.0"]
pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
complexity,
"transmutes that could be a pointer cast"
/// core::intrinsics::transmute(t) // where the result type is the same as
/// // `*t` or `&t`'s
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CROSSPOINTER_TRANSMUTE,
complexity,
"transmutes that have to or from types that are a pointer to the other"
/// // can be written:
/// let _: &T = &*p;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_PTR_TO_REF,
complexity,
"transmutes from a pointer to a reference type"
/// // should be:
/// let _ = std::char::from_u32(x).unwrap();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_CHAR,
complexity,
"transmutes from an integer to a `char`"
/// // should be:
/// let _ = std::str::from_utf8(b).unwrap();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_BYTES_TO_STR,
complexity,
"transmutes from a `&[u8]` to a `&str`"
/// // should be:
/// let _: bool = x != 0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_BOOL,
complexity,
"transmutes from an integer to a `bool`"
/// // should be:
/// let _: f32 = f32::from_bits(1_u32);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_FLOAT,
complexity,
"transmutes from an integer to a float"
/// // should be:
/// let _: u32 = 1f32.to_bits();
/// ```
+ #[clippy::version = "1.41.0"]
pub TRANSMUTE_FLOAT_TO_INT,
complexity,
"transmutes from a float to an integer"
}
declare_clippy_lint! {
- /// # What it does
+ /// ### What it does
/// Checks for transmutes from a number to an array of `u8`
///
/// ### Why this is bad?
/// // should be
/// let x: [u8; 8] = 0i64.to_ne_bytes();
/// ```
+ #[clippy::version = "1.58.0"]
pub TRANSMUTE_NUM_TO_BYTES,
complexity,
"transmutes from a number to an array of `u8`"
/// let _ = ptr as *const f32;
/// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_PTR_TO_PTR,
pedantic,
"transmutes from a pointer to a pointer / a reference to a reference"
/// ```rust
/// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
/// ```
+ #[clippy::version = "1.40.0"]
pub UNSOUND_COLLECTION_TRANSMUTE,
correctness,
"transmute between collections of layout-incompatible types"
]);
impl<'tcx> LateLintPass<'tcx> for Transmute {
- #[allow(clippy::similar_names, clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if_chain! {
- if let ExprKind::Call(path_expr, args) = e.kind;
+ if let ExprKind::Call(path_expr, [arg]) = e.kind;
if let ExprKind::Path(ref qpath) = path_expr.kind;
if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
// And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
let const_context = in_constant(cx, e.hir_id);
- let from_ty = cx.typeck_results().expr_ty(&args[0]);
+ let from_ty = cx.typeck_results().expr_ty(arg);
let to_ty = cx.typeck_results().expr_ty(e);
// If useless_transmute is triggered, the other lints can be skipped.
- if useless_transmute::check(cx, e, from_ty, to_ty, args) {
+ if useless_transmute::check(cx, e, from_ty, to_ty, arg) {
return;
}
- let mut linted = wrong_transmute::check(cx, e, from_ty, to_ty);
- linted |= crosspointer_transmute::check(cx, e, from_ty, to_ty);
- linted |= transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, args, qpath);
- linted |= transmute_int_to_char::check(cx, e, from_ty, to_ty, args);
- linted |= transmute_ref_to_ref::check(cx, e, from_ty, to_ty, args, const_context);
- linted |= transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, args);
- linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
- linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
- linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
- linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
- linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
+ let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
+ | crosspointer_transmute::check(cx, e, from_ty, to_ty)
+ | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, qpath)
+ | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg)
+ | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
+ | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
+ | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
+ | unsound_collection_transmute::check(cx, e, from_ty, to_ty);
if !linted {
- transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, args);
+ transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
}
}
}