Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2d83bfd

Browse files
committedOct 27, 2016
Implement portability lints for 16 and 128 bits
1 parent b28e45e commit 2d83bfd

File tree

4 files changed

+201
-61
lines changed

4 files changed

+201
-61
lines changed
 

‎src/librustc_lint/builtin.rs

Lines changed: 131 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,102 +1297,172 @@ impl LateLintPass for UnionsWithDropFields {
12971297
}
12981298
}
12991299

1300-
/// Lint for unions that contain fields with possibly non-trivial destructors.
1300+
/// Lints for non-portable integer conversions.
1301+
pub struct NonPortable1632;
13011302
pub struct NonPortable3264;
1303+
pub struct NonPortable64128;
13021304

1305+
declare_lint! {
1306+
NONPORTABLE_16_32,
1307+
Allow,
1308+
"conversions not portable between 32-bit and 16-bit platforms"
1309+
}
13031310
declare_lint! {
13041311
NONPORTABLE_32_64,
13051312
Warn,
13061313
"conversions not portable between 64-bit and 32-bit platforms"
13071314
}
1315+
declare_lint! {
1316+
NONPORTABLE_64_128,
1317+
Allow,
1318+
"conversions not portable between 64-bit and 128-bit platforms"
1319+
}
13081320

1321+
impl LintPass for NonPortable1632 {
1322+
fn get_lints(&self) -> LintArray {
1323+
lint_array!(NONPORTABLE_16_32)
1324+
}
1325+
}
13091326
impl LintPass for NonPortable3264 {
13101327
fn get_lints(&self) -> LintArray {
13111328
lint_array!(NONPORTABLE_32_64)
13121329
}
13131330
}
1331+
impl LintPass for NonPortable64128 {
1332+
fn get_lints(&self) -> LintArray {
1333+
lint_array!(NONPORTABLE_64_128)
1334+
}
1335+
}
13141336

1315-
fn is_nonportable_conv(src: subst::Kind, dst: subst::Kind) -> bool {
1316-
match (src.as_type(), dst.as_type()) {
1317-
(Some(src), Some(dst)) => {
1318-
use syntax::ast::IntTy::*;
1319-
use syntax::ast::UintTy::*;
1320-
match (&src.sty, &dst.sty) {
1321-
// All conditional impls from libcore/num/mod.rs
1322-
// not including "32" and "64" at the same time.
1323-
(&TyUint(U64), &TyUint(Us)) |
1324-
(&TyUint(Us), &TyUint(U16)) |
1325-
(&TyUint(Us), &TyUint(U32)) |
1326-
(&TyInt(I64), &TyInt(Is)) |
1327-
(&TyInt(Is), &TyInt(I16)) |
1328-
(&TyInt(Is), &TyInt(I32)) |
1329-
(&TyUint(U32), &TyInt(Is)) |
1330-
(&TyUint(Us), &TyInt(I32)) |
1331-
(&TyUint(Us), &TyInt(I64)) => true,
1332-
_ => false,
1333-
}
1337+
mod pred {
1338+
use super::*;
1339+
use syntax::ast::IntTy::*;
1340+
use syntax::ast::UintTy::*;
1341+
1342+
pub fn is_nonportable_conv_32_64(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool {
1343+
match (src, dst) {
1344+
// All conditional impls from libcore/num/mod.rs
1345+
// not including "32" and "64" at the same time.
1346+
(&TyUint(U64), &TyUint(Us)) |
1347+
(&TyUint(Us), &TyUint(U16)) |
1348+
(&TyUint(Us), &TyUint(U32)) |
1349+
(&TyInt(I64), &TyInt(Is)) |
1350+
(&TyInt(Is), &TyInt(I16)) |
1351+
(&TyInt(Is), &TyInt(I32)) |
1352+
(&TyUint(U32), &TyInt(Is)) |
1353+
(&TyUint(Us), &TyInt(I32)) |
1354+
(&TyUint(Us), &TyInt(I64)) => true,
1355+
_ => false,
13341356
}
1357+
}
1358+
1359+
pub fn is_nonportable_conv_16_32(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool {
1360+
match (src, dst) {
1361+
// All conditional impls from libcore/num/mod.rs
1362+
// not including "16" and "32" at the same time.
1363+
(&TyUint(U32), &TyUint(Us)) |
1364+
(&TyUint(Us), &TyUint(U16)) |
1365+
(&TyInt(I32), &TyInt(Is)) |
1366+
(&TyInt(Is), &TyInt(I16)) |
1367+
(&TyUint(U16), &TyInt(Is)) |
1368+
(&TyUint(Us), &TyInt(I32)) => true,
1369+
_ => false,
1370+
}
1371+
}
1372+
1373+
pub fn is_nonportable_conv_64_128(src: &ty::TypeVariants, dst: &ty::TypeVariants) -> bool {
1374+
match (src, dst) {
1375+
// All conditional impls from libcore/num/mod.rs
1376+
// not including "64" and potentially "128" at the same time.
1377+
(&TyUint(Us), &TyUint(U64)) |
1378+
(&TyInt(Is), &TyInt(I64)) => true,
1379+
_ => false,
1380+
}
1381+
}
1382+
}
1383+
1384+
fn is_nonportable_conv<Pred>(src: subst::Kind, dst: subst::Kind, pred: Pred) -> bool
1385+
where Pred: Fn(&ty::TypeVariants, &ty::TypeVariants) -> bool
1386+
{
1387+
match (src.as_type(), dst.as_type()) {
1388+
(Some(src), Some(dst)) => pred(&src.sty, &dst.sty),
13351389
_ => false,
13361390
}
13371391
}
13381392

1339-
impl LateLintPass for NonPortable3264 {
1340-
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
1341-
let tcx = cx.tcx;
1342-
let report_lint = |span, src: subst::Kind, dst: subst::Kind| {
1343-
let src_ty = src.as_type().unwrap();
1344-
let dst_ty = dst.as_type().unwrap();
1345-
cx.span_lint(NONPORTABLE_32_64, span,
1346-
&format!("conversion `{}` -> `{}` is not portable \
1347-
between 64-bit and 32-bit platforms", src_ty, dst_ty));
1348-
};
1349-
match e.node {
1350-
hir::ExprMethodCall(name, ..) => {
1351-
if name.node.as_str() == "into" {
1352-
if let Some(callee) = tcx.tables.borrow().method_map
1353-
.get(&ty::MethodCall::expr(e.id)).cloned() {
1354-
if let ty::TyFnDef(def_id, substs, _) = callee.ty.sty {
1355-
let ti = tcx.impl_or_trait_item(def_id);
1356-
if let ty::TraitContainer(trait_def_id) = ti.container() {
1357-
if substs.len() == 2 {
1358-
if tcx.item_name(trait_def_id).as_str() == "Into" {
1359-
if is_nonportable_conv(substs[0], substs[1]) {
1360-
report_lint(name.span, substs[0], substs[1]);
1361-
}
1393+
fn nonportable_check_expr<Pred>(cx: &LateContext, e: &hir::Expr, w1: u8, w2: u8,
1394+
lint: &'static Lint, pred: Pred)
1395+
where Pred: Fn(&ty::TypeVariants, &ty::TypeVariants) -> bool
1396+
{
1397+
let tcx = cx.tcx;
1398+
let report_lint = |span, src: subst::Kind, dst: subst::Kind| {
1399+
let src_ty = src.as_type().unwrap();
1400+
let dst_ty = dst.as_type().unwrap();
1401+
cx.span_lint(lint, span,
1402+
&format!("conversion `{}` -> `{}` is not portable \
1403+
between {}-bit and {}-bit platforms", src_ty, dst_ty, w1, w2));
1404+
};
1405+
match e.node {
1406+
hir::ExprMethodCall(name, ..) => {
1407+
if name.node.as_str() == "into" {
1408+
if let Some(callee) = tcx.tables.borrow().method_map
1409+
.get(&ty::MethodCall::expr(e.id)).cloned() {
1410+
if let ty::TyFnDef(def_id, substs, _) = callee.ty.sty {
1411+
let ti = tcx.impl_or_trait_item(def_id);
1412+
if let ty::TraitContainer(trait_def_id) = ti.container() {
1413+
if substs.len() == 2 {
1414+
if tcx.item_name(trait_def_id).as_str() == "Into" {
1415+
if is_nonportable_conv(substs[0], substs[1], pred) {
1416+
report_lint(name.span, substs[0], substs[1]);
13621417
}
13631418
}
13641419
}
13651420
}
13661421
}
13671422
}
13681423
}
1369-
hir::ExprPath(..) => {
1370-
if let Def::Method(def_id) = tcx.expect_def(e.id) {
1371-
let ti = tcx.impl_or_trait_item(def_id);
1372-
if let ty::MethodTraitItem(ref method) = ti {
1373-
if let ty::TraitContainer(trait_def_id) = ti.container() {
1374-
let substs = tcx.node_id_item_substs(e.id).substs;
1375-
if substs.len() == 2 {
1376-
if method.name.as_str() == "into" {
1377-
if tcx.item_name(trait_def_id).as_str() == "Into" {
1378-
if is_nonportable_conv(substs[0], substs[1]) {
1379-
report_lint(e.span, substs[0], substs[1]);
1380-
}
1424+
}
1425+
hir::ExprPath(..) => {
1426+
if let Def::Method(def_id) = tcx.expect_def(e.id) {
1427+
let ti = tcx.impl_or_trait_item(def_id);
1428+
if let ty::MethodTraitItem(ref method) = ti {
1429+
if let ty::TraitContainer(trait_def_id) = ti.container() {
1430+
let substs = tcx.node_id_item_substs(e.id).substs;
1431+
if substs.len() == 2 {
1432+
if method.name.as_str() == "into" {
1433+
if tcx.item_name(trait_def_id).as_str() == "Into" {
1434+
if is_nonportable_conv(substs[0], substs[1], pred) {
1435+
report_lint(e.span, substs[0], substs[1]);
13811436
}
13821437
}
1383-
if method.name.as_str() == "from" {
1384-
if tcx.item_name(trait_def_id).as_str() == "From" {
1385-
if is_nonportable_conv(substs[1], substs[0]) {
1386-
report_lint(e.span, substs[1], substs[0]);
1387-
}
1438+
} else if method.name.as_str() == "from" {
1439+
if tcx.item_name(trait_def_id).as_str() == "From" {
1440+
if is_nonportable_conv(substs[1], substs[0], pred) {
1441+
report_lint(e.span, substs[1], substs[0]);
13881442
}
13891443
}
13901444
}
13911445
}
13921446
}
13931447
}
13941448
}
1395-
_ => {}
13961449
}
1450+
_ => {}
1451+
}
1452+
}
1453+
1454+
impl LateLintPass for NonPortable1632 {
1455+
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
1456+
nonportable_check_expr(cx, e, 32, 16, NONPORTABLE_16_32, pred::is_nonportable_conv_16_32)
1457+
}
1458+
}
1459+
impl LateLintPass for NonPortable3264 {
1460+
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
1461+
nonportable_check_expr(cx, e, 64, 32, NONPORTABLE_32_64, pred::is_nonportable_conv_32_64)
1462+
}
1463+
}
1464+
impl LateLintPass for NonPortable64128 {
1465+
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
1466+
nonportable_check_expr(cx, e, 64, 128, NONPORTABLE_64_128, pred::is_nonportable_conv_64_128)
13971467
}
13981468
}

‎src/librustc_lint/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#![feature(box_patterns)]
3333
#![feature(box_syntax)]
3434
#![feature(dotdot_in_tuple_patterns)]
35+
#![feature(item_like_imports)]
3536
#![feature(quote)]
3637
#![feature(rustc_diagnostic_macros)]
3738
#![feature(rustc_private)]
@@ -143,7 +144,9 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
143144
PluginAsLibrary,
144145
MutableTransmutes,
145146
UnionsWithDropFields,
147+
NonPortable1632,
146148
NonPortable3264,
149+
NonPortable64128,
147150
);
148151

149152
add_builtin_with_new!(sess,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
#![deny(nonportable_16_32)]
13+
14+
fn check() {
15+
let _: usize = 0u32.into();
16+
//~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms
17+
let _: usize = Into::into(0u32);
18+
//~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms
19+
let _: usize = From::from(0u32);
20+
//~^ ERROR conversion `u32` -> `usize` is not portable between 32-bit and 16-bit platforms
21+
22+
let _: isize = 0i32.into();
23+
//~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms
24+
let _: isize = Into::into(0i32);
25+
//~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms
26+
let _: isize = From::from(0i32);
27+
//~^ ERROR conversion `i32` -> `isize` is not portable between 32-bit and 16-bit platforms
28+
29+
let _: isize = 0u16.into();
30+
//~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms
31+
let _: isize = Into::into(0u16);
32+
//~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms
33+
let _: isize = From::from(0u16);
34+
//~^ ERROR conversion `u16` -> `isize` is not portable between 32-bit and 16-bit platforms
35+
}
36+
37+
fn main() {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
#![deny(nonportable_64_128)]
13+
14+
fn check() {
15+
let _: u64 = 0usize.into();
16+
//~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms
17+
let _: u64 = Into::into(0usize);
18+
//~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms
19+
let _: u64 = From::from(0usize);
20+
//~^ ERROR conversion `usize` -> `u64` is not portable between 64-bit and 128-bit platforms
21+
22+
let _: i64 = 0isize.into();
23+
//~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms
24+
let _: i64 = Into::into(0isize);
25+
//~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms
26+
let _: i64 = From::from(0isize);
27+
//~^ ERROR conversion `isize` -> `i64` is not portable between 64-bit and 128-bit platforms
28+
}
29+
30+
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.