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