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