forked from rust-lang/rust-clippy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
make cast_possible_wrap not lint on conversions for sizes that cannot…
… wrap, and make it work correctly for 16 bit {u,i}size
- Loading branch information
1 parent
58fb801
commit 6681914
Showing
4 changed files
with
171 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,81 @@ | ||
use clippy_utils::diagnostics::span_lint; | ||
use clippy_utils::ty::is_isize_or_usize; | ||
use rustc_hir::Expr; | ||
use rustc_lint::LateContext; | ||
use rustc_middle::ty::Ty; | ||
|
||
use super::{utils, CAST_POSSIBLE_WRAP}; | ||
|
||
// this should be kept in sync with the allowed bit widths of `usize` and `isize` | ||
const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; | ||
|
||
// whether the lint should be emitted, and the required pointer size, if it matters | ||
enum EmitState { | ||
NoLint, | ||
LintAlways, | ||
LintOnPtrSize(u64), | ||
} | ||
|
||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { | ||
if !(cast_from.is_integral() && cast_to.is_integral()) { | ||
return; | ||
} | ||
|
||
let arch_64_suffix = " on targets with 64-bit wide pointers"; | ||
let arch_32_suffix = " on targets with 32-bit wide pointers"; | ||
let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); | ||
// emit a lint if a cast is: | ||
// 1. unsigned to signed | ||
// and | ||
// 2. either: | ||
// 2a. between two types of constant size that are always the same size | ||
// 2b. between one target-dependent size and one constant size integer, | ||
// and the constant integer is in the allowed set of target dependent sizes | ||
// (the ptr size could be chosen to be the same as the constant size) | ||
|
||
if cast_from.is_signed() || !cast_to.is_signed() { | ||
return; | ||
} | ||
|
||
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); | ||
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); | ||
|
||
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { | ||
(true, true) | (false, false) => (to_nbits == from_nbits && cast_unsigned_to_signed, ""), | ||
(true, false) => (to_nbits <= 32 && cast_unsigned_to_signed, arch_32_suffix), | ||
(false, true) => ( | ||
cast_unsigned_to_signed, | ||
if from_nbits == 64 { | ||
arch_64_suffix | ||
let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) { | ||
(true, true) => { | ||
// casts between two ptr sized integers are trivially always the same size | ||
// so do not depend on any specific pointer size to be the same | ||
EmitState::LintAlways | ||
}, | ||
(true, false) => { | ||
// the first type is `usize` and the second is a constant sized signed integer | ||
if ALLOWED_POINTER_SIZES.contains(&to_nbits) { | ||
EmitState::LintOnPtrSize(to_nbits) | ||
} else { | ||
EmitState::NoLint | ||
} | ||
}, | ||
(false, true) => { | ||
// the first type is a constant sized unsigned integer, and the second is `isize` | ||
if ALLOWED_POINTER_SIZES.contains(&from_nbits) { | ||
EmitState::LintOnPtrSize(from_nbits) | ||
} else { | ||
EmitState::NoLint | ||
} | ||
}, | ||
(false, false) => { | ||
// the types are both a constant known size | ||
// and do not depend on any specific pointer size to be the same | ||
if from_nbits == to_nbits { | ||
EmitState::LintAlways | ||
} else { | ||
arch_32_suffix | ||
}, | ||
EmitState::NoLint | ||
} | ||
}, | ||
}; | ||
|
||
let message = match should_lint { | ||
EmitState::NoLint => return, | ||
EmitState::LintAlways => format!("casting `{cast_from}` to `{cast_to}` may wrap around the value"), | ||
EmitState::LintOnPtrSize(ptr_size) => format!( | ||
"casting `{cast_from}` to `{cast_to}` may wrap around the value on targets with {ptr_size}-bit wide pointers", | ||
), | ||
}; | ||
|
||
if should_lint { | ||
span_lint( | ||
cx, | ||
CAST_POSSIBLE_WRAP, | ||
expr.span, | ||
&format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",), | ||
); | ||
} | ||
span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, message.as_str()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters