@@ -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