@@ -4,18 +4,19 @@ use clippy_utils::get_attr;
44use clippy_utils:: source:: { indent_of, snippet} ;
55use rustc_errors:: { Applicability , Diagnostic } ;
66use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
7- use rustc_hir:: { Expr , ExprKind , MatchSource } ;
7+ use rustc_hir:: { Arm , Expr , ExprKind , MatchSource } ;
88use rustc_lint:: { LateContext , LintContext } ;
99use rustc_middle:: ty:: subst:: GenericArgKind ;
1010use rustc_middle:: ty:: { Ty , TypeAndMut } ;
11- use rustc_span:: Span ;
11+ use rustc_span:: { Span } ;
1212
1313use super :: SIGNIFICANT_DROP_IN_SCRUTINEE ;
1414
1515pub ( super ) fn check < ' tcx > (
1616 cx : & LateContext < ' tcx > ,
1717 expr : & ' tcx Expr < ' tcx > ,
1818 scrutinee : & ' tcx Expr < ' _ > ,
19+ arms : & ' tcx [ Arm < ' _ > ] ,
1920 source : MatchSource ,
2021) {
2122 if let Some ( ( suggestions, message) ) = has_significant_drop_in_scrutinee ( cx, scrutinee, source) {
@@ -25,8 +26,14 @@ pub(super) fn check<'tcx>(
2526 let s = Span :: new ( expr. span . hi ( ) , expr. span . hi ( ) , expr. span . ctxt ( ) , None ) ;
2627 diag. span_label (
2728 s,
28- "temporary lives until here. If mutex is locked within block, deadlocks can occur. " ,
29+ "original temporary lives until here" ,
2930 ) ;
31+ if let Some ( spans) = has_significant_drop_in_arms ( cx, arms) {
32+ for span in spans {
33+ diag. span_label ( span, "significant drop in arm here" ) ;
34+ }
35+ diag. note ( "this might lead to deadlocks or other unexpected behavior" ) ;
36+ }
3037 } ) ;
3138 }
3239 }
@@ -93,14 +100,69 @@ fn has_significant_drop_in_scrutinee<'tcx, 'a>(
93100 } )
94101}
95102
103+ struct SigDropChecker < ' a , ' tcx > {
104+ seen_types : FxHashSet < Ty < ' tcx > > ,
105+ cx : & ' a LateContext < ' tcx > ,
106+ }
107+
108+ impl < ' a , ' tcx > SigDropChecker < ' a , ' tcx > {
109+ fn new ( cx : & ' a LateContext < ' tcx > ) -> SigDropChecker < ' a , ' tcx > {
110+ SigDropChecker {
111+ seen_types : Default :: default ( ) ,
112+ cx
113+ }
114+ }
115+
116+ fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
117+ self . cx . typeck_results ( ) . expr_ty ( ex)
118+ }
119+
120+ fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
121+ !self . seen_types . insert ( ty)
122+ }
123+
124+ fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
125+ if let Some ( adt) = ty. ty_adt_def ( ) {
126+ if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
127+ return true ;
128+ }
129+ }
130+
131+ match ty. kind ( ) {
132+ rustc_middle:: ty:: Adt ( a, b) => {
133+ for f in a. all_fields ( ) {
134+ let ty = f. ty ( cx. tcx , b) ;
135+ if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
136+ return true ;
137+ }
138+ }
139+
140+ for generic_arg in b. iter ( ) {
141+ if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
142+ if self . has_sig_drop_attr ( cx, ty) {
143+ return true ;
144+ }
145+ }
146+ }
147+ false
148+ } ,
149+ rustc_middle:: ty:: Array ( ty, _)
150+ | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
151+ | rustc_middle:: ty:: Ref ( _, ty, _)
152+ | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
153+ _ => false ,
154+ }
155+ }
156+ }
157+
96158struct SigDropHelper < ' a , ' tcx > {
97159 cx : & ' a LateContext < ' tcx > ,
98160 is_chain_end : bool ,
99- seen_types : FxHashSet < Ty < ' tcx > > ,
100161 has_significant_drop : bool ,
101162 current_sig_drop : Option < FoundSigDrop > ,
102163 sig_drop_spans : Option < Vec < FoundSigDrop > > ,
103164 special_handling_for_binary_op : bool ,
165+ sig_drop_checker : SigDropChecker < ' a , ' tcx >
104166}
105167
106168#[ expect( clippy:: enum_variant_names) ]
@@ -123,11 +185,11 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
123185 SigDropHelper {
124186 cx,
125187 is_chain_end : true ,
126- seen_types : FxHashSet :: default ( ) ,
127188 has_significant_drop : false ,
128189 current_sig_drop : None ,
129190 sig_drop_spans : None ,
130191 special_handling_for_binary_op : false ,
192+ sig_drop_checker : SigDropChecker :: new ( cx)
131193 }
132194 }
133195
@@ -168,7 +230,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
168230 if self . current_sig_drop . is_some ( ) {
169231 return ;
170232 }
171- let ty = self . get_type ( expr) ;
233+ let ty = self . sig_drop_checker . get_type ( expr) ;
172234 if ty. is_ref ( ) {
173235 // We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
174236 // but let's avoid any chance of an ICE
@@ -192,14 +254,6 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
192254 }
193255 }
194256
195- fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
196- self . cx . typeck_results ( ) . expr_ty ( ex)
197- }
198-
199- fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
200- !self . seen_types . insert ( ty)
201- }
202-
203257 fn visit_exprs_for_binary_ops (
204258 & mut self ,
205259 left : & ' tcx Expr < ' _ > ,
@@ -220,43 +274,12 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
220274 self . special_handling_for_binary_op = false ;
221275 }
222276
223- fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
224- if let Some ( adt) = ty. ty_adt_def ( ) {
225- if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
226- return true ;
227- }
228- }
229277
230- match ty. kind ( ) {
231- rustc_middle:: ty:: Adt ( a, b) => {
232- for f in a. all_fields ( ) {
233- let ty = f. ty ( cx. tcx , b) ;
234- if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
235- return true ;
236- }
237- }
238-
239- for generic_arg in b. iter ( ) {
240- if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
241- if self . has_sig_drop_attr ( cx, ty) {
242- return true ;
243- }
244- }
245- }
246- false
247- } ,
248- rustc_middle:: ty:: Array ( ty, _)
249- | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
250- | rustc_middle:: ty:: Ref ( _, ty, _)
251- | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
252- _ => false ,
253- }
254- }
255278}
256279
257280impl < ' a , ' tcx > Visitor < ' tcx > for SigDropHelper < ' a , ' tcx > {
258281 fn visit_expr ( & mut self , ex : & ' tcx Expr < ' _ > ) {
259- if !self . is_chain_end && self . has_sig_drop_attr ( self . cx , self . get_type ( ex) ) {
282+ if !self . is_chain_end && self . sig_drop_checker . has_sig_drop_attr ( self . cx , self . sig_drop_checker . get_type ( ex) ) {
260283 self . has_significant_drop = true ;
261284 return ;
262285 }
@@ -334,4 +357,40 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
334357 self . try_setting_current_suggestion ( ex, false ) ;
335358 }
336359 }
360+
361+ }
362+
363+ struct ArmSigDropHelper < ' a , ' tcx > {
364+ sig_drop_checker : SigDropChecker < ' a , ' tcx > ,
365+ found_sig_drop_spans : Option < FxHashSet < Span > >
366+ }
367+
368+ impl < ' a , ' tcx > ArmSigDropHelper < ' a , ' tcx > {
369+ fn new ( cx : & ' a LateContext < ' tcx > ) -> ArmSigDropHelper < ' a , ' tcx > {
370+ ArmSigDropHelper {
371+ sig_drop_checker : SigDropChecker :: new ( cx) ,
372+ found_sig_drop_spans : None
373+ }
374+ }
375+ }
376+
377+ fn has_significant_drop_in_arms < ' tcx , ' a > (
378+ cx : & ' a LateContext < ' tcx > ,
379+ arms : & ' tcx [ Arm < ' _ > ] ,
380+ ) -> Option < FxHashSet < Span > > {
381+ let mut helper = ArmSigDropHelper :: new ( cx) ;
382+ for arm in arms {
383+ helper. visit_expr ( arm. body ) ;
384+ }
385+ helper. found_sig_drop_spans
386+ }
387+
388+ impl < ' a , ' tcx > Visitor < ' tcx > for ArmSigDropHelper < ' a , ' tcx > {
389+ fn visit_expr ( & mut self , ex : & ' tcx Expr < ' tcx > ) {
390+ if self . sig_drop_checker . has_sig_drop_attr ( self . sig_drop_checker . cx , self . sig_drop_checker . get_type ( ex) ) {
391+ self . found_sig_drop_spans . get_or_insert_with ( FxHashSet :: default) . insert ( ex. span ) ;
392+ return ;
393+ }
394+ walk_expr ( self , ex) ;
395+ }
337396}
0 commit comments