Skip to content

Commit b9b11a9

Browse files
committed
Auto merge of #7805 - aDotInTheVoid:transmute-num-bits, r=camsteffen
Add lint transmute_num_to_bytes Closes #7803 changelog: [`transmute_num_to_bytes`] new lint
2 parents 57dc034 + 5896980 commit b9b11a9

8 files changed

+194
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,6 +3025,7 @@ Released 2018-09-13
30253025
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
30263026
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
30273027
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
3028+
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
30283029
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
30293030
[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
30303031
[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
267267
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
268268
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
269269
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
270+
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
270271
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
271272
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
272273
LintId::of(transmute::WRONG_TRANSMUTE),

clippy_lints/src/lib.register_complexity.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
8282
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
8383
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
8484
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
85+
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
8586
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
8687
LintId::of(types::BORROWED_BOX),
8788
LintId::of(types::TYPE_COMPLEXITY),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ store.register_lints(&[
450450
transmute::TRANSMUTE_INT_TO_BOOL,
451451
transmute::TRANSMUTE_INT_TO_CHAR,
452452
transmute::TRANSMUTE_INT_TO_FLOAT,
453+
transmute::TRANSMUTE_NUM_TO_BYTES,
453454
transmute::TRANSMUTE_PTR_TO_PTR,
454455
transmute::TRANSMUTE_PTR_TO_REF,
455456
transmute::UNSOUND_COLLECTION_TRANSMUTE,

clippy_lints/src/transmute/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
33
mod transmute_int_to_bool;
44
mod transmute_int_to_char;
55
mod transmute_int_to_float;
6+
mod transmute_num_to_bytes;
67
mod transmute_ptr_to_ptr;
78
mod transmute_ptr_to_ref;
89
mod transmute_ref_to_ref;
@@ -261,6 +262,28 @@ declare_clippy_lint! {
261262
"transmutes from a float to an integer"
262263
}
263264

265+
declare_clippy_lint! {
266+
/// # What it does
267+
/// Checks for transmutes from a number to an array of `u8`
268+
///
269+
/// ### Why this is bad?
270+
/// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
271+
/// is intuitive and safe.
272+
///
273+
/// ### Example
274+
/// ```rust
275+
/// unsafe {
276+
/// let x: [u8; 8] = std::mem::transmute(1i64);
277+
/// }
278+
///
279+
/// // should be
280+
/// let x: [u8; 8] = 0i64.to_ne_bytes();
281+
/// ```
282+
pub TRANSMUTE_NUM_TO_BYTES,
283+
complexity,
284+
"transmutes from a number to an array of `u8`"
285+
}
286+
264287
declare_clippy_lint! {
265288
/// ### What it does
266289
/// Checks for transmutes from a pointer to a pointer, or
@@ -330,6 +353,7 @@ declare_lint_pass!(Transmute => [
330353
TRANSMUTE_INT_TO_BOOL,
331354
TRANSMUTE_INT_TO_FLOAT,
332355
TRANSMUTE_FLOAT_TO_INT,
356+
TRANSMUTE_NUM_TO_BYTES,
333357
UNSOUND_COLLECTION_TRANSMUTE,
334358
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
335359
]);
@@ -365,6 +389,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
365389
linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
366390
linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
367391
linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
392+
linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
368393
linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
369394

370395
if !linted {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use super::TRANSMUTE_NUM_TO_BYTES;
2+
use clippy_utils::diagnostics::span_lint_and_then;
3+
use clippy_utils::sugg;
4+
use rustc_errors::Applicability;
5+
use rustc_hir::Expr;
6+
use rustc_lint::LateContext;
7+
use rustc_middle::ty::{self, Ty, UintTy};
8+
9+
/// Checks for `transmute_int_to_float` lint.
10+
/// Returns `true` if it's triggered, otherwise returns `false`.
11+
pub(super) fn check<'tcx>(
12+
cx: &LateContext<'tcx>,
13+
e: &'tcx Expr<'_>,
14+
from_ty: Ty<'tcx>,
15+
to_ty: Ty<'tcx>,
16+
args: &'tcx [Expr<'_>],
17+
const_context: bool,
18+
) -> bool {
19+
match (&from_ty.kind(), &to_ty.kind()) {
20+
(ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
21+
if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
22+
return false;
23+
}
24+
if matches!(from_ty.kind(), ty::Float(_)) && const_context {
25+
// TODO: Remove when const_float_bits_conv is stabilized
26+
// rust#72447
27+
return false;
28+
}
29+
30+
span_lint_and_then(
31+
cx,
32+
TRANSMUTE_NUM_TO_BYTES,
33+
e.span,
34+
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
35+
|diag| {
36+
let arg = sugg::Sugg::hir(cx, &args[0], "..");
37+
diag.span_suggestion(
38+
e.span,
39+
"consider using `to_ne_bytes()`",
40+
format!("{}.to_ne_bytes()", arg.to_string()),
41+
Applicability::Unspecified,
42+
);
43+
},
44+
);
45+
true
46+
},
47+
_ => false,
48+
}
49+
}

tests/ui/transmute.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,33 @@ mod int_to_float {
103103
}
104104
}
105105

106+
mod num_to_bytes {
107+
fn test() {
108+
unsafe {
109+
let _: [u8; 1] = std::mem::transmute(0u8);
110+
let _: [u8; 4] = std::mem::transmute(0u32);
111+
let _: [u8; 16] = std::mem::transmute(0u128);
112+
let _: [u8; 1] = std::mem::transmute(0i8);
113+
let _: [u8; 4] = std::mem::transmute(0i32);
114+
let _: [u8; 16] = std::mem::transmute(0i128);
115+
let _: [u8; 4] = std::mem::transmute(0.0f32);
116+
let _: [u8; 8] = std::mem::transmute(0.0f64);
117+
}
118+
}
119+
const fn test_const() {
120+
unsafe {
121+
let _: [u8; 1] = std::mem::transmute(0u8);
122+
let _: [u8; 4] = std::mem::transmute(0u32);
123+
let _: [u8; 16] = std::mem::transmute(0u128);
124+
let _: [u8; 1] = std::mem::transmute(0i8);
125+
let _: [u8; 4] = std::mem::transmute(0i32);
126+
let _: [u8; 16] = std::mem::transmute(0i128);
127+
let _: [u8; 4] = std::mem::transmute(0.0f32);
128+
let _: [u8; 8] = std::mem::transmute(0.0f64);
129+
}
130+
}
131+
}
132+
106133
fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
107134
let _: &str = unsafe { std::mem::transmute(b) };
108135
let _: &mut str = unsafe { std::mem::transmute(mb) };

tests/ui/transmute.stderr

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,105 @@ error: transmute from a `i64` to a `f64`
140140
LL | let _: f64 = unsafe { std::mem::transmute(0_i64) };
141141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
142142

143+
error: transmute from a `u8` to a `[u8; 1]`
144+
--> $DIR/transmute.rs:109:30
145+
|
146+
LL | let _: [u8; 1] = std::mem::transmute(0u8);
147+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
148+
|
149+
= note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
150+
151+
error: transmute from a `u32` to a `[u8; 4]`
152+
--> $DIR/transmute.rs:110:30
153+
|
154+
LL | let _: [u8; 4] = std::mem::transmute(0u32);
155+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
156+
157+
error: transmute from a `u128` to a `[u8; 16]`
158+
--> $DIR/transmute.rs:111:31
159+
|
160+
LL | let _: [u8; 16] = std::mem::transmute(0u128);
161+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
162+
163+
error: transmute from a `i8` to a `[u8; 1]`
164+
--> $DIR/transmute.rs:112:30
165+
|
166+
LL | let _: [u8; 1] = std::mem::transmute(0i8);
167+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
168+
169+
error: transmute from a `i32` to a `[u8; 4]`
170+
--> $DIR/transmute.rs:113:30
171+
|
172+
LL | let _: [u8; 4] = std::mem::transmute(0i32);
173+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
174+
175+
error: transmute from a `i128` to a `[u8; 16]`
176+
--> $DIR/transmute.rs:114:31
177+
|
178+
LL | let _: [u8; 16] = std::mem::transmute(0i128);
179+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
180+
181+
error: transmute from a `f32` to a `[u8; 4]`
182+
--> $DIR/transmute.rs:115:30
183+
|
184+
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
185+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
186+
187+
error: transmute from a `f64` to a `[u8; 8]`
188+
--> $DIR/transmute.rs:116:30
189+
|
190+
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
191+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
192+
193+
error: transmute from a `u8` to a `[u8; 1]`
194+
--> $DIR/transmute.rs:121:30
195+
|
196+
LL | let _: [u8; 1] = std::mem::transmute(0u8);
197+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
198+
199+
error: transmute from a `u32` to a `[u8; 4]`
200+
--> $DIR/transmute.rs:122:30
201+
|
202+
LL | let _: [u8; 4] = std::mem::transmute(0u32);
203+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
204+
205+
error: transmute from a `u128` to a `[u8; 16]`
206+
--> $DIR/transmute.rs:123:31
207+
|
208+
LL | let _: [u8; 16] = std::mem::transmute(0u128);
209+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
210+
211+
error: transmute from a `i8` to a `[u8; 1]`
212+
--> $DIR/transmute.rs:124:30
213+
|
214+
LL | let _: [u8; 1] = std::mem::transmute(0i8);
215+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
216+
217+
error: transmute from a `i32` to a `[u8; 4]`
218+
--> $DIR/transmute.rs:125:30
219+
|
220+
LL | let _: [u8; 4] = std::mem::transmute(0i32);
221+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
222+
223+
error: transmute from a `i128` to a `[u8; 16]`
224+
--> $DIR/transmute.rs:126:31
225+
|
226+
LL | let _: [u8; 16] = std::mem::transmute(0i128);
227+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
228+
143229
error: transmute from a `&[u8]` to a `&str`
144-
--> $DIR/transmute.rs:107:28
230+
--> $DIR/transmute.rs:134:28
145231
|
146232
LL | let _: &str = unsafe { std::mem::transmute(b) };
147233
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
148234
|
149235
= note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
150236

151237
error: transmute from a `&mut [u8]` to a `&mut str`
152-
--> $DIR/transmute.rs:108:32
238+
--> $DIR/transmute.rs:135:32
153239
|
154240
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
155241
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
156242

157-
error: aborting due to 24 previous errors
243+
error: aborting due to 38 previous errors
158244

0 commit comments

Comments
 (0)