@@ -33,8 +33,8 @@ use rustc::hir::def_id::DefId;
3333use middle:: stability;
3434use rustc:: cfg;
3535use 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 } ;
3838use rustc:: traits:: { self , Reveal } ;
3939use rustc:: hir:: map as hir_map;
4040use util:: nodemap:: NodeSet ;
@@ -1296,3 +1296,103 @@ impl LateLintPass for UnionsWithDropFields {
12961296 }
12971297 }
12981298}
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