• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 mod as_ptr_cast_mut;
2 mod as_underscore;
3 mod borrow_as_ptr;
4 mod cast_abs_to_unsigned;
5 mod cast_enum_constructor;
6 mod cast_lossless;
7 mod cast_nan_to_int;
8 mod cast_possible_truncation;
9 mod cast_possible_wrap;
10 mod cast_precision_loss;
11 mod cast_ptr_alignment;
12 mod cast_sign_loss;
13 mod cast_slice_different_sizes;
14 mod cast_slice_from_raw_parts;
15 mod char_lit_as_u8;
16 mod fn_to_numeric_cast;
17 mod fn_to_numeric_cast_any;
18 mod fn_to_numeric_cast_with_truncation;
19 mod ptr_as_ptr;
20 mod ptr_cast_constness;
21 mod unnecessary_cast;
22 mod utils;
23 
24 use clippy_utils::is_hir_ty_cfg_dependant;
25 use clippy_utils::msrvs::{self, Msrv};
26 use rustc_hir::{Expr, ExprKind};
27 use rustc_lint::{LateContext, LateLintPass, LintContext};
28 use rustc_middle::lint::in_external_macro;
29 use rustc_session::{declare_tool_lint, impl_lint_pass};
30 
31 declare_clippy_lint! {
32     /// ### What it does
33     /// Checks for casts from any numerical to a float type where
34     /// the receiving type cannot store all values from the original type without
35     /// rounding errors. This possible rounding is to be expected, so this lint is
36     /// `Allow` by default.
37     ///
38     /// Basically, this warns on casting any integer with 32 or more bits to `f32`
39     /// or any 64-bit integer to `f64`.
40     ///
41     /// ### Why is this bad?
42     /// It's not bad at all. But in some applications it can be
43     /// helpful to know where precision loss can take place. This lint can help find
44     /// those places in the code.
45     ///
46     /// ### Example
47     /// ```rust
48     /// let x = u64::MAX;
49     /// x as f64;
50     /// ```
51     #[clippy::version = "pre 1.29.0"]
52     pub CAST_PRECISION_LOSS,
53     pedantic,
54     "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
55 }
56 
57 declare_clippy_lint! {
58     /// ### What it does
59     /// Checks for casts from a signed to an unsigned numerical
60     /// type. In this case, negative values wrap around to large positive values,
61     /// which can be quite surprising in practice. However, as the cast works as
62     /// defined, this lint is `Allow` by default.
63     ///
64     /// ### Why is this bad?
65     /// Possibly surprising results. You can activate this lint
66     /// as a one-time check to see where numerical wrapping can arise.
67     ///
68     /// ### Example
69     /// ```rust
70     /// let y: i8 = -1;
71     /// y as u128; // will return 18446744073709551615
72     /// ```
73     #[clippy::version = "pre 1.29.0"]
74     pub CAST_SIGN_LOSS,
75     pedantic,
76     "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
77 }
78 
79 declare_clippy_lint! {
80     /// ### What it does
81     /// Checks for casts between numerical types that may
82     /// truncate large values. This is expected behavior, so the cast is `Allow` by
83     /// default. It suggests user either explicitly ignore the lint,
84     /// or use `try_from()` and handle the truncation, default, or panic explicitly.
85     ///
86     /// ### Why is this bad?
87     /// In some problem domains, it is good practice to avoid
88     /// truncation. This lint can be activated to help assess where additional
89     /// checks could be beneficial.
90     ///
91     /// ### Example
92     /// ```rust
93     /// fn as_u8(x: u64) -> u8 {
94     ///     x as u8
95     /// }
96     /// ```
97     /// Use instead:
98     /// ```
99     /// fn as_u8(x: u64) -> u8 {
100     ///     if let Ok(x) = u8::try_from(x) {
101     ///         x
102     ///     } else {
103     ///         todo!();
104     ///     }
105     /// }
106     /// // Or
107     /// #[allow(clippy::cast_possible_truncation)]
108     /// fn as_u16(x: u64) -> u16 {
109     ///     x as u16
110     /// }
111     /// ```
112     #[clippy::version = "pre 1.29.0"]
113     pub CAST_POSSIBLE_TRUNCATION,
114     pedantic,
115     "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
116 }
117 
118 declare_clippy_lint! {
119     /// ### What it does
120     /// Checks for casts from an unsigned type to a signed type of
121     /// the same size, or possibly smaller due to target dependent integers.
122     /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is
123     /// changed at the bit level, and the binary representation of the value is
124     /// reinterpreted. This can cause wrapping if the value is too big
125     /// for the target signed type. However, the cast works as defined, so this lint
126     /// is `Allow` by default.
127     ///
128     /// ### Why is this bad?
129     /// While such a cast is not bad in itself, the results can
130     /// be surprising when this is not the intended behavior, as demonstrated by the
131     /// example below.
132     ///
133     /// ### Example
134     /// ```rust
135     /// u32::MAX as i32; // will yield a value of `-1`
136     /// ```
137     #[clippy::version = "pre 1.29.0"]
138     pub CAST_POSSIBLE_WRAP,
139     pedantic,
140     "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
141 }
142 
143 declare_clippy_lint! {
144     /// ### What it does
145     /// Checks for casts between numerical types that may
146     /// be replaced by safe conversion functions.
147     ///
148     /// ### Why is this bad?
149     /// Rust's `as` keyword will perform many kinds of
150     /// conversions, including silently lossy conversions. Conversion functions such
151     /// as `i32::from` will only perform lossless conversions. Using the conversion
152     /// functions prevents conversions from turning into silent lossy conversions if
153     /// the types of the input expressions ever change, and make it easier for
154     /// people reading the code to know that the conversion is lossless.
155     ///
156     /// ### Example
157     /// ```rust
158     /// fn as_u64(x: u8) -> u64 {
159     ///     x as u64
160     /// }
161     /// ```
162     ///
163     /// Using `::from` would look like this:
164     ///
165     /// ```rust
166     /// fn as_u64(x: u8) -> u64 {
167     ///     u64::from(x)
168     /// }
169     /// ```
170     #[clippy::version = "pre 1.29.0"]
171     pub CAST_LOSSLESS,
172     pedantic,
173     "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
174 }
175 
176 declare_clippy_lint! {
177     /// ### What it does
178     /// Checks for casts to the same type, casts of int literals to integer types, casts of float
179     /// literals to float types and casts between raw pointers without changing type or constness.
180     ///
181     /// ### Why is this bad?
182     /// It's just unnecessary.
183     ///
184     /// ### Example
185     /// ```rust
186     /// let _ = 2i32 as i32;
187     /// let _ = 0.5 as f32;
188     /// ```
189     ///
190     /// Better:
191     ///
192     /// ```rust
193     /// let _ = 2_i32;
194     /// let _ = 0.5_f32;
195     /// ```
196     #[clippy::version = "pre 1.29.0"]
197     pub UNNECESSARY_CAST,
198     complexity,
199     "cast to the same type, e.g., `x as i32` where `x: i32`"
200 }
201 
202 declare_clippy_lint! {
203     /// ### What it does
204     /// Checks for casts, using `as` or `pointer::cast`,
205     /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
206     ///
207     /// ### Why is this bad?
208     /// Dereferencing the resulting pointer may be undefined
209     /// behavior.
210     ///
211     /// ### Known problems
212     /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
213     /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
214     /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
215     ///
216     /// ### Example
217     /// ```rust
218     /// let _ = (&1u8 as *const u8) as *const u16;
219     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
220     ///
221     /// (&1u8 as *const u8).cast::<u16>();
222     /// (&mut 1u8 as *mut u8).cast::<u16>();
223     /// ```
224     #[clippy::version = "pre 1.29.0"]
225     pub CAST_PTR_ALIGNMENT,
226     pedantic,
227     "cast from a pointer to a more-strictly-aligned pointer"
228 }
229 
230 declare_clippy_lint! {
231     /// ### What it does
232     /// Checks for casts of function pointers to something other than usize
233     ///
234     /// ### Why is this bad?
235     /// Casting a function pointer to anything other than usize/isize is not portable across
236     /// architectures, because you end up losing bits if the target type is too small or end up with a
237     /// bunch of extra bits that waste space and add more instructions to the final binary than
238     /// strictly necessary for the problem
239     ///
240     /// Casting to isize also doesn't make sense since there are no signed addresses.
241     ///
242     /// ### Example
243     /// ```rust
244     /// fn fun() -> i32 { 1 }
245     /// let _ = fun as i64;
246     /// ```
247     ///
248     /// Use instead:
249     /// ```rust
250     /// # fn fun() -> i32 { 1 }
251     /// let _ = fun as usize;
252     /// ```
253     #[clippy::version = "pre 1.29.0"]
254     pub FN_TO_NUMERIC_CAST,
255     style,
256     "casting a function pointer to a numeric type other than usize"
257 }
258 
259 declare_clippy_lint! {
260     /// ### What it does
261     /// Checks for casts of a function pointer to a numeric type not wide enough to
262     /// store address.
263     ///
264     /// ### Why is this bad?
265     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
266     /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
267     /// a comment) to perform the truncation.
268     ///
269     /// ### Example
270     /// ```rust
271     /// fn fn1() -> i16 {
272     ///     1
273     /// };
274     /// let _ = fn1 as i32;
275     /// ```
276     ///
277     /// Use instead:
278     /// ```rust
279     /// // Cast to usize first, then comment with the reason for the truncation
280     /// fn fn1() -> i16 {
281     ///     1
282     /// };
283     /// let fn_ptr = fn1 as usize;
284     /// let fn_ptr_truncated = fn_ptr as i32;
285     /// ```
286     #[clippy::version = "pre 1.29.0"]
287     pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
288     style,
289     "casting a function pointer to a numeric type not wide enough to store the address"
290 }
291 
292 declare_clippy_lint! {
293     /// ### What it does
294     /// Checks for casts of a function pointer to any integer type.
295     ///
296     /// ### Why is this bad?
297     /// Casting a function pointer to an integer can have surprising results and can occur
298     /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
299     /// low-level with function pointers then you can opt-out of casting functions to integers in
300     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
301     /// pointer casts in your code.
302     ///
303     /// ### Example
304     /// ```rust
305     /// // fn1 is cast as `usize`
306     /// fn fn1() -> u16 {
307     ///     1
308     /// };
309     /// let _ = fn1 as usize;
310     /// ```
311     ///
312     /// Use instead:
313     /// ```rust
314     /// // maybe you intended to call the function?
315     /// fn fn2() -> u16 {
316     ///     1
317     /// };
318     /// let _ = fn2() as usize;
319     ///
320     /// // or
321     ///
322     /// // maybe you intended to cast it to a function type?
323     /// fn fn3() -> u16 {
324     ///     1
325     /// }
326     /// let _ = fn3 as fn() -> u16;
327     /// ```
328     #[clippy::version = "1.58.0"]
329     pub FN_TO_NUMERIC_CAST_ANY,
330     restriction,
331     "casting a function pointer to any integer type"
332 }
333 
334 declare_clippy_lint! {
335     /// ### What it does
336     /// Checks for expressions where a character literal is cast
337     /// to `u8` and suggests using a byte literal instead.
338     ///
339     /// ### Why is this bad?
340     /// In general, casting values to smaller types is
341     /// error-prone and should be avoided where possible. In the particular case of
342     /// converting a character literal to u8, it is easy to avoid by just using a
343     /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
344     /// than `'a' as u8`.
345     ///
346     /// ### Example
347     /// ```rust,ignore
348     /// 'x' as u8
349     /// ```
350     ///
351     /// A better version, using the byte literal:
352     ///
353     /// ```rust,ignore
354     /// b'x'
355     /// ```
356     #[clippy::version = "pre 1.29.0"]
357     pub CHAR_LIT_AS_U8,
358     complexity,
359     "casting a character literal to `u8` truncates"
360 }
361 
362 declare_clippy_lint! {
363     /// ### What it does
364     /// Checks for `as` casts between raw pointers without changing its mutability,
365     /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
366     ///
367     /// ### Why is this bad?
368     /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
369     /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
370     ///
371     /// ### Example
372     /// ```rust
373     /// let ptr: *const u32 = &42_u32;
374     /// let mut_ptr: *mut u32 = &mut 42_u32;
375     /// let _ = ptr as *const i32;
376     /// let _ = mut_ptr as *mut i32;
377     /// ```
378     /// Use instead:
379     /// ```rust
380     /// let ptr: *const u32 = &42_u32;
381     /// let mut_ptr: *mut u32 = &mut 42_u32;
382     /// let _ = ptr.cast::<i32>();
383     /// let _ = mut_ptr.cast::<i32>();
384     /// ```
385     #[clippy::version = "1.51.0"]
386     pub PTR_AS_PTR,
387     pedantic,
388     "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
389 }
390 
391 declare_clippy_lint! {
392     /// ### What it does
393     /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
394     /// `*mut T` and `*mut T` to `*const T`.
395     ///
396     /// ### Why is this bad?
397     /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and
398     /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another
399     /// type.
400     ///
401     /// ### Example
402     /// ```rust
403     /// let ptr: *const u32 = &42_u32;
404     /// let mut_ptr = ptr as *mut u32;
405     /// let ptr = mut_ptr as *const u32;
406     /// ```
407     /// Use instead:
408     /// ```rust
409     /// let ptr: *const u32 = &42_u32;
410     /// let mut_ptr = ptr.cast_mut();
411     /// let ptr = mut_ptr.cast_const();
412     /// ```
413     #[clippy::version = "1.71.0"]
414     pub PTR_CAST_CONSTNESS,
415     pedantic,
416     "casting using `as` from and to raw pointers to change constness when specialized methods apply"
417 }
418 
419 declare_clippy_lint! {
420     /// ### What it does
421     /// Checks for casts from an enum type to an integral type which will definitely truncate the
422     /// value.
423     ///
424     /// ### Why is this bad?
425     /// The resulting integral value will not match the value of the variant it came from.
426     ///
427     /// ### Example
428     /// ```rust
429     /// enum E { X = 256 };
430     /// let _ = E::X as u8;
431     /// ```
432     #[clippy::version = "1.61.0"]
433     pub CAST_ENUM_TRUNCATION,
434     suspicious,
435     "casts from an enum type to an integral type which will truncate the value"
436 }
437 
438 declare_clippy_lint! {
439     /// ### What it does
440     /// Checks for `as` casts between raw pointers to slices with differently sized elements.
441     ///
442     /// ### Why is this bad?
443     /// The produced raw pointer to a slice does not update its length metadata. The produced
444     /// pointer will point to a different number of bytes than the original pointer because the
445     /// length metadata of a raw slice pointer is in elements rather than bytes.
446     /// Producing a slice reference from the raw pointer will either create a slice with
447     /// less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
448     ///
449     /// ### Example
450     /// // Missing data
451     /// ```rust
452     /// let a = [1_i32, 2, 3, 4];
453     /// let p = &a as *const [i32] as *const [u8];
454     /// unsafe {
455     ///     println!("{:?}", &*p);
456     /// }
457     /// ```
458     /// // Undefined Behavior (note: also potential alignment issues)
459     /// ```rust
460     /// let a = [1_u8, 2, 3, 4];
461     /// let p = &a as *const [u8] as *const [u32];
462     /// unsafe {
463     ///     println!("{:?}", &*p);
464     /// }
465     /// ```
466     /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
467     /// ```rust
468     /// let a = [1_i32, 2, 3, 4];
469     /// let old_ptr = &a as *const [i32];
470     /// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
471     /// // The length comes from the known length of 4 i32s times the 4 bytes per i32
472     /// let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
473     /// unsafe {
474     ///     println!("{:?}", &*new_ptr);
475     /// }
476     /// ```
477     #[clippy::version = "1.61.0"]
478     pub CAST_SLICE_DIFFERENT_SIZES,
479     correctness,
480     "casting using `as` between raw pointers to slices of types with different sizes"
481 }
482 
483 declare_clippy_lint! {
484     /// ### What it does
485     /// Checks for casts from an enum tuple constructor to an integer.
486     ///
487     /// ### Why is this bad?
488     /// The cast is easily confused with casting a c-like enum value to an integer.
489     ///
490     /// ### Example
491     /// ```rust
492     /// enum E { X(i32) };
493     /// let _ = E::X as usize;
494     /// ```
495     #[clippy::version = "1.61.0"]
496     pub CAST_ENUM_CONSTRUCTOR,
497     suspicious,
498     "casts from an enum tuple constructor to an integer"
499 }
500 
501 declare_clippy_lint! {
502     /// ### What it does
503     /// Checks for usage of the `abs()` method that cast the result to unsigned.
504     ///
505     /// ### Why is this bad?
506     /// The `unsigned_abs()` method avoids panic when called on the MIN value.
507     ///
508     /// ### Example
509     /// ```rust
510     /// let x: i32 = -42;
511     /// let y: u32 = x.abs() as u32;
512     /// ```
513     /// Use instead:
514     /// ```rust
515     /// let x: i32 = -42;
516     /// let y: u32 = x.unsigned_abs();
517     /// ```
518     #[clippy::version = "1.62.0"]
519     pub CAST_ABS_TO_UNSIGNED,
520     suspicious,
521     "casting the result of `abs()` to an unsigned integer can panic"
522 }
523 
524 declare_clippy_lint! {
525     /// ### What it does
526     /// Checks for the usage of `as _` conversion using inferred type.
527     ///
528     /// ### Why is this bad?
529     /// The conversion might include lossy conversion and dangerous cast that might go
530     /// undetected due to the type being inferred.
531     ///
532     /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
533     ///
534     /// ### Example
535     /// ```rust
536     /// fn foo(n: usize) {}
537     /// let n: u16 = 256;
538     /// foo(n as _);
539     /// ```
540     /// Use instead:
541     /// ```rust
542     /// fn foo(n: usize) {}
543     /// let n: u16 = 256;
544     /// foo(n as usize);
545     /// ```
546     #[clippy::version = "1.63.0"]
547     pub AS_UNDERSCORE,
548     restriction,
549     "detects `as _` conversion"
550 }
551 
552 declare_clippy_lint! {
553     /// ### What it does
554     /// Checks for the usage of `&expr as *const T` or
555     /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
556     /// `ptr::addr_of_mut` instead.
557     ///
558     /// ### Why is this bad?
559     /// This would improve readability and avoid creating a reference
560     /// that points to an uninitialized value or unaligned place.
561     /// Read the `ptr::addr_of` docs for more information.
562     ///
563     /// ### Example
564     /// ```rust
565     /// let val = 1;
566     /// let p = &val as *const i32;
567     ///
568     /// let mut val_mut = 1;
569     /// let p_mut = &mut val_mut as *mut i32;
570     /// ```
571     /// Use instead:
572     /// ```rust
573     /// let val = 1;
574     /// let p = std::ptr::addr_of!(val);
575     ///
576     /// let mut val_mut = 1;
577     /// let p_mut = std::ptr::addr_of_mut!(val_mut);
578     /// ```
579     #[clippy::version = "1.60.0"]
580     pub BORROW_AS_PTR,
581     pedantic,
582     "borrowing just to cast to a raw pointer"
583 }
584 
585 declare_clippy_lint! {
586     /// ### What it does
587     /// Checks for a raw slice being cast to a slice pointer
588     ///
589     /// ### Why is this bad?
590     /// This can result in multiple `&mut` references to the same location when only a pointer is
591     /// required.
592     /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
593     /// the same [safety requirements] to be upheld.
594     ///
595     /// ### Example
596     /// ```rust,ignore
597     /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
598     /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
599     /// ```
600     /// Use instead:
601     /// ```rust,ignore
602     /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
603     /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
604     /// ```
605     /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
606     #[clippy::version = "1.65.0"]
607     pub CAST_SLICE_FROM_RAW_PARTS,
608     suspicious,
609     "casting a slice created from a pointer and length to a slice pointer"
610 }
611 
612 declare_clippy_lint! {
613     /// ### What it does
614     /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
615     ///
616     /// ### Why is this bad?
617     /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
618     /// mutability is used, making it unlikely that having it as a mutable pointer is correct.
619     ///
620     /// ### Example
621     /// ```rust
622     /// let mut vec = Vec::<u8>::with_capacity(1);
623     /// let ptr = vec.as_ptr() as *mut u8;
624     /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
625     /// ```
626     /// Use instead:
627     /// ```rust
628     /// let mut vec = Vec::<u8>::with_capacity(1);
629     /// let ptr = vec.as_mut_ptr();
630     /// unsafe { ptr.write(4) };
631     /// ```
632     #[clippy::version = "1.66.0"]
633     pub AS_PTR_CAST_MUT,
634     nursery,
635     "casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
636 }
637 
638 declare_clippy_lint! {
639     /// ### What it does
640     /// Checks for a known NaN float being cast to an integer
641     ///
642     /// ### Why is this bad?
643     /// NaNs are cast into zero, so one could simply use this and make the
644     /// code more readable. The lint could also hint at a programmer error.
645     ///
646     /// ### Example
647     /// ```rust,ignore
648     /// let _: (0.0_f32 / 0.0) as u64;
649     /// ```
650     /// Use instead:
651     /// ```rust,ignore
652     /// let _: = 0_u64;
653     /// ```
654     #[clippy::version = "1.66.0"]
655     pub CAST_NAN_TO_INT,
656     suspicious,
657     "casting a known floating-point NaN into an integer"
658 }
659 
660 pub struct Casts {
661     msrv: Msrv,
662 }
663 
664 impl Casts {
665     #[must_use]
new(msrv: Msrv) -> Self666     pub fn new(msrv: Msrv) -> Self {
667         Self { msrv }
668     }
669 }
670 
671 impl_lint_pass!(Casts => [
672     CAST_PRECISION_LOSS,
673     CAST_SIGN_LOSS,
674     CAST_POSSIBLE_TRUNCATION,
675     CAST_POSSIBLE_WRAP,
676     CAST_LOSSLESS,
677     CAST_PTR_ALIGNMENT,
678     CAST_SLICE_DIFFERENT_SIZES,
679     UNNECESSARY_CAST,
680     FN_TO_NUMERIC_CAST_ANY,
681     FN_TO_NUMERIC_CAST,
682     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
683     CHAR_LIT_AS_U8,
684     PTR_AS_PTR,
685     PTR_CAST_CONSTNESS,
686     CAST_ENUM_TRUNCATION,
687     CAST_ENUM_CONSTRUCTOR,
688     CAST_ABS_TO_UNSIGNED,
689     AS_UNDERSCORE,
690     BORROW_AS_PTR,
691     CAST_SLICE_FROM_RAW_PARTS,
692     AS_PTR_CAST_MUT,
693     CAST_NAN_TO_INT,
694 ]);
695 
696 impl<'tcx> LateLintPass<'tcx> for Casts {
check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)697     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
698         if !in_external_macro(cx.sess(), expr.span) {
699             ptr_as_ptr::check(cx, expr, &self.msrv);
700         }
701 
702         if expr.span.from_expansion() {
703             return;
704         }
705 
706         if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
707             if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
708                 return;
709             }
710             let (cast_from, cast_to) = (
711                 cx.typeck_results().expr_ty(cast_expr),
712                 cx.typeck_results().expr_ty(expr),
713             );
714 
715             if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
716                 return;
717             }
718             cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
719             ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
720             as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
721             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
722             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
723             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
724 
725             if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
726                 cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
727                 if cast_from.is_numeric() {
728                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
729                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
730                     cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
731                     cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
732                     cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
733                 }
734                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
735                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
736             }
737 
738             as_underscore::check(cx, expr, cast_to_hir);
739 
740             if self.msrv.meets(msrvs::BORROW_AS_PTR) {
741                 borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
742             }
743         }
744 
745         cast_ptr_alignment::check(cx, expr);
746         char_lit_as_u8::check(cx, expr);
747         ptr_as_ptr::check(cx, expr, &self.msrv);
748         cast_slice_different_sizes::check(cx, expr, &self.msrv);
749     }
750 
751     extract_msrv_attr!(LateContext);
752 }
753