@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
262262 ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
263263 tcx : TyCtxt < ' tcx > ,
264264 source : MirSource < ' tcx > ,
265- can_const_prop : IndexVec < Local , bool > ,
265+ can_const_prop : IndexVec < Local , ConstPropMode > ,
266266 param_env : ParamEnv < ' tcx > ,
267267 // FIXME(eddyb) avoid cloning these two fields more than once,
268268 // by accessing them through `ecx` instead.
@@ -708,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
708708 }
709709}
710710
711+ /// The mode that `ConstProp` is allowed to run in for a given `Local`.
712+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
713+ enum ConstPropMode {
714+ /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
715+ FullConstProp ,
716+ /// The `Local` can be propagated into but reads cannot be propagated.
717+ OnlyPropagateInto ,
718+ /// No propagation is allowed at all.
719+ NoPropagation ,
720+ }
721+
711722struct CanConstProp {
712- can_const_prop : IndexVec < Local , bool > ,
723+ can_const_prop : IndexVec < Local , ConstPropMode > ,
713724 // false at the beginning, once set, there are not allowed to be any more assignments
714725 found_assignment : IndexVec < Local , bool > ,
715726}
716727
717728impl CanConstProp {
718729 /// returns true if `local` can be propagated
719- fn check ( body : ReadOnlyBodyAndCache < ' _ , ' _ > ) -> IndexVec < Local , bool > {
730+ fn check ( body : ReadOnlyBodyAndCache < ' _ , ' _ > ) -> IndexVec < Local , ConstPropMode > {
720731 let mut cpv = CanConstProp {
721- can_const_prop : IndexVec :: from_elem ( true , & body. local_decls ) ,
732+ can_const_prop : IndexVec :: from_elem ( ConstPropMode :: FullConstProp , & body. local_decls ) ,
722733 found_assignment : IndexVec :: from_elem ( false , & body. local_decls ) ,
723734 } ;
724735 for ( local, val) in cpv. can_const_prop . iter_enumerated_mut ( ) {
@@ -728,10 +739,10 @@ impl CanConstProp {
728739 // FIXME(oli-obk): lint variables until they are used in a condition
729740 // FIXME(oli-obk): lint if return value is constant
730741 let local_kind = body. local_kind ( local) ;
731- * val = local_kind == LocalKind :: Temp || local_kind == LocalKind :: ReturnPointer ;
732742
733- if !* val {
734- trace ! ( "local {:?} can't be propagated because it's not a temporary" , local) ;
743+ if local_kind == LocalKind :: Arg || local_kind == LocalKind :: Var {
744+ * val = ConstPropMode :: OnlyPropagateInto ;
745+ trace ! ( "local {:?} can't be const propagated because it's not a temporary" , local) ;
735746 }
736747 }
737748 cpv. visit_body ( body) ;
@@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
753764 // only occur in independent execution paths
754765 MutatingUse ( MutatingUseContext :: Store ) => if self . found_assignment [ local] {
755766 trace ! ( "local {:?} can't be propagated because of multiple assignments" , local) ;
756- self . can_const_prop [ local] = false ;
767+ self . can_const_prop [ local] = ConstPropMode :: NoPropagation ;
757768 } else {
758769 self . found_assignment [ local] = true
759770 } ,
@@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
766777 NonUse ( _) => { } ,
767778 _ => {
768779 trace ! ( "local {:?} can't be propagaged because it's used: {:?}" , local, context) ;
769- self . can_const_prop [ local] = false ;
780+ self . can_const_prop [ local] = ConstPropMode :: NoPropagation ;
770781 } ,
771782 }
772783 }
@@ -800,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
800811 if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
801812 if let Some ( local) = place. as_local ( ) {
802813 let source = statement. source_info ;
814+ let can_const_prop = self . can_const_prop [ local] ;
803815 if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source, place) {
804- if self . can_const_prop [ local] {
805- trace ! ( "propagated into {:?}" , local) ;
806-
816+ if can_const_prop == ConstPropMode :: FullConstProp ||
817+ can_const_prop == ConstPropMode :: OnlyPropagateInto {
807818 if let Some ( value) = self . get_const ( local) {
808819 if self . should_const_prop ( value) {
809820 trace ! ( "replacing {:?} with {:?}" , rval, value) ;
@@ -812,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
812823 value,
813824 statement. source_info ,
814825 ) ;
826+
827+ if can_const_prop == ConstPropMode :: FullConstProp {
828+ trace ! ( "propagated into {:?}" , local) ;
829+ }
815830 }
816831 }
817- } else {
818- trace ! ( "can't propagate into {:?}" , local) ;
819- if local != RETURN_PLACE {
820- self . remove_const ( local) ;
821- }
832+ }
833+ }
834+ if self . can_const_prop [ local] != ConstPropMode :: FullConstProp {
835+ trace ! ( "can't propagate into {:?}" , local) ;
836+ if local != RETURN_PLACE {
837+ self . remove_const ( local) ;
822838 }
823839 }
824840 }
825841 }
826842 } else {
827843 match statement. kind {
828844 StatementKind :: StorageLive ( local) |
829- StatementKind :: StorageDead ( local) if self . can_const_prop [ local ] => {
845+ StatementKind :: StorageDead ( local) => {
830846 let frame = self . ecx . frame_mut ( ) ;
831847 frame. locals [ local] . value =
832848 if let StatementKind :: StorageLive ( _) = statement. kind {
0 commit comments