@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
262
262
ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
263
263
tcx : TyCtxt < ' tcx > ,
264
264
source : MirSource < ' tcx > ,
265
- can_const_prop : IndexVec < Local , bool > ,
265
+ can_const_prop : IndexVec < Local , ConstPropMode > ,
266
266
param_env : ParamEnv < ' tcx > ,
267
267
// FIXME(eddyb) avoid cloning these two fields more than once,
268
268
// by accessing them through `ecx` instead.
@@ -708,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
708
708
}
709
709
}
710
710
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
+
711
722
struct CanConstProp {
712
- can_const_prop : IndexVec < Local , bool > ,
723
+ can_const_prop : IndexVec < Local , ConstPropMode > ,
713
724
// false at the beginning, once set, there are not allowed to be any more assignments
714
725
found_assignment : IndexVec < Local , bool > ,
715
726
}
716
727
717
728
impl CanConstProp {
718
729
/// returns true if `local` can be propagated
719
- fn check ( body : ReadOnlyBodyAndCache < ' _ , ' _ > ) -> IndexVec < Local , bool > {
730
+ fn check ( body : ReadOnlyBodyAndCache < ' _ , ' _ > ) -> IndexVec < Local , ConstPropMode > {
720
731
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 ) ,
722
733
found_assignment : IndexVec :: from_elem ( false , & body. local_decls ) ,
723
734
} ;
724
735
for ( local, val) in cpv. can_const_prop . iter_enumerated_mut ( ) {
@@ -728,10 +739,10 @@ impl CanConstProp {
728
739
// FIXME(oli-obk): lint variables until they are used in a condition
729
740
// FIXME(oli-obk): lint if return value is constant
730
741
let local_kind = body. local_kind ( local) ;
731
- * val = local_kind == LocalKind :: Temp || local_kind == LocalKind :: ReturnPointer ;
732
742
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) ;
735
746
}
736
747
}
737
748
cpv. visit_body ( body) ;
@@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
753
764
// only occur in independent execution paths
754
765
MutatingUse ( MutatingUseContext :: Store ) => if self . found_assignment [ local] {
755
766
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 ;
757
768
} else {
758
769
self . found_assignment [ local] = true
759
770
} ,
@@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
766
777
NonUse ( _) => { } ,
767
778
_ => {
768
779
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 ;
770
781
} ,
771
782
}
772
783
}
@@ -800,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
800
811
if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
801
812
if let Some ( local) = place. as_local ( ) {
802
813
let source = statement. source_info ;
814
+ let can_const_prop = self . can_const_prop [ local] ;
803
815
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 {
807
818
if let Some ( value) = self . get_const ( local) {
808
819
if self . should_const_prop ( value) {
809
820
trace ! ( "replacing {:?} with {:?}" , rval, value) ;
@@ -812,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
812
823
value,
813
824
statement. source_info ,
814
825
) ;
826
+
827
+ if can_const_prop == ConstPropMode :: FullConstProp {
828
+ trace ! ( "propagated into {:?}" , local) ;
829
+ }
815
830
}
816
831
}
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) ;
822
838
}
823
839
}
824
840
}
825
841
}
826
842
} else {
827
843
match statement. kind {
828
844
StatementKind :: StorageLive ( local) |
829
- StatementKind :: StorageDead ( local) if self . can_const_prop [ local ] => {
845
+ StatementKind :: StorageDead ( local) => {
830
846
let frame = self . ecx . frame_mut ( ) ;
831
847
frame. locals [ local] . value =
832
848
if let StatementKind :: StorageLive ( _) = statement. kind {
0 commit comments