@@ -7,13 +7,17 @@ use rustc_errors::{
77    Applicability ,  Diag ,  EmissionGuarantee ,  SubdiagMessageOp ,  Subdiagnostic ,  SuggestionStyle , 
88} ; 
99use  rustc_hir:: { self  as  hir,  HirIdSet } ; 
10- use  rustc_macros:: LintDiagnostic ; 
11- use  rustc_middle:: ty:: TyCtxt ; 
10+ use  rustc_macros:: { LintDiagnostic ,  Subdiagnostic } ; 
1211use  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 } ; 
1316use  rustc_session:: lint:: { FutureIncompatibilityReason ,  LintId } ; 
1417use  rustc_session:: { declare_lint,  impl_lint_pass} ; 
15- use  rustc_span:: Span ; 
1618use  rustc_span:: edition:: Edition ; 
19+ use  rustc_span:: { DUMMY_SP ,  Span } ; 
20+ use  smallvec:: SmallVec ; 
1721
1822use  crate :: { LateContext ,  LateLintPass } ; 
1923
@@ -130,13 +134,15 @@ impl IfLetRescope {
130134            hir:: ExprKind :: If ( _cond,  _conseq,  Some ( alt) )  => alt. span . shrink_to_hi ( ) , 
131135            _ => return , 
132136        } ; 
137+         let  mut  seen_dyn = false ; 
133138        let  mut  add_bracket_to_match_head = match_head_needs_bracket ( tcx,  expr) ; 
134139        let  mut  significant_droppers = vec ! [ ] ; 
135140        let  mut  lifetime_ends = vec ! [ ] ; 
136141        let  mut  closing_brackets = 0 ; 
137142        let  mut  alt_heads = vec ! [ ] ; 
138143        let  mut  match_heads = vec ! [ ] ; 
139144        let  mut  consequent_heads = vec ! [ ] ; 
145+         let  mut  destructors = vec ! [ ] ; 
140146        let  mut  first_if_to_lint = None ; 
141147        let  mut  first_if_to_rewrite = false ; 
142148        let  mut  empty_alt = false ; 
@@ -160,11 +166,25 @@ impl IfLetRescope {
160166                let  before_conseq = conseq. span . shrink_to_lo ( ) ; 
161167                let  lifetime_end = source_map. end_point ( conseq. span ) ; 
162168
163-                 if  let  ControlFlow :: Break ( significant_dropper )  =
169+                 if  let  ControlFlow :: Break ( ( drop_span ,  drop_tys ) )  =
164170                    ( FindSignificantDropper  {  cx } ) . check_if_let_scrutinee ( init) 
165171                { 
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+                     } ) ) ; 
166186                    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 ) ; 
168188                    lifetime_ends. push ( lifetime_end) ; 
169189                    if  ty_ascription. is_some ( ) 
170190                        || !expr. span . can_be_used_for_suggestions ( ) 
@@ -227,6 +247,7 @@ impl IfLetRescope {
227247                hir_id, 
228248                span, 
229249                IfLetRescopeLint  { 
250+                     destructors, 
230251                    significant_droppers, 
231252                    lifetime_ends, 
232253                    rewrite :  first_if_to_rewrite. then_some ( IfLetRescopeRewrite  { 
@@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
288309#[ derive( LintDiagnostic ) ]  
289310#[ diag( lint_if_let_rescope) ]  
290311struct  IfLetRescopeLint  { 
312+     #[ subdiagnostic]  
313+     destructors :  Vec < DestructorLabel > , 
291314    #[ label]  
292315    significant_droppers :  Vec < Span > , 
293316    #[ help]  
@@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
347370    } 
348371} 
349372
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+ 
350381struct  AltHead ( Span ) ; 
351382
352383struct  ConsequentRewrite  { 
@@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
374405/// of the scrutinee itself, and also recurses into the expression to find any ref 
375406/// exprs (or autoref) which would promote temporaries that would be scoped to the 
376407/// 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 ] > ) >  { 
378412        self . check_promoted_temp_with_drop ( init) ?; 
379413        self . visit_expr ( init) 
380414    } 
@@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
385419/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref) 
386420/// or is the scrutinee of the `if let`, *and* the expression is not a place 
387421/// 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| { 
390427            self . cx 
391428                . typeck_results ( ) 
392429                . adjustments ( ) 
393430                . get ( base. hir_id ) 
394431                . 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 ( ( ) ) ; 
404434        } 
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) ) 
405446    } 
406447} 
407448
408449impl < ' tcx >  Visitor < ' tcx >  for  FindSignificantDropper < ' _ ,  ' tcx >  { 
409-     type  Result  = ControlFlow < Span > ; 
450+     type  Result  = ControlFlow < ( Span ,   SmallVec < [ Ty < ' tcx > ;   4 ] > ) > ; 
410451
411452    fn  visit_block ( & mut  self ,  b :  & ' tcx  hir:: Block < ' tcx > )  -> Self :: Result  { 
412453        // Blocks introduce temporary terminating scope for all of its 
0 commit comments