@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
7
7
use rustc_errors:: Applicability ;
8
8
use rustc_hir:: intravisit:: { walk_qpath, FnKind , Visitor } ;
9
9
use rustc_hir:: {
10
- Body , Closure , Expr , ExprKind , FnDecl , HirId , HirIdMap , HirIdSet , Impl , ItemKind , Mutability , Node , PatKind , QPath ,
10
+ BlockCheckMode , Body , Closure , Expr , ExprKind , FnDecl , HirId , HirIdMap , HirIdSet , Impl , ItemKind , Mutability , Node ,
11
+ PatKind , QPath ,
11
12
} ;
12
13
use rustc_hir_typeck:: expr_use_visitor as euv;
13
14
use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
139
140
let hir_id = cx. tcx . hir ( ) . local_def_id_to_hir_id ( fn_def_id) ;
140
141
let is_async = match kind {
141
142
FnKind :: ItemFn ( .., header) => {
143
+ if header. is_unsafe ( ) {
144
+ // We don't check unsafe functions.
145
+ return ;
146
+ }
142
147
let attrs = cx. tcx . hir ( ) . attrs ( hir_id) ;
143
148
if header. abi != Abi :: Rust || requires_exact_signature ( attrs) {
144
149
return ;
145
150
}
146
151
header. is_async ( )
147
152
} ,
148
- FnKind :: Method ( .., sig) => sig. header . is_async ( ) ,
153
+ FnKind :: Method ( .., sig) => {
154
+ if sig. header . is_unsafe ( ) {
155
+ // We don't check unsafe functions.
156
+ return ;
157
+ }
158
+ sig. header . is_async ( )
159
+ } ,
149
160
FnKind :: Closure => return ,
150
161
} ;
151
162
@@ -304,10 +315,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
304
315
}
305
316
self . aliases . insert ( alias, target) ;
306
317
}
318
+
319
+ // The goal here is to find if the current scope is unsafe or not. It stops when it finds
320
+ // a function or an unsafe block.
321
+ fn is_in_unsafe_block ( & self , item : HirId ) -> bool {
322
+ let hir = self . tcx . hir ( ) ;
323
+ for ( parent, node) in hir. parent_iter ( item) {
324
+ if let Some ( fn_sig) = hir. fn_sig_by_hir_id ( parent) {
325
+ return fn_sig. header . is_unsafe ( ) ;
326
+ } else if let Node :: Block ( block) = node {
327
+ if matches ! ( block. rules, BlockCheckMode :: UnsafeBlock ( _) ) {
328
+ return true ;
329
+ }
330
+ }
331
+ }
332
+ false
333
+ }
307
334
}
308
335
309
336
impl < ' tcx > euv:: Delegate < ' tcx > for MutablyUsedVariablesCtxt < ' tcx > {
310
- fn consume ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , _id : HirId ) {
337
+ #[ allow( clippy:: if_same_then_else) ]
338
+ fn consume ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
311
339
if let euv:: Place {
312
340
base :
313
341
euv:: PlaceBase :: Local ( vid)
@@ -327,13 +355,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
327
355
&& matches ! ( base_ty. ref_mutability( ) , Some ( Mutability :: Mut ) )
328
356
{
329
357
self . add_mutably_used_var ( * vid) ;
358
+ } else if self . is_in_unsafe_block ( id) {
359
+ // If we are in an unsafe block, any operation on this variable must not be warned
360
+ // upon!
361
+ self . add_mutably_used_var ( * vid) ;
330
362
}
331
363
self . prev_bind = None ;
332
364
self . prev_move_to_closure . remove ( vid) ;
333
365
}
334
366
}
335
367
336
- fn borrow ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , _id : HirId , borrow : ty:: BorrowKind ) {
368
+ #[ allow( clippy:: if_same_then_else) ]
369
+ fn borrow ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId , borrow : ty:: BorrowKind ) {
337
370
self . prev_bind = None ;
338
371
if let euv:: Place {
339
372
base :
@@ -355,6 +388,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
355
388
|| ( borrow == ty:: BorrowKind :: UniqueImmBorrow && base_ty. ref_mutability ( ) == Some ( Mutability :: Mut ) )
356
389
{
357
390
self . add_mutably_used_var ( * vid) ;
391
+ } else if self . is_in_unsafe_block ( id) {
392
+ // If we are in an unsafe block, any operation on this variable must not be warned
393
+ // upon!
394
+ self . add_mutably_used_var ( * vid) ;
358
395
}
359
396
} else if borrow == ty:: ImmBorrow {
360
397
// If there is an `async block`, it'll contain a call to a closure which we need to
@@ -397,7 +434,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
397
434
}
398
435
}
399
436
400
- fn copy ( & mut self , _cmt : & euv:: PlaceWithHirId < ' tcx > , _id : HirId ) {
437
+ fn copy ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
438
+ if let euv:: Place {
439
+ base :
440
+ euv:: PlaceBase :: Local ( vid)
441
+ | euv:: PlaceBase :: Upvar ( UpvarId {
442
+ var_path : UpvarPath { hir_id : vid } ,
443
+ ..
444
+ } ) ,
445
+ ..
446
+ } = & cmt. place
447
+ {
448
+ if self . is_in_unsafe_block ( id) {
449
+ self . add_mutably_used_var ( * vid) ;
450
+ }
451
+ }
401
452
self . prev_bind = None ;
402
453
}
403
454
@@ -427,8 +478,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
427
478
}
428
479
}
429
480
430
- fn bind ( & mut self , _cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
481
+ fn bind ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
431
482
self . prev_bind = Some ( id) ;
483
+ if let euv:: Place {
484
+ base :
485
+ euv:: PlaceBase :: Local ( vid)
486
+ | euv:: PlaceBase :: Upvar ( UpvarId {
487
+ var_path : UpvarPath { hir_id : vid } ,
488
+ ..
489
+ } ) ,
490
+ ..
491
+ } = & cmt. place
492
+ {
493
+ if self . is_in_unsafe_block ( id) {
494
+ self . add_mutably_used_var ( * vid) ;
495
+ }
496
+ }
432
497
}
433
498
}
434
499
0 commit comments