@@ -4,18 +4,19 @@ use clippy_utils::get_attr;
4
4
use clippy_utils:: source:: { indent_of, snippet} ;
5
5
use rustc_errors:: { Applicability , Diagnostic } ;
6
6
use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
7
- use rustc_hir:: { Expr , ExprKind , MatchSource } ;
7
+ use rustc_hir:: { Arm , Expr , ExprKind , MatchSource } ;
8
8
use rustc_lint:: { LateContext , LintContext } ;
9
9
use rustc_middle:: ty:: subst:: GenericArgKind ;
10
10
use rustc_middle:: ty:: { Ty , TypeAndMut } ;
11
- use rustc_span:: Span ;
11
+ use rustc_span:: { Span } ;
12
12
13
13
use super :: SIGNIFICANT_DROP_IN_SCRUTINEE ;
14
14
15
15
pub ( super ) fn check < ' tcx > (
16
16
cx : & LateContext < ' tcx > ,
17
17
expr : & ' tcx Expr < ' tcx > ,
18
18
scrutinee : & ' tcx Expr < ' _ > ,
19
+ arms : & ' tcx [ Arm < ' _ > ] ,
19
20
source : MatchSource ,
20
21
) {
21
22
if let Some ( ( suggestions, message) ) = has_significant_drop_in_scrutinee ( cx, scrutinee, source) {
@@ -25,8 +26,14 @@ pub(super) fn check<'tcx>(
25
26
let s = Span :: new ( expr. span . hi ( ) , expr. span . hi ( ) , expr. span . ctxt ( ) , None ) ;
26
27
diag. span_label (
27
28
s,
28
- "temporary lives until here. If mutex is locked within block, deadlocks can occur. " ,
29
+ "original temporary lives until here" ,
29
30
) ;
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
+ }
30
37
} ) ;
31
38
}
32
39
}
@@ -93,14 +100,69 @@ fn has_significant_drop_in_scrutinee<'tcx, 'a>(
93
100
} )
94
101
}
95
102
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
+
96
158
struct SigDropHelper < ' a , ' tcx > {
97
159
cx : & ' a LateContext < ' tcx > ,
98
160
is_chain_end : bool ,
99
- seen_types : FxHashSet < Ty < ' tcx > > ,
100
161
has_significant_drop : bool ,
101
162
current_sig_drop : Option < FoundSigDrop > ,
102
163
sig_drop_spans : Option < Vec < FoundSigDrop > > ,
103
164
special_handling_for_binary_op : bool ,
165
+ sig_drop_checker : SigDropChecker < ' a , ' tcx >
104
166
}
105
167
106
168
#[ expect( clippy:: enum_variant_names) ]
@@ -123,11 +185,11 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
123
185
SigDropHelper {
124
186
cx,
125
187
is_chain_end : true ,
126
- seen_types : FxHashSet :: default ( ) ,
127
188
has_significant_drop : false ,
128
189
current_sig_drop : None ,
129
190
sig_drop_spans : None ,
130
191
special_handling_for_binary_op : false ,
192
+ sig_drop_checker : SigDropChecker :: new ( cx)
131
193
}
132
194
}
133
195
@@ -168,7 +230,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
168
230
if self . current_sig_drop . is_some ( ) {
169
231
return ;
170
232
}
171
- let ty = self . get_type ( expr) ;
233
+ let ty = self . sig_drop_checker . get_type ( expr) ;
172
234
if ty. is_ref ( ) {
173
235
// We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
174
236
// but let's avoid any chance of an ICE
@@ -192,14 +254,6 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
192
254
}
193
255
}
194
256
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
-
203
257
fn visit_exprs_for_binary_ops (
204
258
& mut self ,
205
259
left : & ' tcx Expr < ' _ > ,
@@ -220,43 +274,12 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
220
274
self . special_handling_for_binary_op = false ;
221
275
}
222
276
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
- }
229
277
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
- }
255
278
}
256
279
257
280
impl < ' a , ' tcx > Visitor < ' tcx > for SigDropHelper < ' a , ' tcx > {
258
281
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) ) {
260
283
self . has_significant_drop = true ;
261
284
return ;
262
285
}
@@ -334,4 +357,40 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
334
357
self . try_setting_current_suggestion ( ex, false ) ;
335
358
}
336
359
}
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
+ }
337
396
}
0 commit comments