@@ -124,10 +124,7 @@ pub struct Scope<'tcx> {
124124 /// The cache for drop chain on "generator drop" exit.
125125 cached_generator_drop : Option < BasicBlock > ,
126126
127- /// The cache for drop chain on "unwind" exit. This block
128- /// contains code to run the current drop and all the preceding
129- /// drops (i.e., those having lower index in Drop’s Scope drop
130- /// array)
127+ /// The cache for drop chain on "unwind" exit.
131128 cached_unwind : CachedBlock ,
132129}
133130
@@ -144,7 +141,21 @@ struct DropData<'tcx> {
144141}
145142
146143#[ derive( Debug , Default , Clone , Copy ) ]
147- pub ( crate ) struct CachedBlock ( Option < BasicBlock > ) ;
144+ pub ( crate ) struct CachedBlock {
145+ /// The cached block for the cleanups-on-diverge path. This block
146+ /// contains code to run the current drop and all the preceding
147+ /// drops (i.e., those having lower index in Drop’s Scope drop
148+ /// array)
149+ unwind : Option < BasicBlock > ,
150+
151+ /// The cached block for unwinds during cleanups-on-generator-drop path
152+ ///
153+ /// This is split from the standard unwind path here to prevent drop
154+ /// elaboration from creating drop flags that would have to be captured
155+ /// by the generator. I'm not sure how important this optimization is,
156+ /// but it is here.
157+ generator_drop : Option < BasicBlock > ,
158+ }
148159
149160#[ derive( Debug ) ]
150161pub ( crate ) enum DropKind {
@@ -170,15 +181,24 @@ pub struct BreakableScope<'tcx> {
170181
171182impl CachedBlock {
172183 fn invalidate ( & mut self ) {
173- self . 0 = None ;
184+ self . generator_drop = None ;
185+ self . unwind = None ;
174186 }
175187
176- fn get ( & self ) -> Option < BasicBlock > {
177- self . 0
188+ fn get ( & self , generator_drop : bool ) -> Option < BasicBlock > {
189+ if generator_drop {
190+ self . generator_drop
191+ } else {
192+ self . unwind
193+ }
178194 }
179195
180- fn ref_mut ( & mut self ) -> & mut Option < BasicBlock > {
181- & mut self . 0
196+ fn ref_mut ( & mut self , generator_drop : bool ) -> & mut Option < BasicBlock > {
197+ if generator_drop {
198+ & mut self . generator_drop
199+ } else {
200+ & mut self . unwind
201+ }
182202 }
183203}
184204
@@ -358,7 +378,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
358378 assert_eq ! ( scope. region_scope, region_scope. 0 ) ;
359379
360380 let unwind_to = self . scopes . last ( ) . and_then ( |next_scope| {
361- next_scope. cached_unwind . get ( )
381+ next_scope. cached_unwind . get ( false )
362382 } ) . unwrap_or_else ( || self . resume_block ( ) ) ;
363383
364384 unpack ! ( block = build_scope_drops(
@@ -367,6 +387,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
367387 block,
368388 unwind_to,
369389 self . arg_count,
390+ false ,
370391 ) ) ;
371392
372393 block. unit ( )
@@ -421,7 +442,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
421442 }
422443 } ;
423444
424- let unwind_to = next_scope. cached_unwind . get ( ) . unwrap_or_else ( || {
445+ let unwind_to = next_scope. cached_unwind . get ( false ) . unwrap_or_else ( || {
425446 debug_assert ! ( !may_panic, "cached block not present?" ) ;
426447 START_BLOCK
427448 } ) ;
@@ -432,6 +453,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
432453 block,
433454 unwind_to,
434455 self . arg_count,
456+ false ,
435457 ) ) ;
436458
437459 scope = next_scope;
@@ -448,7 +470,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
448470 /// None indicates there’s no cleanup to do at this point.
449471 pub fn generator_drop_cleanup ( & mut self ) -> Option < BasicBlock > {
450472 // Fill in the cache for unwinds
451- self . diverge_cleanup_gen ( ) ;
473+ self . diverge_cleanup_gen ( true ) ;
452474
453475 let src_info = self . scopes [ 0 ] . source_info ( self . fn_span ) ;
454476 let resume_block = self . resume_block ( ) ;
@@ -474,7 +496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
474496 } ;
475497
476498 let unwind_to = scopes. peek ( ) . as_ref ( ) . map ( |scope| {
477- scope. cached_unwind . get ( ) . unwrap_or_else ( || {
499+ scope. cached_unwind . get ( true ) . unwrap_or_else ( || {
478500 span_bug ! ( src_info. span, "cached block not present?" )
479501 } )
480502 } ) . unwrap_or ( resume_block) ;
@@ -485,6 +507,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
485507 block,
486508 unwind_to,
487509 self . arg_count,
510+ true ,
488511 ) ) ;
489512 }
490513
@@ -737,7 +760,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
737760 /// This path terminates in Resume. Returns the start of the path.
738761 /// See module comment for more details.
739762 pub fn diverge_cleanup ( & mut self ) -> BasicBlock {
740- self . diverge_cleanup_gen ( )
763+ self . diverge_cleanup_gen ( false )
741764 }
742765
743766 fn resume_block ( & mut self ) -> BasicBlock {
@@ -756,7 +779,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
756779 }
757780 }
758781
759- fn diverge_cleanup_gen ( & mut self ) -> BasicBlock {
782+ fn diverge_cleanup_gen ( & mut self , generator_drop : bool ) -> BasicBlock {
760783 // Build up the drops in **reverse** order. The end result will
761784 // look like:
762785 //
@@ -770,15 +793,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
770793
771794 // Find the last cached block
772795 let ( mut target, first_uncached) = if let Some ( cached_index) = self . scopes . iter ( )
773- . rposition ( |scope| scope. cached_unwind . get ( ) . is_some ( ) ) {
774- ( self . scopes [ cached_index] . cached_unwind . get ( ) . unwrap ( ) , cached_index + 1 )
796+ . rposition ( |scope| scope. cached_unwind . get ( generator_drop ) . is_some ( ) ) {
797+ ( self . scopes [ cached_index] . cached_unwind . get ( generator_drop ) . unwrap ( ) , cached_index + 1 )
775798 } else {
776799 ( self . resume_block ( ) , 0 )
777800 } ;
778801
779802 for scope in self . scopes [ first_uncached..] . iter_mut ( ) {
780803 target = build_diverge_scope ( & mut self . cfg , scope. region_scope_span ,
781- scope, target, self . is_generator ) ;
804+ scope, target, generator_drop , self . is_generator ) ;
782805 }
783806
784807 target
@@ -858,6 +881,7 @@ fn build_scope_drops<'tcx>(
858881 mut block : BasicBlock ,
859882 last_unwind_to : BasicBlock ,
860883 arg_count : usize ,
884+ generator_drop : bool ,
861885) -> BlockAnd < ( ) > {
862886 debug ! ( "build_scope_drops({:?} -> {:?}" , block, scope) ;
863887
@@ -878,7 +902,7 @@ fn build_scope_drops<'tcx>(
878902
879903 let mut unwind_blocks = scope. drops . iter ( ) . rev ( ) . filter_map ( |drop_data| {
880904 if let DropKind :: Value { cached_block } = drop_data. kind {
881- Some ( cached_block. get ( ) . unwrap_or_else ( || {
905+ Some ( cached_block. get ( generator_drop ) . unwrap_or_else ( || {
882906 span_bug ! ( drop_data. span, "cached block not present?" )
883907 } ) )
884908 } else {
@@ -922,12 +946,13 @@ fn build_scope_drops<'tcx>(
922946 block. unit ( )
923947}
924948
925- fn build_diverge_scope ( cfg : & mut CFG < ' tcx > ,
926- span : Span ,
927- scope : & mut Scope < ' tcx > ,
928- mut target : BasicBlock ,
929- is_generator : bool )
930- -> BasicBlock
949+ fn build_diverge_scope < ' tcx > ( cfg : & mut CFG < ' tcx > ,
950+ span : Span ,
951+ scope : & mut Scope < ' tcx > ,
952+ mut target : BasicBlock ,
953+ generator_drop : bool ,
954+ is_generator : bool )
955+ -> BasicBlock
931956{
932957 // Build up the drops in **reverse** order. The end result will
933958 // look like:
@@ -979,7 +1004,7 @@ fn build_diverge_scope(cfg: &mut CFG<'tcx>,
9791004 }
9801005 DropKind :: Storage => { }
9811006 DropKind :: Value { ref mut cached_block } => {
982- let cached_block = cached_block. ref_mut ( ) ;
1007+ let cached_block = cached_block. ref_mut ( generator_drop ) ;
9831008 target = if let Some ( cached_block) = * cached_block {
9841009 storage_deads. clear ( ) ;
9851010 target_built_by_us = false ;
@@ -1002,7 +1027,7 @@ fn build_diverge_scope(cfg: &mut CFG<'tcx>,
10021027 } ;
10031028 }
10041029 push_storage_deads ( cfg, & mut target, & mut storage_deads, target_built_by_us, source_scope) ;
1005- * scope. cached_unwind . ref_mut ( ) = Some ( target) ;
1030+ * scope. cached_unwind . ref_mut ( generator_drop ) = Some ( target) ;
10061031
10071032 assert ! ( storage_deads. is_empty( ) ) ;
10081033 debug ! ( "build_diverge_scope({:?}, {:?}) = {:?}" , scope, span, target) ;
0 commit comments