@@ -151,15 +151,13 @@ struct DropData {
151151
152152 /// Whether this is a value Drop or a StorageDead.
153153 kind : DropKind ,
154-
155- /// Whether this is a backwards-incompatible drop lint
156- backwards_incompatible_lint : bool ,
157154}
158155
159156#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
160157pub ( crate ) enum DropKind {
161158 Value ,
162159 Storage ,
160+ ForLint ,
163161}
164162
165163#[ derive( Debug ) ]
@@ -248,7 +246,7 @@ impl Scope {
248246 /// use of optimizations in the MIR coroutine transform.
249247 fn needs_cleanup ( & self ) -> bool {
250248 self . drops . iter ( ) . any ( |drop| match drop. kind {
251- DropKind :: Value => true ,
249+ DropKind :: Value | DropKind :: ForLint => true ,
252250 DropKind :: Storage => false ,
253251 } )
254252 }
@@ -277,12 +275,8 @@ impl DropTree {
277275 // represents the block in the tree that should be jumped to once all
278276 // of the required drops have been performed.
279277 let fake_source_info = SourceInfo :: outermost ( DUMMY_SP ) ;
280- let fake_data = DropData {
281- source_info : fake_source_info,
282- local : Local :: MAX ,
283- kind : DropKind :: Storage ,
284- backwards_incompatible_lint : false ,
285- } ;
278+ let fake_data =
279+ DropData { source_info : fake_source_info, local : Local :: MAX , kind : DropKind :: Storage } ;
286280 let drops = IndexVec :: from_raw ( vec ! [ DropNode { data: fake_data, next: DropIdx :: MAX } ] ) ;
287281 Self { drops, entry_points : Vec :: new ( ) , existing_drops_map : FxHashMap :: default ( ) }
288282 }
@@ -411,6 +405,27 @@ impl DropTree {
411405 } ;
412406 cfg. terminate ( block, drop_node. data . source_info , terminator) ;
413407 }
408+ DropKind :: ForLint => {
409+ let stmt = Statement {
410+ source_info : drop_node. data . source_info ,
411+ kind : StatementKind :: BackwardIncompatibleDropHint {
412+ place : Box :: new ( drop_node. data . local . into ( ) ) ,
413+ reason : BackwardIncompatibleDropReason :: Edition2024 ,
414+ } ,
415+ } ;
416+ cfg. push ( block, stmt) ;
417+ let target = blocks[ drop_node. next ] . unwrap ( ) ;
418+ if target != block {
419+ // Diagnostics don't use this `Span` but debuginfo
420+ // might. Since we don't want breakpoints to be placed
421+ // here, especially when this is on an unwind path, we
422+ // use `DUMMY_SP`.
423+ let source_info =
424+ SourceInfo { span : DUMMY_SP , ..drop_node. data . source_info } ;
425+ let terminator = TerminatorKind :: Goto { target } ;
426+ cfg. terminate ( block, source_info, terminator) ;
427+ }
428+ }
414429 // Root nodes don't correspond to a drop.
415430 DropKind :: Storage if drop_idx == ROOT_NODE => { }
416431 DropKind :: Storage => {
@@ -770,12 +785,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
770785 let local =
771786 place. as_local ( ) . unwrap_or_else ( || bug ! ( "projection in tail call args" ) ) ;
772787
773- Some ( DropData {
774- source_info,
775- local,
776- kind : DropKind :: Value ,
777- backwards_incompatible_lint : false ,
778- } )
788+ Some ( DropData { source_info, local, kind : DropKind :: Value } )
779789 }
780790 Operand :: Constant ( _) => None ,
781791 } )
@@ -822,6 +832,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
822832 } ) ;
823833 block = next;
824834 }
835+ DropKind :: ForLint => {
836+ self . cfg . push ( block, Statement {
837+ source_info,
838+ kind : StatementKind :: BackwardIncompatibleDropHint {
839+ place : Box :: new ( local. into ( ) ) ,
840+ reason : BackwardIncompatibleDropReason :: Edition2024 ,
841+ } ,
842+ } ) ;
843+ }
825844 DropKind :: Storage => {
826845 // Only temps and vars need their storage dead.
827846 assert ! ( local. index( ) > self . arg_count) ;
@@ -1021,7 +1040,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10211040 drop_kind : DropKind ,
10221041 ) {
10231042 let needs_drop = match drop_kind {
1024- DropKind :: Value => {
1043+ DropKind :: Value | DropKind :: ForLint => {
10251044 if !self . local_decls [ local] . ty . needs_drop ( self . tcx , self . typing_env ( ) ) {
10261045 return ;
10271046 }
@@ -1101,7 +1120,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11011120 source_info : SourceInfo { span : scope_end, scope : scope. source_scope } ,
11021121 local,
11031122 kind : drop_kind,
1104- backwards_incompatible_lint : false ,
11051123 } ) ;
11061124
11071125 return ;
@@ -1135,8 +1153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11351153 scope. drops . push ( DropData {
11361154 source_info : SourceInfo { span : scope_end, scope : scope. source_scope } ,
11371155 local,
1138- kind : DropKind :: Value ,
1139- backwards_incompatible_lint : true ,
1156+ kind : DropKind :: ForLint ,
11401157 } ) ;
11411158
11421159 return ;
@@ -1379,12 +1396,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13791396}
13801397
13811398/// Builds drops for `pop_scope` and `leave_top_scope`.
1399+ ///
1400+ /// # Parameters
1401+ ///
1402+ /// * `unwind_drops`, the drop tree data structure storing what needs to be cleaned up if unwind occurs
1403+ /// * `scope`, describes the drops that will occur on exiting the scope in regular execution
1404+ /// * `block`, the block to branch to once drops are complete (assuming no unwind occurs)
1405+ /// * `unwind_to`, describes the drops that would occur at this point in the code if a
1406+ /// panic occurred (a subset of the drops in `scope`, since we sometimes elide StorageDead and other
1407+ /// instructions on unwinding)
1408+ /// * `storage_dead_on_unwind`, if true, then we should emit `StorageDead` even when unwinding
1409+ /// * `arg_count`, number of MIR local variables corresponding to fn arguments (used to assert that we don't drop those)
13821410fn build_scope_drops < ' tcx > (
13831411 cfg : & mut CFG < ' tcx > ,
13841412 unwind_drops : & mut DropTree ,
13851413 scope : & Scope ,
1386- mut block : BasicBlock ,
1387- mut unwind_to : DropIdx ,
1414+ block : BasicBlock ,
1415+ unwind_to : DropIdx ,
13881416 storage_dead_on_unwind : bool ,
13891417 arg_count : usize ,
13901418) -> BlockAnd < ( ) > {
@@ -1409,6 +1437,18 @@ fn build_scope_drops<'tcx>(
14091437 // drops for the unwind path should have already been generated by
14101438 // `diverge_cleanup_gen`.
14111439
1440+ // `unwind_to` indicates what needs to be dropped should unwinding occur.
1441+ // This is a subset of what needs to be dropped when exiting the scope.
1442+ // As we unwind the scope, we will also move `unwind_to` backwards to match,
1443+ // so that we can use it should a destructor panic.
1444+ let mut unwind_to = unwind_to;
1445+
1446+ // The block that we should jump to after drops complete. We start by building the final drop (`drops[n]`
1447+ // in the diagram above) and then build the drops (e.g., `drop[1]`, `drop[0]`) that come before it.
1448+ // block begins as the successor of `drops[n]` and then becomes `drops[n]` so that `drops[n-1]`
1449+ // will branch to `drops[n]`.
1450+ let mut block = block;
1451+
14121452 for drop_data in scope. drops . iter ( ) . rev ( ) {
14131453 let source_info = drop_data. source_info ;
14141454 let local = drop_data. local ;
@@ -1418,6 +1458,9 @@ fn build_scope_drops<'tcx>(
14181458 // `unwind_to` should drop the value that we're about to
14191459 // schedule. If dropping this value panics, then we continue
14201460 // with the *next* value on the unwind path.
1461+ //
1462+ // We adjust this BEFORE we create the drop (e.g., `drops[n]`)
1463+ // because `drops[n]` should unwind to `drops[n-1]`.
14211464 debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. local, drop_data. local) ;
14221465 debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. kind, drop_data. kind) ;
14231466 unwind_to = unwind_drops. drops [ unwind_to] . next ;
@@ -1430,27 +1473,50 @@ fn build_scope_drops<'tcx>(
14301473 continue ;
14311474 }
14321475
1433- if drop_data. backwards_incompatible_lint {
1434- cfg. push ( block, Statement {
1435- source_info,
1436- kind : StatementKind :: BackwardIncompatibleDropHint {
1437- place : Box :: new ( local. into ( ) ) ,
1438- reason : BackwardIncompatibleDropReason :: Edition2024 ,
1439- } ,
1440- } ) ;
1441- } else {
1442- unwind_drops. add_entry_point ( block, unwind_to) ;
1443- let next = cfg. start_new_block ( ) ;
1444- cfg. terminate ( block, source_info, TerminatorKind :: Drop {
1445- place : local. into ( ) ,
1446- target : next,
1447- unwind : UnwindAction :: Continue ,
1448- replace : false ,
1449- } ) ;
1450- block = next;
1476+ unwind_drops. add_entry_point ( block, unwind_to) ;
1477+ let next = cfg. start_new_block ( ) ;
1478+ cfg. terminate ( block, source_info, TerminatorKind :: Drop {
1479+ place : local. into ( ) ,
1480+ target : next,
1481+ unwind : UnwindAction :: Continue ,
1482+ replace : false ,
1483+ } ) ;
1484+ block = next;
1485+ }
1486+ DropKind :: ForLint => {
1487+ // As in the `DropKind::Storage` case below:
1488+ // normally lint-related drops are not emitted for unwind,
1489+ // so we can just leave `unwind_to` unmodified, but in some
1490+ // cases we emit things ALSO on the unwind path, so we need to adjust
1491+ // `unwind_to` in that case.
1492+ if storage_dead_on_unwind {
1493+ debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. local, drop_data. local) ;
1494+ debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. kind, drop_data. kind) ;
1495+ unwind_to = unwind_drops. drops [ unwind_to] . next ;
14511496 }
1497+
1498+ // If the operand has been moved, and we are not on an unwind
1499+ // path, then don't generate the drop. (We only take this into
1500+ // account for non-unwind paths so as not to disturb the
1501+ // caching mechanism.)
1502+ if scope. moved_locals . iter ( ) . any ( |& o| o == local) {
1503+ continue ;
1504+ }
1505+
1506+ cfg. push ( block, Statement {
1507+ source_info,
1508+ kind : StatementKind :: BackwardIncompatibleDropHint {
1509+ place : Box :: new ( local. into ( ) ) ,
1510+ reason : BackwardIncompatibleDropReason :: Edition2024 ,
1511+ } ,
1512+ } ) ;
14521513 }
14531514 DropKind :: Storage => {
1515+ // Ordinarily, storage-dead nodes are not emitted on unwind, so we don't
1516+ // need to adjust `unwind_to` on this path. However, in some specific cases
1517+ // we *do* emit storage-dead nodes on the unwind path, and in that case now that
1518+ // the storage-dead has completed, we need to adjust the `unwind_to` pointer
1519+ // so that any future drops we emit will not register storage-dead.
14541520 if storage_dead_on_unwind {
14551521 debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. local, drop_data. local) ;
14561522 debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . data. kind, drop_data. kind) ;
@@ -1489,7 +1555,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
14891555 let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
14901556 for ( drop_idx, drop_node) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
14911557 match drop_node. data . kind {
1492- DropKind :: Storage => {
1558+ DropKind :: Storage | DropKind :: ForLint => {
14931559 if is_coroutine {
14941560 let unwind_drop = self
14951561 . scopes
0 commit comments