about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_complexity.rs1
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/transmute/mod.rs25
-rw-r--r--clippy_lints/src/transmute/transmute_num_to_bytes.rs49
-rw-r--r--tests/ui/transmute.rs27
-rw-r--r--tests/ui/transmute.stderr92
8 files changed, 194 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13067e4e92a..4c0b1991fd4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3024,6 +3024,7 @@ Released 2018-09-13
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 [`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 3e6e0244754..8d0a3e7423b 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -266,6 +266,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
     LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index 64b82fc0faa..c51341bdf0c 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -82,6 +82,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
     LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
     LintId::of(types::BORROWED_BOX),
     LintId::of(types::TYPE_COMPLEXITY),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 3c4b720671a..8d17317c38e 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -449,6 +449,7 @@ store.register_lints(&[
     transmute::TRANSMUTE_INT_TO_BOOL,
     transmute::TRANSMUTE_INT_TO_CHAR,
     transmute::TRANSMUTE_INT_TO_FLOAT,
+    transmute::TRANSMUTE_NUM_TO_BYTES,
     transmute::TRANSMUTE_PTR_TO_PTR,
     transmute::TRANSMUTE_PTR_TO_REF,
     transmute::UNSOUND_COLLECTION_TRANSMUTE,
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index 33ec9c331ce..374999473a4 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
@@ -262,6 +263,28 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// # What it does
+    /// Checks for transmutes from a number to an array of `u8`
+    ///
+    /// ### Why this is bad?
+    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+    /// is intuitive and safe.
+    ///
+    /// ### Example
+    /// ```rust
+    /// unsafe {
+    ///     let x: [u8; 8] = std::mem::transmute(1i64);
+    /// }
+    ///
+    /// // should be
+    /// let x: [u8; 8] = 0i64.to_ne_bytes();
+    /// ```
+    pub TRANSMUTE_NUM_TO_BYTES,
+    complexity,
+    "transmutes from a number to an array of `u8`"
+}
+
+declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes from a pointer to a pointer, or
     /// from a reference to a reference.
@@ -330,6 +353,7 @@ declare_lint_pass!(Transmute => [
     TRANSMUTE_INT_TO_BOOL,
     TRANSMUTE_INT_TO_FLOAT,
     TRANSMUTE_FLOAT_TO_INT,
+    TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 ]);
@@ -365,6 +389,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 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);
 
                 if !linted {
diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs
new file mode 100644
index 00000000000..dd5ded1c91a
--- /dev/null
+++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs
@@ -0,0 +1,49 @@
+use super::TRANSMUTE_NUM_TO_BYTES;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, UintTy};
+
+/// Checks for `transmute_int_to_float` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    args: &'tcx [Expr<'_>],
+    const_context: bool,
+) -> bool {
+    match (&from_ty.kind(), &to_ty.kind()) {
+        (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
+            if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
+                return false;
+            }
+            if matches!(from_ty.kind(), ty::Float(_)) && const_context {
+                // TODO: Remove when const_float_bits_conv is stabilized
+                // rust#72447
+                return false;
+            }
+
+            span_lint_and_then(
+                cx,
+                TRANSMUTE_NUM_TO_BYTES,
+                e.span,
+                &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+                |diag| {
+                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    diag.span_suggestion(
+                        e.span,
+                        "consider using `to_ne_bytes()`",
+                        format!("{}.to_ne_bytes()", arg.to_string()),
+                        Applicability::Unspecified,
+                    );
+                },
+            );
+            true
+        },
+        _ => false,
+    }
+}
diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs
index bce4c81b78a..6a7037d8f38 100644
--- a/tests/ui/transmute.rs
+++ b/tests/ui/transmute.rs
@@ -103,6 +103,33 @@ mod int_to_float {
     }
 }
 
+mod num_to_bytes {
+    fn test() {
+        unsafe {
+            let _: [u8; 1] = std::mem::transmute(0u8);
+            let _: [u8; 4] = std::mem::transmute(0u32);
+            let _: [u8; 16] = std::mem::transmute(0u128);
+            let _: [u8; 1] = std::mem::transmute(0i8);
+            let _: [u8; 4] = std::mem::transmute(0i32);
+            let _: [u8; 16] = std::mem::transmute(0i128);
+            let _: [u8; 4] = std::mem::transmute(0.0f32);
+            let _: [u8; 8] = std::mem::transmute(0.0f64);
+        }
+    }
+    const fn test_const() {
+        unsafe {
+            let _: [u8; 1] = std::mem::transmute(0u8);
+            let _: [u8; 4] = std::mem::transmute(0u32);
+            let _: [u8; 16] = std::mem::transmute(0u128);
+            let _: [u8; 1] = std::mem::transmute(0i8);
+            let _: [u8; 4] = std::mem::transmute(0i32);
+            let _: [u8; 16] = std::mem::transmute(0i128);
+            let _: [u8; 4] = std::mem::transmute(0.0f32);
+            let _: [u8; 8] = std::mem::transmute(0.0f64);
+        }
+    }
+}
+
 fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
     let _: &str = unsafe { std::mem::transmute(b) };
     let _: &mut str = unsafe { std::mem::transmute(mb) };
diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr
index e31accb982a..86537153e32 100644
--- a/tests/ui/transmute.stderr
+++ b/tests/ui/transmute.stderr
@@ -140,8 +140,94 @@ error: transmute from a `i64` to a `f64`
 LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
+error: transmute from a `u8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:109:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0u8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+   |
+   = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
+
+error: transmute from a `u32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:110:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0u32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:111:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0u128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:112:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0i8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:113:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0i32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:114:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0i128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
+error: transmute from a `f32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:115:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
+
+error: transmute from a `f64` to a `[u8; 8]`
+  --> $DIR/transmute.rs:116:30
+   |
+LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
+
+error: transmute from a `u8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:121:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0u8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+
+error: transmute from a `u32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:122:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0u32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:123:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0u128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:124:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0i8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:125:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0i32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:126:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0i128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
 error: transmute from a `&[u8]` to a `&str`
-  --> $DIR/transmute.rs:107:28
+  --> $DIR/transmute.rs:134:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(b) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
@@ -149,10 +235,10 @@ LL |     let _: &str = unsafe { std::mem::transmute(b) };
    = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> $DIR/transmute.rs:108:32
+  --> $DIR/transmute.rs:135:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
-error: aborting due to 24 previous errors
+error: aborting due to 38 previous errors