@@ -153,8 +153,10 @@ struct BreakableScope<'tcx> {
153
153
/// The destination of the loop/block expression itself (i.e., where to put
154
154
/// the result of a `break` or `return` expression)
155
155
break_destination : Place < ' tcx > ,
156
- /// Drops that happen on the
157
- drops : DropTree ,
156
+ /// Drops that happen on the `break`/`return` path.
157
+ break_drops : DropTree ,
158
+ /// Drops that happen on the `continue` path.
159
+ continue_drops : Option < DropTree > ,
158
160
}
159
161
160
162
/// The target of an expression that breaks out of a scope
@@ -170,10 +172,8 @@ rustc_index::newtype_index! {
170
172
}
171
173
172
174
const ROOT_NODE : DropIdx = DropIdx :: from_u32_const ( 0 ) ;
173
- const CONTINUE_NODE : DropIdx = DropIdx :: from_u32_const ( 1 ) ;
174
175
175
- /// A tree (usually, sometimes this is a forest of two trees) of drops that we
176
- /// have deferred lowering. It's used for:
176
+ /// A tree of drops that we have deferred lowering. It's used for:
177
177
///
178
178
/// * Drops on unwind paths
179
179
/// * Drops on generator drop paths (when a suspended generator is dropped)
@@ -187,12 +187,10 @@ struct DropTree {
187
187
drops : IndexVec < DropIdx , ( DropData , DropIdx ) > ,
188
188
/// Map for finding the inverse of the `next_drop` relation:
189
189
///
190
- /// `previous_drops[(next_drop [i], drops[i].local, drops[i].kind] == i`
190
+ /// `previous_drops[(drops [i].1 , drops[i].0. local, drops[i].0 .kind] == i`
191
191
previous_drops : FxHashMap < ( DropIdx , Local , DropKind ) , DropIdx > ,
192
192
/// Edges into the `DropTree` that need to be added once it's lowered.
193
193
entry_points : Vec < ( DropIdx , BasicBlock ) > ,
194
- /// The first non-root nodes in the forest.
195
- first_non_root : DropIdx ,
196
194
}
197
195
198
196
impl Scope {
@@ -223,18 +221,17 @@ trait DropTreeBuilder<'tcx> {
223
221
}
224
222
225
223
impl DropTree {
226
- fn new ( num_roots : usize ) -> Self {
224
+ fn new ( ) -> Self {
227
225
let fake_source_info = SourceInfo { span : DUMMY_SP , scope : OUTERMOST_SOURCE_SCOPE } ;
228
226
let fake_data = DropData {
229
227
source_info : fake_source_info,
230
228
local : Local :: MAX ,
231
229
kind : DropKind :: Storage ,
232
230
} ;
233
231
let drop_idx = DropIdx :: MAX ;
234
- let drops = IndexVec :: from_elem_n ( ( fake_data, drop_idx) , num_roots ) ;
232
+ let drops = IndexVec :: from_elem_n ( ( fake_data, drop_idx) , 1 ) ;
235
233
Self {
236
234
drops,
237
- first_non_root : DropIdx :: from_usize ( num_roots) ,
238
235
entry_points : Vec :: new ( ) ,
239
236
previous_drops : FxHashMap :: default ( ) ,
240
237
}
@@ -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 ,
@@ -351,7 +351,7 @@ impl DropTree {
351
351
) ;
352
352
}
353
353
// Root nodes don't correspond to a drop.
354
- DropKind :: Storage if drop_idx < self . first_non_root => { }
354
+ DropKind :: Storage if drop_idx == ROOT_NODE => { }
355
355
DropKind :: Storage => {
356
356
let stmt = Statement {
357
357
source_info : drop_data. 0 . source_info ,
@@ -370,12 +370,12 @@ impl DropTree {
370
370
}
371
371
372
372
impl < ' tcx > Scopes < ' tcx > {
373
- pub ( crate ) fn new ( is_generator : bool ) -> Self {
373
+ pub ( crate ) fn new ( ) -> Self {
374
374
Self {
375
375
scopes : Vec :: new ( ) ,
376
376
breakable_scopes : Vec :: new ( ) ,
377
- unwind_drops : DropTree :: new ( 1 ) ,
378
- generator_drops : DropTree :: new ( is_generator as usize ) ,
377
+ unwind_drops : DropTree :: new ( ) ,
378
+ generator_drops : DropTree :: new ( ) ,
379
379
}
380
380
}
381
381
@@ -436,13 +436,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
436
436
let scope = BreakableScope {
437
437
region_scope,
438
438
break_destination,
439
- drops : DropTree :: new ( 1 + loop_block. is_some ( ) as usize ) ,
439
+ break_drops : DropTree :: new ( ) ,
440
+ continue_drops : loop_block. map ( |_| DropTree :: new ( ) ) ,
440
441
} ;
441
442
self . scopes . breakable_scopes . push ( scope) ;
442
443
let normal_exit_block = f ( self ) ;
443
444
let breakable_scope = self . scopes . breakable_scopes . pop ( ) . unwrap ( ) ;
444
445
assert ! ( breakable_scope. region_scope == region_scope) ;
445
- let break_block = self . build_exit_tree ( breakable_scope. drops , loop_block) ;
446
+ let break_block = self . build_exit_tree ( breakable_scope. break_drops , None ) ;
447
+ breakable_scope. continue_drops . map ( |drops| {
448
+ self . build_exit_tree ( drops, loop_block) ;
449
+ } ) ;
446
450
match ( normal_exit_block, break_block) {
447
451
( Some ( block) , None ) | ( None , Some ( block) ) => block,
448
452
( None , None ) => self . cfg . start_new_block ( ) . unit ( ) ,
@@ -602,10 +606,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
602
606
603
607
let region_scope = self . scopes . breakable_scopes [ break_index] . region_scope ;
604
608
let scope_index = self . scopes . scope_index ( region_scope, span) ;
605
- let exited_scopes = & self . scopes . scopes [ scope_index + 1 ..] ;
606
- let scope_drops = exited_scopes. iter ( ) . flat_map ( |scope| & scope. drops ) ;
609
+ let drops = if destination. is_some ( ) {
610
+ & mut self . scopes . breakable_scopes [ break_index] . break_drops
611
+ } else {
612
+ self . scopes . breakable_scopes [ break_index] . continue_drops . as_mut ( ) . unwrap ( )
613
+ } ;
607
614
608
- let drops = & mut self . scopes . breakable_scopes [ break_index] . drops ;
609
615
let mut drop_idx = DropIdx :: from_u32 ( destination. is_none ( ) as u32 ) ;
610
616
for drop in scope_drops {
611
617
drop_idx = drops. add_drop ( * drop, drop_idx) ;
@@ -1103,15 +1109,13 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
1103
1109
continue_block : Option < BasicBlock > ,
1104
1110
) -> Option < BlockAnd < ( ) > > {
1105
1111
let mut blocks = IndexVec :: from_elem ( None , & drops. drops ) ;
1106
- if continue_block. is_some ( ) {
1107
- blocks[ CONTINUE_NODE ] = continue_block;
1108
- }
1112
+ blocks[ ROOT_NODE ] = continue_block;
1113
+
1109
1114
drops. build_mir :: < ExitScopes > ( & mut self . cfg , & mut blocks) ;
1110
1115
if drops. drops . iter ( ) . any ( |( drop, _) | drop. kind == DropKind :: Value ) {
1111
1116
let unwind_target = self . diverge_cleanup ( ) ;
1112
- let num_roots = drops. first_non_root . index ( ) ;
1113
- let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, num_roots) ;
1114
- for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( num_roots) {
1117
+ let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
1118
+ for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
1115
1119
match drop_data. 0 . kind {
1116
1120
DropKind :: Storage => {
1117
1121
if self . is_generator {
0 commit comments