@@ -83,7 +83,7 @@ that contains only loops and breakable blocks. It tracks where a `break`,
83
83
84
84
use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder , CFG } ;
85
85
use crate :: thir:: { Expr , ExprRef , LintLevel } ;
86
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
86
+ use rustc_data_structures:: fx:: FxHashMap ;
87
87
use rustc_index:: vec:: IndexVec ;
88
88
use rustc_middle:: middle:: region;
89
89
use rustc_middle:: mir:: * ;
@@ -120,6 +120,8 @@ struct Scope {
120
120
/// end of the vector (top of the stack) first.
121
121
drops : Vec < DropData > ,
122
122
123
+ moved_locals : Vec < Local > ,
124
+
123
125
/// The drop index that will drop everything in and below this scope on an
124
126
/// unwind path.
125
127
cached_unwind_block : Option < DropIdx > ,
@@ -403,6 +405,7 @@ impl<'tcx> Scopes<'tcx> {
403
405
region_scope : region_scope. 0 ,
404
406
region_scope_span : region_scope. 1 . span ,
405
407
drops : vec ! [ ] ,
408
+ moved_locals : vec ! [ ] ,
406
409
cached_unwind_block : None ,
407
410
cached_generator_drop_block : None ,
408
411
} ) ;
@@ -893,19 +896,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
893
896
) ;
894
897
895
898
// look for moves of a local variable, like `MOVE(_X)`
896
- let locals_moved = operands
897
- . iter ( )
898
- . filter_map ( |operand| match operand {
899
- Operand :: Copy ( _) | Operand :: Constant ( _) => None ,
900
- Operand :: Move ( place) => place. as_local ( ) ,
901
- } )
902
- . collect :: < FxHashSet < _ > > ( ) ;
899
+ let locals_moved = operands. iter ( ) . flat_map ( |operand| match operand {
900
+ Operand :: Copy ( _) | Operand :: Constant ( _) => None ,
901
+ Operand :: Move ( place) => place. as_local ( ) ,
902
+ } ) ;
903
903
904
- // Remove the drops for the moved operands.
905
- scope
906
- . drops
907
- . retain ( |drop| drop. kind == DropKind :: Storage || !locals_moved. contains ( & drop. local ) ) ;
908
- scope. invalidate_cache ( ) ;
904
+ for local in locals_moved {
905
+ // check if we have a Drop for this operand and -- if so
906
+ // -- add it to the list of moved operands. Note that this
907
+ // local might not have been an operand created for this
908
+ // call, it could come from other places too.
909
+ if scope. drops . iter ( ) . any ( |drop| drop. local == local && drop. kind == DropKind :: Value ) {
910
+ scope. moved_locals . push ( local) ;
911
+ }
912
+ }
909
913
}
910
914
911
915
// Other
@@ -1150,6 +1154,14 @@ fn build_scope_drops<'tcx>(
1150
1154
debug_assert_eq ! ( unwind_drops. drops[ unwind_to] . 0 . kind, drop_data. kind) ;
1151
1155
unwind_to = unwind_drops. drops [ unwind_to] . 1 ;
1152
1156
1157
+ // If the operand has been moved, and we are not on an unwind
1158
+ // path, then don't generate the drop. (We only take this into
1159
+ // account for non-unwind paths so as not to disturb the
1160
+ // caching mechanism.)
1161
+ if scope. moved_locals . iter ( ) . any ( |& o| o == local) {
1162
+ continue ;
1163
+ }
1164
+
1153
1165
unwind_drops. add_entry ( block, unwind_to) ;
1154
1166
1155
1167
let next = cfg. start_new_block ( ) ;
0 commit comments