diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1046945013157..15b79d7abb34f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1297,68 +1297,123 @@ impl LateLintPass for UnionsWithDropFields { } } -/// Lint for unions that contain fields with possibly non-trivial destructors. +/// Lints for non-portable integer conversions. +pub struct NonPortable1632; pub struct NonPortable3264; +pub struct NonPortable64128; +declare_lint! { + NONPORTABLE_16_32, + Allow, + "conversions not portable between 32-bit and 16-bit platforms" +} declare_lint! { NONPORTABLE_32_64, Warn, "conversions not portable between 64-bit and 32-bit platforms" } +declare_lint! { + NONPORTABLE_64_128, + Allow, + "conversions not portable between 64-bit and 128-bit platforms" +} +impl LintPass for NonPortable1632 { + fn get_lints(&self) -> LintArray { + lint_array!(NONPORTABLE_16_32) + } +} impl LintPass for NonPortable3264 { fn get_lints(&self) -> LintArray { lint_array!(NONPORTABLE_32_64) } } +impl LintPass for NonPortable64128 { + fn get_lints(&self) -> LintArray { + lint_array!(NONPORTABLE_64_128) + } +} -fn is_nonportable_conv(src: subst::Kind, dst: subst::Kind) -> bool { - match (src.as_type(), dst.as_type()) { - (Some(src), Some(dst)) => { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; - match (&src.sty, &dst.sty) { - // All conditional impls from libcore/num/mod.rs - // not including "32" and "64" at the same time. - (&TyUint(U64), &TyUint(Us)) | - (&TyUint(Us), &TyUint(U16)) | - (&TyUint(Us), &TyUint(U32)) | - (&TyInt(I64), &TyInt(Is)) | - (&TyInt(Is), &TyInt(I16)) | - (&TyInt(Is), &TyInt(I32)) | - (&TyUint(U32), &TyInt(Is)) | - (&TyUint(Us), &TyInt(I32)) | - (&TyUint(Us), &TyInt(I64)) => true, - _ => false, - } +mod pred { + use super::*; + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + + pub fn is_nonportable_conv_32_64(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool { + match (src, dst) { + // All conditional impls from libcore/num/mod.rs + // not including "32" and "64" at the same time. + (&TyUint(U64), &TyUint(Us)) | + (&TyUint(Us), &TyUint(U16)) | + (&TyUint(Us), &TyUint(U32)) | + (&TyInt(I64), &TyInt(Is)) | + (&TyInt(Is), &TyInt(I16)) | + (&TyInt(Is), &TyInt(I32)) | + (&TyUint(U32), &TyInt(Is)) | + (&TyUint(Us), &TyInt(I32)) | + (&TyUint(Us), &TyInt(I64)) => true, + _ => false, } + } + + pub fn is_nonportable_conv_16_32(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool { + match (src, dst) { + // All conditional impls from libcore/num/mod.rs + // not including "16" and "32" at the same time. + (&TyUint(U32), &TyUint(Us)) | + (&TyUint(Us), &TyUint(U16)) | + (&TyInt(I32), &TyInt(Is)) | + (&TyInt(Is), &TyInt(I16)) | + (&TyUint(U16), &TyInt(Is)) | + (&TyUint(Us), &TyInt(I32)) => true, + _ => false, + } + } + + pub fn is_nonportable_conv_64_128(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool { + match (src, dst) { + // All conditional impls from libcore/num/mod.rs + // not including "64" and potentially "128" at the same time. + (&TyUint(Us), &TyUint(U64)) | + (&TyInt(Is), &TyInt(I64)) => true, + _ => false, + } + } +} + +fn is_nonportable_conv(src: subst::Kind, dst: subst::Kind, pred: Pred) -> bool + where Pred: Fn(&ty::TypeVariants, &ty::TypeVariants) -> bool +{ + match (src.as_type(), dst.as_type()) { + (Some(src), Some(dst)) => pred(&src.sty, &dst.sty), _ => false, } } -impl LateLintPass for NonPortable3264 { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - let tcx = cx.tcx; - let report_lint = |span, src: subst::Kind, dst: subst::Kind| { - let src_ty = src.as_type().unwrap(); - let dst_ty = dst.as_type().unwrap(); - cx.span_lint(NONPORTABLE_32_64, span, - &format!("conversion `{}` -> `{}` is not portable \ - between 64-bit and 32-bit platforms", src_ty, dst_ty)); - }; - match e.node { - hir::ExprMethodCall(name, ..) => { - if name.node.as_str() == "into" { - if let Some(callee) = tcx.tables.borrow().method_map - .get(&ty::MethodCall::expr(e.id)).cloned() { - if let ty::TyFnDef(def_id, substs, _) = callee.ty.sty { - let ti = tcx.impl_or_trait_item(def_id); - if let ty::TraitContainer(trait_def_id) = ti.container() { - if substs.len() == 2 { - if tcx.item_name(trait_def_id).as_str() == "Into" { - if is_nonportable_conv(substs[0], substs[1]) { - report_lint(name.span, substs[0], substs[1]); - } +fn nonportable_check_expr(cx: &LateContext, e: &hir::Expr, w1: u8, w2: u8, + lint: &'static Lint, pred: Pred) + where Pred: Fn(&ty::TypeVariants, &ty::TypeVariants) -> bool +{ + let tcx = cx.tcx; + let report_lint = |span, src: subst::Kind, dst: subst::Kind| { + let src_ty = src.as_type().unwrap(); + let dst_ty = dst.as_type().unwrap(); + cx.span_lint(lint, span, + &format!("conversion `{}` -> `{}` is not portable \ + between {}-bit and {}-bit platforms", src_ty, dst_ty, w1, w2)); + }; + match e.node { + hir::ExprMethodCall(name, ..) => { + if name.node.as_str() == "into" { + if let Some(callee) = tcx.tables.borrow().method_map + .get(&ty::MethodCall::expr(e.id)).cloned() { + if let ty::TyFnDef(def_id, substs, _) = callee.ty.sty { + let ti = tcx.impl_or_trait_item(def_id); + if let ty::TraitContainer(trait_def_id) = ti.container() { + if substs.len() == 2 { + if tcx.item_name(trait_def_id).as_str() == "Into" { + if is_nonportable_conv(substs[0], substs[1], pred) { + report_lint(name.span, substs[0], substs[1]); } } } @@ -1366,25 +1421,24 @@ impl LateLintPass for NonPortable3264 { } } } - hir::ExprPath(..) => { - if let Def::Method(def_id) = tcx.expect_def(e.id) { - let ti = tcx.impl_or_trait_item(def_id); - if let ty::MethodTraitItem(ref method) = ti { - if let ty::TraitContainer(trait_def_id) = ti.container() { - let substs = tcx.node_id_item_substs(e.id).substs; - if substs.len() == 2 { - if method.name.as_str() == "into" { - if tcx.item_name(trait_def_id).as_str() == "Into" { - if is_nonportable_conv(substs[0], substs[1]) { - report_lint(e.span, substs[0], substs[1]); - } + } + hir::ExprPath(..) => { + if let Def::Method(def_id) = tcx.expect_def(e.id) { + let ti = tcx.impl_or_trait_item(def_id); + if let ty::MethodTraitItem(ref method) = ti { + if let ty::TraitContainer(trait_def_id) = ti.container() { + let substs = tcx.node_id_item_substs(e.id).substs; + if substs.len() == 2 { + if method.name.as_str() == "into" { + if tcx.item_name(trait_def_id).as_str() == "Into" { + if is_nonportable_conv(substs[0], substs[1], pred) { + report_lint(e.span, substs[0], substs[1]); } } - if method.name.as_str() == "from" { - if tcx.item_name(trait_def_id).as_str() == "From" { - if is_nonportable_conv(substs[1], substs[0]) { - report_lint(e.span, substs[1], substs[0]); - } + } else if method.name.as_str() == "from" { + if tcx.item_name(trait_def_id).as_str() == "From" { + if is_nonportable_conv(substs[1], substs[0], pred) { + report_lint(e.span, substs[1], substs[0]); } } } @@ -1392,7 +1446,23 @@ impl LateLintPass for NonPortable3264 { } } } - _ => {} } + _ => {} + } +} + +impl LateLintPass for NonPortable1632 { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + nonportable_check_expr(cx, e, 32, 16, NONPORTABLE_16_32, pred::is_nonportable_conv_16_32) + } +} +impl LateLintPass for NonPortable3264 { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + nonportable_check_expr(cx, e, 64, 32, NONPORTABLE_32_64, pred::is_nonportable_conv_32_64) + } +} +impl LateLintPass for NonPortable64128 { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + nonportable_check_expr(cx, e, 64, 128, NONPORTABLE_64_128, pred::is_nonportable_conv_64_128) } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 7ec12975e75d1..cbc78e9b478e2 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -32,6 +32,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(dotdot_in_tuple_patterns)] +#![feature(item_like_imports)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -143,7 +144,9 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { PluginAsLibrary, MutableTransmutes, UnionsWithDropFields, + NonPortable1632, NonPortable3264, + NonPortable64128, ); add_builtin_with_new!(sess, diff --git a/src/test/compile-fail/lint-nonportable-16-32.rs b/src/test/compile-fail/lint-nonportable-16-32.rs new file mode 100644 index 0000000000000..594bff85c7f0e --- /dev/null +++ b/src/test/compile-fail/lint-nonportable-16-32.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] +#![deny(nonportable_16_32)] + +fn check() { + let _: usize = 0u32.into(); + //~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms + let _: usize = Into::into(0u32); + //~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms + let _: usize = From::from(0u32); + //~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms + + let _: isize = 0i32.into(); + //~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms + let _: isize = Into::into(0i32); + //~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms + let _: isize = From::from(0i32); + //~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms + + let _: isize = 0u16.into(); + //~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms + let _: isize = Into::into(0u16); + //~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms + let _: isize = From::from(0u16); + //~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms +} + +fn main() {} diff --git a/src/test/compile-fail/lint-nonportable-64-128.rs b/src/test/compile-fail/lint-nonportable-64-128.rs new file mode 100644 index 0000000000000..969ce1838c5d6 --- /dev/null +++ b/src/test/compile-fail/lint-nonportable-64-128.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] +#![deny(nonportable_64_128)] + +fn check() { + let _: u64 = 0usize.into(); + //~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms + let _: u64 = Into::into(0usize); + //~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms + let _: u64 = From::from(0usize); + //~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms + + let _: i64 = 0isize.into(); + //~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms + let _: i64 = Into::into(0isize); + //~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms + let _: i64 = From::from(0isize); + //~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms +} + +fn main() {}