about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-11 23:00:38 +0000
committerbors <bors@rust-lang.org>2019-12-11 23:00:38 +0000
commitde0abf7599023b71dd72b44f0165e86c040ee7ea (patch)
treebe49c0cf5e2200c6d31133d7c336d99dee41d90c /src
parent27d6f55f47e8875e71083a28ed84ea5a88e1b596 (diff)
parentd96485d49e3745a9b9f4b2ed6ba9cebf265f142e (diff)
downloadrust-de0abf7599023b71dd72b44f0165e86c040ee7ea.tar.gz
rust-de0abf7599023b71dd72b44f0165e86c040ee7ea.zip
Auto merge of #66650 - matthewjasper:nonuniform-array-move, r=pnkfelix
Remove uniform array move MIR passes

This PR fixes a number of bugs caused by limitations of this pass

* Projections from constant indexes weren't being canonicalized
* Constant indexes from the start weren't being canonicalized (they could have different min_lengths)
* It didn't apply to non-moves

This PR makes the following changes to support removing this pass:

* ConstantIndex of arrays are now generated in a canonical form (from the start, min_length is the actual length).
* Subslices are now split when generating move paths and when checking subslices have been moved.

Additionally

* The parent move path of a projection from an array element is now calculated correctly

closes #66502
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/mod.rs24
-rw-r--r--src/librustc/mir/tcx.rs9
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs3
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs5
-rw-r--r--src/librustc_mir/borrow_check/mod.rs88
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs23
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs42
-rw-r--r--src/librustc_mir/build/matches/util.rs31
-rw-r--r--src/librustc_mir/dataflow/move_paths/abs_domain.rs4
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs131
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs5
-rw-r--r--src/librustc_mir/interpret/place.rs14
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs9
-rw-r--r--src/librustc_mir/transform/mod.rs3
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs2
-rw-r--r--src/librustc_mir/transform/uniform_array_move_out.rs381
-rw-r--r--src/test/mir-opt/const_prop/return_place.rs6
-rw-r--r--src/test/mir-opt/uniform_array_move_out.rs56
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs69
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs69
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use.rs99
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr143
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array.rs69
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array.stderr100
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs66
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs60
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr86
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs61
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs (renamed from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs)46
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr (renamed from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr)24
-rw-r--r--src/test/ui/drop/dynamic-drop.rs32
32 files changed, 1131 insertions, 631 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index a89bc28f40d..ba8feb4ee73 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1714,18 +1714,25 @@ pub enum ProjectionElem<V, T> {
     ConstantIndex {
         /// index or -index (in Python terms), depending on from_end
         offset: u32,
-        /// thing being indexed must be at least this long
+        /// The thing being indexed must be at least this long. For arrays this
+        /// is always the exact length.
         min_length: u32,
-        /// counting backwards from end?
+        /// Counting backwards from end? This is always false when indexing an
+        /// array.
         from_end: bool,
     },
 
     /// These indices are generated by slice patterns.
     ///
-    /// slice[from:-to] in Python terms.
+    /// If `from_end` is true `slice[from..slice.len() - to]`.
+    /// Otherwise `array[from..to]`.
     Subslice {
         from: u32,
         to: u32,
+        /// Whether `to` counts from the start or end of the array/slice.
+        /// For `PlaceElem`s this is `true` if and only if the base is a slice.
+        /// For `ProjectionKind`, this can also be `true` for arrays.
+        from_end: bool,
     },
 
     /// "Downcast" to a variant of an ADT. Currently, we only introduce
@@ -1914,15 +1921,18 @@ impl Debug for Place<'_> {
                 ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
                     write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
                 }
-                ProjectionElem::Subslice { from, to } if *to == 0 => {
+                ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => {
                     write!(fmt, "[{:?}:]", from)?;
                 }
-                ProjectionElem::Subslice { from, to } if *from == 0 => {
+                ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => {
                     write!(fmt, "[:-{:?}]", to)?;
                 }
-                ProjectionElem::Subslice { from, to } => {
+                ProjectionElem::Subslice { from, to, from_end: true } => {
                     write!(fmt, "[{:?}:-{:?}]", from, to)?;
                 }
+                ProjectionElem::Subslice { from, to, from_end: false } => {
+                    write!(fmt, "[{:?}..{:?}]", from, to)?;
+                }
             }
         }
 
@@ -2456,7 +2466,7 @@ impl UserTypeProjection {
     }
 
     pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
-        self.projs.push(ProjectionElem::Subslice { from, to });
+        self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
         self
     }
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index a66a49f103f..445fa6ea8ca 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -88,14 +88,17 @@ impl<'tcx> PlaceTy<'tcx> {
             }
             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                 PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
-            ProjectionElem::Subslice { from, to } => {
+            ProjectionElem::Subslice { from, to, from_end } => {
                 PlaceTy::from_ty(match self.ty.kind {
-                    ty::Array(inner, size) => {
+                    ty::Slice(..) => self.ty,
+                    ty::Array(inner, _) if !from_end => {
+                        tcx.mk_array(inner, (to - from) as u64)
+                    }
+                    ty::Array(inner, size) if from_end => {
                         let size = size.eval_usize(tcx, param_env);
                         let len = size - (from as u64) - (to as u64);
                         tcx.mk_array(inner, len)
                     }
-                    ty::Slice(..) => self.ty,
                     _ => {
                         bug!("cannot subslice non-array type: `{:?}`", self)
                     }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 703e0cc78c2..5d273fe85b6 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -954,7 +954,7 @@ macro_rules! visit_place_fns {
                     );
                 }
                 ProjectionElem::Deref |
-                ProjectionElem::Subslice { from: _, to: _ } |
+                ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
                 ProjectionElem::ConstantIndex { offset: _,
                                                 min_length: _,
                                                 from_end: _ } |
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index e60b8861faf..5e13cabced0 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -565,7 +565,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let llindex = bx.sub(lllen, lloffset);
                         cg_base.project_index(bx, llindex)
                     }
-                    mir::ProjectionElem::Subslice { from, to } => {
+                    mir::ProjectionElem::Subslice { from, to, from_end } => {
                         let mut subslice = cg_base.project_index(bx,
                             bx.cx().const_usize(*from as u64));
                         let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
@@ -573,6 +573,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
 
                         if subslice.layout.is_unsized() {
+                            assert!(from_end, "slice subslices should be `from_end`");
                             subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
                                 bx.cx().const_usize((*from as u64) + (*to as u64))));
                         }
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 252b31e4d3c..1cd43d4fdd4 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -78,10 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             .collect();
 
         if move_out_indices.is_empty() {
-            let root_place = self
-                .prefixes(used_place, PrefixSet::All)
-                .last()
-                .unwrap();
+            let root_place = PlaceRef { projection: &[], ..used_place };
 
             if !self.uninitialized_error_reported.insert(root_place) {
                 debug!(
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 427003f24cb..b4f2e2377ac 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -174,7 +174,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let mut errors_buffer = Vec::new();
     let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
-        match MoveData::gather_moves(&body, tcx) {
+        match MoveData::gather_moves(&body, tcx, param_env) {
             Ok(move_data) => (move_data, None),
             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
         };
@@ -1600,7 +1600,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         (prefix, place_span.0, place_span.1),
                         mpi,
                     );
-                    return; // don't bother finding other problems.
                 }
             }
             Err(NoMovePathFound::ReachedStatic) => {
@@ -1614,6 +1613,46 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
+    /// Subslices correspond to multiple move paths, so we iterate through the
+    /// elements of the base array. For each element we check
+    ///
+    /// * Does this element overlap with our slice.
+    /// * Is any part of it uninitialized.
+    fn check_if_subslice_element_is_moved(
+        &mut self,
+        location: Location,
+        desired_action: InitializationRequiringAction,
+        place_span: (PlaceRef<'cx, 'tcx>, Span),
+        maybe_uninits: &FlowAtLocation<'tcx, MaybeUninitializedPlaces<'cx, 'tcx>>,
+        from: u32,
+        to: u32,
+    ) {
+        if let Some(mpi) = self.move_path_for_place(place_span.0) {
+            let mut child = self.move_data.move_paths[mpi].first_child;
+            while let Some(child_mpi) = child {
+                let child_move_place = &self.move_data.move_paths[child_mpi];
+                let child_place = &child_move_place.place;
+                let last_proj = child_place.projection.last().unwrap();
+                if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
+                    debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
+
+                    if (from..to).contains(offset) {
+                        if let Some(uninit_child) = maybe_uninits.has_any_child_of(child_mpi) {
+                            self.report_use_of_moved_or_uninitialized(
+                                location,
+                                desired_action,
+                                (place_span.0, place_span.0, place_span.1),
+                                uninit_child,
+                            );
+                            return; // don't bother finding other problems.
+                        }
+                    }
+                }
+                child = child_move_place.next_sibling;
+            }
+        }
+    }
+
     fn check_if_path_or_subpath_is_moved(
         &mut self,
         location: Location,
@@ -1640,6 +1679,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
 
+        if let [
+            base_proj @ ..,
+            ProjectionElem::Subslice { from, to, from_end: false },
+        ] = place_span.0.projection {
+            let place_ty = Place::ty_from(
+                place_span.0.base,
+                base_proj,
+                self.body(),
+                self.infcx.tcx,
+            );
+            if let ty::Array(..) = place_ty.ty.kind {
+                let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
+                self.check_if_subslice_element_is_moved(
+                    location,
+                    desired_action,
+                    (array_place, place_span.1),
+                    maybe_uninits,
+                    *from,
+                    *to,
+                );
+                return;
+            }
+        }
+
         // A move of any shallow suffix of `place` also interferes
         // with an attempt to use `place`. This is scenario 3 above.
         //
@@ -1675,25 +1738,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// static variable, as we do not track those in the MoveData.
     fn move_path_closest_to(
         &mut self,
-        place: PlaceRef<'cx, 'tcx>,
+        place: PlaceRef<'_, 'tcx>,
     ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
-        let mut last_prefix = place.base;
-
-        for prefix in self.prefixes(place, PrefixSet::All) {
-            if let Some(mpi) = self.move_path_for_place(prefix) {
-                return Ok((prefix, mpi));
-            }
-
-            last_prefix = prefix.base;
-        }
-
-        match last_prefix {
-            PlaceBase::Local(_) => panic!("should have move path for every Local"),
-            PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic),
+        match self.move_data.rev_lookup.find(place) {
+            LookupResult::Parent(Some(mpi))
+            | LookupResult::Exact(mpi) => Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi)),
+            LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic),
         }
     }
 
-    fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option<MovePathIndex> {
+    fn move_path_for_place(&mut self, place: PlaceRef<'_, 'tcx>) -> Option<MovePathIndex> {
         // If returns None, then there is no move path corresponding
         // to a direct owner of `place` (which means there is nothing
         // that borrowck tracks for its analysis).
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 cddc3b4a271..1e3723edc56 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -675,23 +675,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     }),
                 )
             }
-            ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
+            ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty(
                 match base_ty.kind {
-                    ty::Array(inner, size) => {
-                        let size = size.eval_usize(tcx, self.cx.param_env);
-                        let min_size = (from as u64) + (to as u64);
-                        if let Some(rest_size) = size.checked_sub(min_size) {
-                            tcx.mk_array(inner, rest_size)
-                        } else {
-                            span_mirbug_and_err!(
-                                self,
-                                place,
-                                "taking too-small slice of {:?}",
-                                base_ty
-                            )
-                        }
+                    ty::Array(inner, _) => {
+                        assert!(!from_end, "array subslices should not use from_end");
+                        tcx.mk_array(inner, (to - from) as u64)
                     }
-                    ty::Slice(..) => base_ty,
+                    ty::Slice(..) => {
+                        assert!(from_end, "slice subslices should use from_end");
+                        base_ty
+                    },
                     _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
                 },
             ),
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 87a431a7fb8..9245064f875 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -503,34 +503,62 @@ fn place_projection_conflict<'tcx>(
                 Overlap::Disjoint
             }
         }
+        (
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
+            ProjectionElem::Subslice { from, to, from_end: false }
+        )
+        | (
+            ProjectionElem::Subslice { from, to, from_end: false },
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }
+        ) => {
+            if (from..to).contains(&offset) {
+                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
+                Overlap::EqualOrDisjoint
+            } else {
+                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
+                Overlap::Disjoint
+            }
+        }
         (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
          ProjectionElem::Subslice {from, .. })
         | (ProjectionElem::Subslice {from, .. },
             ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
             if offset >= from {
                 debug!(
-                    "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
+                    "place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");
                 Overlap::EqualOrDisjoint
             } else {
-                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
+                debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
                 Overlap::Disjoint
             }
         }
         (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
-         ProjectionElem::Subslice {from: _, to })
-        | (ProjectionElem::Subslice {from: _, to },
+         ProjectionElem::Subslice { to, from_end: true, .. })
+        | (ProjectionElem::Subslice { to, from_end: true, .. },
             ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
             if offset > to {
                 debug!("place_element_conflict: \
-                       DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+                       DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
                 Overlap::EqualOrDisjoint
             } else {
-                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+                debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
+                Overlap::Disjoint
+            }
+        }
+        (
+            ProjectionElem::Subslice { from: f1, to: t1, from_end: false },
+            ProjectionElem::Subslice { from: f2, to: t2, from_end: false }
+        ) => {
+            if f2 >= t1 || f1 >= t2 {
+                debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");
                 Overlap::Disjoint
+            } else {
+                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
+                Overlap::EqualOrDisjoint
             }
         }
         (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
-            debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
+            debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
              Overlap::EqualOrDisjoint
         }
         (ProjectionElem::Deref, _)
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index aec9e6e57d4..ec8b3c5e24b 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -2,6 +2,7 @@ use crate::build::Builder;
 use crate::build::matches::MatchPair;
 use crate::hair::*;
 use rustc::mir::*;
+use rustc::ty;
 use smallvec::SmallVec;
 use std::u32;
 use std::convert::TryInto;
@@ -31,9 +32,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                      prefix: &'pat [Pat<'tcx>],
                                      opt_slice: Option<&'pat Pat<'tcx>>,
                                      suffix: &'pat [Pat<'tcx>]) {
-        let min_length = prefix.len() + suffix.len();
-        let min_length = min_length.try_into().unwrap();
         let tcx = self.hir.tcx();
+        let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
+            ty::Array(_, length) => (
+                length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(),
+                true
+            ),
+            _ => (
+                (prefix.len() + suffix.len()).try_into().unwrap(),
+                false,
+            ),
+        };
 
         match_pairs.extend(
             prefix.iter()
@@ -50,10 +59,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         );
 
         if let Some(subslice_pat) = opt_slice {
-            let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
-                from: prefix.len() as u32,
-                to: suffix.len() as u32
-            });
+            let suffix_len = suffix.len() as u32;
+            let subslice = tcx.mk_place_elem(
+                place.clone(),
+                ProjectionElem::Subslice {
+                    from: prefix.len() as u32,
+                    to: if exact_size { min_length - suffix_len } else { suffix_len },
+                    from_end: !exact_size,
+                },
+            );
             match_pairs.push(MatchPair::new(subslice, subslice_pat));
         }
 
@@ -62,10 +76,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                   .rev()
                   .enumerate()
                   .map(|(idx, subpattern)| {
+                      let end_offset = (idx + 1) as u32;
                       let elem = ProjectionElem::ConstantIndex {
-                          offset: (idx+1) as u32,
+                          offset: if exact_size { min_length - end_offset } else { end_offset },
                           min_length,
-                          from_end: true,
+                          from_end: !exact_size,
                       };
                       let place = tcx.mk_place_elem(place.clone(), elem);
                       MatchPair::new(place, subpattern)
diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
index d97f3b74172..0665c0fb72c 100644
--- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs
+++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
@@ -49,8 +49,8 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
             ProjectionElem::Deref => ProjectionElem::Deref,
             ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
             ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
-            ProjectionElem::Subslice { from, to } => {
-                ProjectionElem::Subslice { from: from, to: to }
+            ProjectionElem::Subslice { from, to, from_end } => {
+                ProjectionElem::Subslice { from, to, from_end }
             }
             ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
                 ProjectionElem::ConstantIndex { offset, min_length, from_end }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 52016d4c936..fa0864e0de7 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc_index::vec::IndexVec;
 use smallvec::{smallvec, SmallVec};
 
-use std::collections::hash_map::Entry;
+use std::convert::TryInto;
 use std::mem;
 
 use super::abs_domain::Lift;
@@ -17,12 +17,13 @@ use super::{
 struct MoveDataBuilder<'a, 'tcx> {
     body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     data: MoveData<'tcx>,
     errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
 }
 
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
-    fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+    fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
         let mut move_paths = IndexVec::new();
         let mut path_map = IndexVec::new();
         let mut init_path_map = IndexVec::new();
@@ -30,6 +31,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         MoveDataBuilder {
             body,
             tcx,
+            param_env,
             errors: Vec::new(),
             data: MoveData {
                 moves: IndexVec::new(),
@@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                             InteriorOfSliceOrArray { ty: place_ty, is_index: true },
                         ));
                     }
-                    _ => {
-                        // FIXME: still badly broken
-                    }
+                    _ => {}
                 },
                 _ => {}
             };
 
-            let proj = &place.projection[..i+1];
-            base = match self
-                .builder
-                .data
-                .rev_lookup
-                .projections
-                .entry((base, 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 {
-                                base: place.base.clone(),
-                                projection: tcx.intern_place_elems(proj),
-                            },
-                        );
-                        ent.insert(path);
-                        path
-                    }
-                };
+            base = self.add_move_path(base, elem, |tcx| {
+                Place {
+                    base: place.base.clone(),
+                    projection: tcx.intern_place_elems(&place.projection[..i+1]),
+                }
+            });
         }
 
         Ok(base)
     }
 
+    fn add_move_path(
+        &mut self,
+        base: MovePathIndex,
+        elem: &PlaceElem<'tcx>,
+        mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>,
+    ) -> MovePathIndex {
+        let MoveDataBuilder {
+            data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. },
+            tcx,
+            ..
+        } = self.builder;
+        *rev_lookup.projections
+            .entry((base, elem.lift()))
+            .or_insert_with(move || {
+                let path = MoveDataBuilder::new_move_path(
+                    move_paths,
+                    path_map,
+                    init_path_map,
+                    Some(base),
+                    mk_place(*tcx),
+                );
+                path
+            })
+    }
+
     fn create_move_path(&mut self, place: &Place<'tcx>) {
         // This is an non-moving access (such as an overwrite or
         // drop), so this not being a valid move path is OK.
@@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
 pub(super) fn gather_moves<'tcx>(
     body: &Body<'tcx>,
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 ) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
-    let mut builder = MoveDataBuilder::new(body, tcx);
+    let mut builder = MoveDataBuilder::new(body, tcx, param_env);
 
     builder.gather_args();
 
@@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     fn gather_move(&mut self, place: &Place<'tcx>) {
         debug!("gather_move({:?}, {:?})", self.loc, place);
 
-        let path = match self.move_path_for(place) {
-            Ok(path) | Err(MoveError::UnionMove { path }) => path,
-            Err(error @ MoveError::IllegalMove { .. }) => {
-                self.builder.errors.push((place.clone(), error));
-                return;
+        if let [
+            ref base @ ..,
+            ProjectionElem::Subslice { from, to, from_end: false },
+        ] = **place.projection {
+            // Split `Subslice` patterns into the corresponding list of
+            // `ConstIndex` patterns. This is done to ensure that all move paths
+            // are disjoint, which is expected by drop elaboration.
+            let base_place = Place {
+                base: place.base.clone(),
+                projection: self.builder.tcx.intern_place_elems(base),
+            };
+            let base_path = match self.move_path_for(&base_place) {
+                Ok(path) => path,
+                Err(MoveError::UnionMove { path }) => {
+                    self.record_move(place, path);
+                    return;
+                }
+                Err(error @ MoveError::IllegalMove { .. }) => {
+                    self.builder.errors.push((base_place, error));
+                    return;
+                }
+            };
+            let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
+            let len: u32 = match base_ty.kind {
+                ty::Array(_, size) => {
+                    let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
+                    length.try_into().expect(
+                        "slice pattern of array with more than u32::MAX elements"
+                    )
+                }
+                _ => bug!("from_end: false slice pattern of non-array type"),
+            };
+            for offset in from..to {
+                let elem = ProjectionElem::ConstantIndex {
+                    offset,
+                    min_length: len,
+                    from_end: false,
+                };
+                let path = self.add_move_path(
+                    base_path,
+                    &elem,
+                    |tcx| tcx.mk_place_elem(base_place.clone(), elem),
+                );
+                self.record_move(place, path);
             }
-        };
-        let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
+        } else {
+            match self.move_path_for(place) {
+                Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
+                Err(error @ MoveError::IllegalMove { .. }) => {
+                    self.builder.errors.push((place.clone(), error));
+                }
+            };
+        }
+    }
 
+    fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) {
+        let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
         debug!(
             "gather_move({:?}, {:?}): adding move {:?} of {:?}",
             self.loc, place, move_out, path
         );
-
         self.builder.data.path_map[path].push(move_out);
         self.builder.data.loc_map[self.loc].push(move_out);
     }
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index b599f479944..89ef9b245ce 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -1,6 +1,6 @@
 use core::slice::Iter;
 use rustc::mir::*;
-use rustc::ty::{Ty, TyCtxt};
+use rustc::ty::{Ty, TyCtxt, ParamEnv};
 use rustc::util::nodemap::FxHashMap;
 use rustc_index::vec::{Enumerated, Idx, IndexVec};
 use smallvec::SmallVec;
@@ -318,8 +318,9 @@ impl<'tcx> MoveData<'tcx> {
     pub fn gather_moves(
         body: &Body<'tcx>,
         tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
     ) -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
-        builder::gather_moves(body, tcx)
+        builder::gather_moves(body, tcx, param_env)
     }
 
     /// For the move path `mpi`, returns the root local variable (if any) that starts the path.
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index a600eb11e1d..42fbfeca3f0 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -451,9 +451,15 @@ where
         base: MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
         to: u64,
+        from_end: bool,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
-        assert!(from <= len - to);
+        let actual_to = if from_end {
+            assert!(from <= len - to);
+            len - to
+        } else {
+            to
+        };
 
         // Not using layout method because that works with usize, and does not work with slices
         // (that have count 0 in their layout).
@@ -464,7 +470,7 @@ where
         };
 
         // Compute meta and new layout
-        let inner_len = len - to - from;
+        let inner_len = actual_to - from;
         let (meta, ty) = match base.layout.ty.kind {
             // It is not nice to match on the type, but that seems to be the only way to
             // implement this.
@@ -528,8 +534,8 @@ where
                 self.mplace_field(base, index)?
             }
 
-            Subslice { from, to } =>
-                self.mplace_subslice(base, u64::from(from), u64::from(to))?,
+            Subslice { from, to, from_end } =>
+                self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?,
         })
     }
 
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 9970752a376..1cacf1f3b0a 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
 
         let def_id = src.def_id();
         let param_env = tcx.param_env(src.def_id()).with_reveal_all();
-        let move_data = match MoveData::gather_moves(body, tcx) {
+        let move_data = match MoveData::gather_moves(body, tcx, param_env) {
             Ok(move_data) => move_data,
             Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
         };
@@ -234,12 +234,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
 
     fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
-            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
+            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                debug_assert!(size == *min_length, "min_length should be exact for arrays");
+                assert!(!from_end, "from_end should not be used for array element ConstantIndex");
                 *offset == index
             }
-            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
-                size - offset == index
-            }
             _ => false,
         })
     }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index bedf2a95c02..2e1a08a0224 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -35,7 +35,6 @@ pub mod copy_prop;
 pub mod const_prop;
 pub mod generator;
 pub mod inline;
-pub mod uniform_array_move_out;
 pub mod uninhabited_enum_branching;
 
 pub(crate) fn provide(providers: &mut Providers<'_>) {
@@ -229,7 +228,6 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
         // What we need to do constant evaluation.
         &simplify::SimplifyCfg::new("initial"),
         &rustc_peek::SanityCheck,
-        &uniform_array_move_out::UniformArrayMoveOut,
     ]);
     body.ensure_predecessors();
     tcx.alloc_steal_mir(body)
@@ -294,7 +292,6 @@ fn run_optimization_passes<'tcx>(
         // Optimizations begin.
         &uninhabited_enum_branching::UninhabitedEnumBranching,
         &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
-        &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
         &inline::Inline,
 
         // Lowering generator control-flow and variables
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 2a81e97b8ff..4345fc66bb9 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
 
         let attributes = tcx.get_attrs(def_id);
         let param_env = tcx.param_env(def_id);
-        let move_data = MoveData::gather_moves(body, tcx).unwrap();
+        let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
         let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
         let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
         let flow_inits =
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
deleted file mode 100644
index 71dd405386a..00000000000
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ /dev/null
@@ -1,381 +0,0 @@
-// This pass converts move out from array by Subslice and
-// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin
-// of array. It allows detect error by mir borrowck and elaborate
-// drops for array without additional work.
-//
-// Example:
-//
-// let a = [ box 1,box 2, box 3];
-// if b {
-//  let [_a.., _] = a;
-// } else {
-//  let [.., _b] = a;
-// }
-//
-//  mir statement _10 = move _2[:-1]; replaced by:
-//  StorageLive(_12);
-//  _12 = move _2[0 of 3];
-//  StorageLive(_13);
-//  _13 = move _2[1 of 3];
-//  _10 = [move _12, move _13]
-//  StorageDead(_12);
-//  StorageDead(_13);
-//
-//  and mir statement _11 = move _2[-1 of 1]; replaced by:
-//  _11 = move _2[2 of 3];
-//
-// FIXME: integrate this transformation to the mir build
-
-use rustc::ty;
-use rustc::ty::TyCtxt;
-use rustc::mir::*;
-use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext};
-use rustc_index::vec::{IndexVec};
-use crate::transform::{MirPass, MirSource};
-use crate::util::patch::MirPatch;
-
-pub struct UniformArrayMoveOut;
-
-impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
-        let mut patch = MirPatch::new(body);
-        let param_env = tcx.param_env(src.def_id());
-        {
-            let read_only_cache = read_only!(body);
-            let mut visitor
-                = UniformArrayMoveOutVisitor{ body, patch: &mut patch, tcx, param_env};
-            visitor.visit_body(read_only_cache);
-        }
-        patch.apply(body);
-    }
-}
-
-struct UniformArrayMoveOutVisitor<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    patch: &'a mut MirPatch<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
-    fn visit_assign(&mut self,
-                    dst_place: &Place<'tcx>,
-                    rvalue: &Rvalue<'tcx>,
-                    location: Location) {
-        if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
-            if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
-                if let ProjectionElem::ConstantIndex{offset: _,
-                                                     min_length: _,
-                                                     from_end: false} = elem {
-                    // no need to transformation
-                } else {
-                    let place_ty =
-                        Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
-                    if let ty::Array(item_ty, const_size) = place_ty.kind {
-                        if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
-                            assert!(size <= u32::max_value() as u64,
-                                    "uniform array move out doesn't supported
-                                     for array bigger then u32");
-                            self.uniform(
-                                location,
-                                dst_place,
-                                &src_place.base,
-                                &src_place.projection,
-                                item_ty,
-                                size as u32,
-                            );
-                        }
-                    }
-
-                }
-            }
-        }
-        self.super_assign(dst_place, rvalue, location)
-    }
-}
-
-impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
-    fn uniform(&mut self,
-               location: Location,
-               dst_place: &Place<'tcx>,
-               base: &PlaceBase<'tcx>,
-               proj: &[PlaceElem<'tcx>],
-               item_ty: &'tcx ty::TyS<'tcx>,
-               size: u32) {
-        if let [proj_base @ .., elem] = proj {
-            match elem {
-                // uniforms statements like_10 = move _2[:-1];
-                ProjectionElem::Subslice{from, to} => {
-                    self.patch.make_nop(location);
-                    let temps : Vec<_> = (*from..(size-*to)).map(|i| {
-                        let temp =
-                            self.patch.new_temp(item_ty, self.body.source_info(location).span);
-                        self.patch.add_statement(location, StatementKind::StorageLive(temp));
-
-                        let mut projection = proj_base.to_vec();
-                        projection.push(ProjectionElem::ConstantIndex {
-                            offset: i,
-                            min_length: size,
-                            from_end: false,
-                        });
-                        self.patch.add_assign(
-                            location,
-                            Place::from(temp),
-                            Rvalue::Use(Operand::Move(Place {
-                                base: base.clone(),
-                                projection: self.tcx.intern_place_elems(&projection),
-                            })),
-                        );
-                        temp
-                    }).collect();
-                    self.patch.add_assign(
-                        location,
-                        dst_place.clone(),
-                        Rvalue::Aggregate(
-                            box AggregateKind::Array(item_ty),
-                            temps.iter().map(
-                                |x| Operand::Move(Place::from(*x))
-                            ).collect()
-                        )
-                    );
-                    for temp in temps {
-                        self.patch.add_statement(location, StatementKind::StorageDead(temp));
-                    }
-                }
-                // uniforms statements like _11 = move _2[-1 of 1];
-                ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
-                    self.patch.make_nop(location);
-
-                    let mut projection = proj_base.to_vec();
-                    projection.push(ProjectionElem::ConstantIndex {
-                        offset: size - offset,
-                        min_length: size,
-                        from_end: false,
-                    });
-                    self.patch.add_assign(
-                        location,
-                        dst_place.clone(),
-                        Rvalue::Use(Operand::Move(Place {
-                            base: base.clone(),
-                            projection: self.tcx.intern_place_elems(&projection),
-                        })),
-                    );
-                }
-                _ => {}
-            }
-        }
-    }
-}
-
-// Restore Subslice move out after analysis
-// Example:
-//
-//  next statements:
-//   StorageLive(_12);
-//   _12 = move _2[0 of 3];
-//   StorageLive(_13);
-//   _13 = move _2[1 of 3];
-//   _10 = [move _12, move _13]
-//   StorageDead(_12);
-//   StorageDead(_13);
-//
-// replaced by _10 = move _2[:-1];
-
-pub struct RestoreSubsliceArrayMoveOut<'tcx> {
-    tcx: TyCtxt<'tcx>
-}
-
-impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
-        let mut patch = MirPatch::new(body);
-        let param_env = tcx.param_env(src.def_id());
-        {
-            let read_only_cache = read_only!(body);
-            let mut visitor = RestoreDataCollector {
-                locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls),
-                candidates: vec![],
-            };
-            visitor.visit_body(read_only_cache);
-
-            for candidate in &visitor.candidates {
-                let statement = &body[candidate.block].statements[candidate.statement_index];
-                if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
-                    if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
-                        let items : Vec<_> = items.iter().map(|item| {
-                            if let Operand::Move(place) = item {
-                                if let Some(local) = place.as_local() {
-                                    let local_use = &visitor.locals_use[local];
-                                    let opt_index_and_place =
-                                        Self::try_get_item_source(local_use, body);
-                                    // each local should be used twice:
-                                    //  in assign and in aggregate statements
-                                    if local_use.use_count == 2 && opt_index_and_place.is_some() {
-                                        let (index, src_place) = opt_index_and_place.unwrap();
-                                        return Some((local_use, index, src_place));
-                                    }
-                                }
-                            }
-                            None
-                        }).collect();
-
-                        let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
-                        let opt_size = opt_src_place.and_then(|src_place| {
-                            let src_ty = Place::ty_from(
-                                src_place.base,
-                                src_place.projection,
-                                &**body,
-                                tcx
-                            ).ty;
-                            if let ty::Array(_, ref size_o) = src_ty.kind {
-                                size_o.try_eval_usize(tcx, param_env)
-                            } else {
-                                None
-                            }
-                        });
-                        let restore_subslice = RestoreSubsliceArrayMoveOut { tcx };
-                        restore_subslice
-                            .check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
-                    }
-                }
-            }
-        }
-        patch.apply(body);
-    }
-}
-
-impl RestoreSubsliceArrayMoveOut<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
-        RestoreSubsliceArrayMoveOut { tcx }
-    }
-
-    // Checks that source has size, all locals are inited from same source place and
-    // indices is an integer interval. If all checks pass do the replacent.
-    // items are Vec<Option<LocalUse, index in source array, source place for init local>>
-    fn check_and_patch(&self,
-                       candidate: Location,
-                       items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
-                       opt_size: Option<u64>,
-                       patch: &mut MirPatch<'tcx>,
-                       dst_place: &Place<'tcx>) {
-        let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
-
-        if opt_size.is_some() && items.iter().all(
-            |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
-            let src_place = opt_src_place.unwrap();
-
-            let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
-            for i in 1..indices.len() {
-                if indices[i - 1] + 1 != indices[i] {
-                    return;
-                }
-            }
-
-            let min = *indices.first().unwrap();
-            let max = *indices.last().unwrap();
-
-            for item in items {
-                let locals_use = item.unwrap().0;
-                patch.make_nop(locals_use.alive.unwrap());
-                patch.make_nop(locals_use.dead.unwrap());
-                patch.make_nop(locals_use.first_use.unwrap());
-            }
-            patch.make_nop(candidate);
-            let size = opt_size.unwrap() as u32;
-
-            let mut projection = src_place.projection.to_vec();
-            projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
-            patch.add_assign(
-                candidate,
-                dst_place.clone(),
-                Rvalue::Use(Operand::Move(Place {
-                    base: src_place.base.clone(),
-                    projection: self.tcx.intern_place_elems(&projection),
-                })),
-            );
-        }
-    }
-
-    fn try_get_item_source<'a>(local_use: &LocalUse,
-                               body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
-        if let Some(location) = local_use.first_use {
-            let block = &body[location.block];
-            if block.statements.len() > location.statement_index {
-                let statement = &block.statements[location.statement_index];
-                if let StatementKind::Assign(
-                    box(place, Rvalue::Use(Operand::Move(src_place)))
-                ) = &statement.kind {
-                    if let (Some(_), PlaceRef {
-                        base: _,
-                        projection: &[.., ProjectionElem::ConstantIndex {
-                            offset, min_length: _, from_end: false
-                        }],
-                    }) = (place.as_local(), src_place.as_ref()) {
-                        if let StatementKind::Assign(
-                            box(_, Rvalue::Use(Operand::Move(place)))
-                        ) = &statement.kind {
-                            if let PlaceRef {
-                                base,
-                                projection: &[ref proj_base @ .., _],
-                            } = place.as_ref() {
-                                return Some((offset, PlaceRef {
-                                    base,
-                                    projection: proj_base,
-                                }))
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        None
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-struct LocalUse {
-    alive: Option<Location>,
-    dead: Option<Location>,
-    use_count: u32,
-    first_use: Option<Location>,
-}
-
-impl LocalUse {
-    pub fn new() -> Self {
-        LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
-    }
-}
-
-struct RestoreDataCollector {
-    locals_use: IndexVec<Local, LocalUse>,
-    candidates: Vec<Location>,
-}
-
-impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
-    fn visit_assign(&mut self,
-                    place: &Place<'tcx>,
-                    rvalue: &Rvalue<'tcx>,
-                    location: Location) {
-        if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
-            self.candidates.push(location);
-        }
-        self.super_assign(place, rvalue, location)
-    }
-
-    fn visit_local(&mut self,
-                   local: &Local,
-                   context: PlaceContext,
-                   location: Location) {
-        let local_use = &mut self.locals_use[*local];
-        match context {
-            PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
-            PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
-            PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {}
-            _ => {
-                local_use.use_count += 1;
-                if local_use.first_use.is_none() {
-                    local_use.first_use = Some(location);
-                }
-            }
-        }
-    }
-}
diff --git a/src/test/mir-opt/const_prop/return_place.rs b/src/test/mir-opt/const_prop/return_place.rs
index cc9951b554d..ea7c1e7ccd0 100644
--- a/src/test/mir-opt/const_prop/return_place.rs
+++ b/src/test/mir-opt/const_prop/return_place.rs
@@ -21,9 +21,6 @@ fn main() {
 //         _0 = move (_1.0: u32);
 //         return;
 //     }
-//     bb2 (cleanup): {
-//         resume;
-//     }
 // }
 // END rustc.add.ConstProp.before.mir
 // START rustc.add.ConstProp.after.mir
@@ -38,9 +35,6 @@ fn main() {
 //         _0 = const 4u32;
 //         return;
 //     }
-//     bb2 (cleanup): {
-//         resume;
-//     }
 // }
 // END rustc.add.ConstProp.after.mir
 // START rustc.add.PreCodegen.before.mir
diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs
index c249154c71e..f2e1864096e 100644
--- a/src/test/mir-opt/uniform_array_move_out.rs
+++ b/src/test/mir-opt/uniform_array_move_out.rs
@@ -18,58 +18,12 @@ fn main() {
 
 // END RUST SOURCE
 
-// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir
-//     StorageLive(_6);
-//      _6 = move _1[-1 of 1];
-//      _0 = ();
-// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir
-
-// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir
-//     StorageLive(_6);
+// START rustc.move_out_from_end.mir_map.0.mir
 //      _6 = move _1[1 of 2];
-//      nop;
 //      _0 = ();
-// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir
-
-// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
-//     StorageLive(_6);
-//      _6 = move _1[0:];
-// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
-
-// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
-//     StorageLive(_6);
-//     StorageLive(_7);
-//     _7 = move _1[0 of 2];
-//     StorageLive(_8);
-//     _8 = move _1[1 of 2];
-//     _6 = [move _7, move _8];
-//     StorageDead(_7);
-//     StorageDead(_8);
-//     nop;
-//     _0 = ();
-// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
-
-// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
-//     StorageLive(_6);
-//     StorageLive(_7);
-//     _7 = move _1[0 of 2];
-//     StorageLive(_8);
-//     _8 = move _1[1 of 2];
-//     _6 = [move _7, move _8];
-//     StorageDead(_7);
-//     StorageDead(_8);
-//     _0 = ();
-// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
+// END rustc.move_out_from_end.mir_map.0.mir
 
-// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
-//     StorageLive(_6);
-//     nop;
-//     nop;
-//     nop;
-//     nop;
-//     _6 = move _1[0:];
-//     nop;
-//     nop;
-//     nop;
+// START rustc.move_out_by_subslice.mir_map.0.mir
+//     _6 = move _1[0..2];
 //     _0 = ();
-// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
+// END rustc.move_out_by_subslice.mir_map.0.mir
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
new file mode 100644
index 00000000000..8f274cf73cb
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
@@ -0,0 +1,69 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_, _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    let [_, _y @ ..] = a;
+    let [(_x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    let [_y @ .., _] = a;
+    let [.., (_x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
new file mode 100644
index 00000000000..57ce2417570
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
@@ -0,0 +1,69 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., ref _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_, ref _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    let [_, _y @ ..] = a;
+    let [(ref _x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    let [_y @ .., _] = a;
+    let [.., (ref _x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
new file mode 100644
index 00000000000..778beefbf2c
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
@@ -0,0 +1,99 @@
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (ref _y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    let [_y @ .., _, _] = a;
+    let [(ref _x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    let [_, _, _y @ ..] = a;
+    let [.., (ref _x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _] = a;
+    let [_, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+// Move + Assign
+
+fn move_out_and_assign_end() {
+    let mut a = array();
+    let [_, _, _x] = a;
+    a[2] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_and_assign_end_field() {
+    let mut a = array();
+    let [_, _, (_x, _)] = a;
+    a[2].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end() {
+    let mut a = array();
+    let [_, _, _x @ ..] = a;
+    a[0] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end_field() {
+    let mut a = array();
+    let [_, _, _x @ ..] = a;
+    a[0].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
new file mode 100644
index 00000000000..2a7b89132c1
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -0,0 +1,143 @@
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:12:14
+   |
+LL |     let [_, _, _x] = a;
+   |                -- value moved here
+LL |     let [.., ref _y] = a;
+   |              ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:18:14
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., ref _y] = a;
+   |              ^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-use.rs:24:15
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., (ref _y, _)] = a;
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:32:10
+   |
+LL |     let [_x, _, _] = a;
+   |          -- value moved here
+LL |     let [ref _y @ .., _, _] = a;
+   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:38:16
+   |
+LL |     let [.., _x] = a;
+   |              -- value moved here
+LL |     let [_, _, ref _y @ ..] = a;
+   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:44:10
+   |
+LL |     let [(_x, _), _, _] = a;
+   |           -- value moved here
+LL |     let [ref _y @ .., _, _] = a;
+   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:50:16
+   |
+LL |     let [.., (_x, _)] = a;
+   |               -- value moved here
+LL |     let [_, _, ref _y @ ..] = a;
+   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:56:11
+   |
+LL |     let [_y @ .., _, _] = a;
+   |          ------- value moved here
+LL |     let [(ref _x, _), _, _] = a;
+   |           ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:62:15
+   |
+LL |     let [_, _, _y @ ..] = a;
+   |                ------- value moved here
+LL |     let [.., (ref _x, _)] = a;
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:70:13
+   |
+LL |     let [x @ .., _] = a;
+   |          ------ value moved here
+LL |     let [_, ref _y @ ..] = a;
+   |             ^^^^^^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:78:5
+   |
+LL |     let [_, _, _x] = a;
+   |                -- value moved here
+LL |     a[2] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:84:5
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     a[2].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:90:5
+   |
+LL |     let [_, _, _x @ ..] = a;
+   |                ------- value moved here
+LL |     a[0] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:96:5
+   |
+LL |     let [_, _, _x @ ..] = a;
+   |                ------- value moved here
+LL |     a[0].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.rs b/src/test/ui/borrowck/borrowck-move-out-from-array.rs
index ee6abf407a3..f9d3f6f2c07 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.rs
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.rs
@@ -1,16 +1,73 @@
-#![feature(box_syntax)]
 #![feature(slice_patterns)]
 
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
 fn move_out_from_begin_and_end() {
-    let a = [box 1, box 2];
-    let [_, _x] = a;
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
     let [.., _y] = a; //~ ERROR [E0382]
 }
 
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
 fn move_out_by_const_index_and_subslice() {
-    let a = [box 1, box 2];
-    let [_x, _] = a;
-    let [_y @ ..] = a; //~ ERROR [E0382]
+    let a = array();
+    let [_x, _, _] = a;
+    let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    let [_y @ .., _, _] = a;
+    let [(_x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    let [_, _, _y @ ..] = a;
+    let [.., (_x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _] = a;
+    let [_, _y @ ..] = a; //~ ERROR [E0382]
 }
 
 fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index b34c03e6def..08134a2a323 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -1,23 +1,103 @@
 error[E0382]: use of moved value: `a[..]`
-  --> $DIR/borrowck-move-out-from-array.rs:7:14
+  --> $DIR/borrowck-move-out-from-array.rs:12:14
    |
-LL |     let [_, _x] = a;
-   |             -- value moved here
+LL |     let [_, _, _x] = a;
+   |                -- value moved here
 LL |     let [.., _y] = a;
    |              ^^ value used here after move
    |
-   = note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value: `a[..]`
-  --> $DIR/borrowck-move-out-from-array.rs:13:10
+  --> $DIR/borrowck-move-out-from-array.rs:18:14
    |
-LL |     let [_x, _] = a;
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., _y] = a;
+   |              ^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:24:15
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., (_y, _)] = a;
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:32:10
+   |
+LL |     let [_x, _, _] = a;
    |          -- value moved here
-LL |     let [_y @ ..] = a;
-   |          ^^^^^^^ value used here after move
+LL |     let [_y @ .., _, _] = a;
+   |          ^^^^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:38:16
+   |
+LL |     let [.., _x] = a;
+   |              -- value moved here
+LL |     let [_, _, _y @ ..] = a;
+   |                ^^^^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:44:10
+   |
+LL |     let [(_x, _), _, _] = a;
+   |           -- value moved here
+LL |     let [_y @ .., _, _] = a;
+   |          ^^^^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:50:16
+   |
+LL |     let [.., (_x, _)] = a;
+   |               -- value moved here
+LL |     let [_, _, _y @ ..] = a;
+   |                ^^^^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:56:11
+   |
+LL |     let [_y @ .., _, _] = a;
+   |          ------- value moved here
+LL |     let [(_x, _), _, _] = a;
+   |           ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:62:15
+   |
+LL |     let [_, _, _y @ ..] = a;
+   |                ------- value moved here
+LL |     let [.., (_x, _)] = a;
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:70:13
+   |
+LL |     let [x @ .., _] = a;
+   |          ------ value moved here
+LL |     let [_, _y @ ..] = a;
+   |             ^^^^^^^ value used here after partial move
    |
-   = note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
 
-error: aborting due to 2 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
new file mode 100644
index 00000000000..7d91a212647
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
@@ -0,0 +1,66 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32; 4]) {
+    let [ref first, ref second, _, ref fourth, ..] = *s;
+    let [_, _, ref mut third, ..] = *s;
+    nop(&[first, second, third, fourth]);
+}
+
+fn const_index_from_end_ok(s: &mut [i32; 4]) {
+    let [.., ref fourth, ref third, _, ref first] = *s;
+    let [.., ref mut second, _] = *s;
+    nop(&[first, second, third, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+    let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+    let [ref mut from_begin0, ..] = *s;
+    nop(&[from_begin0, from_end1, from_end3, from_end4]);
+    let [_, ref mut from_begin1, ..] = *s;
+    nop(&[from_begin1, from_end1, from_end3, from_end4]);
+
+    let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+    let [.., ref mut from_end1] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+    let [.., ref mut from_end2, _] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
+    let [.., ref mut from_end4, _, _, _] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, _, ref mut tail @ ..] = *s;
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) {
+    let [.., ref second, ref first] = *s;
+    let [ref mut tail @ .., _, _] = *s;
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn subslices(s: &mut [i32; 4]) {
+    let [_, _, ref s1 @ ..] = *s;
+    let [ref mut s2 @ .., _, _] = *s;
+    nop_subslice(s1);
+    nop_subslice(s2);
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_ok(&mut v);
+    const_index_from_end_ok(&mut v);
+    const_index_and_subslice_ok(&mut v);
+    const_index_and_subslice_from_end_ok(&mut v);
+    subslices(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
new file mode 100644
index 00000000000..f03a2ab8fa8
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
@@ -0,0 +1,60 @@
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_err(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, ref mut  second2, ref mut third, ..] = *s; //~ERROR
+    nop(&[first, second, second2, third]);
+}
+
+fn const_index_from_end_err(s: &mut [i32; 4]) {
+    let [.., ref fourth, ref third, _, ref first] = *s;
+    let [.., ref mut third2, _, _] = *s; //~ERROR
+    nop(&[first, third, third2, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+    let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+    let [_, _, ref mut from_begin2, ..] = *s; //~ERROR
+    nop(&[from_begin2, from_end1, from_end3, from_end4]);
+    let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR
+    nop(&[from_begin3, from_end1, from_end3, from_end4]);
+
+    let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+    let [.., ref mut from_end3, _,  _] = *s; //~ERROR
+    nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+}
+
+fn const_index_and_subslice_err(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, ref mut tail @ ..] = *s; //~ERROR
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) {
+    let [.., ref second, ref first] = *s;
+    let [ref mut tail @ .., _] = *s; //~ERROR
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn subslices_overlap(s: &mut [i32; 4]) {
+    let [_,  ref s1 @ ..] = *s;
+    let [ref mut s2 @ .., _, _] = *s; //~ERROR
+    nop_subslice(s1);
+    nop_subslice(s2);
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_err(&mut v);
+    const_index_from_end_err(&mut v);
+    const_index_and_subslice_err(&mut v);
+    const_index_and_subslice_from_end_err(&mut v);
+    subslices_overlap(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
new file mode 100644
index 00000000000..e50e7eb3e22
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
@@ -0,0 +1,86 @@
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:8:13
+   |
+LL |     let [ref first, ref second, ..] = *s;
+   |                     ---------- immutable borrow occurs here
+LL |     let [_, ref mut  second2, ref mut third, ..] = *s;
+   |             ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second, second2, third]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:14:14
+   |
+LL |     let [.., ref fourth, ref third, _, ref first] = *s;
+   |                          --------- immutable borrow occurs here
+LL |     let [.., ref mut third2, _, _] = *s;
+   |              ^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, third, third2, fourth]);
+   |                  ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:16
+   |
+LL |     let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+   |                 ------------- immutable borrow occurs here
+LL | 
+LL |     let [_, _, ref mut from_begin2, ..] = *s;
+   |                ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin2, from_end1, from_end3, from_end4]);
+   |                                              --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:23:19
+   |
+LL |     let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+   |                                ------------- immutable borrow occurs here
+...
+LL |     let [_, _, _, ref mut from_begin3, ..] = *s;
+   |                   ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin3, from_end1, from_end3, from_end4]);
+   |                                   --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:28:14
+   |
+LL |     let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+   |                                               --------------- immutable borrow occurs here
+LL | 
+LL |     let [.., ref mut from_end3, _,  _] = *s;
+   |              ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+   |                                     ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:34:13
+   |
+LL |     let [ref first, ref second, ..] = *s;
+   |                     ---------- immutable borrow occurs here
+LL |     let [_, ref mut tail @ ..] = *s;
+   |             ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:41:10
+   |
+LL |     let [.., ref second, ref first] = *s;
+   |              ---------- immutable borrow occurs here
+LL |     let [ref mut tail @ .., _] = *s;
+   |          ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:48:10
+   |
+LL |     let [_,  ref s1 @ ..] = *s;
+   |              ----------- immutable borrow occurs here
+LL |     let [ref mut s2 @ .., _, _] = *s;
+   |          ^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop_subslice(s1);
+   |                  -- immutable borrow later used here
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
new file mode 100644
index 00000000000..e69071f8772
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
@@ -0,0 +1,61 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32]) {
+    if let [ref first, ref second, _, ref fourth, ..] = *s {
+        if let [_, _, ref mut third, ..] = *s {
+            nop(&[first, second, third, fourth]);
+        }
+    }
+}
+
+fn const_index_from_end_ok(s: &mut [i32]) {
+    if let [.., ref fourth, ref third, _, ref first] = *s {
+        if let [.., ref mut second, _] = *s {
+            nop(&[first, second, third, fourth]);
+        }
+    }
+}
+
+fn const_index_mixed(s: &mut [i32]) {
+    if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+        if let [ref mut from_begin0, ..] = *s {
+            nop(&[from_begin0, from_end1, from_end3, from_end4]);
+        }
+    }
+    if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+        if let [.., ref mut from_end1] = *s {
+            nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+        }
+    }
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32]) {
+    if let [ref first, ref second, ..] = *s {
+        if let [_, _, ref mut tail @ ..] = *s {
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
+    if let [.., ref second, ref first] = *s {
+        if let [ref mut tail @ .., _, _] = *s {
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_ok(&mut v);
+    const_index_from_end_ok(&mut v);
+    const_index_and_subslice_ok(&mut v);
+    const_index_and_subslice_from_end_ok(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
index a6b54f9537d..2ef98741dc3 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
@@ -1,18 +1,8 @@
-//compile-flags: -Z borrowck=mir
-
 #![feature(slice_patterns)]
 
 fn nop(_s: &[& i32]) {}
 fn nop_subslice(_s: &[i32]) {}
 
-fn const_index_ok(s: &mut [i32]) {
-    if let [ref first, ref second, _, ref fourth, ..] = *s {
-        if let [_, _, ref mut third, ..] = *s {
-            nop(&[first, second, third, fourth]);
-        }
-    }
-}
-
 fn const_index_err(s: &mut [i32]) {
     if let [ref first, ref second, ..] = *s {
         if let [_, ref mut  second2, ref mut third, ..] = *s { //~ERROR
@@ -21,14 +11,6 @@ fn const_index_err(s: &mut [i32]) {
     }
 }
 
-fn const_index_from_end_ok(s: &mut [i32]) {
-    if let [.., ref fourth, ref third, _, ref first] = *s {
-        if let [.., ref mut second, _] = *s {
-            nop(&[first, second, third, fourth]);
-        }
-    }
-}
-
 fn const_index_from_end_err(s: &mut [i32]) {
     if let [.., ref fourth, ref third, _, ref first] = *s {
         if let [.., ref mut third2, _, _] = *s { //~ERROR
@@ -39,9 +21,6 @@ fn const_index_from_end_err(s: &mut [i32]) {
 
 fn const_index_mixed(s: &mut [i32]) {
     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
-        if let [ref mut from_begin0, ..] = *s {
-            nop(&[from_begin0, from_end1, from_end3, from_end4]);
-        }
         if let [_, ref mut from_begin1, ..] = *s { //~ERROR
             nop(&[from_begin1, from_end1, from_end3, from_end4]);
         }
@@ -53,9 +32,6 @@ fn const_index_mixed(s: &mut [i32]) {
         }
     }
     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
-        if let [.., ref mut from_end1] = *s {
-            nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
-        }
         if let [.., ref mut from_end2, _] = *s { //~ERROR
             nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
         }
@@ -68,15 +44,6 @@ fn const_index_mixed(s: &mut [i32]) {
     }
 }
 
-fn const_index_and_subslice_ok(s: &mut [i32]) {
-    if let [ref first, ref second, ..] = *s {
-        if let [_, _, ref mut tail @ ..] = *s {
-            nop(&[first, second]);
-            nop_subslice(tail);
-        }
-    }
-}
-
 fn const_index_and_subslice_err(s: &mut [i32]) {
     if let [ref first, ref second, ..] = *s {
         if let [_, ref mut tail @ ..] = *s { //~ERROR
@@ -86,15 +53,6 @@ fn const_index_and_subslice_err(s: &mut [i32]) {
     }
 }
 
-fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
-    if let [.., ref second, ref first] = *s {
-        if let [ref mut tail @ .., _, _] = *s {
-            nop(&[first, second]);
-            nop_subslice(tail);
-        }
-    }
-}
-
 fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
     if let [.., ref second, ref first] = *s {
         if let [ref mut tail @ .., _] = *s { //~ERROR
@@ -115,13 +73,9 @@ fn subslices(s: &mut [i32]) {
 
 fn main() {
     let mut v = [1,2,3,4];
-    const_index_ok(&mut v);
     const_index_err(&mut v);
-    const_index_from_end_ok(&mut v);
     const_index_from_end_err(&mut v);
-    const_index_and_subslice_ok(&mut v);
     const_index_and_subslice_err(&mut v);
-    const_index_and_subslice_from_end_ok(&mut v);
     const_index_and_subslice_from_end_err(&mut v);
     subslices(&mut v);
 }
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
index 2c019f44611..b6f5ac64b20 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:18:20
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:8:20
    |
 LL |     if let [ref first, ref second, ..] = *s {
    |                        ---------- immutable borrow occurs here
@@ -9,7 +9,7 @@ LL |             nop(&[first, second, second2, third]);
    |                          ------ immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:34:21
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:16:21
    |
 LL |     if let [.., ref fourth, ref third, _, ref first] = *s {
    |                             --------- immutable borrow occurs here
@@ -19,18 +19,17 @@ LL |             nop(&[first, third, third2, fourth]);
    |                          ----- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:45:20
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:24:20
    |
 LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
    |                    ------------- immutable borrow occurs here
-...
 LL |         if let [_, ref mut from_begin1, ..] = *s {
    |                    ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[from_begin1, from_end1, from_end3, from_end4]);
    |                                                      --------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:48:23
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:27:23
    |
 LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
    |                                   ------------- immutable borrow occurs here
@@ -41,7 +40,7 @@ LL |             nop(&[from_begin2, from_end1, from_end3, from_end4]);
    |                                           --------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:51:26
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:30:26
    |
 LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
    |                                   ------------- immutable borrow occurs here
@@ -52,18 +51,17 @@ LL |             nop(&[from_begin3, from_end1, from_end3, from_end4]);
    |                                           --------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:59:21
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:35:21
    |
 LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
    |                                                  --------------- immutable borrow occurs here
-...
 LL |         if let [.., ref mut from_end2, _] = *s {
    |                     ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
    |                                             ----------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:62:21
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:38:21
    |
 LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
    |                                                  --------------- immutable borrow occurs here
@@ -74,7 +72,7 @@ LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
    |                                             ----------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:65:21
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:41:21
    |
 LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
    |                              --------------- immutable borrow occurs here
@@ -85,7 +83,7 @@ LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
    |                                ----------- immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:82:20
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:49:20
    |
 LL |     if let [ref first, ref second, ..] = *s {
    |                        ---------- immutable borrow occurs here
@@ -95,7 +93,7 @@ LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:100:17
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:58:17
    |
 LL |     if let [.., ref second, ref first] = *s {
    |                 ---------- immutable borrow occurs here
@@ -105,7 +103,7 @@ LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
 error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-slice-pattern-element-loan.rs:109:17
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:67:17
    |
 LL |     if let [_, _, _, ref s1 @ ..] = *s {
    |                      ----------- immutable borrow occurs here
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 29dcbfe9609..0f0ec0ba460 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -269,6 +269,28 @@ fn subslice_pattern_reassign(a: &Allocator) {
     let[_, _y @ ..] = ar;
 }
 
+fn index_field_mixed_ends(a: &Allocator) {
+    let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
+    let[(_x, _), ..] = ar;
+    let[(_, _y), _] = ar;
+    let[_, (_, _w)] = ar;
+    let[.., (_z, _)] = ar;
+}
+
+fn subslice_mixed_min_lengths(a: &Allocator, c: i32) {
+    let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
+    match c {
+        0 => { let[_x, ..] = ar; }
+        1 => { let[_x, _, ..] = ar; }
+        2 => { let[_x, _] = ar; }
+        3 => { let[(_x, _), _, ..] = ar; }
+        4 => { let[.., (_x, _)] = ar; }
+        5 => { let[.., (_x, _), _] = ar; }
+        6 => { let [_y @ ..] = ar; }
+        _ => { let [_y @ .., _] = ar; }
+    }
+}
+
 fn panic_after_return(a: &Allocator) -> Ptr<'_> {
     // Panic in the drop of `p` or `q` can leak
     let exceptions = vec![8, 9];
@@ -422,6 +444,16 @@ fn main() {
     run_test(|a| slice_pattern_reassign(a));
     run_test(|a| subslice_pattern_reassign(a));
 
+    run_test(|a| index_field_mixed_ends(a));
+    run_test(|a| subslice_mixed_min_lengths(a, 0));
+    run_test(|a| subslice_mixed_min_lengths(a, 1));
+    run_test(|a| subslice_mixed_min_lengths(a, 2));
+    run_test(|a| subslice_mixed_min_lengths(a, 3));
+    run_test(|a| subslice_mixed_min_lengths(a, 4));
+    run_test(|a| subslice_mixed_min_lengths(a, 5));
+    run_test(|a| subslice_mixed_min_lengths(a, 6));
+    run_test(|a| subslice_mixed_min_lengths(a, 7));
+
     run_test(|a| {
         panic_after_return(a);
     });