@@ -326,6 +326,8 @@ struct ConstPropagator<'mir, 'tcx> {
326326 // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store 
327327 // the last known `SourceInfo` here and just keep revisiting it. 
328328 source_info :  Option < SourceInfo > , 
329+  // Locals we need to forget at the end of the current block 
330+  locals_of_current_block :  BitSet < Local > , 
329331} 
330332
331333impl < ' mir ,  ' tcx >  LayoutOf  for  ConstPropagator < ' mir ,  ' tcx >  { 
@@ -395,6 +397,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
395397 //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it 
396398 local_decls :  body. local_decls . clone ( ) , 
397399 source_info :  None , 
400+  locals_of_current_block :  BitSet :: new_empty ( body. local_decls . len ( ) ) , 
398401 } 
399402 } 
400403
@@ -409,8 +412,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
409412 } 
410413 } 
411414
412-  fn  remove_const ( & mut  self ,  local :  Local )  { 
413-  self . ecx . frame_mut ( ) . locals [ local]  =
415+  /// Remove `local` from the pool of `Locals`. Allows writing to them, 
416+ /// but not reading from them anymore. 
417+ fn  remove_const ( ecx :  & mut  InterpCx < ' mir ,  ' tcx ,  ConstPropMachine < ' mir ,  ' tcx > > ,  local :  Local )  { 
418+  ecx. frame_mut ( ) . locals [ local]  =
414419 LocalState  {  value :  LocalValue :: Uninitialized ,  layout :  Cell :: new ( None )  } ; 
415420 } 
416421
@@ -756,6 +761,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
756761enum  ConstPropMode  { 
757762 /// The `Local` can be propagated into and reads of this `Local` can also be propagated. 
758763FullConstProp , 
764+  /// The `Local` can only be propagated into and from its own block. 
765+ OnlyInsideOwnBlock , 
759766 /// The `Local` can be propagated into but reads cannot be propagated. 
760767OnlyPropagateInto , 
761768 /// No propagation is allowed at all. 
@@ -787,10 +794,18 @@ impl CanConstProp {
787794 // lint for x != y 
788795 // FIXME(oli-obk): lint variables until they are used in a condition 
789796 // FIXME(oli-obk): lint if return value is constant 
790-  if  cpv. local_kinds [ local]  == LocalKind :: Arg  || cpv. local_kinds [ local]  == LocalKind :: Var 
791-  { 
797+  if  cpv. local_kinds [ local]  == LocalKind :: Arg  { 
792798 * val = ConstPropMode :: OnlyPropagateInto ; 
793-  trace ! ( "local {:?} can't be const propagated because it's not a temporary" ,  local) ; 
799+  trace ! ( 
800+  "local {:?} can't be const propagated because it's a function argument" , 
801+  local
802+  ) ; 
803+  }  else  if  cpv. local_kinds [ local]  == LocalKind :: Var  { 
804+  * val = ConstPropMode :: OnlyInsideOwnBlock ; 
805+  trace ! ( 
806+  "local {:?} will only be propagated inside its block, because it's a user variable" , 
807+  local
808+  ) ; 
794809 } 
795810 } 
796811 cpv. visit_body ( & body) ; 
@@ -858,25 +873,35 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
858873 if  let  Some ( local)  = place. as_local ( )  { 
859874 let  can_const_prop = self . can_const_prop [ local] ; 
860875 if  let  Some ( ( ) )  = self . const_prop ( rval,  place_layout,  source_info,  place)  { 
861-  if  can_const_prop ==  ConstPropMode :: FullConstProp 
862-  || can_const_prop ==  ConstPropMode :: OnlyPropagateInto 
863-  { 
876+  if  can_const_prop !=  ConstPropMode :: NoPropagation   { 
877+  // This will return None for Locals that are from other blocks, 
878+    // so it should be okay to propagate from here on down. 
864879 if  let  Some ( value)  = self . get_const ( local)  { 
865880 if  self . should_const_prop ( value)  { 
866881 trace ! ( "replacing {:?} with {:?}" ,  rval,  value) ; 
867882 self . replace_with_const ( rval,  value,  statement. source_info ) ; 
868- 
869-  if  can_const_prop == ConstPropMode :: FullConstProp  { 
883+  if  can_const_prop == ConstPropMode :: FullConstProp 
884+  || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock 
885+  { 
870886 trace ! ( "propagated into {:?}" ,  local) ; 
871887 } 
872888 } 
889+  if  can_const_prop == ConstPropMode :: OnlyInsideOwnBlock  { 
890+  trace ! ( 
891+  "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}" , 
892+  local
893+  ) ; 
894+  self . locals_of_current_block . insert ( local) ; 
895+  } 
873896 } 
874897 } 
875898 } 
876-  if  self . can_const_prop [ local]  != ConstPropMode :: FullConstProp  { 
899+  if  self . can_const_prop [ local]  == ConstPropMode :: OnlyPropagateInto 
900+  || self . can_const_prop [ local]  == ConstPropMode :: NoPropagation 
901+  { 
877902 trace ! ( "can't propagate into {:?}" ,  local) ; 
878903 if  local != RETURN_PLACE  { 
879-  self . remove_const ( local) ; 
904+  Self :: remove_const ( & mut   self . ecx ,   local) ; 
880905 } 
881906 } 
882907 } 
@@ -915,7 +940,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
915940 // doesn't use the invalid value 
916941 match  cond { 
917942 Operand :: Move ( ref  place)  | Operand :: Copy ( ref  place)  => { 
918-  self . remove_const ( place. local ) ; 
943+  Self :: remove_const ( & mut   self . ecx ,   place. local ) ; 
919944 } 
920945 Operand :: Constant ( _)  => { } 
921946 } 
@@ -992,5 +1017,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
9921017 //FIXME(wesleywiser) Call does have Operands that could be const-propagated 
9931018 TerminatorKind :: Call  {  .. }  => { } 
9941019 } 
1020+  // We remove all Locals which are restricted in propagation to their containing blocks. 
1021+  // We wouldn't need to clone, but the borrow checker can't see that we're not aliasing 
1022+  // the locals_of_current_block field, so we need to clone it first. 
1023+  // let ecx = &mut self.ecx; 
1024+  for  local in  self . locals_of_current_block . iter ( )  { 
1025+  Self :: remove_const ( & mut  self . ecx ,  local) ; 
1026+  } 
1027+  self . locals_of_current_block . clear ( ) ; 
9951028 } 
9961029} 
0 commit comments