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