@@ -155,8 +155,10 @@ struct BreakableScope<'tcx> {
155
155
/// The destination of the loop/block expression itself (i.e., where to put
156
156
/// the result of a `break` or `return` expression)
157
157
break_destination : Place < ' tcx > ,
158
- /// Drops that happen on the
159
- drops : DropTree ,
158
+ /// Drops that happen on the `break`/`return` path.
159
+ break_drops : DropTree ,
160
+ /// Drops that happen on the `continue` path.
161
+ continue_drops : Option < DropTree > ,
160
162
}
161
163
162
164
/// The target of an expression that breaks out of a scope
@@ -172,10 +174,8 @@ rustc_index::newtype_index! {
172
174
}
173
175
174
176
const ROOT_NODE : DropIdx = DropIdx :: from_u32_const ( 0 ) ;
175
- const CONTINUE_NODE : DropIdx = DropIdx :: from_u32_const ( 1 ) ;
176
177
177
- /// A tree (usually, sometimes this is a forest of two trees) of drops that we
178
- /// have deferred lowering. It's used for:
178
+ /// A tree of drops that we have deferred lowering. It's used for:
179
179
///
180
180
/// * Drops on unwind paths
181
181
/// * Drops on generator drop paths (when a suspended generator is dropped)
@@ -189,12 +189,10 @@ struct DropTree {
189
189
drops : IndexVec < DropIdx , ( DropData , DropIdx ) > ,
190
190
/// Map for finding the inverse of the `next_drop` relation:
191
191
///
192
- /// `previous_drops[(next_drop [i], drops[i].local, drops[i].kind] == i`
192
+ /// `previous_drops[(drops [i].1 , drops[i].0. local, drops[i].0 .kind] == i`
193
193
previous_drops : FxHashMap < ( DropIdx , Local , DropKind ) , DropIdx > ,
194
194
/// Edges into the `DropTree` that need to be added once it's lowered.
195
195
entry_points : Vec < ( DropIdx , BasicBlock ) > ,
196
- /// The first non-root nodes in the forest.
197
- first_non_root : DropIdx ,
198
196
}
199
197
200
198
impl Scope {
@@ -225,15 +223,14 @@ trait DropTreeBuilder<'tcx> {
225
223
}
226
224
227
225
impl DropTree {
228
- fn new ( num_roots : usize ) -> Self {
226
+ fn new ( ) -> Self {
229
227
let fake_source_info = SourceInfo { span : DUMMY_SP , scope : OUTERMOST_SOURCE_SCOPE } ;
230
228
let fake_data =
231
229
DropData { source_info : fake_source_info, local : Local :: MAX , kind : DropKind :: Storage } ;
232
230
let drop_idx = DropIdx :: MAX ;
233
- let drops = IndexVec :: from_elem_n ( ( fake_data, drop_idx) , num_roots ) ;
231
+ let drops = IndexVec :: from_elem_n ( ( fake_data, drop_idx) , 1 ) ;
234
232
Self {
235
233
drops,
236
- first_non_root : DropIdx :: from_usize ( num_roots) ,
237
234
entry_points : Vec :: new ( ) ,
238
235
previous_drops : FxHashMap :: default ( ) ,
239
236
}
@@ -248,6 +245,7 @@ impl DropTree {
248
245
}
249
246
250
247
fn add_entry ( & mut self , from : BasicBlock , to : DropIdx ) {
248
+ debug_assert ! ( to < self . drops. next_index( ) ) ;
251
249
self . entry_points . push ( ( to, from) ) ;
252
250
}
253
251
@@ -285,9 +283,11 @@ impl DropTree {
285
283
}
286
284
287
285
let mut needs_block = IndexVec :: from_elem ( Block :: None , & self . drops ) ;
288
- if self . first_non_root > CONTINUE_NODE {
289
- // `continue` already has its own node.
290
- needs_block[ CONTINUE_NODE ] = Block :: Own ;
286
+ if blocks[ ROOT_NODE ] . is_some ( ) {
287
+ // In some cases (such as drops for `continue`) the root node
288
+ // already has a block. In this case, make sure that we don't
289
+ // override it.
290
+ needs_block[ ROOT_NODE ] = Block :: Own ;
291
291
}
292
292
293
293
// Sort so that we only need to check the last
@@ -315,7 +315,7 @@ impl DropTree {
315
315
if let DropKind :: Value = drop_data. 0 . kind {
316
316
needs_block[ drop_data. 1 ] = Block :: Own ;
317
317
} else {
318
- if drop_idx >= self . first_non_root {
318
+ if drop_idx != ROOT_NODE {
319
319
match & mut needs_block[ drop_data. 1 ] {
320
320
pred @ Block :: None => * pred = Block :: Shares ( drop_idx) ,
321
321
pred @ Block :: Shares ( _) => * pred = Block :: Own ,
@@ -347,7 +347,7 @@ impl DropTree {
347
347
cfg. terminate ( block, drop_data. 0 . source_info , terminator) ;
348
348
}
349
349
// Root nodes don't correspond to a drop.
350
- DropKind :: Storage if drop_idx < self . first_non_root => { }
350
+ DropKind :: Storage if drop_idx == ROOT_NODE => { }
351
351
DropKind :: Storage => {
352
352
let stmt = Statement {
353
353
source_info : drop_data. 0 . source_info ,
@@ -366,12 +366,12 @@ impl DropTree {
366
366
}
367
367
368
368
impl < ' tcx > Scopes < ' tcx > {
369
- pub ( crate ) fn new ( is_generator : bool ) -> Self {
369
+ pub ( crate ) fn new ( ) -> Self {
370
370
Self {
371
371
scopes : Vec :: new ( ) ,
372
372
breakable_scopes : Vec :: new ( ) ,
373
- unwind_drops : DropTree :: new ( 1 ) ,
374
- generator_drops : DropTree :: new ( is_generator as usize ) ,
373
+ unwind_drops : DropTree :: new ( ) ,
374
+ generator_drops : DropTree :: new ( ) ,
375
375
}
376
376
}
377
377
@@ -429,13 +429,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
429
429
let scope = BreakableScope {
430
430
region_scope,
431
431
break_destination,
432
- drops : DropTree :: new ( 1 + loop_block. is_some ( ) as usize ) ,
432
+ break_drops : DropTree :: new ( ) ,
433
+ continue_drops : loop_block. map ( |_| DropTree :: new ( ) ) ,
433
434
} ;
434
435
self . scopes . breakable_scopes . push ( scope) ;
435
436
let normal_exit_block = f ( self ) ;
436
437
let breakable_scope = self . scopes . breakable_scopes . pop ( ) . unwrap ( ) ;
437
438
assert ! ( breakable_scope. region_scope == region_scope) ;
438
- let break_block = self . build_exit_tree ( breakable_scope. drops , loop_block) ;
439
+ let break_block = self . build_exit_tree ( breakable_scope. break_drops , None ) ;
440
+ breakable_scope. continue_drops . map ( |drops| {
441
+ self . build_exit_tree ( drops, loop_block) ;
442
+ } ) ;
439
443
match ( normal_exit_block, break_block) {
440
444
( Some ( block) , None ) | ( None , Some ( block) ) => block,
441
445
( None , None ) => self . cfg . start_new_block ( ) . unit ( ) ,
@@ -600,10 +604,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
600
604
601
605
let region_scope = self . scopes . breakable_scopes [ break_index] . region_scope ;
602
606
let scope_index = self . scopes . scope_index ( region_scope, span) ;
603
- let exited_scopes = & self . scopes . scopes [ scope_index + 1 ..] ;
604
- let scope_drops = exited_scopes. iter ( ) . flat_map ( |scope| & scope. drops ) ;
607
+ let drops = if destination. is_some ( ) {
608
+ & mut self . scopes . breakable_scopes [ break_index] . break_drops
609
+ } else {
610
+ self . scopes . breakable_scopes [ break_index] . continue_drops . as_mut ( ) . unwrap ( )
611
+ } ;
605
612
606
- let drops = & mut self . scopes . breakable_scopes [ break_index] . drops ;
607
613
let mut drop_idx = DropIdx :: from_u32 ( destination. is_none ( ) as u32 ) ;
608
614
for drop in scope_drops {
609
615
drop_idx = drops. add_drop ( * drop, drop_idx) ;
@@ -1095,15 +1101,13 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
1095
1101
continue_block : Option < BasicBlock > ,
1096
1102
) -> Option < BlockAnd < ( ) > > {
1097
1103
let mut blocks = IndexVec :: from_elem ( None , & drops. drops ) ;
1098
- if continue_block. is_some ( ) {
1099
- blocks[ CONTINUE_NODE ] = continue_block;
1100
- }
1104
+ blocks[ ROOT_NODE ] = continue_block;
1105
+
1101
1106
drops. build_mir :: < ExitScopes > ( & mut self . cfg , & mut blocks) ;
1102
1107
if drops. drops . iter ( ) . any ( |( drop, _) | drop. kind == DropKind :: Value ) {
1103
1108
let unwind_target = self . diverge_cleanup ( ) ;
1104
- let num_roots = drops. first_non_root . index ( ) ;
1105
- let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, num_roots) ;
1106
- for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( num_roots) {
1109
+ let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
1110
+ for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
1107
1111
match drop_data. 0 . kind {
1108
1112
DropKind :: Storage => {
1109
1113
if self . is_generator {
0 commit comments