@@ -7,13 +7,17 @@ use rustc_errors::{
7
7
Applicability , Diag , EmissionGuarantee , SubdiagMessageOp , Subdiagnostic , SuggestionStyle ,
8
8
} ;
9
9
use rustc_hir:: { self as hir, HirIdSet } ;
10
- use rustc_macros:: LintDiagnostic ;
11
- use rustc_middle:: ty:: TyCtxt ;
10
+ use rustc_macros:: { LintDiagnostic , Subdiagnostic } ;
12
11
use rustc_middle:: ty:: adjustment:: Adjust ;
12
+ use rustc_middle:: ty:: significant_drop_order:: {
13
+ extract_component_with_significant_dtor, ty_dtor_span,
14
+ } ;
15
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
13
16
use rustc_session:: lint:: { FutureIncompatibilityReason , LintId } ;
14
17
use rustc_session:: { declare_lint, impl_lint_pass} ;
15
- use rustc_span:: Span ;
16
18
use rustc_span:: edition:: Edition ;
19
+ use rustc_span:: { DUMMY_SP , Span } ;
20
+ use smallvec:: SmallVec ;
17
21
18
22
use crate :: { LateContext , LateLintPass } ;
19
23
@@ -130,13 +134,15 @@ impl IfLetRescope {
130
134
hir:: ExprKind :: If ( _cond, _conseq, Some ( alt) ) => alt. span . shrink_to_hi ( ) ,
131
135
_ => return ,
132
136
} ;
137
+ let mut seen_dyn = false ;
133
138
let mut add_bracket_to_match_head = match_head_needs_bracket ( tcx, expr) ;
134
139
let mut significant_droppers = vec ! [ ] ;
135
140
let mut lifetime_ends = vec ! [ ] ;
136
141
let mut closing_brackets = 0 ;
137
142
let mut alt_heads = vec ! [ ] ;
138
143
let mut match_heads = vec ! [ ] ;
139
144
let mut consequent_heads = vec ! [ ] ;
145
+ let mut destructors = vec ! [ ] ;
140
146
let mut first_if_to_lint = None ;
141
147
let mut first_if_to_rewrite = false ;
142
148
let mut empty_alt = false ;
@@ -160,11 +166,25 @@ impl IfLetRescope {
160
166
let before_conseq = conseq. span . shrink_to_lo ( ) ;
161
167
let lifetime_end = source_map. end_point ( conseq. span ) ;
162
168
163
- if let ControlFlow :: Break ( significant_dropper ) =
169
+ if let ControlFlow :: Break ( ( drop_span , drop_tys ) ) =
164
170
( FindSignificantDropper { cx } ) . check_if_let_scrutinee ( init)
165
171
{
172
+ destructors. extend ( drop_tys. into_iter ( ) . filter_map ( |ty| {
173
+ if let Some ( span) = ty_dtor_span ( tcx, ty) {
174
+ Some ( DestructorLabel { span, dtor_kind : "concrete" } )
175
+ } else if matches ! ( ty. kind( ) , ty:: Dynamic ( ..) ) {
176
+ if seen_dyn {
177
+ None
178
+ } else {
179
+ seen_dyn = true ;
180
+ Some ( DestructorLabel { span : DUMMY_SP , dtor_kind : "dyn" } )
181
+ }
182
+ } else {
183
+ None
184
+ }
185
+ } ) ) ;
166
186
first_if_to_lint = first_if_to_lint. or_else ( || Some ( ( span, expr. hir_id ) ) ) ;
167
- significant_droppers. push ( significant_dropper ) ;
187
+ significant_droppers. push ( drop_span ) ;
168
188
lifetime_ends. push ( lifetime_end) ;
169
189
if ty_ascription. is_some ( )
170
190
|| !expr. span . can_be_used_for_suggestions ( )
@@ -227,6 +247,7 @@ impl IfLetRescope {
227
247
hir_id,
228
248
span,
229
249
IfLetRescopeLint {
250
+ destructors,
230
251
significant_droppers,
231
252
lifetime_ends,
232
253
rewrite : first_if_to_rewrite. then_some ( IfLetRescopeRewrite {
@@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
288
309
#[ derive( LintDiagnostic ) ]
289
310
#[ diag( lint_if_let_rescope) ]
290
311
struct IfLetRescopeLint {
312
+ #[ subdiagnostic]
313
+ destructors : Vec < DestructorLabel > ,
291
314
#[ label]
292
315
significant_droppers : Vec < Span > ,
293
316
#[ help]
@@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
347
370
}
348
371
}
349
372
373
+ #[ derive( Subdiagnostic ) ]
374
+ #[ note( lint_if_let_dtor) ]
375
+ struct DestructorLabel {
376
+ #[ primary_span]
377
+ span : Span ,
378
+ dtor_kind : & ' static str ,
379
+ }
380
+
350
381
struct AltHead ( Span ) ;
351
382
352
383
struct ConsequentRewrite {
@@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
374
405
/// of the scrutinee itself, and also recurses into the expression to find any ref
375
406
/// exprs (or autoref) which would promote temporaries that would be scoped to the
376
407
/// end of this `if`.
377
- fn check_if_let_scrutinee ( & mut self , init : & ' tcx hir:: Expr < ' tcx > ) -> ControlFlow < Span > {
408
+ fn check_if_let_scrutinee (
409
+ & mut self ,
410
+ init : & ' tcx hir:: Expr < ' tcx > ,
411
+ ) -> ControlFlow < ( Span , SmallVec < [ Ty < ' tcx > ; 4 ] > ) > {
378
412
self . check_promoted_temp_with_drop ( init) ?;
379
413
self . visit_expr ( init)
380
414
}
@@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
385
419
/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
386
420
/// or is the scrutinee of the `if let`, *and* the expression is not a place
387
421
/// expr, and it has a significant drop.
388
- fn check_promoted_temp_with_drop ( & self , expr : & ' tcx hir:: Expr < ' tcx > ) -> ControlFlow < Span > {
389
- if !expr. is_place_expr ( |base| {
422
+ fn check_promoted_temp_with_drop (
423
+ & self ,
424
+ expr : & ' tcx hir:: Expr < ' tcx > ,
425
+ ) -> ControlFlow < ( Span , SmallVec < [ Ty < ' tcx > ; 4 ] > ) > {
426
+ if expr. is_place_expr ( |base| {
390
427
self . cx
391
428
. typeck_results ( )
392
429
. adjustments ( )
393
430
. get ( base. hir_id )
394
431
. is_some_and ( |x| x. iter ( ) . any ( |adj| matches ! ( adj. kind, Adjust :: Deref ( _) ) ) )
395
- } ) && self
396
- . cx
397
- . typeck_results ( )
398
- . expr_ty ( expr)
399
- . has_significant_drop ( self . cx . tcx , self . cx . typing_env ( ) )
400
- {
401
- ControlFlow :: Break ( expr. span )
402
- } else {
403
- ControlFlow :: Continue ( ( ) )
432
+ } ) {
433
+ return ControlFlow :: Continue ( ( ) ) ;
404
434
}
435
+
436
+ let drop_tys = extract_component_with_significant_dtor (
437
+ self . cx . tcx ,
438
+ self . cx . typing_env ( ) ,
439
+ self . cx . typeck_results ( ) . expr_ty ( expr) ,
440
+ ) ;
441
+ if drop_tys. is_empty ( ) {
442
+ return ControlFlow :: Continue ( ( ) ) ;
443
+ }
444
+
445
+ ControlFlow :: Break ( ( expr. span , drop_tys) )
405
446
}
406
447
}
407
448
408
449
impl < ' tcx > Visitor < ' tcx > for FindSignificantDropper < ' _ , ' tcx > {
409
- type Result = ControlFlow < Span > ;
450
+ type Result = ControlFlow < ( Span , SmallVec < [ Ty < ' tcx > ; 4 ] > ) > ;
410
451
411
452
fn visit_block ( & mut self , b : & ' tcx hir:: Block < ' tcx > ) -> Self :: Result {
412
453
// Blocks introduce temporary terminating scope for all of its
0 commit comments