@@ -243,30 +243,37 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
243243 }
244244
245245 /// 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.
247248 ///
248249 /// `unwind_ladder` is such a list of steps in reverse order,
249250 /// which is called if the matching step of the drop glue panics.
250251 fn drop_halfladder ( & mut self ,
251252 unwind_ladder : & [ Unwind ] ,
252- succ : BasicBlock ,
253+ mut succ : BasicBlock ,
253254 fields : & [ ( Lvalue < ' tcx > , Option < D :: Path > ) ] )
254255 -> Vec < BasicBlock >
255256 {
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+ )
270277 }
271278
272279 /// 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>
283290 /// ELAB(drop location.1 [target=.c2])
284291 /// .c2:
285292 /// 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`.
286296 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 )
288300 -> ( BasicBlock , Unwind )
289301 {
290302 debug ! ( "drop_ladder({:?}, {:?})" , self , fields) ;
@@ -297,20 +309,17 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
297309 debug ! ( "drop_ladder - fields needing drop: {:?}" , fields) ;
298310
299311 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 {
301313 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 ( )
304315 } else {
305316 unwind_ladder
306317 } ;
307318
308- let succ = self . succ ; // FIXME(#6393)
309319 let normal_ladder =
310320 self . drop_halfladder ( & unwind_ladder, succ, & fields) ;
311321
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 ( ) )
314323 }
315324
316325 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>
323332 self . elaborator . field_subpath ( self . path , Field :: new ( i) ) )
324333 } ) . collect ( ) ;
325334
326- self . drop_ladder ( fields) . 0
335+ let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
336+ self . drop_ladder ( fields, succ, unwind) . 0
327337 }
328338
329339 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>
370380 }
371381 }
372382
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 ;
389414
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)
405421 ) ;
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 ( ) ) ;
463452 }
453+ let ( normal, _) = self . drop_ladder ( fields, succ, unwind) ;
454+ normal_blocks. push ( normal) ;
455+ } else {
456+ have_otherwise = true ;
457+ }
458+ }
464459
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+ ) ;
471466 }
467+ } else {
468+ values. pop ( ) ;
472469 }
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+ } ) )
473477 }
474478
475479 fn adt_switch_block ( & mut self ,
@@ -652,8 +656,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
652656 } ) ;
653657
654658 // 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)
657661 }
658662
659663 /// 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>
707711 debug ! ( "complete_drop({:?},{:?})" , self , drop_mode) ;
708712
709713 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)
711721 }
712722
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
718727 {
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) ;
725729
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
727734 }
728735
729736 fn elaborated_drop_block < ' a > ( & mut self ) -> BasicBlock {
0 commit comments