@@ -4,7 +4,7 @@ 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 } ;
@@ -16,12 +16,21 @@ 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) {
22
23
for found in suggestions {
23
24
span_lint_and_then ( cx, SIGNIFICANT_DROP_IN_SCRUTINEE , found. found_span , message, |diag| {
24
25
set_diagnostic ( diag, cx, expr, found) ;
26
+ let s = Span :: new ( expr. span . hi ( ) , expr. span . hi ( ) , expr. span . ctxt ( ) , None ) ;
27
+ diag. span_label ( s, "original temporary lives until here" ) ;
28
+ if let Some ( spans) = has_significant_drop_in_arms ( cx, arms) {
29
+ for span in spans {
30
+ diag. span_label ( span, "significant drop in arm here" ) ;
31
+ }
32
+ diag. note ( "this might lead to deadlocks or other unexpected behavior" ) ;
33
+ }
25
34
} ) ;
26
35
}
27
36
}
@@ -80,22 +89,77 @@ fn has_significant_drop_in_scrutinee<'tcx, 'a>(
80
89
let mut helper = SigDropHelper :: new ( cx) ;
81
90
helper. find_sig_drop ( scrutinee) . map ( |drops| {
82
91
let message = if source == MatchSource :: Normal {
83
- "temporary with significant drop in match scrutinee"
92
+ "temporary with drop impl with side effects in match scrutinee lives to end of block "
84
93
} else {
85
- "temporary with significant drop in for loop"
94
+ "temporary with drop impl with side effects in for loop condition lives to end of block "
86
95
} ;
87
96
( drops, message)
88
97
} )
89
98
}
90
99
100
+ struct SigDropChecker < ' a , ' tcx > {
101
+ seen_types : FxHashSet < Ty < ' tcx > > ,
102
+ cx : & ' a LateContext < ' tcx > ,
103
+ }
104
+
105
+ impl < ' a , ' tcx > SigDropChecker < ' a , ' tcx > {
106
+ fn new ( cx : & ' a LateContext < ' tcx > ) -> SigDropChecker < ' a , ' tcx > {
107
+ SigDropChecker {
108
+ seen_types : FxHashSet :: default ( ) ,
109
+ cx,
110
+ }
111
+ }
112
+
113
+ fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
114
+ self . cx . typeck_results ( ) . expr_ty ( ex)
115
+ }
116
+
117
+ fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
118
+ !self . seen_types . insert ( ty)
119
+ }
120
+
121
+ fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
122
+ if let Some ( adt) = ty. ty_adt_def ( ) {
123
+ if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
124
+ return true ;
125
+ }
126
+ }
127
+
128
+ match ty. kind ( ) {
129
+ rustc_middle:: ty:: Adt ( a, b) => {
130
+ for f in a. all_fields ( ) {
131
+ let ty = f. ty ( cx. tcx , b) ;
132
+ if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
133
+ return true ;
134
+ }
135
+ }
136
+
137
+ for generic_arg in b. iter ( ) {
138
+ if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
139
+ if self . has_sig_drop_attr ( cx, ty) {
140
+ return true ;
141
+ }
142
+ }
143
+ }
144
+ false
145
+ } ,
146
+ rustc_middle:: ty:: Array ( ty, _)
147
+ | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
148
+ | rustc_middle:: ty:: Ref ( _, ty, _)
149
+ | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
150
+ _ => false ,
151
+ }
152
+ }
153
+ }
154
+
91
155
struct SigDropHelper < ' a , ' tcx > {
92
156
cx : & ' a LateContext < ' tcx > ,
93
157
is_chain_end : bool ,
94
- seen_types : FxHashSet < Ty < ' tcx > > ,
95
158
has_significant_drop : bool ,
96
159
current_sig_drop : Option < FoundSigDrop > ,
97
160
sig_drop_spans : Option < Vec < FoundSigDrop > > ,
98
161
special_handling_for_binary_op : bool ,
162
+ sig_drop_checker : SigDropChecker < ' a , ' tcx > ,
99
163
}
100
164
101
165
#[ expect( clippy:: enum_variant_names) ]
@@ -118,11 +182,11 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
118
182
SigDropHelper {
119
183
cx,
120
184
is_chain_end : true ,
121
- seen_types : FxHashSet :: default ( ) ,
122
185
has_significant_drop : false ,
123
186
current_sig_drop : None ,
124
187
sig_drop_spans : None ,
125
188
special_handling_for_binary_op : false ,
189
+ sig_drop_checker : SigDropChecker :: new ( cx) ,
126
190
}
127
191
}
128
192
@@ -163,7 +227,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
163
227
if self . current_sig_drop . is_some ( ) {
164
228
return ;
165
229
}
166
- let ty = self . get_type ( expr) ;
230
+ let ty = self . sig_drop_checker . get_type ( expr) ;
167
231
if ty. is_ref ( ) {
168
232
// We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
169
233
// but let's avoid any chance of an ICE
@@ -187,14 +251,6 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
187
251
}
188
252
}
189
253
190
- fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
191
- self . cx . typeck_results ( ) . expr_ty ( ex)
192
- }
193
-
194
- fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
195
- !self . seen_types . insert ( ty)
196
- }
197
-
198
254
fn visit_exprs_for_binary_ops (
199
255
& mut self ,
200
256
left : & ' tcx Expr < ' _ > ,
@@ -214,44 +270,15 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
214
270
215
271
self . special_handling_for_binary_op = false ;
216
272
}
217
-
218
- fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
219
- if let Some ( adt) = ty. ty_adt_def ( ) {
220
- if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
221
- return true ;
222
- }
223
- }
224
-
225
- match ty. kind ( ) {
226
- rustc_middle:: ty:: Adt ( a, b) => {
227
- for f in a. all_fields ( ) {
228
- let ty = f. ty ( cx. tcx , b) ;
229
- if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
230
- return true ;
231
- }
232
- }
233
-
234
- for generic_arg in b. iter ( ) {
235
- if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
236
- if self . has_sig_drop_attr ( cx, ty) {
237
- return true ;
238
- }
239
- }
240
- }
241
- false
242
- } ,
243
- rustc_middle:: ty:: Array ( ty, _)
244
- | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
245
- | rustc_middle:: ty:: Ref ( _, ty, _)
246
- | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
247
- _ => false ,
248
- }
249
- }
250
273
}
251
274
252
275
impl < ' a , ' tcx > Visitor < ' tcx > for SigDropHelper < ' a , ' tcx > {
253
276
fn visit_expr ( & mut self , ex : & ' tcx Expr < ' _ > ) {
254
- if !self . is_chain_end && self . has_sig_drop_attr ( self . cx , self . get_type ( ex) ) {
277
+ if !self . is_chain_end
278
+ && self
279
+ . sig_drop_checker
280
+ . has_sig_drop_attr ( self . cx , self . sig_drop_checker . get_type ( ex) )
281
+ {
255
282
self . has_significant_drop = true ;
256
283
return ;
257
284
}
@@ -330,3 +357,40 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
330
357
}
331
358
}
332
359
}
360
+
361
+ struct ArmSigDropHelper < ' a , ' tcx > {
362
+ sig_drop_checker : SigDropChecker < ' a , ' tcx > ,
363
+ found_sig_drop_spans : Option < FxHashSet < Span > > ,
364
+ }
365
+
366
+ impl < ' a , ' tcx > ArmSigDropHelper < ' a , ' tcx > {
367
+ fn new ( cx : & ' a LateContext < ' tcx > ) -> ArmSigDropHelper < ' a , ' tcx > {
368
+ ArmSigDropHelper {
369
+ sig_drop_checker : SigDropChecker :: new ( cx) ,
370
+ found_sig_drop_spans : None ,
371
+ }
372
+ }
373
+ }
374
+
375
+ fn has_significant_drop_in_arms < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , arms : & ' tcx [ Arm < ' _ > ] ) -> Option < FxHashSet < Span > > {
376
+ let mut helper = ArmSigDropHelper :: new ( cx) ;
377
+ for arm in arms {
378
+ helper. visit_expr ( arm. body ) ;
379
+ }
380
+ helper. found_sig_drop_spans
381
+ }
382
+
383
+ impl < ' a , ' tcx > Visitor < ' tcx > for ArmSigDropHelper < ' a , ' tcx > {
384
+ fn visit_expr ( & mut self , ex : & ' tcx Expr < ' tcx > ) {
385
+ if self
386
+ . sig_drop_checker
387
+ . has_sig_drop_attr ( self . sig_drop_checker . cx , self . sig_drop_checker . get_type ( ex) )
388
+ {
389
+ self . found_sig_drop_spans
390
+ . get_or_insert_with ( FxHashSet :: default)
391
+ . insert ( ex. span ) ;
392
+ return ;
393
+ }
394
+ walk_expr ( self , ex) ;
395
+ }
396
+ }
0 commit comments