@@ -1159,83 +1159,97 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Casts {
11591159 }
11601160 }
11611161 if cast_from. is_numeric ( ) && cast_to. is_numeric ( ) && !in_external_macro ( cx. sess ( ) , expr. span ) {
1162- match ( cast_from. is_integral ( ) , cast_to. is_integral ( ) ) {
1163- ( true , false ) => {
1164- let from_nbits = int_ty_to_nbits ( cast_from, cx. tcx ) ;
1165- let to_nbits = if let ty:: Float ( FloatTy :: F32 ) = cast_to. sty {
1166- 32
1167- } else {
1168- 64
1169- } ;
1170- if is_isize_or_usize ( cast_from) || from_nbits >= to_nbits {
1171- span_precision_loss_lint ( cx, expr, cast_from, to_nbits == 64 ) ;
1172- }
1173- if from_nbits < to_nbits {
1174- span_lossless_lint ( cx, expr, ex, cast_from, cast_to) ;
1175- }
1176- } ,
1177- ( false , true ) => {
1178- span_lint (
1179- cx,
1180- CAST_POSSIBLE_TRUNCATION ,
1181- expr. span ,
1182- & format ! ( "casting {} to {} may truncate the value" , cast_from, cast_to) ,
1183- ) ;
1184- if !cast_to. is_signed ( ) {
1185- span_lint (
1186- cx,
1187- CAST_SIGN_LOSS ,
1188- expr. span ,
1189- & format ! ( "casting {} to {} may lose the sign of the value" , cast_from, cast_to) ,
1190- ) ;
1191- }
1192- } ,
1193- ( true , true ) => {
1194- check_loss_of_sign ( cx, expr, ex, cast_from, cast_to) ;
1195- check_truncation_and_wrapping ( cx, expr, cast_from, cast_to) ;
1196- check_lossless ( cx, expr, ex, cast_from, cast_to) ;
1197- } ,
1198- ( false , false ) => {
1199- if let ( & ty:: Float ( FloatTy :: F64 ) , & ty:: Float ( FloatTy :: F32 ) ) = ( & cast_from. sty , & cast_to. sty ) {
1200- span_lint (
1201- cx,
1202- CAST_POSSIBLE_TRUNCATION ,
1203- expr. span ,
1204- "casting f64 to f32 may truncate the value" ,
1205- ) ;
1206- }
1207- if let ( & ty:: Float ( FloatTy :: F32 ) , & ty:: Float ( FloatTy :: F64 ) ) = ( & cast_from. sty , & cast_to. sty ) {
1208- span_lossless_lint ( cx, expr, ex, cast_from, cast_to) ;
1209- }
1210- } ,
1211- }
1162+ lint_numeric_casts ( cx, expr, ex, cast_from, cast_to) ;
12121163 }
12131164
1214- if_chain ! {
1215- if let ty:: RawPtr ( from_ptr_ty) = & cast_from. sty;
1216- if let ty:: RawPtr ( to_ptr_ty) = & cast_to. sty;
1217- if let Ok ( from_layout) = cx. layout_of( from_ptr_ty. ty) ;
1218- if let Ok ( to_layout) = cx. layout_of( to_ptr_ty. ty) ;
1219- if from_layout. align. abi < to_layout. align. abi;
1220- // with c_void, we inherently need to trust the user
1221- if !is_c_void( cx, from_ptr_ty. ty) ;
1222- // when casting from a ZST, we don't know enough to properly lint
1223- if !from_layout. is_zst( ) ;
1224- then {
1225- span_lint(
1226- cx,
1227- CAST_PTR_ALIGNMENT ,
1228- expr. span,
1229- & format!(
1230- "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)" ,
1231- cast_from,
1232- cast_to,
1233- from_layout. align. abi. bytes( ) ,
1234- to_layout. align. abi. bytes( ) ,
1235- ) ,
1236- ) ;
1237- }
1165+ lint_cast_ptr_alignment ( cx, expr, cast_from, cast_to) ;
1166+ }
1167+ }
1168+ }
1169+
1170+ fn lint_numeric_casts < ' tcx > (
1171+ cx : & LateContext < ' _ , ' tcx > ,
1172+ expr : & Expr ,
1173+ cast_expr : & Expr ,
1174+ cast_from : Ty < ' tcx > ,
1175+ cast_to : Ty < ' tcx > ,
1176+ ) {
1177+ match ( cast_from. is_integral ( ) , cast_to. is_integral ( ) ) {
1178+ ( true , false ) => {
1179+ let from_nbits = int_ty_to_nbits ( cast_from, cx. tcx ) ;
1180+ let to_nbits = if let ty:: Float ( FloatTy :: F32 ) = cast_to. sty {
1181+ 32
1182+ } else {
1183+ 64
1184+ } ;
1185+ if is_isize_or_usize ( cast_from) || from_nbits >= to_nbits {
1186+ span_precision_loss_lint ( cx, expr, cast_from, to_nbits == 64 ) ;
12381187 }
1188+ if from_nbits < to_nbits {
1189+ span_lossless_lint ( cx, expr, cast_expr, cast_from, cast_to) ;
1190+ }
1191+ } ,
1192+ ( false , true ) => {
1193+ span_lint (
1194+ cx,
1195+ CAST_POSSIBLE_TRUNCATION ,
1196+ expr. span ,
1197+ & format ! ( "casting {} to {} may truncate the value" , cast_from, cast_to) ,
1198+ ) ;
1199+ if !cast_to. is_signed ( ) {
1200+ span_lint (
1201+ cx,
1202+ CAST_SIGN_LOSS ,
1203+ expr. span ,
1204+ & format ! ( "casting {} to {} may lose the sign of the value" , cast_from, cast_to) ,
1205+ ) ;
1206+ }
1207+ } ,
1208+ ( true , true ) => {
1209+ check_loss_of_sign ( cx, expr, cast_expr, cast_from, cast_to) ;
1210+ check_truncation_and_wrapping ( cx, expr, cast_from, cast_to) ;
1211+ check_lossless ( cx, expr, cast_expr, cast_from, cast_to) ;
1212+ } ,
1213+ ( false , false ) => {
1214+ if let ( & ty:: Float ( FloatTy :: F64 ) , & ty:: Float ( FloatTy :: F32 ) ) = ( & cast_from. sty , & cast_to. sty ) {
1215+ span_lint (
1216+ cx,
1217+ CAST_POSSIBLE_TRUNCATION ,
1218+ expr. span ,
1219+ "casting f64 to f32 may truncate the value" ,
1220+ ) ;
1221+ }
1222+ if let ( & ty:: Float ( FloatTy :: F32 ) , & ty:: Float ( FloatTy :: F64 ) ) = ( & cast_from. sty , & cast_to. sty ) {
1223+ span_lossless_lint ( cx, expr, cast_expr, cast_from, cast_to) ;
1224+ }
1225+ } ,
1226+ }
1227+ }
1228+
1229+ fn lint_cast_ptr_alignment < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , expr : & Expr , cast_from : Ty < ' tcx > , cast_to : Ty < ' tcx > ) {
1230+ if_chain ! {
1231+ if let ty:: RawPtr ( from_ptr_ty) = & cast_from. sty;
1232+ if let ty:: RawPtr ( to_ptr_ty) = & cast_to. sty;
1233+ if let Ok ( from_layout) = cx. layout_of( from_ptr_ty. ty) ;
1234+ if let Ok ( to_layout) = cx. layout_of( to_ptr_ty. ty) ;
1235+ if from_layout. align. abi < to_layout. align. abi;
1236+ // with c_void, we inherently need to trust the user
1237+ if !is_c_void( cx, from_ptr_ty. ty) ;
1238+ // when casting from a ZST, we don't know enough to properly lint
1239+ if !from_layout. is_zst( ) ;
1240+ then {
1241+ span_lint(
1242+ cx,
1243+ CAST_PTR_ALIGNMENT ,
1244+ expr. span,
1245+ & format!(
1246+ "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)" ,
1247+ cast_from,
1248+ cast_to,
1249+ from_layout. align. abi. bytes( ) ,
1250+ to_layout. align. abi. bytes( ) ,
1251+ ) ,
1252+ ) ;
12391253 }
12401254 }
12411255}
0 commit comments