@@ -105,8 +105,6 @@ pub struct Scopes<'tcx> {
105105
106106 /// Drops that need to be done on paths to the `GeneratorDrop` terminator.
107107 generator_drops : DropTree ,
108- // TODO: implement caching
109- // cached_unwind_drop: DropIdx,
110108}
111109
112110#[ derive( Debug ) ]
@@ -127,6 +125,14 @@ struct Scope {
127125 drops : Vec < DropData > ,
128126
129127 moved_locals : Vec < Local > ,
128+
129+ /// The drop index that will drop everything in and below this scope on an
130+ /// unwind path.
131+ cached_unwind_block : Option < DropIdx > ,
132+
133+ /// The drop index that will drop everything in and below this scope on a
134+ /// generator drop path.
135+ cached_generator_drop_block : Option < DropIdx > ,
130136}
131137
132138#[ derive( Clone , Copy , Debug ) ]
@@ -213,6 +219,11 @@ impl Scope {
213219 DropKind :: Storage => false ,
214220 } )
215221 }
222+
223+ fn invalidate_cache ( & mut self ) {
224+ self . cached_unwind_block = None ;
225+ self . cached_generator_drop_block = None ;
226+ }
216227}
217228
218229/// A trait that determined how [DropTree::lower_to_mir] creates its blocks and
@@ -229,11 +240,7 @@ impl DropTree {
229240 DropData { source_info : fake_source_info, local : Local :: MAX , kind : DropKind :: Storage } ;
230241 let drop_idx = DropIdx :: MAX ;
231242 let drops = IndexVec :: from_elem_n ( ( fake_data, drop_idx) , 1 ) ;
232- Self {
233- drops,
234- entry_points : Vec :: new ( ) ,
235- previous_drops : FxHashMap :: default ( ) ,
236- }
243+ Self { drops, entry_points : Vec :: new ( ) , previous_drops : FxHashMap :: default ( ) }
237244 }
238245
239246 fn add_drop ( & mut self , drop : DropData , next : DropIdx ) -> DropIdx {
@@ -383,6 +390,8 @@ impl<'tcx> Scopes<'tcx> {
383390 region_scope_span : region_scope. 1 . span ,
384391 drops : vec ! [ ] ,
385392 moved_locals : vec ! [ ] ,
393+ cached_unwind_block : None ,
394+ cached_generator_drop_block : None ,
386395 } ) ;
387396 }
388397
@@ -399,10 +408,6 @@ impl<'tcx> Scopes<'tcx> {
399408 . unwrap_or_else ( || span_bug ! ( span, "region_scope {:?} does not enclose" , region_scope) )
400409 }
401410
402- fn iter_mut ( & mut self ) -> impl DoubleEndedIterator < Item = & mut Scope > + ' _ {
403- self . scopes . iter_mut ( ) . rev ( )
404- }
405-
406411 /// Returns the topmost active scope, which is known to be alive until
407412 /// the next scope expression.
408413 fn topmost ( & self ) -> region:: Scope {
@@ -609,10 +614,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
609614 } else {
610615 self . scopes . breakable_scopes [ break_index] . continue_drops . as_mut ( ) . unwrap ( )
611616 } ;
612-
613- let mut drop_idx = DropIdx :: from_u32 ( destination. is_none ( ) as u32 ) ;
614- for drop in scope_drops {
615- drop_idx = drops. add_drop ( * drop, drop_idx) ;
617+ let mut drop_idx = ROOT_NODE ;
618+ for scope in & self . scopes . scopes [ scope_index + 1 ..] {
619+ for drop in & scope. drops {
620+ drop_idx = drops. add_drop ( * drop, drop_idx) ;
621+ }
616622 }
617623 drops. add_entry ( block, drop_idx) ;
618624 // `build_drop_tree` doesn't have access to our source_info, so we
@@ -668,19 +674,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
668674 ) )
669675 }
670676
671- /// Sets up a path that performs all required cleanup for dropping a generator.
672- ///
673- /// This path terminates in GeneratorDrop. Returns the start of the path.
674- /// None indicates there’s no cleanup to do at this point.
675- crate fn generator_drop_cleanup ( & mut self , yield_block : BasicBlock ) {
676- let drops = self . scopes . scopes . iter ( ) . flat_map ( |scope| & scope. drops ) ;
677- let mut next_drop = ROOT_NODE ;
678- for drop in drops {
679- next_drop = self . scopes . generator_drops . add_drop ( * drop, next_drop) ;
680- }
681- self . scopes . generator_drops . add_entry ( yield_block, next_drop) ;
682- }
683-
684677 /// Creates a new source scope, nested in the current one.
685678 crate fn new_source_scope (
686679 & mut self ,
@@ -777,8 +770,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
777770 local : Local ,
778771 drop_kind : DropKind ,
779772 ) {
780- // TODO: add back in caching.
781- let _needs_drop = match drop_kind {
773+ let needs_drop = match drop_kind {
782774 DropKind :: Value => {
783775 if !self . hir . needs_drop ( self . local_decls [ local] . ty ) {
784776 return ;
@@ -798,23 +790,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
798790 }
799791 } ;
800792
801- let scope = self
802- . scopes
803- . iter_mut ( )
804- . find ( |scope| scope. region_scope == region_scope)
805- . unwrap_or_else ( || {
806- span_bug ! ( span, "region scope {:?} not in scope to drop {:?}" , region_scope, local) ;
807- } ) ;
808-
809- let region_scope_span = region_scope. span ( self . hir . tcx ( ) , & self . hir . region_scope_tree ) ;
810- // Attribute scope exit drops to scope's closing brace.
811- let scope_end = self . hir . tcx ( ) . sess . source_map ( ) . end_point ( region_scope_span) ;
812-
813- scope. drops . push ( DropData {
814- source_info : SourceInfo { span : scope_end, scope : scope. source_scope } ,
815- local,
816- kind : drop_kind,
817- } ) ;
793+ let invalidate_caches = needs_drop || self . is_generator ;
794+ for scope in self . scopes . scopes . iter_mut ( ) . rev ( ) {
795+ if invalidate_caches {
796+ scope. invalidate_cache ( ) ;
797+ }
798+
799+ if scope. region_scope == region_scope {
800+ let region_scope_span =
801+ 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) ;
804+
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) ;
818816 }
819817
820818 /// Indicates that the "local operand" stored in `local` is
@@ -861,9 +859,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
861859 }
862860
863861 Some ( local_scope) => self
862+ . scopes
864863 . scopes
865864 . iter_mut ( )
866- . find ( |scope| scope. region_scope == local_scope)
865+ . rfind ( |scope| scope. region_scope == local_scope)
867866 . unwrap_or_else ( || bug ! ( "scope {:?} not found in scope list!" , local_scope) ) ,
868867 } ;
869868
@@ -913,6 +912,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
913912 // Manually drop the condition on both branches.
914913 let top_scope = self . scopes . scopes . last_mut ( ) . unwrap ( ) ;
915914 let top_drop_data = top_scope. drops . pop ( ) . unwrap ( ) ;
915+ if self . is_generator {
916+ top_scope. invalidate_cache ( ) ;
917+ }
916918
917919 match top_drop_data. kind {
918920 DropKind :: Value { .. } => {
@@ -943,17 +945,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
943945
944946 fn diverge_cleanup ( & mut self ) -> DropIdx {
945947 let is_generator = self . is_generator ;
946- let drops = self
948+ let ( uncached_scope , mut cached_drop ) = self
947949 . scopes
948950 . scopes
949951 . iter ( )
950- . flat_map ( |scope| & scope. drops )
951- . filter ( |drop| is_generator || drop. kind == DropKind :: Value ) ;
952- let mut next_drop = ROOT_NODE ;
953- for drop in drops {
954- next_drop = self . scopes . unwind_drops . add_drop ( * drop, next_drop) ;
952+ . enumerate ( )
953+ . rev ( )
954+ . find_map ( |( scope_idx, scope) | {
955+ scope. cached_unwind_block . map ( |cached_block| ( scope_idx + 1 , cached_block) )
956+ } )
957+ . unwrap_or ( ( 0 , ROOT_NODE ) ) ;
958+ for scope in & mut self . scopes . scopes [ uncached_scope..] {
959+ for drop in & scope. drops {
960+ if is_generator || drop. kind == DropKind :: Value {
961+ cached_drop = self . scopes . unwind_drops . add_drop ( * drop, cached_drop) ;
962+ }
963+ }
964+ scope. cached_unwind_block = Some ( cached_drop) ;
955965 }
956- next_drop
966+ cached_drop
957967 }
958968
959969 /// Prepares to create a path that performs all required cleanup for
@@ -966,6 +976,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
966976 self . scopes . unwind_drops . add_entry ( start, next_drop) ;
967977 }
968978
979+ /// Sets up a path that performs all required cleanup for dropping a generator.
980+ ///
981+ /// This path terminates in GeneratorDrop. Returns the start of the path.
982+ /// None indicates there’s no cleanup to do at this point.
983+ crate fn generator_drop_cleanup ( & mut self , yield_block : BasicBlock ) {
984+ let ( uncached_scope, mut cached_drop) = self
985+ . scopes
986+ . scopes
987+ . iter ( )
988+ . enumerate ( )
989+ . 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+
9691003 /// Utility function for *non*-scope code to build their own drops
9701004 crate fn build_drop_and_replace (
9711005 & mut self ,
@@ -1022,6 +1056,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10221056 assert_eq ! ( top_scope. region_scope, region_scope) ;
10231057
10241058 top_scope. drops . clear ( ) ;
1059+ top_scope. invalidate_cache ( ) ;
10251060 }
10261061}
10271062
0 commit comments