From 5de9cb0703555ee6e2e0af8305be138f09545485 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 19:36:48 -0300
Subject: [PATCH 01/12] super_ty on MutVisitor is empty so avoid the call

---
 src/librustc_mir/transform/erase_regions.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 38a04ce8f3815..e9ce84a25838f 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -25,7 +25,6 @@ impl EraseRegionsVisitor<'tcx> {
 impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
         *ty = self.tcx.erase_regions(ty);
-        self.super_ty(ty);
     }
 
     fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {

From e069e9ccacbe92de1c893be5ad77fd5d6173f937 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 16:39:20 -0300
Subject: [PATCH 02/12] Prepare promote_consts MutVisitor to have projections
 interned

---
 src/librustc_mir/transform/promote_consts.rs | 26 +++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 5d241ffe1c06a..d1c79c5ae2ada 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -191,6 +191,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         });
     }
 
+    fn is_temp_kind(&self, local: Local) -> bool {
+        self.source.local_kind(local) == LocalKind::Temp
+    }
+
     /// Copies the initialization of this temp to the
     /// promoted MIR, recursing through temps.
     fn promote_temp(&mut self, temp: Local) -> Local {
@@ -396,10 +400,30 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
                    local: &mut Local,
                    _: PlaceContext,
                    _: Location) {
-        if self.source.local_kind(*local) == LocalKind::Temp {
+        if self.is_temp_kind(*local) {
             *local = self.promote_temp(*local);
         }
     }
+
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            match elem {
+                PlaceElem::Index(local) if self.is_temp_kind(*local) => {
+                    PlaceElem::Index(self.promote_temp(*local))
+                }
+                _ => elem.clone(),
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
 }
 
 pub fn promote_candidates<'tcx>(

From 591cc9aede4aec9b8816b8489eb98c2f2a3bfe90 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 17:58:28 -0300
Subject: [PATCH 03/12] Prepare simplify MutVisitor to have projections
 interned

---
 src/librustc_mir/transform/simplify.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 9ffff9a92fa53..57bc1c8fab969 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -366,7 +366,27 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
         });
         self.super_basic_block_data(block, data);
     }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
+
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            if let PlaceElem::Index(local) = elem {
+                PlaceElem::Index(self.map[*local].unwrap())
+            } else {
+                elem.clone()
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
 }

From bb7d6d1c70964d1d3efd5fb448538b7de50bbe3c Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 18:15:19 -0300
Subject: [PATCH 04/12] Prepare renumber MutVisitor to have projections
 interned

---
 src/librustc_mir/borrow_check/nll/renumber.rs | 23 +++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 88ad1fb129509..6eb5735cb16ba 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,7 +1,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::mir::{Location, Body, Promoted};
-use rustc::mir::visit::{MutVisitor, TyContext};
+use rustc::mir::{Body, Location, Place, PlaceElem, Promoted};
+use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc_index::vec::IndexVec;
 
@@ -62,6 +62,25 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            if let PlaceElem::Field(field, ty) = elem {
+                PlaceElem::Field(*field, self.renumber_regions(ty))
+            } else {
+                elem.clone()
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
+
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
         debug!("visit_substs(substs={:?}, location={:?})", substs, location);
 

From e3e99516730f72fa05cb964ae341156e1ca85c39 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 18:23:39 -0300
Subject: [PATCH 05/12] Prepare inline MutVisitor to have projections interned

---
 src/librustc_mir/transform/inline.rs | 51 +++++++++++++++++++---------
 1 file changed, 35 insertions(+), 16 deletions(-)

diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 9830ed35ffc3e..3a71d22da7873 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -647,38 +647,45 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
         debug!("updating target `{:?}`, new: `{:?}`", tgt, new);
         new
     }
-}
 
-impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
-    fn visit_local(&mut self,
-                   local: &mut Local,
-                   _ctxt: PlaceContext,
-                   _location: Location) {
+    fn make_integrate_local(&self, local: &Local) -> Local {
         if *local == RETURN_PLACE {
             match self.destination {
                 Place {
                     base: PlaceBase::Local(l),
                     projection: box [],
                 } => {
-                    *local = l;
-                    return;
+                    return l;
                 },
                 ref place => bug!("Return place is {:?}, not local", place)
             }
         }
+
         let idx = local.index() - 1;
         if idx < self.args.len() {
-            *local = self.args[idx];
-            return;
+            return self.args[idx];
         }
-        *local = self.local_map[Local::new(idx - self.args.len())];
+
+        self.local_map[Local::new(idx - self.args.len())]
     }
+}
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    _ctxt: PlaceContext,
-                    _location: Location) {
+impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn visit_local(
+        &mut self,
+        local: &mut Local,
+        _ctxt: PlaceContext,
+        _location: Location,
+    ) {
+        *local = self.make_integrate_local(local);
+    }
 
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
         match place {
             Place {
                 base: PlaceBase::Local(RETURN_PLACE),
@@ -687,7 +694,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 // Return pointer; update the place itself
                 *place = self.destination.clone();
             },
-            _ => self.super_place(place, _ctxt, _location)
+            _ => {
+                self.visit_place_base(&mut place.base, context, location);
+
+                let new_projection: Vec<_> = place.projection.iter().map(|elem|
+                    if let PlaceElem::Index(local) = elem {
+                        PlaceElem::Index(self.make_integrate_local(local))
+                    } else {
+                        elem.clone()
+                    }
+                ).collect();
+
+                place.projection = new_projection.into_boxed_slice();
+            }
         }
     }
 

From 0fc063f15936761024183a3bb3790684d5de3bd3 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 19:14:35 -0300
Subject: [PATCH 06/12] Prepare generator MutVisitor to have projections
 interned

---
 src/librustc_mir/transform/generator.rs | 52 +++++++++++++++++++++----
 1 file changed, 45 insertions(+), 7 deletions(-)

diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 865fa012c2995..a801548efab08 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -88,6 +88,24 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
             *local = self.to;
         }
     }
+
+    fn visit_place(&mut self,
+                    place: &mut Place<'tcx>,
+                    context: PlaceContext,
+                    location: Location) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            match elem {
+                PlaceElem::Index(local) if *local == self.from => {
+                    PlaceElem::Index(self.to)
+                }
+                _ => elem.clone(),
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
 }
 
 struct DerefArgVisitor;
@@ -110,7 +128,13 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
                 projection: Box::new([ProjectionElem::Deref]),
             });
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 }
@@ -137,7 +161,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                 projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
             });
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 }
@@ -247,17 +277,25 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
         assert_eq!(self.remap.get(local), None);
     }
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
         if let PlaceBase::Local(l) = place.base {
             // Replace an Local in the remap with a generator struct access
             if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
                 replace_base(place, self.make_field(variant_index, idx, ty));
             }
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 

From 39c9ed3ac19b3f6c79069d32a317daa763371369 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Mon, 7 Oct 2019 19:35:41 -0300
Subject: [PATCH 07/12] Prepare erase_regions MutVisitor to have projections
 interned

---
 src/librustc_mir/transform/erase_regions.rs | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index e9ce84a25838f..132149d5d4337 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -7,7 +7,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::mir::*;
-use rustc::mir::visit::{MutVisitor, TyContext};
+use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext};
 use crate::transform::{MirPass, MirSource};
 
 struct EraseRegionsVisitor<'tcx> {
@@ -38,6 +38,25 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
         *substs = self.tcx.erase_regions(substs);
     }
+
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            if let PlaceElem::Field(field, ty) = elem {
+                PlaceElem::Field(*field, self.tcx.erase_regions(ty))
+            } else {
+                elem.clone()
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
 }
 
 pub struct EraseRegions;

From 2b2e35bfc34618cff7b62a7726ee3a97101d3fa2 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Tue, 8 Oct 2019 00:24:18 -0300
Subject: [PATCH 08/12] Prepare def_use MutVisitor to have projections interned

---
 src/librustc_mir/util/def_use.rs | 36 ++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 3aea25fa8769f..d90be90bd9d49 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -1,6 +1,6 @@
 //! Def-use analysis.
 
-use rustc::mir::{Local, Location, Body};
+use rustc::mir::{Body, Local, Location, Place, PlaceElem};
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc_index::vec::IndexVec;
 use std::mem;
@@ -47,13 +47,13 @@ impl DefUseAnalysis {
         &self.info[local]
     }
 
-    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, mut callback: F)
-                               where F: for<'a> FnMut(&'a mut Local,
+    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, callback: F)
+                               where F: for<'a> Fn(&'a Local,
                                                       PlaceContext,
-                                                      Location) {
+                                                      Location) -> Local {
         for place_use in &self.info[local].defs_and_uses {
             MutateUseVisitor::new(local,
-                                  &mut callback,
+                                  &callback,
                                   body).visit_location(body, place_use.location)
         }
     }
@@ -63,7 +63,7 @@ impl DefUseAnalysis {
                                           local: Local,
                                           body: &mut Body<'_>,
                                           new_local: Local) {
-        self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local)
+        self.mutate_defs_and_uses(local, body, |_, _, _| new_local)
     }
 }
 
@@ -125,7 +125,7 @@ struct MutateUseVisitor<F> {
 impl<F> MutateUseVisitor<F> {
     fn new(query: Local, callback: F, _: &Body<'_>)
            -> MutateUseVisitor<F>
-           where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
+           where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
         MutateUseVisitor {
             query,
             callback,
@@ -134,13 +134,31 @@ impl<F> MutateUseVisitor<F> {
 }
 
 impl<F> MutVisitor<'_> for MutateUseVisitor<F>
-              where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
+              where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
     fn visit_local(&mut self,
                     local: &mut Local,
                     context: PlaceContext,
                     location: Location) {
         if *local == self.query {
-            (self.callback)(local, context, location)
+            *local = (self.callback)(local, context, location)
         }
     }
+
+    fn visit_place(&mut self,
+                    place: &mut Place<'tcx>,
+                    context: PlaceContext,
+                    location: Location) {
+        self.visit_place_base(&mut place.base, context, location);
+
+        let new_projection: Vec<_> = place.projection.iter().map(|elem|
+            match elem {
+                PlaceElem::Index(local) if *local == self.query => {
+                    PlaceElem::Index((self.callback)(&local, context, location))
+                }
+                _ => elem.clone(),
+            }
+        ).collect();
+
+        place.projection = new_projection.into_boxed_slice();
+    }
 }

From 4f2a11036d085227e261824a1aa76dd752c84267 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Tue, 8 Oct 2019 00:33:47 -0300
Subject: [PATCH 09/12] Remove unneeded callback and just use the new_local
 value

---
 src/librustc_mir/util/def_use.rs | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index d90be90bd9d49..5b5f7d83f0746 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -47,13 +47,10 @@ impl DefUseAnalysis {
         &self.info[local]
     }
 
-    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, callback: F)
-                               where F: for<'a> Fn(&'a Local,
-                                                      PlaceContext,
-                                                      Location) -> Local {
+    fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
         for place_use in &self.info[local].defs_and_uses {
             MutateUseVisitor::new(local,
-                                  &callback,
+                                  new_local,
                                   body).visit_location(body, place_use.location)
         }
     }
@@ -63,7 +60,7 @@ impl DefUseAnalysis {
                                           local: Local,
                                           body: &mut Body<'_>,
                                           new_local: Local) {
-        self.mutate_defs_and_uses(local, body, |_, _, _| new_local)
+        self.mutate_defs_and_uses(local, body, new_local)
     }
 }
 
@@ -117,30 +114,27 @@ impl Info {
     }
 }
 
-struct MutateUseVisitor<F> {
+struct MutateUseVisitor {
     query: Local,
-    callback: F,
+    new_local: Local,
 }
 
-impl<F> MutateUseVisitor<F> {
-    fn new(query: Local, callback: F, _: &Body<'_>)
-           -> MutateUseVisitor<F>
-           where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
+impl MutateUseVisitor {
+    fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
         MutateUseVisitor {
             query,
-            callback,
+            new_local,
         }
     }
 }
 
-impl<F> MutVisitor<'_> for MutateUseVisitor<F>
-              where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
+impl MutVisitor<'_> for MutateUseVisitor {
     fn visit_local(&mut self,
                     local: &mut Local,
-                    context: PlaceContext,
-                    location: Location) {
+                    _context: PlaceContext,
+                    _location: Location) {
         if *local == self.query {
-            *local = (self.callback)(local, context, location)
+            *local = self.new_local;
         }
     }
 
@@ -153,7 +147,7 @@ impl<F> MutVisitor<'_> for MutateUseVisitor<F>
         let new_projection: Vec<_> = place.projection.iter().map(|elem|
             match elem {
                 PlaceElem::Index(local) if *local == self.query => {
-                    PlaceElem::Index((self.callback)(&local, context, location))
+                    PlaceElem::Index(self.new_local)
                 }
                 _ => elem.clone(),
             }

From 7fa3425ef675b4bf4177dc2ea232078f4556b4c4 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Tue, 8 Oct 2019 12:16:26 -0300
Subject: [PATCH 10/12] Setup a different visit place set of methods for
 mutable and immutable visitors

In particular, use a blank visit_place for mutable visitor to be sure,
non modified visitors are not trying to mutating place.
---
 src/librustc/mir/visit.rs | 180 ++++++++++++++++++++++----------------
 1 file changed, 103 insertions(+), 77 deletions(-)

diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index edc7922f46eec..0fb43c7f98d16 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -158,22 +158,7 @@ macro_rules! make_mir_visitor {
                 self.super_place_base(base, context, location);
             }
 
-            fn visit_projection(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
-                                projection: & $($mutability)? [PlaceElem<'tcx>],
-                                context: PlaceContext,
-                                location: Location) {
-                self.super_projection(base, projection, context, location);
-            }
-
-            fn visit_projection_elem(&mut self,
-                                     base: & $($mutability)? PlaceBase<'tcx>,
-                                     proj_base: & $($mutability)? [PlaceElem<'tcx>],
-                                     elem: & $($mutability)? PlaceElem<'tcx>,
-                                     context: PlaceContext,
-                                     location: Location) {
-                self.super_projection_elem(base, proj_base, elem, context, location);
-            }
+            visit_place_fns!($($mutability)?);
 
             fn visit_constant(&mut self,
                               constant: & $($mutability)? Constant<'tcx>,
@@ -681,28 +666,6 @@ macro_rules! make_mir_visitor {
                 );
             }
 
-            fn super_place(&mut self,
-                            place: & $($mutability)? Place<'tcx>,
-                            context: PlaceContext,
-                            location: Location) {
-                let mut context = context;
-
-                if !place.projection.is_empty() {
-                    context = if context.is_mutating_use() {
-                        PlaceContext::MutatingUse(MutatingUseContext::Projection)
-                    } else {
-                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
-                    };
-                }
-
-                self.visit_place_base(& $($mutability)? place.base, context, location);
-
-                self.visit_projection(& $($mutability)? place.base,
-                                      & $($mutability)? place.projection,
-                                      context,
-                                      location);
-            }
-
             fn super_place_base(&mut self,
                                 place_base: & $($mutability)? PlaceBase<'tcx>,
                                 context: PlaceContext,
@@ -717,45 +680,6 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            fn super_projection(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
-                                projection: & $($mutability)? [PlaceElem<'tcx>],
-                                context: PlaceContext,
-                                location: Location) {
-                let mut cursor = projection;
-                while let [proj_base @ .., elem] = cursor {
-                    cursor = proj_base;
-                    self.visit_projection_elem(base, cursor, elem, context, location);
-                }
-            }
-
-            fn super_projection_elem(&mut self,
-                                     _base: & $($mutability)? PlaceBase<'tcx>,
-                                     _proj_base: & $($mutability)? [PlaceElem<'tcx>],
-                                     elem: & $($mutability)? PlaceElem<'tcx>,
-                                     _context: PlaceContext,
-                                     location: Location) {
-                match elem {
-                    ProjectionElem::Field(_field, ty) => {
-                        self.visit_ty(ty, TyContext::Location(location));
-                    }
-                    ProjectionElem::Index(local) => {
-                        self.visit_local(
-                            local,
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
-                            location
-                        );
-                    }
-                    ProjectionElem::Deref |
-                    ProjectionElem::Subslice { from: _, to: _ } |
-                    ProjectionElem::ConstantIndex { offset: _,
-                                                    min_length: _,
-                                                    from_end: _ } |
-                    ProjectionElem::Downcast(_, _) => {
-                    }
-                }
-            }
-
             fn super_local_decl(&mut self,
                                 local: Local,
                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
@@ -858,6 +782,108 @@ macro_rules! make_mir_visitor {
     }
 }
 
+macro_rules! visit_place_fns {
+    (mut) => (
+        fn super_place(
+            &mut self,
+            _place: &mut Place<'tcx>,
+            _context: PlaceContext,
+            _location: Location,
+        ) {
+        }
+    );
+
+    () => (
+        fn visit_projection(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            projection: &[PlaceElem<'tcx>],
+            context: PlaceContext,
+            location: Location,
+        ) {
+            self.super_projection(base, projection, context, location);
+        }
+
+        fn visit_projection_elem(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            proj_base: &[PlaceElem<'tcx>],
+            elem: &PlaceElem<'tcx>,
+            context: PlaceContext,
+            location: Location,
+        ) {
+            self.super_projection_elem(base, proj_base, elem, context, location);
+        }
+
+        fn super_place(
+            &mut self,
+            place: &Place<'tcx>,
+            context: PlaceContext,
+            location: Location,
+        ) {
+            let mut context = context;
+
+            if !place.projection.is_empty() {
+                context = if context.is_mutating_use() {
+                    PlaceContext::MutatingUse(MutatingUseContext::Projection)
+                } else {
+                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
+                };
+            }
+
+            self.visit_place_base(&place.base, context, location);
+
+            self.visit_projection(&place.base,
+                                  &place.projection,
+                                  context,
+                                  location);
+        }
+
+        fn super_projection(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            projection: &[PlaceElem<'tcx>],
+            context: PlaceContext,
+            location: Location,
+        ) {
+            let mut cursor = projection;
+            while let [proj_base @ .., elem] = cursor {
+                cursor = proj_base;
+                self.visit_projection_elem(base, cursor, elem, context, location);
+            }
+        }
+
+        fn super_projection_elem(
+            &mut self,
+            _base: &PlaceBase<'tcx>,
+            _proj_base: &[PlaceElem<'tcx>],
+            elem: &PlaceElem<'tcx>,
+            _context: PlaceContext,
+            location: Location,
+        ) {
+            match elem {
+                ProjectionElem::Field(_field, ty) => {
+                    self.visit_ty(ty, TyContext::Location(location));
+                }
+                ProjectionElem::Index(local) => {
+                    self.visit_local(
+                        local,
+                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                        location
+                    );
+                }
+                ProjectionElem::Deref |
+                ProjectionElem::Subslice { from: _, to: _ } |
+                ProjectionElem::ConstantIndex { offset: _,
+                                                min_length: _,
+                                                from_end: _ } |
+                ProjectionElem::Downcast(_, _) => {
+                }
+            }
+        }
+    );
+}
+
 make_mir_visitor!(Visitor,);
 make_mir_visitor!(MutVisitor,mut);
 

From d53fc9cae5b17c138be09383dea8b8f10d3df3a1 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Tue, 8 Oct 2019 15:33:19 -0300
Subject: [PATCH 11/12] Add process_* place hooks to improve code reutilization

---
 src/librustc/mir/visit.rs                     | 28 +++++++++++++++++--
 src/librustc_mir/borrow_check/nll/renumber.rs | 28 +++++++------------
 src/librustc_mir/transform/erase_regions.rs   | 26 ++++++-----------
 src/librustc_mir/transform/inline.rs          | 23 +++++++--------
 src/librustc_mir/transform/promote_consts.rs  | 24 ++++++----------
 src/librustc_mir/transform/simplify.rs        | 24 ++++++----------
 src/librustc_mir/util/def_use.rs              | 26 +++++++----------
 7 files changed, 82 insertions(+), 97 deletions(-)

diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 0fb43c7f98d16..c8a6367899ba9 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -786,10 +786,32 @@ macro_rules! visit_place_fns {
     (mut) => (
         fn super_place(
             &mut self,
-            _place: &mut Place<'tcx>,
-            _context: PlaceContext,
-            _location: Location,
+            place: &mut Place<'tcx>,
+            context: PlaceContext,
+            location: Location,
         ) {
+            self.visit_place_base(&mut place.base, context, location);
+
+            place.projection = self.process_projection(&place.projection);
+        }
+
+        fn process_projection(
+            &mut self,
+            projection: &Box<[PlaceElem<'tcx>]>,
+        ) -> Box<[PlaceElem<'tcx>]> {
+            let new_projection: Vec<_> = projection.iter().map(|elem|
+                self.process_projection_elem(elem)
+            ).collect();
+
+            new_projection.into_boxed_slice()
+        }
+
+        fn process_projection_elem(
+            &mut self,
+            elem: &PlaceElem<'tcx>,
+        ) -> PlaceElem<'tcx> {
+            // FIXME: avoid cloning here
+            elem.clone()
         }
     );
 
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 6eb5735cb16ba..c4a19ce5128b5 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,7 +1,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::mir::{Body, Location, Place, PlaceElem, Promoted};
-use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext};
+use rustc::mir::{Body, Location, PlaceElem, Promoted};
+use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc_index::vec::IndexVec;
 
@@ -62,23 +62,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
-    fn visit_place(
+    fn process_projection_elem(
         &mut self,
-        place: &mut Place<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            if let PlaceElem::Field(field, ty) = elem {
-                PlaceElem::Field(*field, self.renumber_regions(ty))
-            } else {
-                elem.clone()
-            }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        if let PlaceElem::Field(field, ty) = elem {
+            PlaceElem::Field(*field, self.renumber_regions(ty))
+        } else {
+            elem.clone()
+        }
     }
 
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 132149d5d4337..725a8de8fe7d1 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -7,7 +7,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::mir::*;
-use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext};
+use rustc::mir::visit::{MutVisitor, TyContext};
 use crate::transform::{MirPass, MirSource};
 
 struct EraseRegionsVisitor<'tcx> {
@@ -39,23 +39,15 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
         *substs = self.tcx.erase_regions(substs);
     }
 
-    fn visit_place(
+    fn process_projection_elem(
         &mut self,
-        place: &mut Place<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            if let PlaceElem::Field(field, ty) = elem {
-                PlaceElem::Field(*field, self.tcx.erase_regions(ty))
-            } else {
-                elem.clone()
-            }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        if let PlaceElem::Field(field, ty) = elem {
+            PlaceElem::Field(*field, self.tcx.erase_regions(ty))
+        } else {
+            elem.clone()
+        }
     }
 }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 3a71d22da7873..dd13d0c96557d 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -695,21 +695,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 *place = self.destination.clone();
             },
             _ => {
-                self.visit_place_base(&mut place.base, context, location);
-
-                let new_projection: Vec<_> = place.projection.iter().map(|elem|
-                    if let PlaceElem::Index(local) = elem {
-                        PlaceElem::Index(self.make_integrate_local(local))
-                    } else {
-                        elem.clone()
-                    }
-                ).collect();
-
-                place.projection = new_projection.into_boxed_slice();
+                self.super_place(place, context, location);
             }
         }
     }
 
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        if let PlaceElem::Index(local) = elem {
+            PlaceElem::Index(self.make_integrate_local(local))
+        } else {
+            elem.clone()
+        }
+    }
+
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         self.in_cleanup_block = data.is_cleanup;
         self.super_basic_block_data(block, data);
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index d1c79c5ae2ada..565f260546bc7 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -405,24 +405,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
         }
     }
 
-    fn visit_place(
+    fn process_projection_elem(
         &mut self,
-        place: &mut Place<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            match elem {
-                PlaceElem::Index(local) if self.is_temp_kind(*local) => {
-                    PlaceElem::Index(self.promote_temp(*local))
-                }
-                _ => elem.clone(),
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        match elem {
+            PlaceElem::Index(local) if self.is_temp_kind(*local) => {
+                PlaceElem::Index(self.promote_temp(*local))
             }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+            _ => elem.clone(),
+        }
     }
 }
 
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 57bc1c8fab969..7dca3e357cc94 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -371,22 +371,14 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
         *l = self.map[*l].unwrap();
     }
 
-    fn visit_place(
+    fn process_projection_elem(
         &mut self,
-        place: &mut Place<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            if let PlaceElem::Index(local) = elem {
-                PlaceElem::Index(self.map[*local].unwrap())
-            } else {
-                elem.clone()
-            }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        if let PlaceElem::Index(local) = elem {
+            PlaceElem::Index(self.map[*local].unwrap())
+        } else {
+            elem.clone()
+        }
     }
 }
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 5b5f7d83f0746..25930df020aa9 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -1,6 +1,6 @@
 //! Def-use analysis.
 
-use rustc::mir::{Body, Local, Location, Place, PlaceElem};
+use rustc::mir::{Body, Local, Location, PlaceElem};
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc_index::vec::IndexVec;
 use std::mem;
@@ -138,21 +138,15 @@ impl MutVisitor<'_> for MutateUseVisitor {
         }
     }
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            match elem {
-                PlaceElem::Index(local) if *local == self.query => {
-                    PlaceElem::Index(self.new_local)
-                }
-                _ => elem.clone(),
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> PlaceElem<'tcx> {
+        match elem {
+            PlaceElem::Index(local) if *local == self.query => {
+                PlaceElem::Index(self.new_local)
             }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+            _ => elem.clone(),
+        }
     }
 }

From 48349960e68a9d19b17ac54cd12e939a9a46ea7d Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Tue, 8 Oct 2019 23:46:14 -0300
Subject: [PATCH 12/12] Use Cow to handle modifications of projection in
 preparation for interning

---
 src/librustc/mir/visit.rs                     | 33 ++++++++++++-------
 src/librustc_mir/borrow_check/nll/renumber.rs | 12 ++++---
 src/librustc_mir/transform/erase_regions.rs   | 12 ++++---
 src/librustc_mir/transform/generator.rs       | 24 +++++---------
 src/librustc_mir/transform/inline.rs          | 12 ++++---
 src/librustc_mir/transform/promote_consts.rs  |  6 ++--
 src/librustc_mir/transform/simplify.rs        | 11 ++++---
 src/librustc_mir/util/def_use.rs              |  6 ++--
 8 files changed, 67 insertions(+), 49 deletions(-)

diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index c8a6367899ba9..fef406e898783 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -792,26 +792,37 @@ macro_rules! visit_place_fns {
         ) {
             self.visit_place_base(&mut place.base, context, location);
 
-            place.projection = self.process_projection(&place.projection);
+            if let Some(new_projection) = self.process_projection(&place.projection) {
+                place.projection = new_projection;
+            }
         }
 
         fn process_projection(
             &mut self,
-            projection: &Box<[PlaceElem<'tcx>]>,
-        ) -> Box<[PlaceElem<'tcx>]> {
-            let new_projection: Vec<_> = projection.iter().map(|elem|
-                self.process_projection_elem(elem)
-            ).collect();
+            projection: &'a [PlaceElem<'tcx>],
+        ) -> Option<Box<[PlaceElem<'tcx>]>> {
+            let mut projection = Cow::Borrowed(projection);
+
+            for i in 0..projection.len() {
+                if let Some(elem) = projection.get(i) {
+                    if let Some(elem) = self.process_projection_elem(elem) {
+                        let vec = projection.to_mut();
+                        vec[i] = elem;
+                    }
+                }
+            }
 
-            new_projection.into_boxed_slice()
+            match projection {
+                Cow::Borrowed(_) => None,
+                Cow::Owned(vec) => Some(vec.into_boxed_slice()),
+            }
         }
 
         fn process_projection_elem(
             &mut self,
-            elem: &PlaceElem<'tcx>,
-        ) -> PlaceElem<'tcx> {
-            // FIXME: avoid cloning here
-            elem.clone()
+            _elem: &PlaceElem<'tcx>,
+        ) -> Option<PlaceElem<'tcx>> {
+            None
         }
     );
 
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index c4a19ce5128b5..9ecd6f837750e 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -65,12 +65,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
+    ) -> Option<PlaceElem<'tcx>> {
         if let PlaceElem::Field(field, ty) = elem {
-            PlaceElem::Field(*field, self.renumber_regions(ty))
-        } else {
-            elem.clone()
+            let new_ty = self.renumber_regions(ty);
+
+            if new_ty != *ty {
+                return Some(PlaceElem::Field(*field, new_ty));
+            }
         }
+
+        None
     }
 
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 725a8de8fe7d1..439cae2093ae5 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -42,12 +42,16 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
+    ) -> Option<PlaceElem<'tcx>> {
         if let PlaceElem::Field(field, ty) = elem {
-            PlaceElem::Field(*field, self.tcx.erase_regions(ty))
-        } else {
-            elem.clone()
+            let new_ty = self.tcx.erase_regions(ty);
+
+            if new_ty != *ty {
+                return Some(PlaceElem::Field(*field, new_ty));
+            }
         }
+
+        None
     }
 }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index a801548efab08..6533e3c5ba81f 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -89,22 +89,16 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
         }
     }
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
-        self.visit_place_base(&mut place.base, context, location);
-
-        let new_projection: Vec<_> = place.projection.iter().map(|elem|
-            match elem {
-                PlaceElem::Index(local) if *local == self.from => {
-                    PlaceElem::Index(self.to)
-                }
-                _ => elem.clone(),
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) if *local == self.from => {
+                Some(PlaceElem::Index(self.to))
             }
-        ).collect();
-
-        place.projection = new_projection.into_boxed_slice();
+            _ => None,
+        }
     }
 }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index dd13d0c96557d..0cbdcedff4780 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -703,12 +703,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
+    ) -> Option<PlaceElem<'tcx>> {
         if let PlaceElem::Index(local) = elem {
-            PlaceElem::Index(self.make_integrate_local(local))
-        } else {
-            elem.clone()
+            let new_local = self.make_integrate_local(local);
+
+            if new_local != *local {
+                return Some(PlaceElem::Index(new_local))
+            }
         }
+
+        None
     }
 
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 565f260546bc7..ad1785417cd93 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -408,12 +408,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
+    ) -> Option<PlaceElem<'tcx>> {
         match elem {
             PlaceElem::Index(local) if self.is_temp_kind(*local) => {
-                PlaceElem::Index(self.promote_temp(*local))
+                Some(PlaceElem::Index(self.promote_temp(*local)))
             }
-            _ => elem.clone(),
+            _ => None,
         }
     }
 }
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 7dca3e357cc94..606c1a3a1cc09 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -374,11 +374,12 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
-        if let PlaceElem::Index(local) = elem {
-            PlaceElem::Index(self.map[*local].unwrap())
-        } else {
-            elem.clone()
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) => {
+                Some(PlaceElem::Index(self.map[*local].unwrap()))
+            }
+            _ => None
         }
     }
 }
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 25930df020aa9..cdd07ad4b8ff4 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -141,12 +141,12 @@ impl MutVisitor<'_> for MutateUseVisitor {
     fn process_projection_elem(
         &mut self,
         elem: &PlaceElem<'tcx>,
-    ) -> PlaceElem<'tcx> {
+    ) -> Option<PlaceElem<'tcx>> {
         match elem {
             PlaceElem::Index(local) if *local == self.query => {
-                PlaceElem::Index(self.new_local)
+                Some(PlaceElem::Index(self.new_local))
             }
-            _ => elem.clone(),
+            _ => None,
         }
     }
 }