From a0700d062e242940cf9e5644211f2be38e3d88eb Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 00:40:41 +0200
Subject: [PATCH 1/2] Inline move_path_for_projection inside move_path_for

---
 .../dataflow/move_paths/builder.rs            | 114 ++++++++----------
 1 file changed, 53 insertions(+), 61 deletions(-)

diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 7eb4428bf29..507e5a4abab 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -101,7 +101,59 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
                 Err(MoveError::cannot_move_out_of(self.loc, Static))
             }
             Place::Projection(ref proj) => {
-                self.move_path_for_projection(place, proj)
+                let base = self.move_path_for(&proj.base)?;
+                let mir = self.builder.mir;
+                let tcx = self.builder.tcx;
+                let place_ty = proj.base.ty(mir, tcx).ty;
+                match place_ty.sty {
+                    ty::Ref(..) | ty::RawPtr(..) =>
+                        return Err(MoveError::cannot_move_out_of(
+                            self.loc,
+                            BorrowedContent { target_place: place.clone() })),
+                    ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
+                        return Err(MoveError::cannot_move_out_of(self.loc,
+                                                                 InteriorOfTypeWithDestructor {
+                            container_ty: place_ty
+                        })),
+                    // move out of union - always move the entire union
+                    ty::Adt(adt, _) if adt.is_union() =>
+                        return Err(MoveError::UnionMove { path: base }),
+                    ty::Slice(_) =>
+                        return Err(MoveError::cannot_move_out_of(
+                            self.loc,
+                            InteriorOfSliceOrArray {
+                                ty: place_ty, is_index: match proj.elem {
+                                    ProjectionElem::Index(..) => true,
+                                    _ => false
+                                },
+                            })),
+                    ty::Array(..) => match proj.elem {
+                        ProjectionElem::Index(..) =>
+                            return Err(MoveError::cannot_move_out_of(
+                                self.loc,
+                                InteriorOfSliceOrArray {
+                                    ty: place_ty, is_index: true
+                                })),
+                        _ => {
+                            // FIXME: still badly broken
+                        }
+                    },
+                    _ => {}
+                };
+                match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
+                    Entry::Occupied(ent) => Ok(*ent.get()),
+                    Entry::Vacant(ent) => {
+                        let path = MoveDataBuilder::new_move_path(
+                            &mut self.builder.data.move_paths,
+                            &mut self.builder.data.path_map,
+                            &mut self.builder.data.init_path_map,
+                            Some(base),
+                            place.clone()
+                        );
+                        ent.insert(path);
+                        Ok(path)
+                    }
+                }
             }
         }
     }
@@ -111,66 +163,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
         // drop), so this not being a valid move path is OK.
         let _ = self.move_path_for(place);
     }
-
-    fn move_path_for_projection(&mut self,
-                                place: &Place<'tcx>,
-                                proj: &Projection<'tcx>)
-                                -> Result<MovePathIndex, MoveError<'tcx>>
-    {
-        let base = self.move_path_for(&proj.base)?;
-        let mir = self.builder.mir;
-        let tcx = self.builder.tcx;
-        let place_ty = proj.base.ty(mir, tcx).ty;
-        match place_ty.sty {
-            ty::Ref(..) | ty::RawPtr(..) =>
-                return Err(MoveError::cannot_move_out_of(
-                    self.loc,
-                    BorrowedContent { target_place: place.clone() })),
-            ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
-                return Err(MoveError::cannot_move_out_of(self.loc,
-                                                         InteriorOfTypeWithDestructor {
-                    container_ty: place_ty
-                })),
-            // move out of union - always move the entire union
-            ty::Adt(adt, _) if adt.is_union() =>
-                return Err(MoveError::UnionMove { path: base }),
-            ty::Slice(_) =>
-                return Err(MoveError::cannot_move_out_of(
-                    self.loc,
-                    InteriorOfSliceOrArray {
-                        ty: place_ty, is_index: match proj.elem {
-                            ProjectionElem::Index(..) => true,
-                            _ => false
-                        },
-                    })),
-            ty::Array(..) => match proj.elem {
-                ProjectionElem::Index(..) =>
-                    return Err(MoveError::cannot_move_out_of(
-                        self.loc,
-                        InteriorOfSliceOrArray {
-                            ty: place_ty, is_index: true
-                        })),
-                _ => {
-                    // FIXME: still badly broken
-                }
-            },
-            _ => {}
-        };
-        match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
-            Entry::Occupied(ent) => Ok(*ent.get()),
-            Entry::Vacant(ent) => {
-                let path = MoveDataBuilder::new_move_path(
-                    &mut self.builder.data.move_paths,
-                    &mut self.builder.data.path_map,
-                    &mut self.builder.data.init_path_map,
-                    Some(base),
-                    place.clone()
-                );
-                ent.insert(path);
-                Ok(path)
-            }
-        }
-    }
 }
 
 impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {

From 294dc18208e8338631a30767ed0394066638eabf Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Fri, 24 May 2019 00:52:10 +0200
Subject: [PATCH 2/2] Make move_path_for iterate instead of recurse

---
 .../dataflow/move_paths/builder.rs            | 41 ++++++++++++-------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 507e5a4abab..ab0a2d87302 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -95,13 +95,15 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
                      -> Result<MovePathIndex, MoveError<'tcx>>
     {
         debug!("lookup({:?})", place);
-        match *place {
-            Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]),
-            Place::Base(PlaceBase::Static(..)) => {
-                Err(MoveError::cannot_move_out_of(self.loc, Static))
-            }
-            Place::Projection(ref proj) => {
-                let base = self.move_path_for(&proj.base)?;
+        place.iterate(|place_base, place_projection| {
+            let mut base = match place_base {
+                PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
+                PlaceBase::Static(..) => {
+                    return Err(MoveError::cannot_move_out_of(self.loc, Static));
+                }
+            };
+
+            for proj in place_projection {
                 let mir = self.builder.mir;
                 let tcx = self.builder.tcx;
                 let place_ty = proj.base.ty(mir, tcx).ty;
@@ -109,7 +111,9 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
                     ty::Ref(..) | ty::RawPtr(..) =>
                         return Err(MoveError::cannot_move_out_of(
                             self.loc,
-                            BorrowedContent { target_place: place.clone() })),
+                            BorrowedContent {
+                                target_place: Place::Projection(Box::new(proj.clone())),
+                            })),
                     ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
                         return Err(MoveError::cannot_move_out_of(self.loc,
                                                                  InteriorOfTypeWithDestructor {
@@ -140,22 +144,31 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
                     },
                     _ => {}
                 };
-                match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
-                    Entry::Occupied(ent) => Ok(*ent.get()),
+
+                base = match self
+                    .builder
+                    .data
+                    .rev_lookup
+                    .projections
+                    .entry((base, proj.elem.lift()))
+                {
+                    Entry::Occupied(ent) => *ent.get(),
                     Entry::Vacant(ent) => {
                         let path = MoveDataBuilder::new_move_path(
                             &mut self.builder.data.move_paths,
                             &mut self.builder.data.path_map,
                             &mut self.builder.data.init_path_map,
                             Some(base),
-                            place.clone()
+                            Place::Projection(Box::new(proj.clone())),
                         );
                         ent.insert(path);
-                        Ok(path)
+                        path
                     }
-                }
+                };
             }
-        }
+
+            Ok(base)
+        })
     }
 
     fn create_move_path(&mut self, place: &Place<'tcx>) {