From 2e39b9c51f8a94662bf0c7d1f3411ebade7bfeb6 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Thu, 23 May 2019 22:17:45 +0200
Subject: [PATCH 1/8] Make find_local iterate instead of recurse

---
 .../dataflow/impls/borrowed_locals.rs         | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index 42c2387b7052d..65cbc83fbcb84 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -91,16 +91,19 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
 }
 
 fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
-    match *place {
-        Place::Base(PlaceBase::Local(l)) => Some(l),
-        Place::Base(PlaceBase::Static(..)) => None,
-        Place::Projection(ref proj) => {
-            match proj.elem {
-                ProjectionElem::Deref => None,
-                _ => find_local(&proj.base)
+    place.iterate(|place_base, place_projection| {
+        for proj in place_projection {
+            if proj.elem == ProjectionElem::Deref {
+                return None;
             }
         }
-    }
+
+        if let PlaceBase::Local(local) = place_base {
+            Some(*local)
+        } else {
+            None
+        }
+    })
 }
 
 impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {

From 34314caea39300276375f3cd948e09a37bec6873 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 01:15:08 +0200
Subject: [PATCH 2/8] Make find iterate instead of recurse

---
 src/librustc_mir/dataflow/move_paths/mod.rs | 27 +++++++++++----------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 6d619793160fb..7aaf44a8a890e 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -241,21 +241,22 @@ impl MovePathLookup {
     // unknown place, but will rather return the nearest available
     // parent.
     pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
-        match *place {
-            Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
-            Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
-            Place::Projection(ref proj) => {
-                match self.find(&proj.base) {
-                    LookupResult::Exact(base_path) => {
-                        match self.projections.get(&(base_path, proj.elem.lift())) {
-                            Some(&subpath) => LookupResult::Exact(subpath),
-                            None => LookupResult::Parent(Some(base_path))
-                        }
-                    }
-                    inexact => inexact
+        place.iterate(|place_base, place_projection| {
+            let mut result = match place_base {
+                PlaceBase::Local(local) => self.locals[*local],
+                PlaceBase::Static(..) => return LookupResult::Parent(None),
+            };
+
+            for proj in place_projection {
+                if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
+                    result = subpath;
+                } else {
+                    return LookupResult::Parent(Some(result));
                 }
             }
-        }
+
+            LookupResult::Exact(result)
+        })
     }
 
     pub fn find_local(&self, local: Local) -> MovePathIndex {

From 03dc30d3d523753b44daab007d67e160a9a9d794 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Thu, 23 May 2019 21:41:10 +0200
Subject: [PATCH 3/8] Make sanitize_place iterate instead of recurse

---
 .../borrow_check/nll/type_check/mod.rs        | 153 +++++++++---------
 1 file changed, 78 insertions(+), 75 deletions(-)

diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 4589e4ef036a4..52c8f15c44bb9 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -29,7 +29,7 @@ use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionV
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
 use rustc::mir::tcx::PlaceTy;
-use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
+use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
 use rustc::mir::*;
 use rustc::traits::query::type_op;
 use rustc::traits::query::type_op::custom::CustomTypeOp;
@@ -447,92 +447,95 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         context: PlaceContext,
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
-        let place_ty = match place {
-            Place::Base(PlaceBase::Local(index)) =>
-                PlaceTy::from_ty(self.mir.local_decls[*index].ty),
-            Place::Base(PlaceBase::Static(box Static { kind, ty: sty })) => {
-                let sty = self.sanitize_type(place, sty);
-                let check_err =
-                    |verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
-                     place: &Place<'tcx>,
-                     ty,
-                     sty| {
-                        if let Err(terr) = verifier.cx.eq_types(
-                            sty,
-                            ty,
-                            location.to_locations(),
-                            ConstraintCategory::Boring,
-                        ) {
-                            span_mirbug!(
-                            verifier,
-                            place,
-                            "bad promoted type ({:?}: {:?}): {:?}",
-                            ty,
-                            sty,
-                            terr
-                        );
+
+        place.iterate(|place_base, place_projection| {
+            let mut place_ty = match place_base {
+                PlaceBase::Local(index) =>
+                    PlaceTy::from_ty(self.mir.local_decls[*index].ty),
+                PlaceBase::Static(box Static { kind, ty: sty }) => {
+                    let sty = self.sanitize_type(place, sty);
+                    let check_err =
+                        |verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
+                         place: &Place<'tcx>,
+                         ty,
+                         sty| {
+                            if let Err(terr) = verifier.cx.eq_types(
+                                sty,
+                                ty,
+                                location.to_locations(),
+                                ConstraintCategory::Boring,
+                            ) {
+                                span_mirbug!(
+                                verifier,
+                                place,
+                                "bad promoted type ({:?}: {:?}): {:?}",
+                                ty,
+                                sty,
+                                terr
+                            );
+                            };
                         };
-                    };
-                match kind {
-                    StaticKind::Promoted(promoted) => {
-                        if !self.errors_reported {
-                            let promoted_mir = &self.mir.promoted[*promoted];
-                            self.sanitize_promoted(promoted_mir, location);
-
-                            let promoted_ty = promoted_mir.return_ty();
-                            check_err(self, place, promoted_ty, sty);
+                    match kind {
+                        StaticKind::Promoted(promoted) => {
+                            if !self.errors_reported {
+                                let promoted_mir = &self.mir.promoted[*promoted];
+                                self.sanitize_promoted(promoted_mir, location);
+
+                                let promoted_ty = promoted_mir.return_ty();
+                                check_err(self, place, promoted_ty, sty);
+                            }
                         }
-                    }
-                    StaticKind::Static(def_id) => {
-                        let ty = self.tcx().type_of(*def_id);
-                        let ty = self.cx.normalize(ty, location);
+                        StaticKind::Static(def_id) => {
+                            let ty = self.tcx().type_of(*def_id);
+                            let ty = self.cx.normalize(ty, location);
 
-                        check_err(self, place, ty, sty);
+                            check_err(self, place, ty, sty);
+                        }
                     }
+                    PlaceTy::from_ty(sty)
+                }
+            };
+
+            // FIXME use place_projection.is_empty() when is available
+            if let Place::Base(_) = place {
+                if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
+                    let tcx = self.tcx();
+                    let trait_ref = ty::TraitRef {
+                        def_id: tcx.lang_items().copy_trait().unwrap(),
+                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
+                    };
+
+                    // In order to have a Copy operand, the type T of the
+                    // value must be Copy. Note that we prove that T: Copy,
+                    // rather than using the `is_copy_modulo_regions`
+                    // test. This is important because
+                    // `is_copy_modulo_regions` ignores the resulting region
+                    // obligations and assumes they pass. This can result in
+                    // bounds from Copy impls being unsoundly ignored (e.g.,
+                    // #29149). Note that we decide to use Copy before knowing
+                    // whether the bounds fully apply: in effect, the rule is
+                    // that if a value of some type could implement Copy, then
+                    // it must.
+                    self.cx.prove_trait_ref(
+                        trait_ref,
+                        location.to_locations(),
+                        ConstraintCategory::CopyBound,
+                    );
                 }
-                PlaceTy::from_ty(sty)
             }
-            Place::Projection(ref proj) => {
-                let base_context = if context.is_mutating_use() {
-                    PlaceContext::MutatingUse(MutatingUseContext::Projection)
-                } else {
-                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
-                };
-                let base_ty = self.sanitize_place(&proj.base, location, base_context);
-                if base_ty.variant_index.is_none() {
-                    if base_ty.ty.references_error() {
+
+            for proj in place_projection {
+                if place_ty.variant_index.is_none() {
+                    if place_ty.ty.references_error() {
                         assert!(self.errors_reported);
                         return PlaceTy::from_ty(self.tcx().types.err);
                     }
                 }
-                self.sanitize_projection(base_ty, &proj.elem, place, location)
+                place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
             }
-        };
-        if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-            let tcx = self.tcx();
-            let trait_ref = ty::TraitRef {
-                def_id: tcx.lang_items().copy_trait().unwrap(),
-                substs: tcx.mk_substs_trait(place_ty.ty, &[]),
-            };
 
-            // In order to have a Copy operand, the type T of the
-            // value must be Copy. Note that we prove that T: Copy,
-            // rather than using the `is_copy_modulo_regions`
-            // test. This is important because
-            // `is_copy_modulo_regions` ignores the resulting region
-            // obligations and assumes they pass. This can result in
-            // bounds from Copy impls being unsoundly ignored (e.g.,
-            // #29149). Note that we decide to use Copy before knowing
-            // whether the bounds fully apply: in effect, the rule is
-            // that if a value of some type could implement Copy, then
-            // it must.
-            self.cx.prove_trait_ref(
-                trait_ref,
-                location.to_locations(),
-                ConstraintCategory::CopyBound,
-            );
-        }
-        place_ty
+            place_ty
+        })
     }
 
     fn sanitize_promoted(&mut self, promoted_mir: &'b Mir<'tcx>, location: Location) {

From 96137798556e662e9bb744fb58055e06147b9330 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Thu, 23 May 2019 21:43:21 +0200
Subject: [PATCH 4/8] Make borrow_of_local_data iterate instead of recurse

---
 src/librustc_mir/borrow_check/path_utils.rs | 28 ++++++++++-----------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 0c2a4ef45f104..caef8d8bc5a92 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -131,22 +131,20 @@ pub(super) fn is_active<'tcx>(
 /// Determines if a given borrow is borrowing local data
 /// This is called for all Yield statements on movable generators
 pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
-    match place {
-        Place::Base(PlaceBase::Static(..)) => false,
-        Place::Base(PlaceBase::Local(..)) => true,
-        Place::Projection(box proj) => {
-            match proj.elem {
-                // Reborrow of already borrowed data is ignored
-                // Any errors will be caught on the initial borrow
-                ProjectionElem::Deref => false,
+    place.iterate(|place_base, place_projection| {
+        match place_base {
+            PlaceBase::Static(..) => return false,
+            PlaceBase::Local(..) => {},
+        }
 
-                // For interior references and downcasts, find out if the base is local
-                ProjectionElem::Field(..)
-                    | ProjectionElem::Index(..)
-                    | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. }
-                | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
+        for proj in place_projection {
+            // Reborrow of already borrowed data is ignored
+            // Any errors will be caught on the initial borrow
+            if proj.elem == ProjectionElem::Deref {
+                return false;
             }
         }
-    }
+
+        true
+    })
 }

From 10fe26962c644d6b1a381ecea93d6fe516bd861f Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Thu, 23 May 2019 21:53:59 +0200
Subject: [PATCH 5/8] Make ignore_borrow iterate instead of recurse

---
 src/librustc_mir/borrow_check/place_ext.rs | 68 +++++++++++-----------
 1 file changed, 33 insertions(+), 35 deletions(-)

diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index cf9a6165d71a2..9ad0e936e1b2d 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -25,40 +25,36 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
         mir: &Mir<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
-        match self {
-            // If a local variable is immutable, then we only need to track borrows to guard
-            // against two kinds of errors:
-            // * The variable being dropped while still borrowed (e.g., because the fn returns
-            //   a reference to a local variable)
-            // * The variable being moved while still borrowed
-            //
-            // In particular, the variable cannot be mutated -- the "access checks" will fail --
-            // so we don't have to worry about mutation while borrowed.
-            Place::Base(PlaceBase::Local(index)) => {
-                match locals_state_at_exit {
-                    LocalsStateAtExit::AllAreInvalidated => false,
-                    LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
-                        let ignore = !has_storage_dead_or_moved.contains(*index) &&
-                            mir.local_decls[*index].mutability == Mutability::Not;
-                        debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
-                        ignore
+        self.iterate(|place_base, place_projection| {
+            let ignore = match place_base {
+                // If a local variable is immutable, then we only need to track borrows to guard
+                // against two kinds of errors:
+                // * The variable being dropped while still borrowed (e.g., because the fn returns
+                //   a reference to a local variable)
+                // * The variable being moved while still borrowed
+                //
+                // In particular, the variable cannot be mutated -- the "access checks" will fail --
+                // so we don't have to worry about mutation while borrowed.
+                PlaceBase::Local(index) => {
+                    match locals_state_at_exit {
+                        LocalsStateAtExit::AllAreInvalidated => false,
+                        LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
+                            let ignore = !has_storage_dead_or_moved.contains(*index) &&
+                                mir.local_decls[*index].mutability == Mutability::Not;
+                            debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
+                            ignore
+                        }
                     }
                 }
-            }
-            Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
-                false,
-            Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
-                tcx.is_mutable_static(*def_id)
-            }
-            Place::Projection(proj) => match proj.elem {
-                ProjectionElem::Field(..)
-                | ProjectionElem::Downcast(..)
-                | ProjectionElem::Subslice { .. }
-                | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Index(_) => proj.base.ignore_borrow(
-                    tcx, mir, locals_state_at_exit),
+                PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) =>
+                    false,
+                PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
+                    tcx.is_mutable_static(*def_id)
+                }
+            };
 
-                ProjectionElem::Deref => {
+            for proj in place_projection {
+                if proj.elem == ProjectionElem::Deref {
                     let ty = proj.base.ty(mir, tcx).ty;
                     match ty.sty {
                         // For both derefs of raw pointers and `&T`
@@ -71,11 +67,13 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
                         // original path into a new variable and
                         // borrowed *that* one, leaving the original
                         // path unborrowed.
-                        ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
-                        _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
+                        ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
+                        _ => {}
                     }
                 }
-            },
-        }
+            }
+
+            ignore
+        })
     }
 }

From 8173febf930121e954a4be09043482ee771c0794 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 20:37:57 +0200
Subject: [PATCH 6/8] Avoid catch-all arm, use Base(PlaceBase::Static(_))

---
 src/librustc_mir/interpret/operand.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 9c2b491925f47..11bf750e8c7c1 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -472,13 +472,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
         let op = match *mir_place {
             Base(PlaceBase::Local(mir::RETURN_PLACE)) => return err!(ReadFromReturnPointer),
             Base(PlaceBase::Local(local)) => self.access_local(self.frame(), local, layout)?,
+            Base(PlaceBase::Static(_)) => self.eval_place_to_mplace(mir_place)?.into(),
 
             Projection(ref proj) => {
                 let op = self.eval_place_to_op(&proj.base, None)?;
                 self.operand_projection(op, &proj.elem)?
             }
-
-            _ => self.eval_place_to_mplace(mir_place)?.into(),
         };
 
         trace!("eval_place_to_op: got {:?}", *op);

From 6d7a36231a902a57bd627c1f1f6cd658ea9ab717 Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 22:35:32 +0200
Subject: [PATCH 7/8] Make eval_place_to_mplace take PlaceBase::Static

---
 src/librustc_mir/interpret/operand.rs | 10 +++++----
 src/librustc_mir/interpret/place.rs   | 30 +++++++++++++--------------
 2 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 11bf750e8c7c1..669e00c1f01ed 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -469,12 +469,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::Place::*;
         use rustc::mir::PlaceBase;
-        let op = match *mir_place {
+        let op = match mir_place {
             Base(PlaceBase::Local(mir::RETURN_PLACE)) => return err!(ReadFromReturnPointer),
-            Base(PlaceBase::Local(local)) => self.access_local(self.frame(), local, layout)?,
-            Base(PlaceBase::Static(_)) => self.eval_place_to_mplace(mir_place)?.into(),
+            Base(PlaceBase::Local(local)) => self.access_local(self.frame(), *local, layout)?,
+            Base(PlaceBase::Static(place_static)) => {
+                self.eval_static_to_mplace(place_static)?.into()
+            }
 
-            Projection(ref proj) => {
+            Projection(proj) => {
                 let op = self.eval_place_to_op(&proj.base, None)?;
                 self.operand_projection(op, &proj.elem)?
             }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 0cc480028161f..65e5e23e38424 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -562,15 +562,14 @@ where
 
     /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
     /// `eval_place` and `eval_place_to_op`.
-    pub(super) fn eval_place_to_mplace(
+    pub(super) fn eval_static_to_mplace(
         &self,
-        mir_place: &mir::Place<'tcx>
+        place_static: &mir::Static<'tcx>
     ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        use rustc::mir::Place::*;
-        use rustc::mir::PlaceBase;
-        use rustc::mir::{Static, StaticKind};
-        Ok(match *mir_place {
-            Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })) => {
+        use rustc::mir::StaticKind;
+
+        Ok(match place_static.kind {
+            StaticKind::Promoted(promoted) => {
                 let instance = self.frame().instance;
                 self.const_eval_raw(GlobalId {
                     instance,
@@ -578,7 +577,8 @@ where
                 })?
             }
 
-            Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty })) => {
+            StaticKind::Static(def_id) => {
+                let ty = place_static.ty;
                 assert!(!ty.needs_subst());
                 let layout = self.layout_of(ty)?;
                 let instance = ty::Instance::mono(*self.tcx, def_id);
@@ -600,8 +600,6 @@ where
                 let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
                 MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
             }
-
-            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
         })
     }
 
@@ -613,7 +611,7 @@ where
     ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::Place::*;
         use rustc::mir::PlaceBase;
-        let place = match *mir_place {
+        let place = match mir_place {
             Base(PlaceBase::Local(mir::RETURN_PLACE)) => match self.frame().return_place {
                 Some(return_place) =>
                     // We use our layout to verify our assumption; caller will validate
@@ -628,17 +626,19 @@ where
                 // This works even for dead/uninitialized locals; we check further when writing
                 place: Place::Local {
                     frame: self.cur_frame(),
-                    local,
+                    local: *local,
                 },
-                layout: self.layout_of_local(self.frame(), local, None)?,
+                layout: self.layout_of_local(self.frame(), *local, None)?,
             },
 
-            Projection(ref proj) => {
+            Projection(proj) => {
                 let place = self.eval_place(&proj.base)?;
                 self.place_projection(place, &proj.elem)?
             }
 
-            _ => self.eval_place_to_mplace(mir_place)?.into(),
+            Base(PlaceBase::Static(place_static)) => {
+                self.eval_static_to_mplace(place_static)?.into()
+            }
         };
 
         self.dump_place(place.place);

From e38b399d03605f68ddbec50bf31e2f6fb12d278d Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 01:28:41 +0200
Subject: [PATCH 8/8] Make eval_place_to_op iterate instead of recurse

---
 src/librustc_mir/interpret/operand.rs | 37 +++++++++++++++++----------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 669e00c1f01ed..a674389a93695 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -467,23 +467,34 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
         mir_place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        use rustc::mir::Place::*;
+        use rustc::mir::Place;
         use rustc::mir::PlaceBase;
-        let op = match mir_place {
-            Base(PlaceBase::Local(mir::RETURN_PLACE)) => return err!(ReadFromReturnPointer),
-            Base(PlaceBase::Local(local)) => self.access_local(self.frame(), *local, layout)?,
-            Base(PlaceBase::Static(place_static)) => {
-                self.eval_static_to_mplace(place_static)?.into()
-            }
 
-            Projection(proj) => {
-                let op = self.eval_place_to_op(&proj.base, None)?;
-                self.operand_projection(op, &proj.elem)?
+        mir_place.iterate(|place_base, place_projection| {
+            let mut op = match place_base {
+                PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
+                PlaceBase::Local(local) => {
+                    // FIXME use place_projection.is_empty() when is available
+                    let layout = if let Place::Base(_) = mir_place {
+                        layout
+                    } else {
+                        None
+                    };
+
+                    self.access_local(self.frame(), *local, layout)?
+                }
+                PlaceBase::Static(place_static) => {
+                    self.eval_static_to_mplace(place_static)?.into()
+                }
+            };
+
+            for proj in place_projection {
+                op = self.operand_projection(op, &proj.elem)?
             }
-        };
 
-        trace!("eval_place_to_op: got {:?}", *op);
-        Ok(op)
+            trace!("eval_place_to_op: got {:?}", *op);
+            Ok(op)
+        })
     }
 
     /// Evaluate the operand, returning a place where you can then find the data.