Added support for isize/usize in the CastPass lint pass.

Extracted the match that determines an integer types's size in a
utility function and implemented support for usize/isize.
Added a needed feature to the crate root.
Added some tests to cover those cases, and a test I previously forgot.
Silenced two errors signaled by dogfood.sh in unicode.rs.
This commit is contained in:
R.Chavignat 2015-08-21 03:03:37 +02:00
parent dbc9b7f46e
commit ad0bc66402
4 changed files with 46 additions and 20 deletions

View File

@ -1,6 +1,6 @@
#![feature(plugin_registrar, box_syntax)]
#![feature(rustc_private, core, collections)]
#![feature(str_split_at)]
#![feature(str_split_at, num_bits_bytes)]
#![allow(unknown_lints)]
#[macro_use]

View File

@ -146,6 +146,18 @@ declare_lint!(pub CAST_SIGN_LOSS, Allow,
declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow,
"casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`");
/// Returns the size in bits of an integral type.
/// Will return 0 if the type is not an int or uint variant
fn int_ty_to_nbits(typ: &ty::TyS) -> usize {
let n = match &typ.sty {
&ty::TyInt(i) => 4 << (i as usize),
&ty::TyUint(u) => 4 << (u as usize),
_ => 0
};
// n == 4 is the usize/isize case
if n == 4 { ::std::usize::BITS } else { n }
}
impl LintPass for CastPass {
fn get_lints(&self) -> LintArray {
lint_array!(CAST_PRECISION_LOSS,
@ -159,18 +171,13 @@ impl LintPass for CastPass {
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
match (cast_from.is_integral(), cast_to.is_integral()) {
(true, false) => {
let from_nbits = match &cast_from.sty {
&ty::TyInt(i) => 4 << (i as usize),
&ty::TyUint(u) => 4 << (u as usize),
_ => 0
};
let from_nbits = int_ty_to_nbits(cast_from);
let to_nbits : usize = match &cast_to.sty {
&ty::TyFloat(ast::TyF32) => 32,
&ty::TyFloat(ast::TyF64) => 64,
_ => 0
};
if from_nbits != 4 {
// Handle TyIs/TyUs separately (pointer size is arch dependant)
if from_nbits != 0 {
if from_nbits >= to_nbits {
span_lint(cx, CAST_PRECISION_LOSS, expr.span,
&format!("converting from {0} to {1}, which causes a loss of precision \
@ -192,16 +199,8 @@ impl LintPass for CastPass {
span_lint(cx, CAST_SIGN_LOSS, expr.span,
&format!("casting from {} to {} loses the sign of the value", cast_from, cast_to));
}
let from_nbits = match &cast_from.sty {
&ty::TyInt(i) => 4 << (i as usize),
&ty::TyUint(u) => 4 << (u as usize),
_ => 0
};
let to_nbits = match &cast_to.sty {
&ty::TyInt(i) => 4 << (i as usize),
&ty::TyUint(u) => 4 << (u as usize),
_ => 0
};
let from_nbits = int_ty_to_nbits(cast_from);
let to_nbits = int_ty_to_nbits(cast_to);
if to_nbits < from_nbits ||
(!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) {
span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span,

View File

@ -40,6 +40,7 @@ fn check_str(cx: &Context, string: &str, span: Span) {
}
}
#[allow(cast_possible_truncation)]
fn str_pos_lint(cx: &Context, lint: &'static Lint, span: Span, index: usize, msg: &str) {
span_lint(cx, lint, Span { lo: span.lo + BytePos((1 + index) as u32),
hi: span.lo + BytePos((1 + index) as u32),

View File

@ -2,6 +2,7 @@
#![plugin(clippy)]
#[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss)]
#[allow(dead_code)]
fn main() {
let i : i32 = 42;
let u : u32 = 42;
@ -16,7 +17,7 @@ fn main() {
(u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
i as f64; // Should not trigger the lint
u as f64; // Should not trigger the lint
// Test cast_possible_truncation
f as i32; //~ERROR casting f32 to i32 may cause truncation of the value
f as u32; //~ERROR casting f32 to u32 may cause truncation of the value
@ -25,7 +26,32 @@ fn main() {
//~^ERROR casting from i32 to u8 loses the sign of the value
(f as f64) as f32; //~ERROR casting f64 to f32 may cause truncation of the value
i as i8; //~ERROR casting i32 to i8 may cause truncation of the value
u as i32; //~ERROR casting u32 to i32 may cause truncation of the value
// Test cast_sign_loss
i as u32; //~ERROR casting from i32 to u32 loses the sign of the value
// Extra checks for usize/isize
let is : isize = -42;
is as usize; //~ERROR casting from isize to usize loses the sign of the value
is as i8; //~ERROR casting isize to i8 may cause truncation of the value
// FIXME : enable these checks when we figure out a way to make compiletest deal with conditional compilation
/*
#[cfg(target_pointer_width = "64")]
fn check_64() {
let is : isize = -42;
let us : usize = 42;
is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 64 bits wide, but f32's mantissa is only 23 bits wide)
us as u32; //ERROR casting usize to u32 may cause truncation of the value
us as u64; // Should not trigger any lint
}
#[cfg(target_pointer_width = "32")]
fn check_32() {
let is : isize = -42;
let us : usize = 42;
is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 32 bits wide, but f32's mantissa is only 23 bits wide)
us as u32; // Should not trigger any lint
us as u64; // Should not trigger any lint
}*/
}