@@ -33,8 +33,8 @@ use rustc::hir::def_id::DefId;
33
33
use middle::stability;
34
34
use rustc::cfg;
35
35
use rustc::ty::subst::Substs;
36
- use rustc::ty::{self, Ty, TyCtxt};
37
- use rustc::ty::adjustment;
36
+ use rustc::ty::{self, Ty, TyCtxt, TyInt, TyUint };
37
+ use rustc::ty::{ adjustment, subst} ;
38
38
use rustc::traits::{self, Reveal};
39
39
use rustc::hir::map as hir_map;
40
40
use util::nodemap::NodeSet;
@@ -1296,3 +1296,103 @@ impl LateLintPass for UnionsWithDropFields {
1296
1296
}
1297
1297
}
1298
1298
}
1299
+
1300
+ /// Lint for unions that contain fields with possibly non-trivial destructors.
1301
+ pub struct NonPortable3264;
1302
+
1303
+ declare_lint! {
1304
+ NONPORTABLE_32_64,
1305
+ Warn,
1306
+ "conversions not portable between 64-bit and 32-bit platforms"
1307
+ }
1308
+
1309
+ impl LintPass for NonPortable3264 {
1310
+ fn get_lints(&self) -> LintArray {
1311
+ lint_array!(NONPORTABLE_32_64)
1312
+ }
1313
+ }
1314
+
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
+ }
1334
+ }
1335
+ _ => false,
1336
+ }
1337
+ }
1338
+
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
+ }
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+ }
1368
+ }
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
+ }
1381
+ }
1382
+ }
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
+ }
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+ }
1393
+ }
1394
+ }
1395
+ _ => {}
1396
+ }
1397
+ }
1398
+ }
0 commit comments