@@ -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,9 +315,26 @@ 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 > {
337
+ #[ allow( clippy:: if_same_then_else) ]
310
338
fn consume ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , _id : HirId ) {
311
339
if let euv:: Place {
312
340
base :
@@ -327,12 +355,17 @@ 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 ( * vid) {
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
368
+ #[ allow( clippy:: if_same_then_else) ]
336
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 {
@@ -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 ( * vid) {
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
0 commit comments