@@ -107,6 +107,9 @@ pub struct Scope<'tcx> {
107
107
/// the extent of this scope within source code.
108
108
extent : CodeExtent ,
109
109
110
+ /// the span of that extent
111
+ extent_span : Span ,
112
+
110
113
/// Whether there's anything to do for the cleanup path, that is,
111
114
/// when unwinding through this scope. This includes destructors,
112
115
/// but not StorageDead statements, which don't get emitted at all
@@ -116,7 +119,7 @@ pub struct Scope<'tcx> {
116
119
/// * pollutting the cleanup MIR with StorageDead creates
117
120
/// landing pads even though there's no actual destructors
118
121
/// * freeing up stack space has no effect during unwinding
119
- pub ( super ) needs_cleanup : bool ,
122
+ needs_cleanup : bool ,
120
123
121
124
/// set of lvalues to drop when exiting this scope. This starts
122
125
/// out empty but grows as variables are declared during the
@@ -197,6 +200,15 @@ pub struct BreakableScope<'tcx> {
197
200
pub break_destination : Lvalue < ' tcx > ,
198
201
}
199
202
203
+ impl DropKind {
204
+ fn may_panic ( & self ) -> bool {
205
+ match * self {
206
+ DropKind :: Value { .. } => true ,
207
+ DropKind :: Storage => false
208
+ }
209
+ }
210
+ }
211
+
200
212
impl < ' tcx > Scope < ' tcx > {
201
213
/// Invalidate all the cached blocks in the scope.
202
214
///
@@ -282,7 +294,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
282
294
where F : FnOnce ( & mut Builder < ' a , ' gcx , ' tcx > ) -> BlockAnd < R >
283
295
{
284
296
debug ! ( "in_opt_scope(opt_extent={:?}, block={:?})" , opt_extent, block) ;
285
- if let Some ( extent) = opt_extent { self . push_scope ( extent. 0 ) ; }
297
+ if let Some ( extent) = opt_extent { self . push_scope ( extent) ; }
286
298
let rv = unpack ! ( block = f( self ) ) ;
287
299
if let Some ( extent) = opt_extent {
288
300
unpack ! ( block = self . pop_scope( extent, block) ) ;
@@ -301,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
301
313
where F : FnOnce ( & mut Builder < ' a , ' gcx , ' tcx > ) -> BlockAnd < R >
302
314
{
303
315
debug ! ( "in_scope(extent={:?}, block={:?})" , extent, block) ;
304
- self . push_scope ( extent. 0 ) ;
316
+ self . push_scope ( extent) ;
305
317
let rv = unpack ! ( block = f( self ) ) ;
306
318
unpack ! ( block = self . pop_scope( extent, block) ) ;
307
319
debug ! ( "in_scope: exiting extent={:?} block={:?}" , extent, block) ;
@@ -312,12 +324,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
312
324
/// scope and call `pop_scope` afterwards. Note that these two
313
325
/// calls must be paired; using `in_scope` as a convenience
314
326
/// wrapper maybe preferable.
315
- pub fn push_scope ( & mut self , extent : CodeExtent ) {
327
+ pub fn push_scope ( & mut self , extent : ( CodeExtent , SourceInfo ) ) {
316
328
debug ! ( "push_scope({:?})" , extent) ;
317
329
let vis_scope = self . visibility_scope ;
318
330
self . scopes . push ( Scope {
319
331
visibility_scope : vis_scope,
320
- extent : extent,
332
+ extent : extent. 0 ,
333
+ extent_span : extent. 1 . span ,
321
334
needs_cleanup : false ,
322
335
drops : vec ! [ ] ,
323
336
free : None ,
@@ -333,9 +346,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
333
346
mut block : BasicBlock )
334
347
-> BlockAnd < ( ) > {
335
348
debug ! ( "pop_scope({:?}, {:?})" , extent, block) ;
336
- // We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
337
- // to make sure all the `cached_block`s are filled in.
338
- self . diverge_cleanup ( extent. 1 . span ) ;
349
+ // If we are emitting a `drop` statement, we need to have the cached
350
+ // diverge cleanup pads ready in case that drop panics.
351
+ let may_panic =
352
+ self . scopes . last ( ) . unwrap ( ) . drops . iter ( ) . any ( |s| s. kind . may_panic ( ) ) ;
353
+ if may_panic {
354
+ self . diverge_cleanup ( ) ;
355
+ }
339
356
let scope = self . scopes . pop ( ) . unwrap ( ) ;
340
357
assert_eq ! ( scope. extent, extent. 0 ) ;
341
358
unpack ! ( block = build_scope_drops( & mut self . cfg,
@@ -366,6 +383,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
366
383
let len = self . scopes . len ( ) ;
367
384
assert ! ( scope_count < len, "should not use `exit_scope` to pop ALL scopes" ) ;
368
385
let tmp = self . get_unit_temp ( ) ;
386
+
387
+ // If we are emitting a `drop` statement, we need to have the cached
388
+ // diverge cleanup pads ready in case that drop panics.
389
+ let may_panic = self . scopes [ ( len - scope_count) ..] . iter ( )
390
+ . any ( |s| s. drops . iter ( ) . any ( |s| s. kind . may_panic ( ) ) ) ;
391
+ if may_panic {
392
+ self . diverge_cleanup ( ) ;
393
+ }
394
+
369
395
{
370
396
let mut rest = & mut self . scopes [ ( len - scope_count) ..] ;
371
397
while let Some ( ( scope, rest_) ) = { rest} . split_last_mut ( ) {
@@ -618,7 +644,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
618
644
/// This path terminates in Resume. Returns the start of the path.
619
645
/// See module comment for more details. None indicates there’s no
620
646
/// cleanup to do at this point.
621
- pub fn diverge_cleanup ( & mut self , span : Span ) -> Option < BasicBlock > {
647
+ pub fn diverge_cleanup ( & mut self ) -> Option < BasicBlock > {
622
648
if !self . scopes . iter ( ) . any ( |scope| scope. needs_cleanup ) {
623
649
return None ;
624
650
}
@@ -652,7 +678,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
652
678
} ;
653
679
654
680
for scope in scopes. iter_mut ( ) {
655
- target = build_diverge_scope ( hir. tcx ( ) , cfg, & unit_temp, span, scope, target) ;
681
+ target = build_diverge_scope (
682
+ hir. tcx ( ) , cfg, & unit_temp, scope. extent_span , scope, target) ;
656
683
}
657
684
Some ( target)
658
685
}
@@ -668,7 +695,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
668
695
}
669
696
let source_info = self . source_info ( span) ;
670
697
let next_target = self . cfg . start_new_block ( ) ;
671
- let diverge_target = self . diverge_cleanup ( span ) ;
698
+ let diverge_target = self . diverge_cleanup ( ) ;
672
699
self . cfg . terminate ( block, source_info,
673
700
TerminatorKind :: Drop {
674
701
location : location,
@@ -686,7 +713,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
686
713
value : Operand < ' tcx > ) -> BlockAnd < ( ) > {
687
714
let source_info = self . source_info ( span) ;
688
715
let next_target = self . cfg . start_new_block ( ) ;
689
- let diverge_target = self . diverge_cleanup ( span ) ;
716
+ let diverge_target = self . diverge_cleanup ( ) ;
690
717
self . cfg . terminate ( block, source_info,
691
718
TerminatorKind :: DropAndReplace {
692
719
location : location,
@@ -709,7 +736,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
709
736
let source_info = self . source_info ( span) ;
710
737
711
738
let success_block = self . cfg . start_new_block ( ) ;
712
- let cleanup = self . diverge_cleanup ( span ) ;
739
+ let cleanup = self . diverge_cleanup ( ) ;
713
740
714
741
self . cfg . terminate ( block, source_info,
715
742
TerminatorKind :: Assert {
@@ -731,45 +758,48 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
731
758
mut block : BasicBlock ,
732
759
arg_count : usize )
733
760
-> BlockAnd < ( ) > {
761
+ debug ! ( "build_scope_drops({:?} -> {:?})" , block, scope) ;
734
762
let mut iter = scope. drops . iter ( ) . rev ( ) . peekable ( ) ;
735
763
while let Some ( drop_data) = iter. next ( ) {
736
764
let source_info = scope. source_info ( drop_data. span ) ;
737
- if let DropKind :: Value { .. } = drop_data. kind {
738
- // Try to find the next block with its cached block
739
- // for us to diverge into in case the drop panics.
740
- let on_diverge = iter. peek ( ) . iter ( ) . filter_map ( |dd| {
741
- match dd. kind {
742
- DropKind :: Value { cached_block } => cached_block,
743
- DropKind :: Storage => None
744
- }
745
- } ) . next ( ) ;
746
- // If there’s no `cached_block`s within current scope,
747
- // we must look for one in the enclosing scope.
748
- let on_diverge = on_diverge. or_else ( ||{
749
- earlier_scopes. iter ( ) . rev ( ) . flat_map ( |s| s. cached_block ( ) ) . next ( )
750
- } ) ;
751
- let next = cfg. start_new_block ( ) ;
752
- cfg. terminate ( block, source_info, TerminatorKind :: Drop {
753
- location : drop_data. location . clone ( ) ,
754
- target : next,
755
- unwind : on_diverge
756
- } ) ;
757
- block = next;
758
- }
759
765
match drop_data. kind {
760
- DropKind :: Value { .. } |
761
- DropKind :: Storage => {
762
- // Only temps and vars need their storage dead.
763
- match drop_data. location {
764
- Lvalue :: Local ( index) if index. index ( ) > arg_count => { }
765
- _ => continue
766
- }
766
+ DropKind :: Value { .. } => {
767
+ // Try to find the next block with its cached block
768
+ // for us to diverge into in case the drop panics.
769
+ let on_diverge = iter. peek ( ) . iter ( ) . filter_map ( |dd| {
770
+ match dd. kind {
771
+ DropKind :: Value { cached_block : None } =>
772
+ span_bug ! ( drop_data. span, "cached block not present?" ) ,
773
+ DropKind :: Value { cached_block } => cached_block,
774
+ DropKind :: Storage => None
775
+ }
776
+ } ) . next ( ) ;
777
+ // If there’s no `cached_block`s within current scope,
778
+ // we must look for one in the enclosing scope.
779
+ let on_diverge = on_diverge. or_else ( || {
780
+ earlier_scopes. iter ( ) . rev ( ) . flat_map ( |s| s. cached_block ( ) ) . next ( )
781
+ } ) ;
782
+ let next = cfg. start_new_block ( ) ;
783
+ cfg. terminate ( block, source_info, TerminatorKind :: Drop {
784
+ location : drop_data. location . clone ( ) ,
785
+ target : next,
786
+ unwind : on_diverge
787
+ } ) ;
788
+ block = next;
789
+ }
790
+ DropKind :: Storage => { }
791
+ }
767
792
793
+ // Drop the storage for both value and storage drops.
794
+ // Only temps and vars need their storage dead.
795
+ match drop_data. location {
796
+ Lvalue :: Local ( index) if index. index ( ) > arg_count => {
768
797
cfg. push ( block, Statement {
769
798
source_info : source_info,
770
799
kind : StatementKind :: StorageDead ( drop_data. location . clone ( ) )
771
800
} ) ;
772
801
}
802
+ _ => continue
773
803
}
774
804
}
775
805
block. unit ( )
0 commit comments