@@ -349,8 +349,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
349
349
}
350
350
}
351
351
352
- fn get_const(&self, local: Local ) -> Option<OpTy<'tcx>> {
353
- let op = self.ecx.access_local(self.ecx.frame(), local , None).ok();
352
+ fn get_const(&self, place: Place<'tcx> ) -> Option<OpTy<'tcx>> {
353
+ let op = self.ecx.eval_place_to_op(place , None).ok();
354
354
355
355
// Try to read the local as an immediate so that if it is representable as a scalar, we can
356
356
// handle it as such, but otherwise, just return the value as is.
@@ -772,13 +772,25 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
772
772
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
773
773
use rustc_middle::mir::visit::PlaceContext::*;
774
774
match context {
775
- // Constants must have at most one write
776
- // FIXME(oli-obk): we could be more powerful here, if the multiple writes
777
- // only occur in independent execution paths
778
- MutatingUse(MutatingUseContext::Store) => {
775
+ // Projections are fine, because `&mut foo.x` will be caught by
776
+ // `MutatingUseContext::Borrow` elsewhere.
777
+ MutatingUse(MutatingUseContext::Projection)
778
+ | MutatingUse(MutatingUseContext::Store) => {
779
779
if !self.found_assignment.insert(local) {
780
- trace!("local {:?} can't be propagated because of multiple assignments", local);
781
- self.can_const_prop[local] = ConstPropMode::NoPropagation;
780
+ match &mut self.can_const_prop[local] {
781
+ // If the local can only get propagated in its own block, then we don't have
782
+ // to worry about multiple assignments, as we'll nuke the const state at the
783
+ // end of the block anyway, and inside the block we overwrite previous
784
+ // states as applicable.
785
+ ConstPropMode::OnlyInsideOwnBlock => {}
786
+ other => {
787
+ trace!(
788
+ "local {:?} can't be propagated because of multiple assignments",
789
+ local,
790
+ );
791
+ *other = ConstPropMode::NoPropagation;
792
+ }
793
+ }
782
794
}
783
795
}
784
796
// Reading constants is allowed an arbitrary number of times
@@ -787,12 +799,6 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
787
799
| NonMutatingUse(NonMutatingUseContext::Inspect)
788
800
| NonMutatingUse(NonMutatingUseContext::Projection)
789
801
| NonUse(_) => {}
790
- // FIXME(felix91gr): explain the reasoning behind this
791
- MutatingUse(MutatingUseContext::Projection) => {
792
- if self.local_kinds[local] != LocalKind::Temp {
793
- self.can_const_prop[local] = ConstPropMode::NoPropagation;
794
- }
795
- }
796
802
_ => {
797
803
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
798
804
self.can_const_prop[local] = ConstPropMode::NoPropagation;
@@ -826,40 +832,50 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
826
832
if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
827
833
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
828
834
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
829
- if let Some(local) = place.as_local() {
830
- let can_const_prop = self.can_const_prop[local];
831
- if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
832
- if can_const_prop != ConstPropMode::NoPropagation {
833
- // This will return None for Locals that are from other blocks,
834
- // so it should be okay to propagate from here on down.
835
- if let Some(value) = self.get_const(local) {
836
- if self.should_const_prop(value) {
837
- trace!("replacing {:?} with {:?}", rval, value);
838
- self.replace_with_const(rval, value, statement.source_info);
839
- if can_const_prop == ConstPropMode::FullConstProp
840
- || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
841
- {
842
- trace!("propagated into {:?}", local);
843
- }
844
- }
845
- if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
846
- trace!(
847
- "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
848
- local
849
- );
850
- self.locals_of_current_block.insert(local);
835
+ let can_const_prop = self.can_const_prop[place.local];
836
+ if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
837
+ if can_const_prop != ConstPropMode::NoPropagation {
838
+ // This will return None for variables that are from other blocks,
839
+ // so it should be okay to propagate from here on down.
840
+ if let Some(value) = self.get_const(place) {
841
+ if self.should_const_prop(value) {
842
+ trace!("replacing {:?} with {:?}", rval, value);
843
+ self.replace_with_const(rval, value, statement.source_info);
844
+ if can_const_prop == ConstPropMode::FullConstProp
845
+ || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
846
+ {
847
+ trace!("propagated into {:?}", place);
851
848
}
852
849
}
850
+ if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
851
+ trace!(
852
+ "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
853
+ place.local
854
+ );
855
+ self.locals_of_current_block.insert(place.local);
856
+ }
853
857
}
854
858
}
855
- if self. can_const_prop[local] == ConstPropMode::OnlyPropagateInto
856
- || self. can_const_prop[local] == ConstPropMode::NoPropagation
859
+ if can_const_prop == ConstPropMode::OnlyPropagateInto
860
+ || can_const_prop == ConstPropMode::NoPropagation
857
861
{
858
- trace!("can't propagate into {:?}", local );
859
- if local != RETURN_PLACE {
860
- Self::remove_const(&mut self.ecx, local);
862
+ trace!("can't propagate into {:?}", place );
863
+ if place. local != RETURN_PLACE {
864
+ Self::remove_const(&mut self.ecx, place. local);
861
865
}
862
866
}
867
+ } else {
868
+ // Const prop failed, so erase the destination, ensuring that whatever happens
869
+ // from here on, does not know about the previous value.
870
+ // This is important in case we have
871
+ // ```rust
872
+ // let mut x = 42;
873
+ // x = SOME_MUTABLE_STATIC;
874
+ // // x must now be undefined
875
+ // ```
876
+ // FIXME: we overzealously erase the entire local, because that's easier to
877
+ // implement.
878
+ Self::remove_const(&mut self.ecx, place.local);
863
879
}
864
880
}
865
881
} else {
@@ -993,7 +1009,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
993
1009
arguments are of the variant `Operand::Copy`. This allows us to
994
1010
simplify our handling of `Operands` in this case.
995
1011
*/
996
- if let Some(l) = opr.place().and_then(|p| p.as_local()) {
1012
+ if let Some(l) = opr.place() {
997
1013
if let Some(value) = self.get_const(l) {
998
1014
if self.should_const_prop(value) {
999
1015
// FIXME(felix91gr): this code only handles `Scalar` cases.
0 commit comments