@@ -83,7 +83,7 @@ should go to.
83
83
*/
84
84
85
85
use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder , CFG } ;
86
- use crate :: hair:: { ExprRef , LintLevel } ;
86
+ use crate :: hair:: { Expr , ExprRef , LintLevel } ;
87
87
use rustc:: middle:: region;
88
88
use rustc:: ty:: Ty ;
89
89
use rustc:: hir;
@@ -829,6 +829,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
829
829
830
830
// Other
831
831
// =====
832
+ /// Branch based on a boolean condition.
833
+ ///
834
+ /// This is a special case because the temporary for the condition needs to
835
+ /// be dropped on both the true and the false arm.
836
+ pub fn test_bool (
837
+ & mut self ,
838
+ mut block : BasicBlock ,
839
+ condition : Expr < ' tcx > ,
840
+ source_info : SourceInfo ,
841
+ ) -> ( BasicBlock , BasicBlock ) {
842
+ let cond = unpack ! ( block = self . as_local_operand( block, condition) ) ;
843
+ let true_block = self . cfg . start_new_block ( ) ;
844
+ let false_block = self . cfg . start_new_block ( ) ;
845
+ let term = TerminatorKind :: if_ (
846
+ self . hir . tcx ( ) ,
847
+ cond. clone ( ) ,
848
+ true_block,
849
+ false_block,
850
+ ) ;
851
+ self . cfg . terminate ( block, source_info, term) ;
852
+
853
+ match cond {
854
+ // Don't try to drop a constant
855
+ Operand :: Constant ( _) => ( ) ,
856
+ // If constants and statics, we don't generate StorageLive for this
857
+ // temporary, so don't try to generate StorageDead for it either.
858
+ _ if self . local_scope ( ) . is_none ( ) => ( ) ,
859
+ Operand :: Copy ( Place :: Base ( PlaceBase :: Local ( cond_temp) ) )
860
+ | Operand :: Move ( Place :: Base ( PlaceBase :: Local ( cond_temp) ) ) => {
861
+ // Manually drop the condition on both branches.
862
+ let top_scope = self . scopes . scopes . last_mut ( ) . unwrap ( ) ;
863
+ let top_drop_data = top_scope. drops . pop ( ) . unwrap ( ) ;
864
+
865
+ match top_drop_data. kind {
866
+ DropKind :: Value { .. } => {
867
+ bug ! ( "Drop scheduled on top of condition variable" )
868
+ }
869
+ DropKind :: Storage => {
870
+ // Drop the storage for both value and storage drops.
871
+ // Only temps and vars need their storage dead.
872
+ match top_drop_data. location {
873
+ Place :: Base ( PlaceBase :: Local ( index) ) => {
874
+ let source_info = top_scope. source_info ( top_drop_data. span ) ;
875
+ assert_eq ! ( index, cond_temp, "Drop scheduled on top of condition" ) ;
876
+ self . cfg . push (
877
+ true_block,
878
+ Statement {
879
+ source_info,
880
+ kind : StatementKind :: StorageDead ( index)
881
+ } ,
882
+ ) ;
883
+ self . cfg . push (
884
+ false_block,
885
+ Statement {
886
+ source_info,
887
+ kind : StatementKind :: StorageDead ( index)
888
+ } ,
889
+ ) ;
890
+ }
891
+ _ => unreachable ! ( ) ,
892
+ }
893
+ }
894
+ }
895
+
896
+ top_scope. invalidate_cache ( true , self . is_generator , true ) ;
897
+ }
898
+ _ => bug ! ( "Expected as_local_operand to produce a temporary" ) ,
899
+ }
900
+
901
+ ( true_block, false_block)
902
+ }
903
+
832
904
/// Creates a path that performs all required cleanup for unwinding.
833
905
///
834
906
/// This path terminates in Resume. Returns the start of the path.
@@ -942,57 +1014,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
942
1014
top_scope. drops . clear ( ) ;
943
1015
top_scope. invalidate_cache ( false , self . is_generator , true ) ;
944
1016
}
945
-
946
- /// Drops the single variable provided
947
- ///
948
- /// * The scope must be the top scope.
949
- /// * The variable must be in that scope.
950
- /// * The variable must be at the top of that scope: it's the next thing
951
- /// scheduled to drop.
952
- /// * The drop must be of `DropKind::Storage`.
953
- ///
954
- /// This is used for the boolean holding the result of the match guard. We
955
- /// do this because:
956
- ///
957
- /// * The boolean is different for each pattern
958
- /// * There is only one exit for the arm scope
959
- /// * The guard expression scope is too short, it ends just before the
960
- /// boolean is tested.
961
- pub ( crate ) fn pop_variable (
962
- & mut self ,
963
- block : BasicBlock ,
964
- region_scope : region:: Scope ,
965
- variable : Local ,
966
- ) {
967
- let top_scope = self . scopes . scopes . last_mut ( ) . unwrap ( ) ;
968
-
969
- assert_eq ! ( top_scope. region_scope, region_scope) ;
970
-
971
- let top_drop_data = top_scope. drops . pop ( ) . unwrap ( ) ;
972
-
973
- match top_drop_data. kind {
974
- DropKind :: Value { .. } => {
975
- bug ! ( "Should not be calling pop_top_variable on non-copy type!" )
976
- }
977
- DropKind :: Storage => {
978
- // Drop the storage for both value and storage drops.
979
- // Only temps and vars need their storage dead.
980
- match top_drop_data. location {
981
- Place :: Base ( PlaceBase :: Local ( index) ) => {
982
- let source_info = top_scope. source_info ( top_drop_data. span ) ;
983
- assert_eq ! ( index, variable) ;
984
- self . cfg . push ( block, Statement {
985
- source_info,
986
- kind : StatementKind :: StorageDead ( index)
987
- } ) ;
988
- }
989
- _ => unreachable ! ( ) ,
990
- }
991
- }
992
- }
993
-
994
- top_scope. invalidate_cache ( true , self . is_generator , true ) ;
995
- }
996
1017
}
997
1018
998
1019
/// Builds drops for pop_scope and exit_scope.
0 commit comments