@@ -243,30 +243,37 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
243
243
}
244
244
245
245
/// Create one-half of the drop ladder for a list of fields, and return
246
- /// the list of steps in it in reverse order.
246
+ /// the list of steps in it in reverse order, with the first step
247
+ /// dropping 0 fields and so on.
247
248
///
248
249
/// `unwind_ladder` is such a list of steps in reverse order,
249
250
/// which is called if the matching step of the drop glue panics.
250
251
fn drop_halfladder ( & mut self ,
251
252
unwind_ladder : & [ Unwind ] ,
252
- succ : BasicBlock ,
253
+ mut succ : BasicBlock ,
253
254
fields : & [ ( Lvalue < ' tcx > , Option < D :: Path > ) ] )
254
255
-> Vec < BasicBlock >
255
256
{
256
- let goto = TerminatorKind :: Goto { target : succ } ;
257
- let mut succ = self . new_block ( unwind_ladder[ 0 ] , goto) ;
258
-
259
- // Always clear the "master" drop flag at the bottom of the
260
- // ladder. This is needed because the "master" drop flag
261
- // protects the ADT's discriminant, which is invalidated
262
- // after the ADT is dropped.
263
- let succ_loc = Location { block : succ, statement_index : 0 } ;
264
- self . elaborator . clear_drop_flag ( succ_loc, self . path , DropFlagMode :: Shallow ) ;
265
-
266
- fields. iter ( ) . rev ( ) . zip ( unwind_ladder) . map ( |( & ( ref lv, path) , & unwind_succ) | {
267
- succ = self . drop_subpath ( lv, path, succ, unwind_succ) ;
268
- succ
269
- } ) . collect ( )
257
+ Some ( succ) . into_iter ( ) . chain (
258
+ fields. iter ( ) . rev ( ) . zip ( unwind_ladder)
259
+ . map ( |( & ( ref lv, path) , & unwind_succ) | {
260
+ succ = self . drop_subpath ( lv, path, succ, unwind_succ) ;
261
+ succ
262
+ } )
263
+ ) . collect ( )
264
+ }
265
+
266
+ fn drop_ladder_bottom ( & mut self ) -> ( BasicBlock , Unwind ) {
267
+ // Clear the "master" drop flag at the end. This is needed
268
+ // because the "master" drop protects the ADT's discriminant,
269
+ // which is invalidated after the ADT is dropped.
270
+ let ( succ, unwind) = ( self . succ , self . unwind ) ; // FIXME(#6393)
271
+ (
272
+ self . drop_flag_reset_block ( DropFlagMode :: Shallow , succ, unwind) ,
273
+ unwind. map ( |unwind| {
274
+ self . drop_flag_reset_block ( DropFlagMode :: Shallow , unwind, Unwind :: InCleanup )
275
+ } )
276
+ )
270
277
}
271
278
272
279
/// Create a full drop ladder, consisting of 2 connected half-drop-ladders
@@ -283,8 +290,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
283
290
/// ELAB(drop location.1 [target=.c2])
284
291
/// .c2:
285
292
/// ELAB(drop location.2 [target=`self.unwind`])
293
+ ///
294
+ /// NOTE: this does not clear the master drop flag, so you need
295
+ /// to point succ/unwind on a `drop_ladder_bottom`.
286
296
fn drop_ladder < ' a > ( & mut self ,
287
- fields : Vec < ( Lvalue < ' tcx > , Option < D :: Path > ) > )
297
+ fields : Vec < ( Lvalue < ' tcx > , Option < D :: Path > ) > ,
298
+ succ : BasicBlock ,
299
+ unwind : Unwind )
288
300
-> ( BasicBlock , Unwind )
289
301
{
290
302
debug ! ( "drop_ladder({:?}, {:?})" , self , fields) ;
@@ -297,20 +309,17 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
297
309
debug ! ( "drop_ladder - fields needing drop: {:?}" , fields) ;
298
310
299
311
let unwind_ladder = vec ! [ Unwind :: InCleanup ; fields. len( ) + 1 ] ;
300
- let unwind_ladder: Vec < _ > = if let Unwind :: To ( target) = self . unwind {
312
+ let unwind_ladder: Vec < _ > = if let Unwind :: To ( target) = unwind {
301
313
let halfladder = self . drop_halfladder ( & unwind_ladder, target, & fields) ;
302
- Some ( self . unwind ) . into_iter ( ) . chain ( halfladder. into_iter ( ) . map ( Unwind :: To ) )
303
- . collect ( )
314
+ halfladder. into_iter ( ) . map ( Unwind :: To ) . collect ( )
304
315
} else {
305
316
unwind_ladder
306
317
} ;
307
318
308
- let succ = self . succ ; // FIXME(#6393)
309
319
let normal_ladder =
310
320
self . drop_halfladder ( & unwind_ladder, succ, & fields) ;
311
321
312
- ( normal_ladder. last ( ) . cloned ( ) . unwrap_or ( succ) ,
313
- unwind_ladder. last ( ) . cloned ( ) . unwrap_or ( self . unwind ) )
322
+ ( * normal_ladder. last ( ) . unwrap ( ) , * unwind_ladder. last ( ) . unwrap ( ) )
314
323
}
315
324
316
325
fn open_drop_for_tuple < ' a > ( & mut self , tys : & [ Ty < ' tcx > ] )
@@ -323,7 +332,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
323
332
self . elaborator . field_subpath ( self . path , Field :: new ( i) ) )
324
333
} ) . collect ( ) ;
325
334
326
- self . drop_ladder ( fields) . 0
335
+ let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
336
+ self . drop_ladder ( fields, succ, unwind) . 0
327
337
}
328
338
329
339
fn open_drop_for_box < ' a > ( & mut self , ty : Ty < ' tcx > ) -> BasicBlock
@@ -370,106 +380,100 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
370
380
}
371
381
}
372
382
373
- fn open_drop_for_adt_contents < ' a > ( & mut self , adt : & ' tcx ty:: AdtDef ,
374
- substs : & ' tcx Substs < ' tcx > )
375
- -> ( BasicBlock , Unwind ) {
376
- match adt. variants . len ( ) {
377
- 1 => {
378
- let fields = self . move_paths_for_fields (
379
- self . lvalue ,
380
- self . path ,
381
- & adt. variants [ 0 ] ,
382
- substs
383
- ) ;
384
- self . drop_ladder ( fields)
385
- }
386
- _ => {
387
- let succ = self . succ ;
388
- let unwind = self . unwind ; // FIXME(#6393)
383
+ fn open_drop_for_adt_contents ( & mut self , adt : & ' tcx ty:: AdtDef ,
384
+ substs : & ' tcx Substs < ' tcx > )
385
+ -> ( BasicBlock , Unwind ) {
386
+ let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
387
+ if adt. variants . len ( ) == 1 {
388
+ let fields = self . move_paths_for_fields (
389
+ self . lvalue ,
390
+ self . path ,
391
+ & adt. variants [ 0 ] ,
392
+ substs
393
+ ) ;
394
+ self . drop_ladder ( fields, succ, unwind)
395
+ } else {
396
+ self . open_drop_for_multivariant ( adt, substs, succ, unwind)
397
+ }
398
+ }
399
+
400
+ fn open_drop_for_multivariant ( & mut self , adt : & ' tcx ty:: AdtDef ,
401
+ substs : & ' tcx Substs < ' tcx > ,
402
+ succ : BasicBlock ,
403
+ unwind : Unwind )
404
+ -> ( BasicBlock , Unwind ) {
405
+ let mut values = Vec :: with_capacity ( adt. variants . len ( ) ) ;
406
+ let mut normal_blocks = Vec :: with_capacity ( adt. variants . len ( ) ) ;
407
+ let mut unwind_blocks = if unwind. is_cleanup ( ) {
408
+ None
409
+ } else {
410
+ Some ( Vec :: with_capacity ( adt. variants . len ( ) ) )
411
+ } ;
412
+
413
+ let mut have_otherwise = false ;
389
414
390
- let mut values = Vec :: with_capacity ( adt. variants . len ( ) ) ;
391
- let mut normal_blocks = Vec :: with_capacity ( adt. variants . len ( ) ) ;
392
- let mut unwind_blocks = if unwind. is_cleanup ( ) {
393
- None
394
- } else {
395
- Some ( Vec :: with_capacity ( adt. variants . len ( ) ) )
396
- } ;
397
- let mut otherwise = None ;
398
- let mut unwind_otherwise = None ;
399
- for ( variant_index, discr) in adt. discriminants ( self . tcx ( ) ) . enumerate ( ) {
400
- let subpath = self . elaborator . downcast_subpath (
401
- self . path , variant_index) ;
402
- if let Some ( variant_path) = subpath {
403
- let base_lv = self . lvalue . clone ( ) . elem (
404
- ProjectionElem :: Downcast ( adt, variant_index)
415
+ for ( variant_index, discr) in adt. discriminants ( self . tcx ( ) ) . enumerate ( ) {
416
+ let subpath = self . elaborator . downcast_subpath (
417
+ self . path , variant_index) ;
418
+ if let Some ( variant_path) = subpath {
419
+ let base_lv = self . lvalue . clone ( ) . elem (
420
+ ProjectionElem :: Downcast ( adt, variant_index)
405
421
) ;
406
- let fields = self . move_paths_for_fields (
407
- & base_lv,
408
- variant_path,
409
- & adt. variants [ variant_index] ,
410
- substs) ;
411
- values. push ( discr) ;
412
- if let Unwind :: To ( unwind) = unwind {
413
- // We can't use the half-ladder from the original
414
- // drop ladder, because this breaks the
415
- // "funclet can't have 2 successor funclets"
416
- // requirement from MSVC:
417
- //
418
- // switch unwind-switch
419
- // / \ / \
420
- // v1.0 v2.0 v2.0-unwind v1.0-unwind
421
- // | | / |
422
- // v1.1-unwind v2.1-unwind |
423
- // ^ |
424
- // \-------------------------------/
425
- //
426
- // Create a duplicate half-ladder to avoid that. We
427
- // could technically only do this on MSVC, but I
428
- // I want to minimize the divergence between MSVC
429
- // and non-MSVC.
430
-
431
- let unwind_blocks = unwind_blocks. as_mut ( ) . unwrap ( ) ;
432
- let unwind_ladder = vec ! [ Unwind :: InCleanup ; fields. len( ) + 1 ] ;
433
- let halfladder =
434
- self . drop_halfladder ( & unwind_ladder, unwind, & fields) ;
435
- unwind_blocks. push ( halfladder. last ( ) . cloned ( ) . unwrap_or ( unwind) ) ;
436
- }
437
- let ( normal, _) = self . drop_ladder ( fields) ;
438
- normal_blocks. push ( normal) ;
439
- } else {
440
- // variant not found - drop the entire enum
441
- if let None = otherwise {
442
- otherwise = Some ( self . complete_drop (
443
- Some ( DropFlagMode :: Shallow ) ,
444
- succ,
445
- unwind) ) ;
446
- if let Unwind :: To ( unwind) = unwind {
447
- unwind_otherwise = Some ( self . complete_drop (
448
- Some ( DropFlagMode :: Shallow ) ,
449
- unwind,
450
- Unwind :: InCleanup
451
- ) ) ;
452
- }
453
- }
454
- }
455
- }
456
- if let Some ( block) = otherwise {
457
- normal_blocks. push ( block) ;
458
- if let Some ( ref mut unwind_blocks) = unwind_blocks {
459
- unwind_blocks. push ( unwind_otherwise. unwrap ( ) ) ;
460
- }
461
- } else {
462
- values. pop ( ) ;
422
+ let fields = self . move_paths_for_fields (
423
+ & base_lv,
424
+ variant_path,
425
+ & adt. variants [ variant_index] ,
426
+ substs) ;
427
+ values. push ( discr) ;
428
+ if let Unwind :: To ( unwind) = unwind {
429
+ // We can't use the half-ladder from the original
430
+ // drop ladder, because this breaks the
431
+ // "funclet can't have 2 successor funclets"
432
+ // requirement from MSVC:
433
+ //
434
+ // switch unwind-switch
435
+ // / \ / \
436
+ // v1.0 v2.0 v2.0-unwind v1.0-unwind
437
+ // | | / |
438
+ // v1.1-unwind v2.1-unwind |
439
+ // ^ |
440
+ // \-------------------------------/
441
+ //
442
+ // Create a duplicate half-ladder to avoid that. We
443
+ // could technically only do this on MSVC, but I
444
+ // I want to minimize the divergence between MSVC
445
+ // and non-MSVC.
446
+
447
+ let unwind_blocks = unwind_blocks. as_mut ( ) . unwrap ( ) ;
448
+ let unwind_ladder = vec ! [ Unwind :: InCleanup ; fields. len( ) + 1 ] ;
449
+ let halfladder =
450
+ self . drop_halfladder ( & unwind_ladder, unwind, & fields) ;
451
+ unwind_blocks. push ( halfladder. last ( ) . cloned ( ) . unwrap ( ) ) ;
463
452
}
453
+ let ( normal, _) = self . drop_ladder ( fields, succ, unwind) ;
454
+ normal_blocks. push ( normal) ;
455
+ } else {
456
+ have_otherwise = true ;
457
+ }
458
+ }
464
459
465
- ( self . adt_switch_block ( adt , normal_blocks , & values , succ , unwind ) ,
466
- unwind . map ( |unwind| {
467
- self . adt_switch_block (
468
- adt , unwind_blocks. unwrap ( ) , & values , unwind , Unwind :: InCleanup
469
- )
470
- } ) )
460
+ if have_otherwise {
461
+ normal_blocks . push ( self . drop_block ( succ , unwind ) ) ;
462
+ if let Unwind :: To ( unwind ) = unwind {
463
+ unwind_blocks. as_mut ( ) . unwrap ( ) . push (
464
+ self . drop_block ( unwind , Unwind :: InCleanup )
465
+ ) ;
471
466
}
467
+ } else {
468
+ values. pop ( ) ;
472
469
}
470
+
471
+ ( self . adt_switch_block ( adt, normal_blocks, & values, succ, unwind) ,
472
+ unwind. map ( |unwind| {
473
+ self . adt_switch_block (
474
+ adt, unwind_blocks. unwrap ( ) , & values, unwind, Unwind :: InCleanup
475
+ )
476
+ } ) )
473
477
}
474
478
475
479
fn adt_switch_block ( & mut self ,
@@ -652,8 +656,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
652
656
} ) ;
653
657
654
658
// FIXME(#34708): handle partially-dropped array/slice elements.
655
- self . drop_flag_test_and_reset_block (
656
- Some ( DropFlagMode :: Deep ) , drop_block , succ, unwind)
659
+ let reset_block = self . drop_flag_reset_block ( DropFlagMode :: Deep , drop_block , unwind ) ;
660
+ self . drop_flag_test_block ( reset_block , succ, unwind)
657
661
}
658
662
659
663
/// The slow-path - create an "open", elaborated drop for a type
@@ -707,23 +711,26 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
707
711
debug ! ( "complete_drop({:?},{:?})" , self , drop_mode) ;
708
712
709
713
let drop_block = self . drop_block ( succ, unwind) ;
710
- self . drop_flag_test_and_reset_block ( drop_mode, drop_block, succ, unwind)
714
+ let drop_block = if let Some ( mode) = drop_mode {
715
+ self . drop_flag_reset_block ( mode, drop_block, unwind)
716
+ } else {
717
+ drop_block
718
+ } ;
719
+
720
+ self . drop_flag_test_block ( drop_block, succ, unwind)
711
721
}
712
722
713
- fn drop_flag_test_and_reset_block ( & mut self ,
714
- drop_mode : Option < DropFlagMode > ,
715
- drop_block : BasicBlock ,
716
- succ : BasicBlock ,
717
- unwind : Unwind ) -> BasicBlock
723
+ fn drop_flag_reset_block ( & mut self ,
724
+ mode : DropFlagMode ,
725
+ succ : BasicBlock ,
726
+ unwind : Unwind ) -> BasicBlock
718
727
{
719
- debug ! ( "drop_flag_test_and_reset_block({:?},{:?})" , self , drop_mode) ;
720
-
721
- if let Some ( mode) = drop_mode {
722
- let block_start = Location { block : drop_block, statement_index : 0 } ;
723
- self . elaborator . clear_drop_flag ( block_start, self . path , mode) ;
724
- }
728
+ debug ! ( "drop_flag_reset_block({:?},{:?})" , self , mode) ;
725
729
726
- self . drop_flag_test_block ( drop_block, succ, unwind)
730
+ let block = self . new_block ( unwind, TerminatorKind :: Goto { target : succ } ) ;
731
+ let block_start = Location { block : block, statement_index : 0 } ;
732
+ self . elaborator . clear_drop_flag ( block_start, self . path , mode) ;
733
+ block
727
734
}
728
735
729
736
fn elaborated_drop_block < ' a > ( & mut self ) -> BasicBlock {
0 commit comments