@@ -38,7 +38,8 @@ use crate::{
38
38
BuiltinUngatedAsyncFnTrackCaller , BuiltinUnnameableTestItems , BuiltinUnpermittedTypeInit ,
39
39
BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub , BuiltinUnsafe ,
40
40
BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
41
- BuiltinWhileTrue , SuggestChangingAssocTypes ,
41
+ BuiltinWhileTrue , RefBinopOnCopyTypeDiag , RefBinopOnCopyTypeSuggestion ,
42
+ SuggestChangingAssocTypes ,
42
43
} ,
43
44
types:: { transparent_newtype_field, CItemKind } ,
44
45
EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext ,
@@ -2888,7 +2889,7 @@ impl ClashingExternDeclarations {
2888
2889
}
2889
2890
( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
2890
2891
// For structural sameness, we don't need the region to be same.
2891
- a_mut == b_mut
2892
+ * a_mut == * b_mut
2892
2893
&& structurally_same_type_impl ( seen_types, cx, * a_ty, * b_ty, ckind)
2893
2894
}
2894
2895
( FnDef ( ..) , FnDef ( ..) ) => {
@@ -3307,6 +3308,118 @@ impl EarlyLintPass for SpecialModuleName {
3307
3308
}
3308
3309
}
3309
3310
3311
+ declare_lint ! {
3312
+ /// The `ref_binop_on_copy_type` lint detects borrowed `Copy` types being passed to binary
3313
+ /// operations that have unnecessary borrows.
3314
+ ///
3315
+ /// ### Example
3316
+ ///
3317
+ /// ```rust
3318
+ /// # #![allow(unused)]
3319
+ /// pub fn slice_of_ints(input: &[(usize, usize, usize, usize)]) -> usize {
3320
+ /// input
3321
+ /// .iter()
3322
+ /// .filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d)
3323
+ /// .count()
3324
+ /// }
3325
+ /// ```
3326
+ ///
3327
+ /// {{produces}}
3328
+ ///
3329
+ /// ### Explanation
3330
+ ///
3331
+ /// When making comparisons (or other binary operations) between two reference values that can
3332
+ /// be copied instead, the compiler will not always remove the references, making the execution
3333
+ /// of the binary operation slower than it otherwise could be by making the machine code "chase
3334
+ /// pointers" before actually finding the underlying value. If the `Copy` value is as small or
3335
+ /// smaller than a 64 bit pointer, we suggest dereferencing the value so the compiler will have
3336
+ /// a better chance of producing optimal instructions.
3337
+ REF_BINOP_ON_COPY_TYPE ,
3338
+ Warn ,
3339
+ "detects binary operations on references to `Copy` types like `&42 < &50`" ,
3340
+ }
3341
+
3342
+ declare_lint_pass ! ( RefBinopOnCopyType => [ REF_BINOP_ON_COPY_TYPE ] ) ;
3343
+
3344
+ impl < ' tcx > LateLintPass < ' tcx > for RefBinopOnCopyType {
3345
+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
3346
+ let hir:: ExprKind :: Binary ( op, left, right) = expr. kind else { return ; } ;
3347
+ let left_ty = cx. typeck_results ( ) . expr_ty_adjusted ( left) ;
3348
+ let right_ty = cx. typeck_results ( ) . expr_ty_adjusted ( right) ;
3349
+ if let ty:: Ref ( _, left_ty, _) = left_ty. kind ( )
3350
+ && let ty:: Ref ( _, left_ty, _) = left_ty. kind ( )
3351
+ && let left_ty = left_ty. peel_refs ( )
3352
+ && left_ty. is_copy_modulo_regions ( cx. tcx , cx. param_env )
3353
+ && let Some ( size) = cx. tcx . layout_of ( cx. param_env . and ( left_ty) ) . ok ( ) . map ( |layout| {
3354
+ layout. size . bytes ( )
3355
+ } )
3356
+ && let ty:: Ref ( _, right_ty, _) = right_ty. kind ( )
3357
+ && let ty:: Ref ( _, right_ty, _) = right_ty. kind ( )
3358
+ && let right_ty = right_ty. peel_refs ( )
3359
+ && right_ty. is_copy_modulo_regions ( cx. tcx , cx. param_env )
3360
+ && let Some ( size_r) = cx. tcx . layout_of ( cx. param_env . and ( right_ty) ) . ok ( ) . map ( |layout| {
3361
+ layout. size . bytes ( )
3362
+ } )
3363
+ && size <= 8
3364
+ && size_r <= 8
3365
+ {
3366
+ let left_start_base = left. span . shrink_to_lo ( ) ;
3367
+ let left_peeled = left. peel_borrows ( ) ;
3368
+ let left_start = left_start_base. to ( left_peeled. span . shrink_to_lo ( ) ) ;
3369
+ let left_sugg = if left_start != left_start_base
3370
+ && !matches ! ( cx. typeck_results( ) . expr_ty_adjusted( left_peeled) . kind( ) , ty:: Ref ( ..) )
3371
+ {
3372
+ ""
3373
+ } else {
3374
+ "*"
3375
+ } ;
3376
+ let ( left_brace_start, left_brace_end, left_end) =
3377
+ if left. precedence ( ) . order ( ) < ast:: ExprPrecedence :: Unary . order ( ) {
3378
+ ( "(" , ")" , Some ( left. span . shrink_to_hi ( ) ) )
3379
+ } else {
3380
+ ( "" , "" , None )
3381
+ } ;
3382
+ let right_start_base = right. span . shrink_to_lo ( ) ;
3383
+ let right_peeled = right. peel_borrows ( ) ;
3384
+ let right_start = right_start_base. to ( right_peeled. span . shrink_to_lo ( ) ) ;
3385
+ let right_sugg = if right_start != right_start_base
3386
+ && !matches ! ( cx. typeck_results( ) . expr_ty_adjusted( right_peeled) . kind( ) , ty:: Ref ( ..) )
3387
+ {
3388
+ ""
3389
+ } else {
3390
+ "*"
3391
+ } ;
3392
+ let ( right_brace_start, right_brace_end, right_end) =
3393
+ if right. precedence ( ) . order ( ) < ast:: ExprPrecedence :: Unary . order ( ) {
3394
+ ( "(" , ")" , Some ( right. span . shrink_to_hi ( ) ) )
3395
+ } else {
3396
+ ( "" , "" , None )
3397
+ } ;
3398
+ cx. emit_spanned_lint (
3399
+ REF_BINOP_ON_COPY_TYPE ,
3400
+ op. span ,
3401
+ RefBinopOnCopyTypeDiag {
3402
+ ty : with_no_trimmed_paths ! ( left_ty. to_string( ) ) ,
3403
+ bytes : size,
3404
+ note : Some ( ( ) ) ,
3405
+ suggestion : RefBinopOnCopyTypeSuggestion {
3406
+ left_brace_start,
3407
+ left_brace_end,
3408
+ left_sugg,
3409
+ left_start,
3410
+ left_end,
3411
+ right_brace_start,
3412
+ right_brace_end,
3413
+ right_sugg,
3414
+ right_start,
3415
+ right_end,
3416
+ } ,
3417
+ } ,
3418
+ ) ;
3419
+ }
3420
+ }
3421
+ }
3422
+
3310
3423
pub use rustc_session:: lint:: builtin:: UNEXPECTED_CFGS ;
3311
3424
3312
3425
declare_lint_pass ! ( UnexpectedCfgs => [ UNEXPECTED_CFGS ] ) ;
0 commit comments