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