@@ -3,11 +3,12 @@ use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_appl
33use clippy_utils:: ty:: is_copy;
44use clippy_utils:: visitors:: for_each_expr;
55use clippy_utils:: {
6- SpanlessEq , can_move_expr_to_closure_no_visit, higher , is_expr_final_block_expr , is_expr_used_or_unified ,
7- peel_hir_expr_while,
6+ SpanlessEq , can_move_expr_to_closure_no_visit, desugar_await , higher , is_expr_final_block_expr ,
7+ is_expr_used_or_unified , paths , peel_hir_expr_while,
88} ;
99use core:: fmt:: { self , Write } ;
1010use rustc_errors:: Applicability ;
11+ use rustc_hir:: def_id:: DefId ;
1112use rustc_hir:: hir_id:: HirIdSet ;
1213use rustc_hir:: intravisit:: { Visitor , walk_body, walk_expr} ;
1314use rustc_hir:: { Block , Expr , ExprKind , HirId , Pat , Stmt , StmtKind , UnOp } ;
@@ -382,6 +383,8 @@ struct InsertSearcher<'cx, 'tcx> {
382383 loops : Vec < HirId > ,
383384 /// Local variables created in the expression. These don't need to be captured.
384385 locals : HirIdSet ,
386+ /// Whether the map is a non-async-aware `MutexGuard`.
387+ map_is_mutex_guard : bool ,
385388}
386389impl < ' tcx > InsertSearcher < ' _ , ' tcx > {
387390 /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but
@@ -524,15 +527,22 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
524527 ExprKind :: If ( cond_expr, then_expr, Some ( else_expr) ) => {
525528 self . is_single_insert = false ;
526529 self . visit_non_tail_expr ( cond_expr) ;
527- // Each branch may contain it's own insert expression.
530+ // Each branch may contain its own insert expression.
528531 let mut is_map_used = self . visit_cond_arm ( then_expr) ;
529532 is_map_used |= self . visit_cond_arm ( else_expr) ;
530533 self . is_map_used = is_map_used;
531534 } ,
532535 ExprKind :: Match ( scrutinee_expr, arms, _) => {
536+ // If the map is a non-async-aware `MutexGuard` and
537+ // `.await` expression appears alongside map insertion in the same `then` or `else` block,
538+ // we cannot suggest using `entry()` because it would hold the lock across the await point,
539+ // triggering `await_holding_lock` and risking deadlock.
540+ if self . map_is_mutex_guard && desugar_await ( expr) . is_some ( ) {
541+ self . can_use_entry = false ;
542+ }
533543 self . is_single_insert = false ;
534544 self . visit_non_tail_expr ( scrutinee_expr) ;
535- // Each branch may contain it's own insert expression.
545+ // Each branch may contain its own insert expression.
536546 let mut is_map_used = self . is_map_used ;
537547 for arm in arms {
538548 self . visit_pat ( arm. pat ) ;
@@ -725,16 +735,32 @@ fn find_insert_calls<'tcx>(
725735 edits : Vec :: new ( ) ,
726736 loops : Vec :: new ( ) ,
727737 locals : HirIdSet :: default ( ) ,
738+ map_is_mutex_guard : false ,
728739 } ;
740+ // Check if the map is a non-async-aware `MutexGuard`
741+ if let rustc_middle:: ty:: Adt ( adt, _) = cx. typeck_results ( ) . expr_ty ( contains_expr. map ) . kind ( )
742+ && is_mutex_guard ( cx, adt. did ( ) )
743+ {
744+ s. map_is_mutex_guard = true ;
745+ }
746+
729747 s. visit_expr ( expr) ;
730- let allow_insert_closure = s. allow_insert_closure ;
731- let is_single_insert = s. is_single_insert ;
748+ if !s. can_use_entry {
749+ return None ;
750+ }
751+
732752 let is_key_used_and_no_copy = s. is_key_used && !is_copy ( cx, cx. typeck_results ( ) . expr_ty ( contains_expr. key ) ) ;
733- let edits = s. edits ;
734- s. can_use_entry . then_some ( InsertSearchResults {
735- edits,
736- allow_insert_closure,
737- is_single_insert,
753+ Some ( InsertSearchResults {
754+ edits : s. edits ,
755+ allow_insert_closure : s. allow_insert_closure ,
756+ is_single_insert : s. is_single_insert ,
738757 is_key_used_and_no_copy,
739758 } )
740759}
760+
761+ fn is_mutex_guard ( cx : & LateContext < ' _ > , def_id : DefId ) -> bool {
762+ match cx. tcx . get_diagnostic_name ( def_id) {
763+ Some ( name) => matches ! ( name, sym:: MutexGuard | sym:: RwLockReadGuard | sym:: RwLockWriteGuard ) ,
764+ None => paths:: PARKING_LOT_GUARDS . iter ( ) . any ( |guard| guard. matches ( cx, def_id) ) ,
765+ }
766+ }
0 commit comments