@@ -3,13 +3,17 @@ use std::mem::swap;
3
3
use rustc_ast:: UnOp ;
4
4
use rustc_hir:: def:: Res ;
5
5
use rustc_hir:: intravisit:: { self , Visitor } ;
6
- use rustc_hir:: { self as hir, Block , Expr , ExprKind , LetStmt , Pat , PatKind , QPath , StmtKind } ;
6
+ use rustc_hir:: {
7
+ self as hir, Block , Expr , ExprKind , HirIdMap , HirIdSet , LetStmt , Pat , PatKind , QPath , StmtKind ,
8
+ } ;
7
9
use rustc_macros:: LintDiagnostic ;
8
- use rustc_middle:: ty;
10
+ use rustc_middle:: hir:: place:: PlaceBase ;
11
+ use rustc_middle:: ty:: { self , Ty } ;
9
12
use rustc_session:: lint:: FutureIncompatibilityReason ;
10
13
use rustc_session:: { declare_lint, declare_lint_pass} ;
11
14
use rustc_span:: edition:: Edition ;
12
15
use rustc_span:: Span ;
16
+ use tracing:: instrument;
13
17
14
18
use crate :: { LateContext , LateLintPass } ;
15
19
@@ -94,35 +98,41 @@ declare_lint! {
94
98
declare_lint_pass ! ( TailExprDropOrder => [ TAIL_EXPR_DROP_ORDER ] ) ;
95
99
96
100
impl TailExprDropOrder {
101
+ #[ instrument( level = "debug" , skip( cx, body) ) ]
97
102
fn check_fn_or_closure < ' tcx > (
98
103
cx : & LateContext < ' tcx > ,
99
104
fn_kind : hir:: intravisit:: FnKind < ' tcx > ,
100
105
body : & ' tcx hir:: Body < ' tcx > ,
101
106
def_id : rustc_span:: def_id:: LocalDefId ,
102
107
) {
103
- let mut locals = vec ! [ ] ;
108
+ let consumed = cx. tcx . extract_tail_expr_consuming_nodes ( def_id. to_def_id ( ) ) ;
109
+ let mut locals = HirIdMap :: default ( ) ;
104
110
if matches ! ( fn_kind, hir:: intravisit:: FnKind :: Closure ) {
105
111
for & capture in cx. tcx . closure_captures ( def_id) {
106
112
if matches ! ( capture. info. capture_kind, ty:: UpvarCapture :: ByValue )
107
113
&& capture. place . ty ( ) . has_significant_drop ( cx. tcx , cx. param_env )
108
114
{
109
- locals. push ( capture. var_ident . span ) ;
115
+ let hir_id = match capture. place . base {
116
+ PlaceBase :: Local ( id) => id,
117
+ PlaceBase :: Upvar ( upvar) => upvar. var_path . hir_id ,
118
+ PlaceBase :: Rvalue | PlaceBase :: StaticItem => continue ,
119
+ } ;
120
+ if consumed. contains ( & hir_id) {
121
+ continue ;
122
+ }
123
+ locals. insert ( hir_id, capture. var_ident . span ) ;
110
124
}
111
125
}
112
126
}
113
127
for param in body. params {
114
- if cx
115
- . typeck_results ( )
116
- . node_type ( param. hir_id )
117
- . has_significant_drop ( cx. tcx , cx. param_env )
118
- {
119
- locals. push ( param. span ) ;
120
- }
128
+ LocalCollector { cx, locals : & mut locals, consumed : & consumed } . visit_pat ( param. pat ) ;
121
129
}
122
130
if let hir:: ExprKind :: Block ( block, _) = body. value . kind {
123
- LintVisitor { cx, locals } . check_block_inner ( block) ;
131
+ LintVisitor { cx, locals, consumed } . check_block_inner ( block) ;
124
132
} else {
125
- LintTailExpr { cx, locals : & locals, is_root_tail_expr : true } . visit_expr ( body. value ) ;
133
+ let locals: Vec < _ > = locals. values ( ) . copied ( ) . collect ( ) ;
134
+ LintTailExpr { cx, locals : & locals, consumed, is_root_tail_expr : true }
135
+ . visit_expr ( body. value ) ;
126
136
}
127
137
}
128
138
}
@@ -146,21 +156,26 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
146
156
struct LintVisitor < ' tcx , ' a > {
147
157
cx : & ' a LateContext < ' tcx > ,
148
158
// We only record locals that have significant drops
149
- locals : Vec < Span > ,
159
+ locals : HirIdMap < Span > ,
160
+ consumed : & ' a HirIdSet ,
150
161
}
151
162
152
163
struct LocalCollector < ' tcx , ' a > {
153
164
cx : & ' a LateContext < ' tcx > ,
154
- locals : & ' a mut Vec < Span > ,
165
+ locals : & ' a mut HirIdMap < Span > ,
166
+ consumed : & ' a HirIdSet ,
155
167
}
156
168
157
169
impl < ' tcx , ' a > Visitor < ' tcx > for LocalCollector < ' tcx , ' a > {
158
170
type Result = ( ) ;
159
171
fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
160
172
if let PatKind :: Binding ( _binding_mode, id, ident, pat) = pat. kind {
173
+ if self . consumed . contains ( & id) {
174
+ return ;
175
+ }
161
176
let ty = self . cx . typeck_results ( ) . node_type ( id) ;
162
177
if ty. has_significant_drop ( self . cx . tcx , self . cx . param_env ) {
163
- self . locals . push ( ident. span ) ;
178
+ self . locals . insert ( id , ident. span ) ;
164
179
}
165
180
if let Some ( pat) = pat {
166
181
self . visit_pat ( pat) ;
@@ -179,7 +194,8 @@ impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> {
179
194
swap ( & mut locals, & mut self . locals ) ;
180
195
}
181
196
fn visit_local ( & mut self , local : & ' tcx LetStmt < ' tcx > ) {
182
- LocalCollector { cx : self . cx , locals : & mut self . locals } . visit_local ( local) ;
197
+ LocalCollector { cx : self . cx , locals : & mut self . locals , consumed : & self . consumed }
198
+ . visit_local ( local) ;
183
199
}
184
200
}
185
201
@@ -200,19 +216,26 @@ impl<'tcx, 'a> LintVisitor<'tcx, 'a> {
200
216
if self . locals . is_empty ( ) {
201
217
return ;
202
218
}
203
- LintTailExpr { cx : self . cx , locals : & self . locals , is_root_tail_expr : true }
204
- . visit_expr ( tail_expr) ;
219
+ let locals: Vec < _ > = self . locals . values ( ) . copied ( ) . collect ( ) ;
220
+ LintTailExpr {
221
+ cx : self . cx ,
222
+ locals : & locals,
223
+ is_root_tail_expr : true ,
224
+ consumed : self . consumed ,
225
+ }
226
+ . visit_expr ( tail_expr) ;
205
227
}
206
228
}
207
229
208
230
struct LintTailExpr < ' tcx , ' a > {
209
231
cx : & ' a LateContext < ' tcx > ,
210
232
is_root_tail_expr : bool ,
211
233
locals : & ' a [ Span ] ,
234
+ consumed : & ' a HirIdSet ,
212
235
}
213
236
214
237
impl < ' tcx , ' a > LintTailExpr < ' tcx , ' a > {
215
- fn expr_eventually_point_into_local ( mut expr : & Expr < ' tcx > ) -> bool {
238
+ fn expr_eventually_point_into_local ( & self , mut expr : & Expr < ' tcx > ) -> bool {
216
239
loop {
217
240
match expr. kind {
218
241
ExprKind :: Index ( access, _, _) | ExprKind :: Field ( access, _) => expr = access,
@@ -231,24 +254,28 @@ impl<'tcx, 'a> LintTailExpr<'tcx, 'a> {
231
254
}
232
255
}
233
256
234
- fn expr_generates_nonlocal_droppy_value ( & self , expr : & Expr < ' tcx > ) -> bool {
235
- if Self :: expr_eventually_point_into_local ( expr) {
236
- return false ;
257
+ fn expr_generates_nonlocal_droppy_value ( & self , expr : & Expr < ' tcx > ) -> Option < Ty < ' tcx > > {
258
+ if self . expr_eventually_point_into_local ( expr) {
259
+ return None ;
260
+ }
261
+ if self . consumed . contains ( & expr. hir_id ) {
262
+ return None ;
237
263
}
238
- self . cx . typeck_results ( ) . expr_ty ( expr) . has_significant_drop ( self . cx . tcx , self . cx . param_env )
264
+ let ty = self . cx . typeck_results ( ) . expr_ty ( expr) ;
265
+ if ty. has_significant_drop ( self . cx . tcx , self . cx . param_env ) { Some ( ty) } else { None }
239
266
}
240
267
}
241
268
242
269
impl < ' tcx , ' a > Visitor < ' tcx > for LintTailExpr < ' tcx , ' a > {
243
270
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
244
271
if self . is_root_tail_expr {
245
272
self . is_root_tail_expr = false ;
246
- } else if self . expr_generates_nonlocal_droppy_value ( expr) {
273
+ } else if let Some ( ty ) = self . expr_generates_nonlocal_droppy_value ( expr) {
247
274
self . cx . tcx . emit_node_span_lint (
248
275
TAIL_EXPR_DROP_ORDER ,
249
276
expr. hir_id ,
250
277
expr. span ,
251
- TailExprDropOrderLint { spans : self . locals . to_vec ( ) } ,
278
+ TailExprDropOrderLint { spans : self . locals . to_vec ( ) , ty } ,
252
279
) ;
253
280
return ;
254
281
}
@@ -294,13 +321,15 @@ impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> {
294
321
}
295
322
}
296
323
fn visit_block ( & mut self , block : & ' tcx Block < ' tcx > ) {
297
- LintVisitor { cx : self . cx , locals : <_ >:: default ( ) } . check_block_inner ( block) ;
324
+ LintVisitor { cx : self . cx , locals : <_ >:: default ( ) , consumed : & <_ >:: default ( ) }
325
+ . check_block_inner ( block) ;
298
326
}
299
327
}
300
328
301
329
#[ derive( LintDiagnostic ) ]
302
330
#[ diag( lint_tail_expr_drop_order) ]
303
- struct TailExprDropOrderLint {
331
+ struct TailExprDropOrderLint < ' a > {
304
332
#[ label]
305
333
pub spans : Vec < Span > ,
334
+ pub ty : Ty < ' a > ,
306
335
}
0 commit comments