@@ -102,9 +102,6 @@ pub struct Scopes<'tcx> {
102
102
103
103
/// Drops that need to be done on paths to the `GeneratorDrop` terminator.
104
104
generator_drops : DropTree ,
105
-
106
- // TODO: implement caching
107
- // cached_unwind_drop: DropIdx,
108
105
}
109
106
110
107
#[ derive( Debug ) ]
@@ -125,6 +122,14 @@ struct Scope {
125
122
drops : Vec < DropData > ,
126
123
127
124
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 > ,
128
133
}
129
134
130
135
#[ derive( Clone , Copy , Debug ) ]
@@ -211,6 +216,11 @@ impl Scope {
211
216
DropKind :: Storage => false ,
212
217
} )
213
218
}
219
+
220
+ fn invalidate_cache ( & mut self ) {
221
+ self . cached_unwind_block = None ;
222
+ self . cached_generator_drop_block = None ;
223
+ }
214
224
}
215
225
216
226
/// A trait that determined how [DropTree::lower_to_mir] creates its blocks and
@@ -387,6 +397,8 @@ impl<'tcx> Scopes<'tcx> {
387
397
region_scope_span : region_scope. 1 . span ,
388
398
drops : vec ! [ ] ,
389
399
moved_locals : vec ! [ ] ,
400
+ cached_unwind_block : None ,
401
+ cached_generator_drop_block : None ,
390
402
} ) ;
391
403
}
392
404
@@ -407,10 +419,6 @@ impl<'tcx> Scopes<'tcx> {
407
419
} )
408
420
}
409
421
410
- fn iter_mut ( & mut self ) -> impl DoubleEndedIterator < Item =& mut Scope > + ' _ {
411
- self . scopes . iter_mut ( ) . rev ( )
412
- }
413
-
414
422
/// Returns the topmost active scope, which is known to be alive until
415
423
/// the next scope expression.
416
424
fn topmost ( & self ) -> region:: Scope {
@@ -611,10 +619,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
611
619
} else {
612
620
self . scopes . breakable_scopes [ break_index] . continue_drops . as_mut ( ) . unwrap ( )
613
621
} ;
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
+ }
618
627
}
619
628
drops. add_entry ( block, drop_idx) ;
620
629
// `build_drop_tree` doesn't have access to our source_info, so we
@@ -671,19 +680,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
671
680
) )
672
681
}
673
682
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
-
687
683
/// Creates a new source scope, nested in the current one.
688
684
crate fn new_source_scope ( & mut self ,
689
685
span : Span ,
@@ -778,8 +774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
778
774
local : Local ,
779
775
drop_kind : DropKind ,
780
776
) {
781
- // TODO: add back in caching.
782
- let _needs_drop = match drop_kind {
777
+ let needs_drop = match drop_kind {
783
778
DropKind :: Value => {
784
779
if !self . hir . needs_drop ( self . local_decls [ local] . ty ) { return }
785
780
true
@@ -796,21 +791,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
796
791
}
797
792
} ;
798
793
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
+ }
804
799
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) ;
808
804
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) ;
814
816
}
815
817
816
818
/// Indicates that the "local operand" stored in `local` is
@@ -857,7 +859,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
857
859
}
858
860
859
861
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)
861
863
. unwrap_or_else ( || bug ! ( "scope {:?} not found in scope list!" , local_scope) )
862
864
}
863
865
} ;
@@ -914,6 +916,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
914
916
// Manually drop the condition on both branches.
915
917
let top_scope = self . scopes . scopes . last_mut ( ) . unwrap ( ) ;
916
918
let top_drop_data = top_scope. drops . pop ( ) . unwrap ( ) ;
919
+ if self . is_generator {
920
+ top_scope. invalidate_cache ( ) ;
921
+ }
917
922
918
923
match top_drop_data. kind {
919
924
DropKind :: Value { .. } => {
@@ -950,14 +955,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
950
955
951
956
fn diverge_cleanup ( & mut self ) -> DropIdx {
952
957
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) ;
959
970
}
960
- next_drop
971
+ cached_drop
961
972
}
962
973
963
974
/// Prepares to create a path that performs all required cleanup for
@@ -970,6 +981,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
970
981
self . scopes . unwind_drops . add_entry ( start, next_drop) ;
971
982
}
972
983
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
+
973
1003
/// Utility function for *non*-scope code to build their own drops
974
1004
crate fn build_drop_and_replace ( & mut self ,
975
1005
block : BasicBlock ,
@@ -1027,6 +1057,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1027
1057
assert_eq ! ( top_scope. region_scope, region_scope) ;
1028
1058
1029
1059
top_scope. drops . clear ( ) ;
1060
+ top_scope. invalidate_cache ( ) ;
1030
1061
}
1031
1062
}
1032
1063
0 commit comments