@@ -154,6 +154,11 @@ struct CachedBlock {
154
154
unwind : Option < BasicBlock > ,
155
155
156
156
/// The cached block for unwinds during cleanups-on-generator-drop path
157
+ ///
158
+ /// This is split from the standard unwind path here to prevent drop
159
+ /// elaboration from creating drop flags that would have to be captured
160
+ /// by the generator. I'm not sure how important this optimization is,
161
+ /// but it is here.
157
162
generator_drop : Option < BasicBlock > ,
158
163
}
159
164
@@ -217,13 +222,26 @@ impl<'tcx> Scope<'tcx> {
217
222
/// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
218
223
/// larger extent of code.
219
224
///
220
- /// `unwind` controls whether caches for the unwind branch are also invalidated.
221
- fn invalidate_cache ( & mut self , unwind : bool ) {
225
+ /// `storage_only` controls whether to invalidate only drop paths run `StorageDead`.
226
+ /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
227
+ /// top-of-scope (as opposed to dependent scopes).
228
+ fn invalidate_cache ( & mut self , storage_only : bool , this_scope_only : bool ) {
229
+ // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
230
+ // with lots of `try!`?
231
+
232
+ // cached exits drop storage and refer to the top-of-scope
222
233
self . cached_exits . clear ( ) ;
223
- if !unwind { return ; }
224
- for dropdata in & mut self . drops {
225
- if let DropKind :: Value { ref mut cached_block } = dropdata. kind {
226
- cached_block. invalidate ( ) ;
234
+
235
+ if !storage_only {
236
+ // the current generator drop ignores storage but refers to top-of-scope
237
+ self . cached_generator_drop = None ;
238
+ }
239
+
240
+ if !storage_only && !this_scope_only {
241
+ for dropdata in & mut self . drops {
242
+ if let DropKind :: Value { ref mut cached_block } = dropdata. kind {
243
+ cached_block. invalidate ( ) ;
244
+ }
227
245
}
228
246
}
229
247
}
@@ -672,8 +690,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
672
690
// invalidating caches of each scope visited. This way bare minimum of the
673
691
// caches gets invalidated. i.e. if a new drop is added into the middle scope, the
674
692
// cache of outer scpoe stays intact.
675
- let invalidate_unwind = needs_drop && !this_scope;
676
- scope. invalidate_cache ( invalidate_unwind) ;
693
+ scope. invalidate_cache ( !needs_drop, this_scope) ;
677
694
if this_scope {
678
695
if let DropKind :: Value { .. } = drop_kind {
679
696
scope. needs_cleanup = true ;
@@ -942,5 +959,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
942
959
target = block
943
960
}
944
961
962
+ debug ! ( "build_diverge_scope({:?}, {:?}) = {:?}" , scope, span, target) ;
963
+
945
964
target
946
965
}
0 commit comments