@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
77use rustc_errors:: Applicability ;
88use rustc_hir:: intravisit:: { walk_qpath, FnKind , Visitor } ;
99use 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 ,
1112} ;
1213use rustc_hir_typeck:: expr_use_visitor as euv;
1314use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
139140 let hir_id = cx. tcx . hir ( ) . local_def_id_to_hir_id ( fn_def_id) ;
140141 let is_async = match kind {
141142 FnKind :: ItemFn ( .., header) => {
143+ if header. is_unsafe ( ) {
144+ // We don't check unsafe functions.
145+ return ;
146+ }
142147 let attrs = cx. tcx . hir ( ) . attrs ( hir_id) ;
143148 if header. abi != Abi :: Rust || requires_exact_signature ( attrs) {
144149 return ;
145150 }
146151 header. is_async ( )
147152 } ,
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+ } ,
149160 FnKind :: Closure => return ,
150161 } ;
151162
@@ -304,10 +315,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
304315 }
305316 self . aliases . insert ( alias, target) ;
306317 }
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+ }
307334}
308335
309336impl < ' 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 ) {
311339 if let euv:: Place {
312340 base :
313341 euv:: PlaceBase :: Local ( vid)
@@ -327,13 +355,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
327355 && matches ! ( base_ty. ref_mutability( ) , Some ( Mutability :: Mut ) )
328356 {
329357 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) ;
330362 }
331363 self . prev_bind = None ;
332364 self . prev_move_to_closure . remove ( vid) ;
333365 }
334366 }
335367
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 ) {
337370 self . prev_bind = None ;
338371 if let euv:: Place {
339372 base :
@@ -355,6 +388,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
355388 || ( borrow == ty:: BorrowKind :: UniqueImmBorrow && base_ty. ref_mutability ( ) == Some ( Mutability :: Mut ) )
356389 {
357390 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) ;
358395 }
359396 } else if borrow == ty:: ImmBorrow {
360397 // 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> {
397434 }
398435 }
399436
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+ }
401452 self . prev_bind = None ;
402453 }
403454
@@ -427,8 +478,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
427478 }
428479 }
429480
430- fn bind ( & mut self , _cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
481+ fn bind ( & mut self , cmt : & euv:: PlaceWithHirId < ' tcx > , id : HirId ) {
431482 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+ }
432497 }
433498}
434499
0 commit comments