@@ -102,9 +102,6 @@ pub struct Scopes<'tcx> {
102102
103103 /// Drops that need to be done on paths to the `GeneratorDrop` terminator.
104104 generator_drops : DropTree ,
105-
106- // TODO: implement caching
107- // cached_unwind_drop: DropIdx,
108105}
109106
110107#[ derive( Debug ) ]
@@ -125,6 +122,14 @@ struct Scope {
125122 drops : Vec < DropData > ,
126123
127124 moved_locals : Vec < Local > ,
125+
126+ /// The drop index that will drop everything in and below this scope on an
127+ /// unwind path.
128+ cached_unwind_block : Option < DropIdx > ,
129+
130+ /// The drop index that will drop everything in and below this scope on a
131+ /// generator drop path.
132+ cached_generator_drop_block : Option < DropIdx > ,
128133}
129134
130135#[ derive( Clone , Copy , Debug ) ]
@@ -211,6 +216,11 @@ impl Scope {
211216 DropKind :: Storage => false ,
212217 } )
213218 }
219+
220+ fn invalidate_cache ( & mut self ) {
221+ self . cached_unwind_block = None ;
222+ self . cached_generator_drop_block = None ;
223+ }
214224}
215225
216226/// A trait that determined how [DropTree::lower_to_mir] creates its blocks and
@@ -387,6 +397,8 @@ impl<'tcx> Scopes<'tcx> {
387397 region_scope_span : region_scope. 1 . span ,
388398 drops : vec ! [ ] ,
389399 moved_locals : vec ! [ ] ,
400+ cached_unwind_block : None ,
401+ cached_generator_drop_block : None ,
390402 } ) ;
391403 }
392404
@@ -407,10 +419,6 @@ impl<'tcx> Scopes<'tcx> {
407419 } )
408420 }
409421
410- fn iter_mut ( & mut self ) -> impl DoubleEndedIterator < Item =& mut Scope > + ' _ {
411- self . scopes . iter_mut ( ) . rev ( )
412- }
413-
414422 /// Returns the topmost active scope, which is known to be alive until
415423 /// the next scope expression.
416424 fn topmost ( & self ) -> region:: Scope {
@@ -611,10 +619,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
611619 } else {
612620 self . scopes . breakable_scopes [ break_index] . continue_drops . as_mut ( ) . unwrap ( )
613621 } ;
614-
615- let mut drop_idx = DropIdx :: from_u32 ( destination. is_none ( ) as u32 ) ;
616- for drop in scope_drops {
617- drop_idx = drops. add_drop ( * drop, drop_idx) ;
622+ let mut drop_idx = ROOT_NODE ;
623+ for scope in & self . scopes . scopes [ scope_index + 1 ..] {
624+ for drop in & scope. drops {
625+ drop_idx = drops. add_drop ( * drop, drop_idx) ;
626+ }
618627 }
619628 drops. add_entry ( block, drop_idx) ;
620629 // `build_drop_tree` doesn't have access to our source_info, so we
@@ -671,19 +680,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
671680 ) )
672681 }
673682
674- /// Sets up a path that performs all required cleanup for dropping a generator.
675- ///
676- /// This path terminates in GeneratorDrop. Returns the start of the path.
677- /// None indicates there’s no cleanup to do at this point.
678- crate fn generator_drop_cleanup ( & mut self , yield_block : BasicBlock ) {
679- let drops = self . scopes . scopes . iter ( ) . flat_map ( |scope| & scope. drops ) ;
680- let mut next_drop = ROOT_NODE ;
681- for drop in drops {
682- next_drop = self . scopes . generator_drops . add_drop ( * drop, next_drop) ;
683- }
684- self . scopes . generator_drops . add_entry ( yield_block, next_drop) ;
685- }
686-
687683 /// Creates a new source scope, nested in the current one.
688684 crate fn new_source_scope ( & mut self ,
689685 span : Span ,
@@ -778,8 +774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
778774 local : Local ,
779775 drop_kind : DropKind ,
780776 ) {
781- // TODO: add back in caching.
782- let _needs_drop = match drop_kind {
777+ let needs_drop = match drop_kind {
783778 DropKind :: Value => {
784779 if !self . hir . needs_drop ( self . local_decls [ local] . ty ) { return }
785780 true
@@ -796,21 +791,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
796791 }
797792 } ;
798793
799- let scope = self . scopes . iter_mut ( )
800- . find ( |scope| scope . region_scope == region_scope )
801- . unwrap_or_else ( || {
802- span_bug ! ( span , "region scope {:?} not in scope to drop {:?}" , region_scope , local ) ;
803- } ) ;
794+ let invalidate_caches = needs_drop || self . is_generator ;
795+ for scope in self . scopes . scopes . iter_mut ( ) . rev ( ) {
796+ if invalidate_caches {
797+ scope. invalidate_cache ( ) ;
798+ }
804799
805- let region_scope_span = region_scope. span ( self . hir . tcx ( ) , & self . hir . region_scope_tree ) ;
806- // Attribute scope exit drops to scope's closing brace.
807- let scope_end = self . hir . tcx ( ) . sess . source_map ( ) . end_point ( region_scope_span) ;
800+ if scope. region_scope == region_scope {
801+ let region_scope_span = region_scope. span ( self . hir . tcx ( ) , & self . hir . region_scope_tree ) ;
802+ // Attribute scope exit drops to scope's closing brace.
803+ let scope_end = self . hir . tcx ( ) . sess . source_map ( ) . end_point ( region_scope_span) ;
808804
809- scope. drops . push ( DropData {
810- source_info : SourceInfo { span : scope_end, scope : scope. source_scope } ,
811- local,
812- kind : drop_kind,
813- } ) ;
805+ scope. drops . push ( DropData {
806+ source_info : SourceInfo { span : scope_end, scope : scope. source_scope } ,
807+ local,
808+ kind : drop_kind,
809+ } ) ;
810+
811+ return ;
812+ }
813+ }
814+
815+ span_bug ! ( span, "region scope {:?} not in scope to drop {:?}" , region_scope, local) ;
814816 }
815817
816818 /// Indicates that the "local operand" stored in `local` is
@@ -857,7 +859,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
857859 }
858860
859861 Some ( local_scope) => {
860- self . scopes . iter_mut ( ) . find ( |scope| scope. region_scope == local_scope)
862+ self . scopes . scopes . iter_mut ( ) . rfind ( |scope| scope. region_scope == local_scope)
861863 . unwrap_or_else ( || bug ! ( "scope {:?} not found in scope list!" , local_scope) )
862864 }
863865 } ;
@@ -914,6 +916,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
914916 // Manually drop the condition on both branches.
915917 let top_scope = self . scopes . scopes . last_mut ( ) . unwrap ( ) ;
916918 let top_drop_data = top_scope. drops . pop ( ) . unwrap ( ) ;
919+ if self . is_generator {
920+ top_scope. invalidate_cache ( ) ;
921+ }
917922
918923 match top_drop_data. kind {
919924 DropKind :: Value { .. } => {
@@ -950,14 +955,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
950955
951956 fn diverge_cleanup ( & mut self ) -> DropIdx {
952957 let is_generator = self . is_generator ;
953- let drops = self . scopes . scopes . iter ( )
954- . flat_map ( |scope| & scope. drops )
955- . filter ( |drop| is_generator || drop. kind == DropKind :: Value ) ;
956- let mut next_drop = ROOT_NODE ;
957- for drop in drops {
958- next_drop = self . scopes . unwind_drops . add_drop ( * drop, next_drop) ;
958+ let ( uncached_scope, mut cached_drop) = self . scopes . scopes . iter ( ) . enumerate ( ) . rev ( )
959+ . find_map ( |( scope_idx, scope) | {
960+ scope. cached_unwind_block . map ( |cached_block| ( scope_idx + 1 , cached_block) )
961+ } )
962+ . unwrap_or ( ( 0 , ROOT_NODE ) ) ;
963+ for scope in & mut self . scopes . scopes [ uncached_scope..] {
964+ for drop in & scope. drops {
965+ if is_generator || drop. kind == DropKind :: Value {
966+ cached_drop = self . scopes . unwind_drops . add_drop ( * drop, cached_drop) ;
967+ }
968+ }
969+ scope. cached_unwind_block = Some ( cached_drop) ;
959970 }
960- next_drop
971+ cached_drop
961972 }
962973
963974 /// Prepares to create a path that performs all required cleanup for
@@ -970,6 +981,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
970981 self . scopes . unwind_drops . add_entry ( start, next_drop) ;
971982 }
972983
984+ /// Sets up a path that performs all required cleanup for dropping a generator.
985+ ///
986+ /// This path terminates in GeneratorDrop. Returns the start of the path.
987+ /// None indicates there’s no cleanup to do at this point.
988+ crate fn generator_drop_cleanup ( & mut self , yield_block : BasicBlock ) {
989+ let ( uncached_scope, mut cached_drop) = self . scopes . scopes . iter ( ) . enumerate ( ) . rev ( )
990+ . find_map ( |( scope_idx, scope) | {
991+ scope. cached_generator_drop_block . map ( |cached_block| ( scope_idx + 1 , cached_block) )
992+ } )
993+ . unwrap_or ( ( 0 , ROOT_NODE ) ) ;
994+ for scope in & mut self . scopes . scopes [ uncached_scope..] {
995+ for drop in & scope. drops {
996+ cached_drop = self . scopes . generator_drops . add_drop ( * drop, cached_drop) ;
997+ }
998+ scope. cached_generator_drop_block = Some ( cached_drop) ;
999+ }
1000+ self . scopes . generator_drops . add_entry ( yield_block, cached_drop) ;
1001+ }
1002+
9731003 /// Utility function for *non*-scope code to build their own drops
9741004 crate fn build_drop_and_replace ( & mut self ,
9751005 block : BasicBlock ,
@@ -1027,6 +1057,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10271057 assert_eq ! ( top_scope. region_scope, region_scope) ;
10281058
10291059 top_scope. drops . clear ( ) ;
1060+ top_scope. invalidate_cache ( ) ;
10301061 }
10311062}
10321063
0 commit comments