Auto merge of #67077 - Aaron1011:build-llvm-in-binary, r=alexcrichton

rustc: Link LLVM directly into rustc again (take two)

This is a continuation of PR https://github.com/rust-lang/rust/pull/65703
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index ff71782..8b0ad16 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -959,7 +959,7 @@
         // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
         // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
         // to change a flag in a binary?
-        if self.config.rust_rpath {
+        if self.config.rust_rpath && util::use_host_linker(&target) {
             let rpath = if target.contains("apple") {
 
                 // Note that we need to take one extra step on macOS to also pass
@@ -969,10 +969,7 @@
                 // flesh out rpath support more fully in the future.
                 rustflags.arg("-Zosx-rpath-install-name");
                 Some("-Wl,-rpath,@loader_path/../lib")
-            } else if !target.contains("windows") &&
-                      !target.contains("wasm32") &&
-                      !target.contains("emscripten") &&
-                      !target.contains("fuchsia") {
+            } else if !target.contains("windows") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
             } else {
                 None
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 90f5f4f..080bef6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -808,12 +808,8 @@
                                                        .and_then(|c| c.linker.as_ref()) {
             Some(linker)
         } else if target != self.config.build &&
-                  !target.contains("msvc") &&
-                  !target.contains("emscripten") &&
-                  !target.contains("wasm32") &&
-                  !target.contains("nvptx") &&
-                  !target.contains("fortanix") &&
-                  !target.contains("fuchsia") {
+                  util::use_host_linker(&target) &&
+                  !target.contains("msvc") {
             Some(self.cc(target))
         } else {
             None
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 6f8a630..6824b7a 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -15,6 +15,7 @@
 
 use crate::config::Config;
 use crate::builder::Builder;
+use crate::cache::Interned;
 
 /// Returns the `name` as the filename of a static library for `target`.
 pub fn staticlib(name: &str, target: &str) -> String {
@@ -306,3 +307,15 @@
         false
     }
 }
+
+pub fn use_host_linker(target: &Interned<String>) -> bool {
+    // FIXME: this information should be gotten by checking the linker flavor
+    // of the rustc target
+    !(
+        target.contains("emscripten") ||
+        target.contains("wasm32") ||
+        target.contains("nvptx") ||
+        target.contains("fortanix") ||
+        target.contains("fuchsia")
+    )
+}
diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs
index d2bdda8..fc96045 100644
--- a/src/liballoc/borrow.rs
+++ b/src/liballoc/borrow.rs
@@ -195,14 +195,10 @@
     }
 
     fn clone_from(&mut self, source: &Self) {
-        if let Owned(ref mut dest) = *self {
-            if let Owned(ref o) = *source {
-                o.borrow().clone_into(dest);
-                return;
-            }
+        match (self, source) {
+            (&mut Owned(ref mut dest), &Owned(ref o)) => o.borrow().clone_into(dest),
+            (t, s) => *t = s.clone(),
         }
-
-        *self = source.clone();
     }
 }
 
@@ -449,9 +445,7 @@
     fn add_assign(&mut self, rhs: &'a str) {
         if self.is_empty() {
             *self = Cow::Borrowed(rhs)
-        } else if rhs.is_empty() {
-            return;
-        } else {
+        } else if !rhs.is_empty() {
             if let Cow::Borrowed(lhs) = *self {
                 let mut s = String::with_capacity(lhs.len() + rhs.len());
                 s.push_str(lhs);
@@ -467,9 +461,7 @@
     fn add_assign(&mut self, rhs: Cow<'a, str>) {
         if self.is_empty() {
             *self = rhs
-        } else if rhs.is_empty() {
-            return;
-        } else {
+        } else if !rhs.is_empty() {
             if let Cow::Borrowed(lhs) = *self {
                 let mut s = String::with_capacity(lhs.len() + rhs.len());
                 s.push_str(lhs);
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 51ad3a0..1c39a37 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -61,7 +61,60 @@
 //! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
 //! [`Global`] allocator with [`Layout::for_value(&*value)`].
 //!
+//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
+//! as a single pointer and is also ABI-compatible with C pointers
+//! (i.e. the C type `T*`). This means that if you have extern "C"
+//! Rust functions that will be called from C, you can define those
+//! Rust functions using `Box<T>` types, and use `T*` as corresponding
+//! type on the C side. As an example, consider this C header which
+//! declares functions that create and destroy some kind of `Foo`
+//! value:
 //!
+//! ```c
+//! /* C header */
+//!
+//! /* Returns ownership to the caller */
+//! struct Foo* foo_new(void);
+//!
+//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! void foo_delete(struct Foo*);
+//! ```
+//!
+//! These two functions might be implemented in Rust as follows. Here, the
+//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures
+//! the ownership constraints. Note also that the nullable argument to
+//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>`
+//! cannot be null.
+//!
+//! ```
+//! #[repr(C)]
+//! pub struct Foo;
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_new() -> Box<Foo> {
+//!     Box::new(Foo)
+//! }
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
+//! ```
+//!
+//! Even though `Box<T>` has the same representation and C ABI as a C pointer,
+//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>`
+//! and expect things to work. `Box<T>` values will always be fully aligned,
+//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to
+//! free the value with the global allocator. In general, the best practice
+//! is to only use `Box<T>` for pointers that originated from the global
+//! allocator.
+//!
+//! **Important.** At least at present, you should avoid using
+//! `Box<T>` types for functions that are defined in C but invoked
+//! from Rust. In those cases, you should directly mirror the C types
+//! as closely as possible. Using types like `Box<T>` where the C
+//! definition is just using `T*` can lead to undefined behavior, as
+//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
+//!
+//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
 //! [dereferencing]: ../../std/ops/trait.Deref.html
 //! [`Box`]: struct.Box.html
 //! [`Box<T>`]: struct.Box.html
diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs
index a0c9263..6ee2283 100644
--- a/src/liballoc/collections/linked_list.rs
+++ b/src/liballoc/collections/linked_list.rs
@@ -808,7 +808,21 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
     fn drop(&mut self) {
-        while let Some(_) = self.pop_front_node() {}
+        struct DropGuard<'a, T>(&'a mut LinkedList<T>);
+
+        impl<'a, T> Drop for DropGuard<'a, T> {
+            fn drop(&mut self) {
+                // Continue the same loop we do below. This only runs when a destructor has
+                // panicked. If another one panics this will abort.
+                while let Some(_) = self.0.pop_front_node() {}
+            }
+        }
+
+        while let Some(node) = self.pop_front_node() {
+            let guard = DropGuard(self);
+            drop(node);
+            mem::forget(guard);
+        }
     }
 }
 
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 7795083..ebd3f01 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -2809,7 +2809,22 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> Extend<A> for VecDeque<A> {
     fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
-        iter.into_iter().for_each(move |elt| self.push_back(elt));
+        // This function should be the moral equivalent of:
+        //
+        //      for item in iter.into_iter() {
+        //          self.push_back(item);
+        //      }
+        let mut iter = iter.into_iter();
+        while let Some(element) = iter.next() {
+            if self.len() == self.capacity() {
+                let (lower, _) = iter.size_hint();
+                self.reserve(lower.saturating_add(1));
+            }
+
+            let head = self.head;
+            self.head = self.wrap_add(self.head, 1);
+            unsafe { self.buffer_write(head, element); }
+        }
     }
 }
 
diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs
index 6f357ed..62a5c24 100644
--- a/src/liballoc/tests/cow_str.rs
+++ b/src/liballoc/tests/cow_str.rs
@@ -138,4 +138,7 @@
     let c2: Cow<'_, str> = Cow::Owned(s);
     c1.clone_from(&c2);
     assert!(c1.into_owned().capacity() >= 25);
+    let mut c3: Cow<'_, str> = Cow::Borrowed("bye");
+    c3.clone_from(&c2);
+    assert_eq!(c2, c3);
 }
diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs
index daa49c4..54a77d6 100644
--- a/src/liballoc/tests/linked_list.rs
+++ b/src/liballoc/tests/linked_list.rs
@@ -1,4 +1,5 @@
 use std::collections::LinkedList;
+use std::panic::catch_unwind;
 
 #[test]
 fn test_basic() {
@@ -529,3 +530,109 @@
         assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
     }
 }
+
+
+#[test]
+fn test_drop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    drop(ring);
+
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+
+    drop(ring.pop_back());
+    drop(ring.pop_front());
+    assert_eq!(unsafe { DROPS }, 2);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.clear();
+    assert_eq!(unsafe { DROPS }, 4);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index 1ec614e..5c63eeb 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -553,8 +553,7 @@
     pub fn is_alphabetic(self) -> bool {
         match self {
             'a'..='z' | 'A'..='Z' => true,
-            c if c > '\x7f' => derived_property::Alphabetic(c),
-            _ => false,
+            c => c > '\x7f' && derived_property::Alphabetic(c),
         }
     }
 
@@ -585,8 +584,7 @@
     pub fn is_lowercase(self) -> bool {
         match self {
             'a'..='z' => true,
-            c if c > '\x7f' => derived_property::Lowercase(c),
-            _ => false,
+            c => c > '\x7f' && derived_property::Lowercase(c),
         }
     }
 
@@ -617,8 +615,7 @@
     pub fn is_uppercase(self) -> bool {
         match self {
             'A'..='Z' => true,
-            c if c > '\x7f' => derived_property::Uppercase(c),
-            _ => false,
+            c => c > '\x7f' && derived_property::Uppercase(c),
         }
     }
 
@@ -646,8 +643,7 @@
     pub fn is_whitespace(self) -> bool {
         match self {
             ' ' | '\x09'..='\x0d' => true,
-            c if c > '\x7f' => property::White_Space(c),
-            _ => false,
+            c => c > '\x7f' && property::White_Space(c),
         }
     }
 
@@ -744,8 +740,7 @@
     pub fn is_numeric(self) -> bool {
         match self {
             '0'..='9' => true,
-            c if c > '\x7f' => general_category::N(c),
-            _ => false,
+            c => c > '\x7f' && general_category::N(c),
         }
     }
 
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 86ee673..288017b 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -29,6 +29,7 @@
 /// [arc]: ../../std/sync/struct.Arc.html
 /// [ub]: ../../reference/behavior-considered-undefined.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")]
 #[rustc_on_unimplemented(
     message="`{Self}` cannot be sent between threads safely",
     label="`{Self}` cannot be sent between threads safely"
@@ -440,6 +441,7 @@
 /// [ub]: ../../reference/behavior-considered-undefined.html
 /// [transmute]: ../../std/mem/fn.transmute.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")]
 #[lang = "sync"]
 #[rustc_on_unimplemented(
     message="`{Self}` cannot be shared between threads safely",
diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs
index a494274..1037da1 100644
--- a/src/libcore/str/pattern.rs
+++ b/src/libcore/str/pattern.rs
@@ -296,12 +296,7 @@
     fn next_match(&mut self) -> Option<(usize, usize)> {
         loop {
             // get the haystack after the last character found
-            let bytes = if let Some(slice) = self.haystack.as_bytes()
-                                                 .get(self.finger..self.finger_back) {
-                slice
-            } else {
-                return None;
-            };
+            let bytes = self.haystack.as_bytes().get(self.finger..self.finger_back)?;
             // the last byte of the utf8 encoded needle
             let last_byte = unsafe { *self.utf8_encoded.get_unchecked(self.utf8_size - 1) };
             if let Some(index) = memchr::memchr(last_byte, bytes) {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index b3ddffc..73977878 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1618,37 +1618,37 @@
     // inlined, despite being large, because it has only two call sites that
     // are extremely hot.
     #[inline(always)]
-    pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
-        match typ.kind {
-            ty::Infer(ty::TyVar(v)) => {
+    pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
+        match infer {
+            ty::TyVar(v) => {
                 use self::type_variable::TypeVariableValue;
 
-                // See the comment in `shallow_resolve()`.
+                // If `inlined_probe` returns a `Known` value its `kind` never
+                // matches `infer`.
                 match self.infcx.type_variables.borrow_mut().inlined_probe(v) {
-                    TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ,
                     TypeVariableValue::Unknown { .. } => false,
+                    TypeVariableValue::Known { .. } => true,
                 }
             }
 
-            ty::Infer(ty::IntVar(v)) => {
-                match self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v) {
-                    Some(v) => v.to_type(self.infcx.tcx) != typ,
-                    None => false,
-                }
+            ty::IntVar(v) => {
+                // If inlined_probe_value returns a value it's always a
+                // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a
+                // `ty::Infer(_)`.
+                self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some()
             }
 
-            ty::Infer(ty::FloatVar(v)) => {
+            ty::FloatVar(v) => {
+                // If inlined_probe_value returns a value it's always a
+                // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`.
+                //
                 // Not `inlined_probe_value(v)` because this call site is colder.
-                match self.infcx.float_unification_table.borrow_mut().probe_value(v) {
-                    Some(v) => v.to_type(self.infcx.tcx) != typ,
-                    None => false,
-                }
+                self.infcx.float_unification_table.borrow_mut().probe_value(v).is_some()
             }
 
-            _ => false,
+            _ => unreachable!(),
         }
     }
-
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index a89bc28..ba8feb4 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1714,18 +1714,25 @@
     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 @@
                 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 @@
     }
 
     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 a66a49f..445fa6e 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -88,14 +88,17 @@
             }
             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 703e0cc..5d273fe 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -954,7 +954,7 @@
                     );
                 }
                 ProjectionElem::Deref |
-                ProjectionElem::Subslice { from: _, to: _ } |
+                ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
                 ProjectionElem::ConstantIndex { offset: _,
                                                 min_length: _,
                                                 from_end: _ } |
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 35017d6..6a11189 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -25,6 +25,7 @@
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::session::DiagnosticMessageId;
 use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use crate::ty::TypeckTables;
 use crate::ty::GenericParamDefKind;
 use crate::ty::error::ExpectedFound;
 use crate::ty::fast_reject;
@@ -2104,52 +2105,69 @@
     ) {
         // First, attempt to add note to this error with an async-await-specific
         // message, and fall back to regular note otherwise.
-        if !self.note_obligation_cause_for_async_await(err, obligation) {
+        if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
             self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code,
                                             &mut vec![]);
         }
     }
 
-    /// Adds an async-await specific note to the diagnostic:
+    /// Adds an async-await specific note to the diagnostic when the future does not implement
+    /// an auto trait because of a captured type.
     ///
     /// ```ignore (diagnostic)
-    /// note: future does not implement `std::marker::Send` because this value is used across an
-    ///       await
-    ///   --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+    /// note: future does not implement `Qux` as this value is used across an await
+    ///   --> $DIR/issue-64130-3-other.rs:17:5
     ///    |
-    /// LL |     let g = x.lock().unwrap();
-    ///    |         - has type `std::sync::MutexGuard<'_, u32>`
+    /// LL |     let x = Foo;
+    ///    |         - has type `Foo`
     /// LL |     baz().await;
-    ///    |     ^^^^^^^^^^^ await occurs here, with `g` maybe used later
+    ///    |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
     /// LL | }
-    ///    | - `g` is later dropped here
+    ///    | - `x` is later dropped here
+    /// ```
+    ///
+    /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic
+    /// is "replaced" with a different message and a more specific error.
+    ///
+    /// ```ignore (diagnostic)
+    /// error: future cannot be sent between threads safely
+    ///   --> $DIR/issue-64130-2-send.rs:21:5
+    ///    |
+    /// LL | fn is_send<T: Send>(t: T) { }
+    ///    |    -------    ---- required by this bound in `is_send`
+    /// ...
+    /// LL |     is_send(bar());
+    ///    |     ^^^^^^^ future returned by `bar` is not send
+    ///    |
+    ///    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not
+    ///            implemented for `Foo`
+    /// note: future is not send as this value is used across an await
+    ///   --> $DIR/issue-64130-2-send.rs:15:5
+    ///    |
+    /// LL |     let x = Foo;
+    ///    |         - has type `Foo`
+    /// LL |     baz().await;
+    ///    |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+    /// LL | }
+    ///    | - `x` is later dropped here
     /// ```
     ///
     /// Returns `true` if an async-await specific note was added to the diagnostic.
-    fn note_obligation_cause_for_async_await(
+    fn maybe_note_obligation_cause_for_async_await(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
     ) -> bool {
-        debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \
+        debug!("maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \
                 obligation.cause.span={:?}", obligation.predicate, obligation.cause.span);
         let source_map = self.tcx.sess.source_map();
 
-        // Look into the obligation predicate to determine the type in the generator which meant
-        // that the predicate was not satisifed.
-        let (trait_ref, target_ty) = match obligation.predicate {
-            ty::Predicate::Trait(trait_predicate) =>
-                (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()),
-            _ => return false,
-        };
-        debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty);
-
         // Attempt to detect an async-await error by looking at the obligation causes, looking
-        // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to
-        // be present.
+        // for a generator to be present.
         //
         // When a future does not implement a trait because of a captured type in one of the
         // generators somewhere in the call stack, then the result is a chain of obligations.
+        //
         // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
         // future is passed as an argument to a function C which requires a `Send` type, then the
         // chain looks something like this:
@@ -2166,102 +2184,224 @@
         // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
         // - `BindingObligation` with `impl_send (Send requirement)
         //
-        // The first obligations in the chain can be used to get the details of the type that is
-        // captured but the entire chain must be inspected to detect this case.
+        // The first obligation in the chain is the most useful and has the generator that captured
+        // the type. The last generator has information about where the bound was introduced. At
+        // least one generator should be present for this diagnostic to be modified.
+        let (mut trait_ref, mut target_ty) = match obligation.predicate {
+            ty::Predicate::Trait(p) =>
+                (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())),
+            _ => (None, None),
+        };
         let mut generator = None;
+        let mut last_generator = None;
         let mut next_code = Some(&obligation.cause.code);
         while let Some(code) = next_code {
-            debug!("note_obligation_cause_for_async_await: code={:?}", code);
+            debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
                 ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) |
                 ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
-                    debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}",
-                           derived_obligation.parent_trait_ref.self_ty().kind);
-                    match derived_obligation.parent_trait_ref.self_ty().kind {
-                        ty::Adt(ty::AdtDef { did, .. }, ..) if
-                            self.tcx.is_diagnostic_item(sym::gen_future, *did) => {},
-                        ty::Generator(did, ..) => generator = generator.or(Some(did)),
-                        ty::GeneratorWitness(_) | ty::Opaque(..) => {},
-                        _ => return false,
+                    let ty = derived_obligation.parent_trait_ref.self_ty();
+                    debug!("maybe_note_obligation_cause_for_async_await: \
+                            parent_trait_ref={:?} self_ty.kind={:?}",
+                           derived_obligation.parent_trait_ref, ty.kind);
+
+                    match ty.kind {
+                        ty::Generator(did, ..) => {
+                            generator = generator.or(Some(did));
+                            last_generator = Some(did);
+                        },
+                        ty::GeneratorWitness(..) => {},
+                        _ if generator.is_none() => {
+                            trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder());
+                            target_ty = Some(ty);
+                        },
+                        _ => {},
                     }
 
                     next_code = Some(derived_obligation.parent_code.as_ref());
                 },
-                ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..)
-                    if generator.is_some() => break,
-                _ => return false,
+                _ => break,
             }
         }
 
-        let generator_did = generator.expect("can only reach this if there was a generator");
-
-        // Only continue to add a note if the generator is from an `async` function.
-        let parent_node = self.tcx.parent(generator_did)
-            .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did));
-        debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node);
-        if let Some(hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(sig, _, _),
-            ..
-        })) = parent_node {
-            debug!("note_obligation_cause_for_async_await: header={:?}", sig.header);
-            if sig.header.asyncness != hir::IsAsync::Async {
-                return false;
-            }
-        }
+        // Only continue if a generator was found.
+        debug!("maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
+                target_ty={:?}", generator, trait_ref, target_ty);
+        let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
+            (Some(generator_did), Some(trait_ref), Some(target_ty)) =>
+                (generator_did, trait_ref, target_ty),
+            _ => return false,
+        };
 
         let span = self.tcx.def_span(generator_did);
+
         // Do not ICE on closure typeck (#66868).
         if let None = self.tcx.hir().as_local_hir_id(generator_did) {
             return false;
         }
-        let tables = self.tcx.typeck_tables_of(generator_did);
-        debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ",
-               generator_did, span);
+
+        // Get the tables from the infcx if the generator is the function we are
+        // currently type-checking; otherwise, get them by performing a query.
+        // This is needed to avoid cycles.
+        let in_progress_tables = self.in_progress_tables.map(|t| t.borrow());
+        let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+        debug!("maybe_note_obligation_cause_for_async_await: generator_did={:?} \
+             generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}",
+            generator_did, generator_did_root,
+            in_progress_tables.as_ref().map(|t| t.local_id_root), span);
+        let query_tables;
+        let tables: &TypeckTables<'tcx> = match &in_progress_tables {
+            Some(t) if t.local_id_root == Some(generator_did_root) => t,
+            _ => {
+                query_tables = self.tcx.typeck_tables_of(generator_did);
+                &query_tables
+            }
+        };
 
         // Look for a type inside the generator interior that matches the target type to get
         // a span.
+        let target_ty_erased = self.tcx.erase_regions(&target_ty);
         let target_span = tables.generator_interior_types.iter()
-            .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty))
+            .find(|ty::GeneratorInteriorTypeCause { ty, .. }| {
+                // Careful: the regions for types that appear in the
+                // generator interior are not generally known, so we
+                // want to erase them when comparing (and anyway,
+                // `Send` and other bounds are generally unaffected by
+                // the choice of region).  When erasing regions, we
+                // also have to erase late-bound regions. This is
+                // because the types that appear in the generator
+                // interior generally contain "bound regions" to
+                // represent regions that are part of the suspended
+                // generator frame. Bound regions are preserved by
+                // `erase_regions` and so we must also call
+                // `erase_late_bound_regions`.
+                let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty));
+                let ty_erased = self.tcx.erase_regions(&ty_erased);
+                let eq = ty::TyS::same_type(ty_erased, target_ty_erased);
+                debug!("maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
+                        target_ty_erased={:?} eq={:?}", ty_erased, target_ty_erased, eq);
+                eq
+            })
             .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }|
                  (span, source_map.span_to_snippet(*span), scope_span));
+        debug!("maybe_note_obligation_cause_for_async_await: target_ty={:?} \
+                generator_interior_types={:?} target_span={:?}",
+                target_ty, tables.generator_interior_types, target_span);
         if let Some((target_span, Ok(snippet), scope_span)) = target_span {
-            // Look at the last interior type to get a span for the `.await`.
-            let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
-            let mut span = MultiSpan::from_span(await_span);
-            span.push_span_label(
-                await_span, format!("await occurs here, with `{}` maybe used later", snippet));
-
-            span.push_span_label(*target_span, format!("has type `{}`", target_ty));
-
-            // If available, use the scope span to annotate the drop location.
-            if let Some(scope_span) = scope_span {
-                span.push_span_label(
-                    source_map.end_point(*scope_span),
-                    format!("`{}` is later dropped here", snippet),
-                );
-            }
-
-            err.span_note(span, &format!(
-                "future does not implement `{}` as this value is used across an await",
-                trait_ref.print_only_trait_path(),
-            ));
-
-            // Add a note for the item obligation that remains - normally a note pointing to the
-            // bound that introduced the obligation (e.g. `T: Send`).
-            debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
-            self.note_obligation_cause_code(
-                err,
-                &obligation.predicate,
-                next_code.unwrap(),
-                &mut Vec::new(),
+            self.note_obligation_cause_for_async_await(
+                err, *target_span, scope_span, snippet, generator_did, last_generator,
+                trait_ref, target_ty, tables, obligation, next_code,
             );
-
             true
         } else {
             false
         }
     }
 
+    /// Unconditionally adds the diagnostic note described in
+    /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
+    fn note_obligation_cause_for_async_await(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        target_span: Span,
+        scope_span: &Option<Span>,
+        snippet: String,
+        first_generator: DefId,
+        last_generator: Option<DefId>,
+        trait_ref: ty::TraitRef<'_>,
+        target_ty: Ty<'tcx>,
+        tables: &ty::TypeckTables<'_>,
+        obligation: &PredicateObligation<'tcx>,
+        next_code: Option<&ObligationCauseCode<'tcx>>,
+    ) {
+        let source_map = self.tcx.sess.source_map();
+
+        let is_async_fn = self.tcx.parent(first_generator)
+            .map(|parent_did| self.tcx.asyncness(parent_did))
+            .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async)
+            .unwrap_or(false);
+        let is_async_move = self.tcx.hir().as_local_hir_id(first_generator)
+            .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id))
+            .map(|body_id| self.tcx.hir().body(body_id))
+            .and_then(|body| body.generator_kind())
+            .map(|generator_kind| match generator_kind {
+                hir::GeneratorKind::Async(..) => true,
+                _ => false,
+            })
+            .unwrap_or(false);
+        let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" };
+
+        // Special case the primary error message when send or sync is the trait that was
+        // not implemented.
+        let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
+        let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
+        let trait_explanation = if is_send || is_sync {
+            let (trait_name, trait_verb) = if is_send {
+                ("`Send`", "sent")
+            } else {
+                ("`Sync`", "shared")
+            };
+
+            err.clear_code();
+            err.set_primary_message(
+                format!("future cannot be {} between threads safely", trait_verb)
+            );
+
+            let original_span = err.span.primary_span().unwrap();
+            let mut span = MultiSpan::from_span(original_span);
+
+            let message = if let Some(name) = last_generator
+                .and_then(|generator_did| self.tcx.parent(generator_did))
+                .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
+                .map(|parent_hir_id| self.tcx.hir().name(parent_hir_id))
+            {
+                format!("future returned by `{}` is not {}", name, trait_name)
+            } else {
+                format!("future is not {}", trait_name)
+            };
+
+            span.push_span_label(original_span, message);
+            err.set_span(span);
+
+            format!("is not {}", trait_name)
+        } else {
+            format!("does not implement `{}`", trait_ref.print_only_trait_path())
+        };
+
+        // Look at the last interior type to get a span for the `.await`.
+        let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
+        let mut span = MultiSpan::from_span(await_span);
+        span.push_span_label(
+            await_span,
+            format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet));
+
+        span.push_span_label(target_span, format!("has type `{}`", target_ty));
+
+        // If available, use the scope span to annotate the drop location.
+        if let Some(scope_span) = scope_span {
+            span.push_span_label(
+                source_map.end_point(*scope_span),
+                format!("`{}` is later dropped here", snippet),
+            );
+        }
+
+        err.span_note(span, &format!(
+            "future {} as this value is used across an {}",
+            trait_explanation,
+            await_or_yield,
+        ));
+
+        // Add a note for the item obligation that remains - normally a note pointing to the
+        // bound that introduced the obligation (e.g. `T: Send`).
+        debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
+        self.note_obligation_cause_code(
+            err,
+            &obligation.predicate,
+            next_code.unwrap(),
+            &mut Vec::new(),
+        );
+    }
+
     fn note_obligation_cause_code<T>(&self,
                                      err: &mut DiagnosticBuilder<'_>,
                                      predicate: &T,
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index a981162..2773199 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -65,7 +65,7 @@
 #[derive(Clone, Debug)]
 pub struct PendingPredicateObligation<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
-    pub stalled_on: Vec<Ty<'tcx>>,
+    pub stalled_on: Vec<ty::InferTy>,
 }
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -263,8 +263,8 @@
             // Match arms are in order of frequency, which matters because this
             // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
             1 => {
-                let ty = pending_obligation.stalled_on[0];
-                ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty)
+                let infer = pending_obligation.stalled_on[0];
+                ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer)
             }
             0 => {
                 // In this case we haven't changed, but wish to make a change.
@@ -274,8 +274,8 @@
                 // This `for` loop was once a call to `all()`, but this lower-level
                 // form was a perf win. See #64545 for details.
                 (|| {
-                    for &ty in &pending_obligation.stalled_on {
-                        if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
+                    for &infer in &pending_obligation.stalled_on {
+                        if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) {
                             return true;
                         }
                     }
@@ -305,6 +305,13 @@
 
         debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
 
+        fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
+            match ty.kind {
+                ty::Infer(infer) => infer,
+                _ => panic!(),
+            }
+        }
+
         match obligation.predicate {
             ty::Predicate::Trait(ref data) => {
                 let trait_obligation = obligation.with(data.clone());
@@ -459,7 +466,7 @@
                     obligation.cause.span,
                 ) {
                     None => {
-                        pending_obligation.stalled_on = vec![ty];
+                        pending_obligation.stalled_on = vec![infer_ty(ty)];
                         ProcessResult::Unchanged
                     }
                     Some(os) => ProcessResult::Changed(mk_pending(os))
@@ -472,8 +479,8 @@
                                                            subtype) {
                     None => {
                         // None means that both are unresolved.
-                        pending_obligation.stalled_on = vec![subtype.skip_binder().a,
-                                                             subtype.skip_binder().b];
+                        pending_obligation.stalled_on = vec![infer_ty(subtype.skip_binder().a),
+                                                             infer_ty(subtype.skip_binder().b)];
                         ProcessResult::Unchanged
                     }
                     Some(Ok(ok)) => {
@@ -517,7 +524,8 @@
                             ))
                         }
                     } else {
-                        pending_obligation.stalled_on = substs.types().collect();
+                        pending_obligation.stalled_on =
+                            substs.types().map(|ty| infer_ty(ty)).collect();
                         ProcessResult::Unchanged
                     }
                 }
@@ -542,13 +550,13 @@
 fn trait_ref_type_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
     t: ty::PolyTraitRef<'tcx>,
-) -> Vec<Ty<'tcx>> {
+) -> Vec<ty::InferTy> {
     t.skip_binder() // ok b/c this check doesn't care about regions
      .input_types()
      .map(|t| selcx.infcx().resolve_vars_if_possible(&t))
      .filter(|t| t.has_infer_types())
      .flat_map(|t| t.walk())
-     .filter(|t| match t.kind { ty::Infer(_) => true, _ => false })
+     .filter_map(|t| match t.kind { ty::Infer(infer) => Some(infer), _ => None })
      .collect()
 }
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index c345b9a..1fdec5f 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -1079,12 +1079,10 @@
                 if !is_default {
                     true
                 } else if obligation.param_env.reveal == Reveal::All {
-                    debug_assert!(!poly_trait_ref.needs_infer());
-                    if !poly_trait_ref.needs_subst() {
-                        true
-                    } else {
-                        false
-                    }
+                    // NOTE(eddyb) inference variables can resolve to parameters, so
+                    // assume `poly_trait_ref` isn't monomorphic, if it contains any.
+                    let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
+                    !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
                 } else {
                     false
                 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 5f32452..94a77c5 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -204,7 +204,10 @@
 #[derive(Clone, Default)]
 pub struct SelectionCache<'tcx> {
     hashmap: Lock<
-        FxHashMap<ty::TraitRef<'tcx>, WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
+        FxHashMap<
+            ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
+            WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
+        >,
     >,
 }
 
@@ -490,7 +493,9 @@
 
 #[derive(Clone, Default)]
 pub struct EvaluationCache<'tcx> {
-    hashmap: Lock<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>,
+    hashmap: Lock<
+        FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
+    >,
 }
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -1143,7 +1148,7 @@
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
             let cache = tcx.evaluation_cache.hashmap.borrow();
-            if let Some(cached) = cache.get(&trait_ref) {
+            if let Some(cached) = cache.get(&param_env.and(trait_ref)) {
                 return Some(cached.get(tcx));
             }
         }
@@ -1151,7 +1156,7 @@
             .evaluation_cache
             .hashmap
             .borrow()
-            .get(&trait_ref)
+            .get(&param_env.and(trait_ref))
             .map(|v| v.get(tcx))
     }
 
@@ -1182,7 +1187,7 @@
                     .evaluation_cache
                     .hashmap
                     .borrow_mut()
-                    .insert(trait_ref, WithDepNode::new(dep_node, result));
+                    .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
                 return;
             }
         }
@@ -1195,7 +1200,7 @@
             .evaluation_cache
             .hashmap
             .borrow_mut()
-            .insert(trait_ref, WithDepNode::new(dep_node, result));
+            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
     }
 
     /// For various reasons, it's possible for a subobligation
@@ -1567,14 +1572,10 @@
     /// Do note that if the type itself is not in the
     /// global tcx, the local caches will be used.
     fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
-        // If there are any where-clauses in scope, then we always use
-        // a cache local to this particular scope. Otherwise, we
-        // switch to a global cache. We used to try and draw
-        // finer-grained distinctions, but that led to a serious of
-        // annoying and weird bugs like #22019 and #18290. This simple
-        // rule seems to be pretty clearly safe and also still retains
-        // a very high hit rate (~95% when compiling rustc).
-        if !param_env.caller_bounds.is_empty() {
+        // If there are any e.g. inference variables in the `ParamEnv`, then we
+        // always use a cache local to this particular scope. Otherwise, we
+        // switch to a global cache.
+        if param_env.has_local_value() {
             return false;
         }
 
@@ -1602,7 +1603,7 @@
         let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
         if self.can_use_global_caches(param_env) {
             let cache = tcx.selection_cache.hashmap.borrow();
-            if let Some(cached) = cache.get(&trait_ref) {
+            if let Some(cached) = cache.get(&param_env.and(*trait_ref)) {
                 return Some(cached.get(tcx));
             }
         }
@@ -1610,7 +1611,7 @@
             .selection_cache
             .hashmap
             .borrow()
-            .get(trait_ref)
+            .get(&param_env.and(*trait_ref))
             .map(|v| v.get(tcx))
     }
 
@@ -1671,7 +1672,7 @@
                     tcx.selection_cache
                         .hashmap
                         .borrow_mut()
-                        .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+                        .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
                     return;
                 }
             }
@@ -1685,7 +1686,7 @@
             .selection_cache
             .hashmap
             .borrow_mut()
-            .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+            .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
     }
 
     fn assemble_candidates<'o>(
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index e60b886..5e13cab 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -565,7 +565,7 @@
                         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 @@
                         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_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 8a5badd..b1931ca 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -128,21 +128,19 @@
     ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
-    /// The list of obligations. In between calls to
-    /// `process_obligations`, this list only contains nodes in the
-    /// `Pending` or `Success` state (with a non-zero number of
-    /// incomplete children). During processing, some of those nodes
-    /// may be changed to the error state, or we may find that they
-    /// are completed (That is, `num_incomplete_children` drops to 0).
-    /// At the end of processing, those nodes will be removed by a
-    /// call to `compress`.
+    /// The list of obligations. In between calls to `process_obligations`,
+    /// this list only contains nodes in the `Pending` or `Success` state.
     ///
     /// `usize` indices are used here and throughout this module, rather than
-    /// `rustc_index::newtype_index!` indices, because this code is hot enough that the
-    /// `u32`-to-`usize` conversions that would be required are significant,
-    /// and space considerations are not important.
+    /// `rustc_index::newtype_index!` indices, because this code is hot enough
+    /// that the `u32`-to-`usize` conversions that would be required are
+    /// significant, and space considerations are not important.
     nodes: Vec<Node<O>>,
 
+    /// The process generation is 1 on the first call to `process_obligations`,
+    /// 2 on the second call, etc.
+    gen: u32,
+
     /// A cache of predicates that have been successfully completed.
     done_cache: FxHashSet<O::Predicate>,
 
@@ -211,31 +209,61 @@
 /// represents the current state of processing for the obligation (of
 /// type `O`) associated with this node.
 ///
-/// Outside of ObligationForest methods, nodes should be either Pending
-/// or Waiting.
+/// The non-`Error` state transitions are as follows.
+/// ```
+/// (Pre-creation)
+///  |
+///  |     register_obligation_at() (called by process_obligations() and
+///  v                               from outside the crate)
+/// Pending
+///  |
+///  |     process_obligations()
+///  v
+/// Success(not_waiting())
+///  |  |
+///  |  |  mark_still_waiting_nodes()
+///  |  v
+///  | Success(still_waiting())
+///  |  |
+///  |  |  compress()
+///  v  v
+/// (Removed)
+/// ```
+/// The `Error` state can be introduced in several places, via `error_at()`.
+///
+/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
+/// `Success`.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum NodeState {
-    /// Obligations for which selection had not yet returned a
-    /// non-ambiguous result.
+    /// This obligation has not yet been selected successfully. Cannot have
+    /// subobligations.
     Pending,
 
-    /// This obligation was selected successfully, but may or
-    /// may not have subobligations.
-    Success,
+    /// This obligation was selected successfully, but it may be waiting on one
+    /// or more pending subobligations, as indicated by the `WaitingState`.
+    Success(WaitingState),
 
-    /// This obligation was selected successfully, but it has
-    /// a pending subobligation.
-    Waiting,
-
-    /// This obligation, along with its subobligations, are complete,
-    /// and will be removed in the next collection.
-    Done,
-
-    /// This obligation was resolved to an error. Error nodes are
-    /// removed from the vector by the compression step.
+    /// This obligation was resolved to an error. It will be removed by the
+    /// next compression step.
     Error,
 }
 
+/// Indicates when a `Success` node was last (if ever) waiting on one or more
+/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`.
+/// - 0: "Not waiting". This is a special value, set by `process_obligation`,
+///   and usable because generation counting starts at 1.
+/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but
+///   waiting no longer. In other words, finished.
+/// - ObligationForest::gen: "Still waiting" in this generation.
+///
+/// Things to note about this encoding:
+/// - Every time `ObligationForest::gen` is incremented, all the "still
+///   waiting" nodes automatically become "was waiting".
+/// - `ObligationForest::is_still_waiting` is very cheap.
+///
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
+struct WaitingState(u32);
+
 #[derive(Debug)]
 pub struct Outcome<O, E> {
     /// Obligations that were completely evaluated, including all
@@ -272,6 +300,7 @@
     pub fn new() -> ObligationForest<O> {
         ObligationForest {
             nodes: vec![],
+            gen: 0,
             done_cache: Default::default(),
             active_cache: Default::default(),
             node_rewrites: RefCell::new(vec![]),
@@ -300,10 +329,7 @@
 
         match self.active_cache.entry(obligation.as_predicate().clone()) {
             Entry::Occupied(o) => {
-                let index = *o.get();
-                debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
-                       obligation, parent, index);
-                let node = &mut self.nodes[index];
+                let node = &mut self.nodes[*o.get()];
                 if let Some(parent_index) = parent {
                     // If the node is already in `active_cache`, it has already
                     // had its chance to be marked with a parent. So if it's
@@ -320,9 +346,6 @@
                 }
             }
             Entry::Vacant(v) => {
-                debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}",
-                       obligation, parent, self.nodes.len());
-
                 let obligation_tree_id = match parent {
                     Some(parent_index) => self.nodes[parent_index].obligation_tree_id,
                     None => self.obligation_tree_id_generator.next().unwrap(),
@@ -382,6 +405,18 @@
             .insert(node.obligation.as_predicate().clone());
     }
 
+    fn not_waiting() -> WaitingState {
+        WaitingState(0)
+    }
+
+    fn still_waiting(&self) -> WaitingState {
+        WaitingState(self.gen)
+    }
+
+    fn is_still_waiting(&self, waiting: WaitingState) -> bool {
+        waiting.0 == self.gen
+    }
+
     /// Performs a pass through the obligation list. This must
     /// be called in a loop until `outcome.stalled` is false.
     ///
@@ -390,7 +425,7 @@
                                   -> Outcome<O, P::Error>
         where P: ObligationProcessor<Obligation=O>
     {
-        debug!("process_obligations(len={})", self.nodes.len());
+        self.gen += 1;
 
         let mut errors = vec![];
         let mut stalled = true;
@@ -407,8 +442,6 @@
         while index < self.nodes.len() {
             let node = &mut self.nodes[index];
 
-            debug!("process_obligations: node {} == {:?}", index, node);
-
             // `processor.process_obligation` can modify the predicate within
             // `node.obligation`, and that predicate is the key used for
             // `self.active_cache`. This means that `self.active_cache` can get
@@ -418,18 +451,15 @@
                 index += 1;
                 continue;
             }
-            let result = processor.process_obligation(&mut node.obligation);
 
-            debug!("process_obligations: node {} got result {:?}", index, result);
-
-            match result {
+            match processor.process_obligation(&mut node.obligation) {
                 ProcessResult::Unchanged => {
                     // No change in state.
                 }
                 ProcessResult::Changed(children) => {
                     // We are not (yet) stalled.
                     stalled = false;
-                    node.state.set(NodeState::Success);
+                    node.state.set(NodeState::Success(Self::not_waiting()));
 
                     for child in children {
                         let st = self.register_obligation_at(
@@ -464,12 +494,10 @@
             };
         }
 
-        self.mark_as_waiting();
+        self.mark_still_waiting_nodes();
         self.process_cycles(processor);
         let completed = self.compress(do_completed);
 
-        debug!("process_obligations: complete");
-
         Outcome {
             completed,
             errors,
@@ -477,56 +505,6 @@
         }
     }
 
-    /// Mark all `NodeState::Success` nodes as `NodeState::Done` and
-    /// report all cycles between them. This should be called
-    /// after `mark_as_waiting` marks all nodes with pending
-    /// subobligations as NodeState::Waiting.
-    fn process_cycles<P>(&self, processor: &mut P)
-        where P: ObligationProcessor<Obligation=O>
-    {
-        let mut stack = vec![];
-
-        debug!("process_cycles()");
-
-        for (index, node) in self.nodes.iter().enumerate() {
-            // For some benchmarks this state test is extremely
-            // hot. It's a win to handle the no-op cases immediately to avoid
-            // the cost of the function call.
-            if node.state.get() == NodeState::Success {
-                self.find_cycles_from_node(&mut stack, processor, index);
-            }
-        }
-
-        debug!("process_cycles: complete");
-
-        debug_assert!(stack.is_empty());
-    }
-
-    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
-        where P: ObligationProcessor<Obligation=O>
-    {
-        let node = &self.nodes[index];
-        if node.state.get() == NodeState::Success {
-            match stack.iter().rposition(|&n| n == index) {
-                None => {
-                    stack.push(index);
-                    for &index in node.dependents.iter() {
-                        self.find_cycles_from_node(stack, processor, index);
-                    }
-                    stack.pop();
-                    node.state.set(NodeState::Done);
-                }
-                Some(rpos) => {
-                    // Cycle detected.
-                    processor.process_backedge(
-                        stack[rpos..].iter().map(GetObligation(&self.nodes)),
-                        PhantomData
-                    );
-                }
-            }
-        }
-    }
-
     /// Returns a vector of obligations for `p` and all of its
     /// ancestors, putting them into the error state in the process.
     fn error_at(&self, mut index: usize) -> Vec<O> {
@@ -560,21 +538,28 @@
         trace
     }
 
+    /// Mark all `Success` nodes that depend on a pending node as still
+    /// waiting. Upon completion, any `Success` nodes that aren't still waiting
+    /// can be removed by `compress`.
+    fn mark_still_waiting_nodes(&self) {
+        for node in &self.nodes {
+            if node.state.get() == NodeState::Pending {
+                // This call site is hot.
+                self.inlined_mark_dependents_as_still_waiting(node);
+            }
+        }
+    }
+
     // This always-inlined function is for the hot call site.
     #[inline(always)]
-    fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+    fn inlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
         for &index in node.dependents.iter() {
             let node = &self.nodes[index];
-            match node.state.get() {
-                NodeState::Waiting | NodeState::Error => {}
-                NodeState::Success => {
-                    node.state.set(NodeState::Waiting);
+            if let NodeState::Success(waiting) = node.state.get() {
+                if !self.is_still_waiting(waiting) {
+                    node.state.set(NodeState::Success(self.still_waiting()));
                     // This call site is cold.
-                    self.uninlined_mark_neighbors_as_waiting_from(node);
-                }
-                NodeState::Pending | NodeState::Done => {
-                    // This call site is cold.
-                    self.uninlined_mark_neighbors_as_waiting_from(node);
+                    self.uninlined_mark_dependents_as_still_waiting(node);
                 }
             }
         }
@@ -582,31 +567,65 @@
 
     // This never-inlined function is for the cold call site.
     #[inline(never)]
-    fn uninlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
-        self.inlined_mark_neighbors_as_waiting_from(node)
+    fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
+        self.inlined_mark_dependents_as_still_waiting(node)
     }
 
-    /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
-    fn mark_as_waiting(&self) {
-        for node in &self.nodes {
-            if node.state.get() == NodeState::Waiting {
-                node.state.set(NodeState::Success);
+    /// Report cycles between all `Success` nodes that aren't still waiting.
+    /// This must be called after `mark_still_waiting_nodes`.
+    fn process_cycles<P>(&self, processor: &mut P)
+        where P: ObligationProcessor<Obligation=O>
+    {
+        let mut stack = vec![];
+
+        for (index, node) in self.nodes.iter().enumerate() {
+            // For some benchmarks this state test is extremely hot. It's a win
+            // to handle the no-op cases immediately to avoid the cost of the
+            // function call.
+            if let NodeState::Success(waiting) = node.state.get() {
+                if !self.is_still_waiting(waiting) {
+                    self.find_cycles_from_node(&mut stack, processor, index, index);
+                }
             }
         }
 
-        for node in &self.nodes {
-            if node.state.get() == NodeState::Pending {
-                // This call site is hot.
-                self.inlined_mark_neighbors_as_waiting_from(node);
+        debug_assert!(stack.is_empty());
+    }
+
+    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, min_index: usize,
+                                index: usize)
+        where P: ObligationProcessor<Obligation=O>
+    {
+        let node = &self.nodes[index];
+        if let NodeState::Success(waiting) = node.state.get() {
+            if !self.is_still_waiting(waiting) {
+                match stack.iter().rposition(|&n| n == index) {
+                    None => {
+                        stack.push(index);
+                        for &dep_index in node.dependents.iter() {
+                            // The index check avoids re-considering a node.
+                            if dep_index >= min_index {
+                                self.find_cycles_from_node(stack, processor, min_index, dep_index);
+                            }
+                        }
+                        stack.pop();
+                    }
+                    Some(rpos) => {
+                        // Cycle detected.
+                        processor.process_backedge(
+                            stack[rpos..].iter().map(GetObligation(&self.nodes)),
+                            PhantomData
+                        );
+                    }
+                }
             }
         }
     }
 
     /// Compresses the vector, removing all popped nodes. This adjusts the
-    /// indices and hence invalidates any outstanding indices.
-    ///
-    /// Beforehand, all nodes must be marked as `Done` and no cycles
-    /// on these nodes may be present. This is done by e.g., `process_cycles`.
+    /// indices and hence invalidates any outstanding indices. `process_cycles`
+    /// must be run beforehand to remove any cycles on not-still-waiting
+    /// `Success` nodes.
     #[inline(never)]
     fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
         let orig_nodes_len = self.nodes.len();
@@ -614,10 +633,10 @@
         debug_assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
-        let mut removed_done_obligations: Vec<O> = vec![];
+        let mut removed_success_obligations: Vec<O> = vec![];
 
-        // Now move all Done/Error nodes to the end, preserving the order of
-        // the Pending/Waiting nodes.
+        // Move removable nodes to the end, preserving the order of the
+        // remaining nodes.
         //
         // LOOP INVARIANT:
         //     self.nodes[0..index - dead_nodes] are the first remaining nodes
@@ -626,13 +645,19 @@
         for index in 0..orig_nodes_len {
             let node = &self.nodes[index];
             match node.state.get() {
-                NodeState::Pending | NodeState::Waiting => {
+                NodeState::Pending => {
                     if dead_nodes > 0 {
                         self.nodes.swap(index, index - dead_nodes);
                         node_rewrites[index] -= dead_nodes;
                     }
                 }
-                NodeState::Done => {
+                NodeState::Success(waiting) if self.is_still_waiting(waiting) => {
+                    if dead_nodes > 0 {
+                        self.nodes.swap(index, index - dead_nodes);
+                        node_rewrites[index] -= dead_nodes;
+                    }
+                }
+                NodeState::Success(_) => {
                     // This lookup can fail because the contents of
                     // `self.active_cache` are not guaranteed to match those of
                     // `self.nodes`. See the comment in `process_obligation`
@@ -646,7 +671,7 @@
                     }
                     if do_completed == DoCompleted::Yes {
                         // Extract the success stories.
-                        removed_done_obligations.push(node.obligation.clone());
+                        removed_success_obligations.push(node.obligation.clone());
                     }
                     node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
@@ -660,7 +685,6 @@
                     node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
                 }
-                NodeState::Success => unreachable!()
             }
         }
 
@@ -674,7 +698,7 @@
         self.node_rewrites.replace(node_rewrites);
 
         if do_completed == DoCompleted::Yes {
-            Some(removed_done_obligations)
+            Some(removed_success_obligations)
         } else {
             None
         }
diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs
index 371f0f6..78cbc12 100644
--- a/src/librustc_data_structures/tiny_list.rs
+++ b/src/librustc_data_structures/tiny_list.rs
@@ -16,41 +16,29 @@
 
 #[derive(Clone)]
 pub struct TinyList<T: PartialEq> {
-    head: Option<Element<T>>
+    head: Option<Element<T>>,
 }
 
 impl<T: PartialEq> TinyList<T> {
     #[inline]
     pub fn new() -> TinyList<T> {
-        TinyList {
-            head: None
-        }
+        TinyList { head: None }
     }
 
     #[inline]
     pub fn new_single(data: T) -> TinyList<T> {
-        TinyList {
-            head: Some(Element {
-                data,
-                next: None,
-            })
-        }
+        TinyList { head: Some(Element { data, next: None }) }
     }
 
     #[inline]
     pub fn insert(&mut self, data: T) {
-        self.head = Some(Element {
-            data,
-            next: self.head.take().map(Box::new)
-        });
+        self.head = Some(Element { data, next: self.head.take().map(Box::new) });
     }
 
     #[inline]
     pub fn remove(&mut self, data: &T) -> bool {
         self.head = match self.head {
-            Some(ref mut head) if head.data == *data => {
-                head.next.take().map(|x| *x)
-            }
+            Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x),
             Some(ref mut head) => return head.remove_next(data),
             None => return false,
         };
@@ -88,12 +76,16 @@
 
 impl<T: PartialEq> Element<T> {
     fn remove_next(&mut self, data: &T) -> bool {
-        let new_next = match self.next {
-            Some(ref mut next) if next.data == *data => next.next.take(),
-            Some(ref mut next) => return next.remove_next(data),
-            None => return false,
-        };
-        self.next = new_next;
-        true
+        let mut n = self;
+        loop {
+            match n.next {
+                Some(ref mut next) if next.data == *data => {
+                    n.next = next.next.take();
+                    return true;
+                }
+                Some(ref mut next) => n = next,
+                None => return false,
+            }
+        }
     }
 }
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index abec979..744f4a4 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -498,10 +498,20 @@
         self
     }
 
+    pub fn clear_code(&mut self) -> &mut Self {
+        self.code = None;
+        self
+    }
+
     pub fn get_code(&self) -> Option<DiagnosticId> {
         self.code.clone()
     }
 
+    pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
+        self.message[0] = (msg.into(), Style::NoStyle);
+        self
+    }
+
     pub fn message(&self) -> String {
         self.message.iter().map(|i| i.0.as_str()).collect::<String>()
     }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index f7de7ec..e6f39cc 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -355,7 +355,9 @@
         match value.kind {
             ast::ExprKind::Paren(ref inner) => {
                 if !Self::is_expr_parens_necessary(inner, followed_by_block) &&
-                    value.attrs.is_empty() {
+                    value.attrs.is_empty() &&
+                    !value.span.from_expansion()
+                {
                     let expr_text = if let Ok(snippet) = cx.sess().source_map()
                         .span_to_snippet(value.span) {
                             snippet
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/constraint_generation.rs
rename to src/librustc_mir/borrow_check/constraint_generation.rs
index dbeccab..28a631a 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/constraint_generation.rs
@@ -1,9 +1,3 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::nll::region_infer::values::LivenessValues;
-use crate::borrow_check::places_conflict;
 use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
@@ -15,6 +9,15 @@
 use rustc::ty::{self, RegionVid, Ty};
 use rustc::ty::subst::SubstsRef;
 
+use crate::borrow_check::{
+    borrow_set::BorrowSet,
+    location::LocationTable,
+    nll::ToRegionVid,
+    facts::AllFacts,
+    region_infer::values::LivenessValues,
+    places_conflict,
+};
+
 pub(super) fn generate_constraints<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/constraints/graph.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/constraints/graph.rs
rename to src/librustc_mir/borrow_check/constraints/graph.rs
index b6a9a7e..3e7aa67 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs
+++ b/src/librustc_mir/borrow_check/constraints/graph.rs
@@ -1,12 +1,15 @@
-use crate::borrow_check::nll::type_check::Locations;
-use crate::borrow_check::nll::constraints::OutlivesConstraintIndex;
-use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint};
 use rustc::mir::ConstraintCategory;
 use rustc::ty::RegionVid;
 use rustc_data_structures::graph;
 use rustc_index::vec::IndexVec;
 use syntax_pos::DUMMY_SP;
 
+use crate::borrow_check::{
+    type_check::Locations,
+    constraints::OutlivesConstraintIndex,
+    constraints::{OutlivesConstraintSet, OutlivesConstraint},
+};
+
 /// The construct graph organizes the constraints by their end-points.
 /// It can be used to view a `R1: R2` constraint as either an edge `R1
 /// -> R2` or `R2 -> R1` depending on the direction type `D`.
diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/constraints/mod.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/constraints/mod.rs
rename to src/librustc_mir/borrow_check/constraints/mod.rs
index 8a242b7..96982b6 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs
+++ b/src/librustc_mir/borrow_check/constraints/mod.rs
@@ -1,4 +1,3 @@
-use crate::borrow_check::nll::type_check::Locations;
 use rustc::mir::ConstraintCategory;
 use rustc::ty::RegionVid;
 use rustc_data_structures::graph::scc::Sccs;
@@ -6,6 +5,8 @@
 use std::fmt;
 use std::ops::Index;
 
+use crate::borrow_check::type_check::Locations;
+
 crate mod graph;
 
 /// A set of NLL region constraints. These include "outlives"
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 252b31e..1cd43d4 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 @@
             .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/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 67c3c36..a463d2c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -1,9 +1,7 @@
+//! Print diagnostics to explain why values are borrowed.
+
 use std::collections::VecDeque;
 
-use crate::borrow_check::borrow_set::BorrowData;
-use crate::borrow_check::nll::region_infer::Cause;
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
 use rustc::mir::{
     CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
     Statement, StatementKind, TerminatorKind,
@@ -16,6 +14,13 @@
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 
+use crate::borrow_check::{
+    borrow_set::BorrowData,
+    region_infer::Cause,
+    nll::ConstraintDescription,
+    MirBorrowckCtxt, WriteKind,
+};
+
 use super::{UseSpans, find_use, RegionName};
 
 #[derive(Debug)]
diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
index 7ab0692..c557e52 100644
--- a/src/librustc_mir/borrow_check/diagnostics/find_use.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
@@ -1,8 +1,7 @@
 use std::collections::VecDeque;
 use std::rc::Rc;
 
-use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
-use crate::borrow_check::nll::ToRegionVid;
+use crate::borrow_check::{nll::ToRegionVid, region_infer::{Cause, RegionInferenceContext}};
 use crate::util::liveness::{self, DefUse};
 use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
 use rustc::mir::{Local, Location, Body};
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 938836d..cc63410 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -223,18 +223,24 @@
 
     fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
-            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
+            let (span, use_spans, original_path, kind,):
+            (
+                Span,
+                Option<UseSpans>,
+                &Place<'tcx>,
+                &IllegalMoveOriginKind<'_>,
+            ) =
                 match error {
                     GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
                     GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
-                        (span, original_path, kind)
+                        (span, None, original_path, kind)
                     }
                     GroupedMoveError::OtherIllegalMove {
                         use_spans,
                         ref original_path,
                         ref kind
                     } => {
-                        (use_spans.args_or_use(), original_path, kind)
+                        (use_spans.args_or_use(), Some(use_spans), original_path, kind)
                     },
                 };
             debug!("report: original_path={:?} span={:?}, kind={:?} \
@@ -250,6 +256,7 @@
                             original_path,
                             target_place,
                             span,
+                            use_spans,
                         )
                     }
                     IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
@@ -296,6 +303,7 @@
         move_place: &Place<'tcx>,
         deref_target_place: &Place<'tcx>,
         span: Span,
+        use_spans: Option<UseSpans>,
     ) -> DiagnosticBuilder<'a> {
         // Inspect the type of the content behind the
         // borrow to provide feedback about why this
@@ -416,7 +424,7 @@
         if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
             let is_option = move_ty.starts_with("std::option::Option");
             let is_result = move_ty.starts_with("std::result::Result");
-            if is_option || is_result {
+            if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
                 err.span_suggestion(
                     span,
                     &format!("consider borrowing the `{}`'s content", if is_option {
diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
index 7aecada..b61c37b 100644
--- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
@@ -13,7 +13,7 @@
 
 use smallvec::SmallVec;
 
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+use crate::borrow_check::region_infer::RegionInferenceContext;
 
 use super::{
     RegionName, RegionNameSource, ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 66f0330..8a37e2d 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -1,10 +1,5 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::type_check::Locations;
-use crate::borrow_check::nll::universal_regions::DefiningTy;
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::Upvar;
-use crate::util::borrowck_errors;
+//! Error reporting machinery for lifetime errors.
+
 use rustc::hir::def_id::DefId;
 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc::infer::InferCtxt;
@@ -19,6 +14,17 @@
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 
+use crate::util::borrowck_errors;
+
+use crate::borrow_check::{
+    constraints::OutlivesConstraint,
+    region_infer::RegionInferenceContext,
+    type_check::Locations,
+    universal_regions::DefiningTy,
+    nll::ConstraintDescription,
+    Upvar,
+};
+
 use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource, RegionErrorNamingCtx};
 
 impl ConstraintDescription for ConstraintCategory {
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index e2e7596..720c77b 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -15,14 +15,13 @@
 use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};
 
 use crate::borrow_check::{
-    nll::region_infer::RegionInferenceContext,
-    nll::universal_regions::DefiningTy,
+    diagnostics::region_errors::ErrorReportingCtx,
+    region_infer::RegionInferenceContext,
+    universal_regions::DefiningTy,
     nll::ToRegionVid,
     Upvar,
 };
 
-use super::region_errors::ErrorReportingCtx;
-
 /// A name for a particular region used in emitting diagnostics. This name could be a generated
 /// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
 #[derive(Debug, Clone)]
diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
index 1ac44c4..839e09b 100644
--- a/src/librustc_mir/borrow_check/diagnostics/var_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
@@ -1,5 +1,4 @@
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::ToRegionVid;
+use crate::borrow_check::{nll::ToRegionVid, region_infer::RegionInferenceContext};
 use crate::borrow_check::Upvar;
 use rustc::mir::{Local, Body};
 use rustc::ty::{RegionVid, TyCtxt};
diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/facts.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/facts.rs
rename to src/librustc_mir/borrow_check/facts.rs
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/invalidation.rs
rename to src/librustc_mir/borrow_check/invalidation.rs
index e442f9c..58fac55 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -1,14 +1,3 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::{JustWrite, WriteAndRead};
-use crate::borrow_check::{AccessDepth, Deep, Shallow};
-use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write};
-use crate::borrow_check::{LocalMutationIsAllowed, MutateMode};
-use crate::borrow_check::ArtificialField;
-use crate::borrow_check::{ReadKind, WriteKind};
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::path_utils::*;
-use crate::dataflow::indexes::BorrowIndex;
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
@@ -17,6 +6,17 @@
 use rustc::mir::{Operand, BorrowKind};
 use rustc_data_structures::graph::dominators::Dominators;
 
+use crate::dataflow::indexes::BorrowIndex;
+
+use crate::borrow_check::{
+    borrow_set::BorrowSet,
+    location::LocationTable,
+    facts::AllFacts,
+    path_utils::*,
+    JustWrite, WriteAndRead, AccessDepth, Deep, Shallow, ReadOrWrite, Activation, Read,
+    Reservation, Write, LocalMutationIsAllowed, MutateMode, ArtificialField, ReadKind, WriteKind,
+};
+
 pub(super) fn generate_invalidates<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/member_constraints.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/member_constraints.rs
rename to src/librustc_mir/borrow_check/member_constraints.rs
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 427003f..11012ef 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1,6 +1,5 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
 use rustc::hir::{self, HirId};
 use rustc::hir::Node;
 use rustc::hir::def_id::DefId;
@@ -41,7 +40,6 @@
 use crate::dataflow::EverInitializedPlaces;
 use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 
-use self::borrow_set::{BorrowData, BorrowSet};
 use self::flows::Flows;
 use self::location::LocationTable;
 use self::prefixes::PrefixSet;
@@ -50,17 +48,31 @@
 
 use self::path_utils::*;
 
-crate mod borrow_set;
 mod diagnostics;
 mod flows;
 mod location;
 mod path_utils;
-crate mod place_ext;
-crate mod places_conflict;
 mod prefixes;
 mod used_muts;
+mod constraint_generation;
+mod facts;
+mod invalidation;
+mod renumber;
+mod member_constraints;
+mod constraints;
+mod universal_regions;
+mod type_check;
+mod region_infer;
+mod borrow_set;
+mod place_ext;
+mod places_conflict;
+mod nll;
 
-pub(crate) mod nll;
+crate use region_infer::RegionInferenceContext;
+crate use borrow_set::{BorrowSet, BorrowData};
+crate use places_conflict::{places_conflict, PlaceConflictBias};
+crate use place_ext::PlaceExt;
+crate use nll::ToRegionVid;
 
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
@@ -174,7 +186,7 @@
 
     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 +1612,6 @@
                         (prefix, place_span.0, place_span.1),
                         mpi,
                     );
-                    return; // don't bother finding other problems.
                 }
             }
             Err(NoMovePathFound::ReachedStatic) => {
@@ -1614,6 +1625,46 @@
         }
     }
 
+    /// 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 +1691,30 @@
 
         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 +1750,16 @@
     /// 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/mod.rs b/src/librustc_mir/borrow_check/nll.rs
similarity index 95%
rename from src/librustc_mir/borrow_check/nll/mod.rs
rename to src/librustc_mir/borrow_check/nll.rs
index 9ea3bd8..6d28a8c 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -1,13 +1,5 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::facts::AllFactsExt;
-use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind};
-use crate::dataflow::FlowAtLocation;
-use crate::dataflow::MaybeInitializedPlaces;
-use crate::transform::MirSource;
-use crate::borrow_check::Upvar;
+//! The entry point of the NLL borrow checker.
+
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
 use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -27,24 +19,23 @@
 
 use self::mir_util::PassWhere;
 use polonius_engine::{Algorithm, Output};
+
 use crate::util as mir_util;
 use crate::util::pretty;
+use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind};
+use crate::dataflow::FlowAtLocation;
+use crate::dataflow::MaybeInitializedPlaces;
+use crate::transform::MirSource;
 
-mod constraint_generation;
-mod facts;
-mod invalidation;
-mod renumber;
-
-mod member_constraints;
-
-crate mod constraints;
-crate mod universal_regions;
-crate mod type_check;
-crate mod region_infer;
-
-use self::facts::{AllFacts, RustcFacts};
-use self::region_infer::RegionInferenceContext;
-use self::universal_regions::UniversalRegions;
+use crate::borrow_check::{
+    borrow_set::BorrowSet,
+    location::LocationTable,
+    facts::{AllFacts, AllFactsExt, RustcFacts},
+    region_infer::{RegionInferenceContext, values::RegionValueElements},
+    universal_regions::UniversalRegions,
+    type_check::{self, MirTypeckResults, MirTypeckRegionConstraints},
+    Upvar, renumber, constraint_generation, invalidation,
+};
 
 crate type PoloniusOutput = Output<RustcFacts>;
 
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 87a431a..9245064f 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -503,34 +503,62 @@
                 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");
+        (
+            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: true },
-         ProjectionElem::Subslice {from: _, to })
-        | (ProjectionElem::Subslice {from: _, to },
-            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
-            if offset > to {
-                debug!("place_element_conflict: \
-                       DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+        (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-SLICE-CONSTANT-INDEX-SUBSLICE");
                 Overlap::EqualOrDisjoint
             } else {
-                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+                debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
                 Overlap::Disjoint
             }
         }
+        (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
+         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-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
+                Overlap::EqualOrDisjoint
+            } else {
+                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/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
rename to src/librustc_mir/borrow_check/region_infer/dump_mir.rs
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
rename to src/librustc_mir/borrow_check/region_infer/graphviz.rs
index fdf2af9..29c6f32 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
+++ b/src/librustc_mir/borrow_check/region_infer/graphviz.rs
@@ -2,11 +2,12 @@
 //! libgraphviz traits, specialized to attaching borrowck analysis
 //! data to rendered labels.
 
-use super::*;
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
 use std::borrow::Cow;
 use std::io::{self, Write};
 
+use super::*;
+use crate::borrow_check::constraints::OutlivesConstraint;
+
 impl<'tcx> RegionInferenceContext<'tcx> {
     /// Write out the region constraint graph.
     crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/region_infer/mod.rs
rename to src/librustc_mir/borrow_check/region_infer/mod.rs
index d62537b..b6946e2 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -23,29 +23,26 @@
 use syntax_pos::symbol::Symbol;
 
 use crate::borrow_check::{
-    nll::{
-        constraints::{
-            graph::NormalConstraintGraph,
-            ConstraintSccIndex,
-            OutlivesConstraint,
-            OutlivesConstraintSet,
-        },
-        member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
-        region_infer::values::{
-            PlaceholderIndices, RegionElement, ToElementIndex
-        },
-        type_check::{free_region_relations::UniversalRegionRelations, Locations},
+    constraints::{
+        graph::NormalConstraintGraph,
+        ConstraintSccIndex,
+        OutlivesConstraint,
+        OutlivesConstraintSet,
     },
+    member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
+    region_infer::values::{
+        PlaceholderIndices, RegionElement, ToElementIndex, LivenessValues, RegionValueElements,
+        RegionValues,
+    },
+    type_check::{free_region_relations::UniversalRegionRelations, Locations},
     diagnostics::{
         OutlivesSuggestionBuilder, RegionErrorNamingCtx,
     },
+    nll::{ToRegionVid, PoloniusOutput},
+    universal_regions::UniversalRegions,
     Upvar,
 };
 
-use self::values::{LivenessValues, RegionValueElements, RegionValues};
-use super::universal_regions::UniversalRegions;
-use super::{PoloniusOutput, ToRegionVid};
-
 mod dump_mir;
 mod graphviz;
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/region_infer/values.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/region_infer/values.rs
rename to src/librustc_mir/borrow_check/region_infer/values.rs
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/renumber.rs
rename to src/librustc_mir/borrow_check/renumber.rs
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
similarity index 95%
rename from src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
rename to src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
index 34ac96b..334477d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
@@ -1,8 +1,3 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::region_infer::TypeTest;
-use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
 use rustc::infer::canonical::QueryRegionConstraints;
 use rustc::infer::canonical::QueryOutlivesConstraint;
 use rustc::infer::outlives::env::RegionBoundPairs;
@@ -14,6 +9,14 @@
 use rustc::ty::{self, TyCtxt};
 use syntax_pos::DUMMY_SP;
 
+use crate::borrow_check::{
+    constraints::OutlivesConstraint,
+    region_infer::TypeTest,
+    type_check::{Locations, MirTypeckRegionConstraints},
+    universal_regions::UniversalRegions,
+    nll::ToRegionVid,
+};
+
 crate struct ConstraintConversion<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
     tcx: TyCtxt<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
rename to src/librustc_mir/borrow_check/type_check/free_region_relations.rs
index 8bb6838..03a7f97 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
@@ -1,7 +1,3 @@
-use crate::borrow_check::nll::type_check::constraint_conversion;
-use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
 use rustc::infer::canonical::QueryRegionConstraints;
 use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 use rustc::infer::region_constraints::GenericKind;
@@ -14,6 +10,13 @@
 use std::rc::Rc;
 use syntax_pos::DUMMY_SP;
 
+use crate::borrow_check::{
+    type_check::constraint_conversion,
+    type_check::{Locations, MirTypeckRegionConstraints},
+    universal_regions::UniversalRegions,
+    nll::ToRegionVid,
+};
+
 #[derive(Debug)]
 crate struct UniversalRegionRelations<'tcx> {
     universal_regions: Rc<UniversalRegions<'tcx>>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/input_output.rs
rename to src/librustc_mir/borrow_check/type_check/input_output.rs
index 35fb677..3df0490 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -7,7 +7,6 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
 use rustc::infer::LateBoundRegionConversionTime;
 use rustc::mir::*;
 use rustc::ty::Ty;
@@ -15,6 +14,8 @@
 use rustc_index::vec::Idx;
 use syntax_pos::Span;
 
+use crate::borrow_check::universal_regions::UniversalRegions;
+
 use super::{Locations, TypeChecker};
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
index ab8c6f2..75e4f61 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
@@ -1,10 +1,12 @@
-use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
-use crate::util::liveness::{categorize, DefUse};
 use rustc::mir::visit::{PlaceContext, Visitor};
 use rustc::mir::{Local, Location, ReadOnlyBodyAndCache};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_data_structures::vec_linked_list as vll;
 
+use crate::util::liveness::{categorize, DefUse};
+
+use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements};
+
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
 /// computation.
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs
similarity index 92%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/mod.rs
index 8f8e9af..ee3d89e 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs
@@ -1,17 +1,21 @@
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::constraints::OutlivesConstraintSet;
-use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt};
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::FlowAtLocation;
-use crate::dataflow::MaybeInitializedPlaces;
 use rustc::mir::{Body, Local, ReadOnlyBodyAndCache};
 use rustc::ty::{RegionVid, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use std::rc::Rc;
 
+use crate::dataflow::move_paths::MoveData;
+use crate::dataflow::FlowAtLocation;
+use crate::dataflow::MaybeInitializedPlaces;
+
+use crate::borrow_check::{
+    location::LocationTable,
+    constraints::OutlivesConstraintSet,
+    facts::{AllFacts, AllFactsExt},
+    region_infer::values::RegionValueElements,
+    universal_regions::UniversalRegions,
+    nll::ToRegionVid,
+};
+
 use super::TypeChecker;
 
 mod local_use_map;
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/trace.rs
index ba6fd75..9afd25a 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
@@ -1,11 +1,3 @@
-use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
-use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
-use crate::borrow_check::nll::type_check::liveness::polonius;
-use crate::borrow_check::nll::type_check::NormalizeLocation;
-use crate::borrow_check::nll::type_check::TypeChecker;
-use crate::dataflow::indexes::MovePathIndex;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
 use rustc::infer::canonical::QueryRegionConstraints;
 use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache};
 use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
@@ -16,6 +8,18 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use std::rc::Rc;
 
+use crate::dataflow::indexes::MovePathIndex;
+use crate::dataflow::move_paths::MoveData;
+use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
+
+use crate::borrow_check::{
+    region_infer::values::{self, PointIndex, RegionValueElements},
+    type_check::liveness::local_use_map::LocalUseMap,
+    type_check::liveness::polonius,
+    type_check::NormalizeLocation,
+    type_check::TypeChecker,
+};
+
 /// This is the heart of the liveness computation. For each variable X
 /// that requires a liveness computation, it walks over all the uses
 /// of X and does a reverse depth-first search ("trace") through the
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/mod.rs
rename to src/librustc_mir/borrow_check/type_check/mod.rs
index cddc3b4..663536b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -34,30 +34,32 @@
 use rustc_index::vec::{Idx, IndexVec};
 use syntax_pos::{DUMMY_SP, Span};
 
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::constraints::{OutlivesConstraint, OutlivesConstraintSet};
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::nll::member_constraints::MemberConstraintSet;
-use crate::borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
-use crate::borrow_check::nll::region_infer::values::LivenessValues;
-use crate::borrow_check::nll::region_infer::values::PlaceholderIndex;
-use crate::borrow_check::nll::region_infer::values::PlaceholderIndices;
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::borrow_check::nll::renumber;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::nll::type_check::free_region_relations::{
-    CreateResult, UniversalRegionRelations,
-};
-use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
 use crate::dataflow::FlowAtLocation;
 use crate::dataflow::MaybeInitializedPlaces;
 use crate::dataflow::move_paths::MoveData;
 use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
 
+use crate::borrow_check::{
+    borrow_set::BorrowSet,
+    location::LocationTable,
+    constraints::{OutlivesConstraintSet, OutlivesConstraint},
+    member_constraints::MemberConstraintSet,
+    facts::AllFacts,
+    region_infer::values::{
+        LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
+    },
+    region_infer::{ClosureRegionRequirementsExt, TypeTest},
+    type_check::free_region_relations::{
+        CreateResult, UniversalRegionRelations,
+    },
+    universal_regions::{DefiningTy, UniversalRegions},
+    nll::ToRegionVid,
+    renumber,
+};
+
 macro_rules! span_mirbug {
     ($context:expr, $elem:expr, $($message:tt)*) => ({
-        $crate::borrow_check::nll::type_check::mirbug(
+        $crate::borrow_check::type_check::mirbug(
             $context.tcx(),
             $context.last_span,
             &format!(
@@ -675,23 +677,16 @@
                     }),
                 )
             }
-            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/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
rename to src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 80bf047..80da8a8 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -1,5 +1,3 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::type_check::{BorrowCheckContext, Locations};
 use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::mir::ConstraintCategory;
@@ -8,6 +6,9 @@
 use rustc::ty::relate::TypeRelation;
 use rustc::ty::{self, Ty};
 
+use crate::borrow_check::constraints::OutlivesConstraint;
+use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
+
 /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
 ///
 /// - "Covariant" `a <: b`
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
similarity index 99%
rename from src/librustc_mir/borrow_check/nll/universal_regions.rs
rename to src/librustc_mir/borrow_check/universal_regions.rs
index 9ad15fc..c035303 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -25,7 +25,7 @@
 use rustc_errors::DiagnosticBuilder;
 use std::iter;
 
-use super::ToRegionVid;
+use crate::borrow_check::nll::ToRegionVid;
 
 #[derive(Debug)]
 pub struct UniversalRegions<'tcx> {
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index aec9e6e..ec8b3c5 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -2,6 +2,7 @@
 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 @@
                                      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 @@
         );
 
         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 @@
                   .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/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 7e7652c..5433b7f 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -1,6 +1,3 @@
-use crate::borrow_check::borrow_set::{BorrowSet, BorrowData};
-use crate::borrow_check::place_ext::PlaceExt;
-
 use rustc::mir::{self, Location, Place, PlaceBase, Body};
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::RegionVid;
@@ -9,10 +6,11 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::{Idx, IndexVec};
 
+use crate::borrow_check::{
+    ToRegionVid, BorrowSet, BorrowData, RegionInferenceContext, PlaceExt, PlaceConflictBias,
+    places_conflict,
+};
 use crate::dataflow::{BitDenotation, BottomValue, GenKillSet};
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::places_conflict;
 
 use std::rc::Rc;
 
@@ -221,13 +219,13 @@
             // locations.
             let definitely_conflicting_borrows = other_borrows_of_local
                 .filter(|&&i| {
-                    places_conflict::places_conflict(
+                    places_conflict(
                         self.tcx,
                         self.param_env,
                         self.body,
                         &self.borrow_set.borrows[i].borrowed_place,
                         place,
-                        places_conflict::PlaceConflictBias::NoOverlap)
+                        PlaceConflictBias::NoOverlap)
                 });
 
             trans.kill_all(definitely_conflicting_borrows);
diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
index d97f3b7..0665c0f 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 @@
             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 52016d4..fa0864e 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_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 @@
 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 @@
         MoveDataBuilder {
             body,
             tcx,
+            param_env,
             errors: Vec::new(),
             data: MoveData {
                 moves: IndexVec::new(),
@@ -148,42 +150,47 @@
                             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 @@
 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 @@
     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 b599f47..89ef9b2 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 @@
     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 a600eb1..42fbfec 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -451,9 +451,15 @@
         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 @@
         };
 
         // 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 @@
                 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 9970752..1cacf1f 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -26,7 +26,7 @@
 
         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 @@
 
     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 bedf2a9..2e1a08a 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -35,7 +35,6 @@
 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 @@
         // 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 @@
         // 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/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index cf2e130..1c95155 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -80,7 +80,7 @@
     for ty in ty.walk() {
         match ty.kind {
             ty::Ref(_, _, hir::Mutability::Mutable) => {
-                if !tcx.features().const_mut_refs {
+                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
                     return Err((
                         span,
                         "mutable references in const fn are unstable".into(),
@@ -220,7 +220,7 @@
         }
 
         | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => {
             Err((span, "loops and conditional expressions are not stable in const fn".into()))
         }
@@ -272,7 +272,7 @@
     while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
-            ProjectionElem::Downcast(..) if !tcx.features().const_if_match
+            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match)
                 => return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
             ProjectionElem::Downcast(_symbol, _variant_index) => {}
 
@@ -329,7 +329,7 @@
 
         | TerminatorKind::FalseEdges { .. }
         | TerminatorKind::SwitchInt { .. }
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => Err((
             span,
             "loops and conditional expressions are not stable in const fn".into(),
@@ -341,7 +341,7 @@
         }
 
         // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
-        TerminatorKind::Unreachable if tcx.features().const_if_match => Ok(()),
+        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),
 
         | TerminatorKind::Abort | TerminatorKind::Unreachable => {
             Err((span, "const fn with unreachable code is not stable".into()))
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 2a81e97..4345fc6 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -37,7 +37,7 @@
 
         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 71dd405..0000000
--- 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/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 42ece96..117b92d 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -459,18 +459,28 @@
     /// Parse `&pat` / `&mut pat`.
     fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
         self.expect_and()?;
+        self.recover_lifetime_in_deref_pat();
         let mutbl = self.parse_mutability();
-
-        if let token::Lifetime(name) = self.token.kind {
-            let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
-            err.span_label(self.token.span, "unexpected lifetime");
-            return Err(err);
-        }
-
         let subpat = self.parse_pat_with_range_pat(false, expected)?;
         Ok(PatKind::Ref(subpat, mutbl))
     }
 
+    fn recover_lifetime_in_deref_pat(&mut self) {
+        if let token::Lifetime(name) = self.token.kind {
+            self.bump(); // `'a`
+
+            let span = self.prev_span;
+            self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
+                .span_suggestion(
+                    span,
+                    "remove the lifetime",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
+    }
+
     /// Parse a tuple or parenthesis pattern.
     fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
         let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 566ba12..e2578d6 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -647,8 +647,6 @@
                 self.r.define(parent, ident, TypeNS, imported_binding);
             }
 
-            ItemKind::GlobalAsm(..) => {}
-
             ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
 
             ItemKind::Mod(..) => {
@@ -667,9 +665,6 @@
                 self.parent_scope.module = module;
             }
 
-            // Handled in `rustc_metadata::{native_libs,link_args}`
-            ItemKind::ForeignMod(..) => {}
-
             // These items live in the value namespace.
             ItemKind::Static(..) => {
                 let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id));
@@ -765,12 +760,6 @@
                 self.insert_field_names_local(def_id, vdata);
             }
 
-            ItemKind::Impl(.., ref impl_items) => {
-                for impl_item in impl_items {
-                    self.resolve_visibility(&impl_item.vis);
-                }
-            }
-
             ItemKind::Trait(..) => {
                 let def_id = self.r.definitions.local_def_id(item.id);
 
@@ -785,6 +774,9 @@
                 self.parent_scope.module = module;
             }
 
+            // These items do not add names to modules.
+            ItemKind::Impl(..) | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
+
             ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
         }
     }
@@ -1118,7 +1110,6 @@
 }
 
 impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
-    method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
     method!(visit_expr:      ast::Expr,     ast::ExprKind::Mac,       walk_expr);
     method!(visit_pat:       ast::Pat,      ast::PatKind::Mac,        walk_pat);
     method!(visit_ty:        ast::Ty,       ast::TyKind::Mac,         walk_ty);
@@ -1202,6 +1193,15 @@
         visit::walk_trait_item(self, item);
     }
 
+    fn visit_impl_item(&mut self, item: &'b ast::ImplItem) {
+        if let ast::ImplItemKind::Macro(..) = item.kind {
+            self.visit_invoc(item.id);
+        } else {
+            self.resolve_visibility(&item.vis);
+            visit::walk_impl_item(self, item);
+        }
+    }
+
     fn visit_token(&mut self, t: Token) {
         if let token::Interpolated(nt) = t.kind {
             if let token::NtExpr(ref expr) = *nt {
diff --git a/src/librustc_session/code_stats.rs b/src/librustc_session/code_stats.rs
index 5baf0c5..764d6d8 100644
--- a/src/librustc_session/code_stats.rs
+++ b/src/librustc_session/code_stats.rs
@@ -132,9 +132,12 @@
 
                 let mut min_offset = discr_size;
 
-                // We want to print fields by increasing offset.
+                // We want to print fields by increasing offset. We also want
+                // zero-sized fields before non-zero-sized fields, otherwise
+                // the loop below goes wrong; hence the `f.size` in the sort
+                // key.
                 let mut fields = fields.clone();
-                fields.sort_by_key(|f| f.offset);
+                fields.sort_by_key(|f| (f.offset, f.size));
 
                 for field in fields.iter() {
                     let FieldInfo { ref name, offset, size, align } = *field;
@@ -146,7 +149,7 @@
                     }
 
                     if offset < min_offset {
-                        // if this happens something is very wrong
+                        // If this happens it's probably a union.
                         println!("print-type-size {}field `.{}`: {} bytes, \
                                   offset: {} bytes, \
                                   alignment: {} bytes",
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index 6de3f1d..ac1ef3e 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -26,7 +26,6 @@
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
 struct GenFuture<T: Generator<Yield = ()>>(T);
 
 // We rely on the fact that async/await futures are immovable in order to create
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index dfb9307..0861432 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -8,8 +8,6 @@
 // Note, however, that we run on lots older linuxes, as well as cross
 // compiling from a newer linux to an older linux, so we also have a
 // fallback implementation to use as well.
-//
-// Due to rust-lang/rust#18804, make sure this is not generic!
 #[cfg(any(
     target_os = "linux",
     target_os = "fuchsia",
diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index bf7960f..1e2f3f9 100644
--- a/src/libsyntax_expand/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -83,7 +83,7 @@
 use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::token::{self, DocComment, Nonterminal, Token};
-use syntax::tokenstream::{DelimSpan, TokenStream};
+use syntax::tokenstream::TokenStream;
 
 use errors::{PResult, FatalError};
 use smallvec::{smallvec, SmallVec};
@@ -164,11 +164,6 @@
     /// The position of the "dot" in this matcher
     idx: usize,
 
-    /// The first span of source that the beginning of this matcher corresponds to. In other
-    /// words, the token in the source whose span is `sp_open` is matched against the first token of
-    /// the matcher.
-    sp_open: Span,
-
     /// For each named metavar in the matcher, we keep track of token trees matched against the
     /// metavar by the black box parser. In particular, there may be more than one match per
     /// metavar if we are in a repetition (each repetition matches each of the variables).
@@ -307,8 +302,8 @@
 }
 
 /// Generates the top-level matcher position in which the "dot" is before the first token of the
-/// matcher `ms` and we are going to start matching at the span `open` in the source.
-fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
+/// matcher `ms`.
+fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree]) -> MatcherPos<'root, 'tt> {
     let match_idx_hi = count_names(ms);
     let matches = create_matches(match_idx_hi);
     MatcherPos {
@@ -316,8 +311,6 @@
         top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
         // The "dot" is before the first token of the matcher
         idx: 0,
-        // We start matching at the span `open` in the source code
-        sp_open: open,
 
         // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
         // `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
@@ -355,7 +348,7 @@
 /// token tree it was derived from.
 #[derive(Debug, Clone)]
 crate enum NamedMatch {
-    MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
+    MatchedSeq(Lrc<NamedMatchVec>),
     MatchedNonterminal(Lrc<Nonterminal>),
 }
 
@@ -497,8 +490,7 @@
                     // Add matches from this repetition to the `matches` of `up`
                     for idx in item.match_lo..item.match_hi {
                         let sub = item.matches[idx].clone();
-                        let span = DelimSpan::from_pair(item.sp_open, token.span);
-                        new_pos.push_match(idx, MatchedSeq(sub, span));
+                        new_pos.push_match(idx, MatchedSeq(sub));
                     }
 
                     // Move the "dot" past the repetition in `up`
@@ -552,7 +544,7 @@
                         new_item.match_cur += seq.num_captures;
                         new_item.idx += 1;
                         for idx in item.match_cur..item.match_cur + seq.num_captures {
-                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]), sp));
+                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![])));
                         }
                         cur_items.push(new_item);
                     }
@@ -568,7 +560,6 @@
                         match_cur: item.match_cur,
                         match_hi: item.match_cur + seq.num_captures,
                         up: Some(item),
-                        sp_open: sp.open,
                         top_elts: Tt(TokenTree::Sequence(sp, seq)),
                     })));
                 }
@@ -663,7 +654,7 @@
     //
     // This MatcherPos instance is allocated on the stack. All others -- and
     // there are frequently *no* others! -- are allocated on the heap.
-    let mut initial = initial_matcher_pos(ms, parser.token.span);
+    let mut initial = initial_matcher_pos(ms);
     let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
     let mut next_items = Vec::new();
 
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index e3c3655..2dd1587 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -379,7 +379,7 @@
 
     // Extract the arguments:
     let lhses = match argument_map[&lhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
@@ -402,7 +402,7 @@
     };
 
     let rhses = match argument_map[&rhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs
index a115766..0605f7f 100644
--- a/src/libsyntax_expand/mbe/transcribe.rs
+++ b/src/libsyntax_expand/mbe/transcribe.rs
@@ -299,7 +299,7 @@
         for &(idx, _) in repeats {
             match matched {
                 MatchedNonterminal(_) => break,
-                MatchedSeq(ref ads, _) => matched = ads.get(idx).unwrap(),
+                MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
             }
         }
 
@@ -382,7 +382,7 @@
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
                     MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
-                    MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
+                    MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
             }
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index e8f7a12..92de56b 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -660,6 +660,7 @@
         _Self,
         self_in_typedefs,
         self_struct_ctor,
+        send_trait,
         should_panic,
         simd,
         simd_extract,
@@ -697,6 +698,7 @@
         sty,
         sub_with_overflow,
         suggestion,
+        sync_trait,
         target_feature,
         target_has_atomic,
         target_has_atomic_load_store,
diff --git a/src/test/mir-opt/const_prop/return_place.rs b/src/test/mir-opt/const_prop/return_place.rs
index cc9951b..ea7c1e7 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 @@
 //         _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 @@
 //         _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 c249154..f2e1864 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 @@
 
 // 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
+// END rustc.move_out_from_end.mir_map.0.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;
+// START rustc.move_out_by_subslice.mir_map.0.mir
+//     _6 = move _1[0..2];
 //     _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
-
-// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
-//     StorageLive(_6);
-//     nop;
-//     nop;
-//     nop;
-//     nop;
-//     _6 = move _1[0:];
-//     nop;
-//     nop;
-//     nop;
-//     _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/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index 1f1bf42..645c903 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -48,10 +48,10 @@
 
 pub fn pass_assert() {
     assert_send(local_dropped_before_await());
-    //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
     assert_send(non_send_temporary_in_match());
-    //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call());
-    //~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
-    //~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+    //~^ ERROR future cannot be sent between threads safely
+    //~^^ ERROR future cannot be sent between threads safely
 }
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index 6e89deb..5c870ca 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -1,79 +1,88 @@
-error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/async-fn-nonsend.rs:50:5
    |
 LL | fn assert_send(_: impl Send) {}
    |    -----------         ---- required by this bound in `assert_send`
 ...
 LL |     assert_send(local_dropped_before_await());
-   |     ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
+   |     ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
-   = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]>`
-   = note: required because it appears within the type `impl std::future::Future`
-   = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:25:5
+   |
+LL |     let x = non_send();
+   |         - has type `impl std::fmt::Debug`
+LL |     drop(x);
+LL |     fut().await;
+   |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
 
-error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/async-fn-nonsend.rs:52:5
    |
 LL | fn assert_send(_: impl Send) {}
    |    -----------         ---- required by this bound in `assert_send`
 ...
 LL |     assert_send(non_send_temporary_in_match());
-   |     ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
+   |     ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
-   = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]>`
-   = note: required because it appears within the type `impl std::future::Future`
-   = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:34:20
+   |
+LL |     match Some(non_send()) {
+   |                ---------- has type `impl std::fmt::Debug`
+LL |         Some(_) => fut().await,
+   |                    ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later
+...
+LL | }
+   | - `non_send()` is later dropped here
 
-error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/async-fn-nonsend.rs:54:5
    |
 LL | fn assert_send(_: impl Send) {}
    |    -----------         ---- required by this bound in `assert_send`
 ...
 LL |     assert_send(non_sync_with_method_call());
-   |     ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
+   |     ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
-   = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
-   = note: required because it appears within the type `std::fmt::Formatter<'_>`
-   = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
-   = note: required because it appears within the type `impl std::future::Future`
-   = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:43:9
+   |
+LL |     let f: &mut std::fmt::Formatter = panic!();
+   |         - has type `&mut std::fmt::Formatter<'_>`
+LL |     if non_sync().fmt(f).unwrap() == () {
+LL |         fut().await;
+   |         ^^^^^^^^^^^ await occurs here, with `f` maybe used later
+LL |     }
+LL | }
+   | - `f` is later dropped here
 
-error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/async-fn-nonsend.rs:54:5
    |
 LL | fn assert_send(_: impl Send) {}
    |    -----------         ---- required by this bound in `assert_send`
 ...
 LL |     assert_send(non_sync_with_method_call());
-   |     ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+   |     ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
-   = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
-   = note: required because it appears within the type `core::fmt::Void`
-   = note: required because it appears within the type `&core::fmt::Void`
-   = note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
-   = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
-   = note: required because it appears within the type `std::fmt::Formatter<'_>`
-   = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
-   = note: required because it appears within the type `impl std::future::Future`
-   = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:43:9
+   |
+LL |     let f: &mut std::fmt::Formatter = panic!();
+   |         - has type `&mut std::fmt::Formatter<'_>`
+LL |     if non_sync().fmt(f).unwrap() == () {
+LL |         fut().await;
+   |         ^^^^^^^^^^^ await occurs here, with `f` maybe used later
+LL |     }
+LL | }
+   | - `f` is later dropped here
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-64130-1-sync.rs b/src/test/ui/async-await/issue-64130-1-sync.rs
new file mode 100644
index 0000000..cc5ca89
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-1-sync.rs
@@ -0,0 +1,23 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the specialized async-await-specific error when futures don't implement an
+// auto trait (which is specifically Sync) due to some type that was captured.
+
+struct Foo;
+
+impl !Sync for Foo {}
+
+fn is_sync<T: Sync>(t: T) { }
+
+async fn bar() {
+    let x = Foo;
+    baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+    is_sync(bar());
+    //~^ ERROR future cannot be shared between threads safely
+}
diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr
new file mode 100644
index 0000000..8beb31f
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-1-sync.stderr
@@ -0,0 +1,22 @@
+error: future cannot be shared between threads safely
+  --> $DIR/issue-64130-1-sync.rs:21:5
+   |
+LL | fn is_sync<T: Sync>(t: T) { }
+   |    -------    ---- required by this bound in `is_sync`
+...
+LL |     is_sync(bar());
+   |     ^^^^^^^ future returned by `bar` is not `Sync`
+   |
+   = help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo`
+note: future is not `Sync` as this value is used across an await
+  --> $DIR/issue-64130-1-sync.rs:15:5
+   |
+LL |     let x = Foo;
+   |         - has type `Foo`
+LL |     baz().await;
+   |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-2-send.rs b/src/test/ui/async-await/issue-64130-2-send.rs
new file mode 100644
index 0000000..1efe2ab
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-2-send.rs
@@ -0,0 +1,23 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the specialized async-await-specific error when futures don't implement an
+// auto trait (which is specifically Send) due to some type that was captured.
+
+struct Foo;
+
+impl !Send for Foo {}
+
+fn is_send<T: Send>(t: T) { }
+
+async fn bar() {
+    let x = Foo;
+    baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+    is_send(bar());
+    //~^ ERROR future cannot be sent between threads safely
+}
diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr
new file mode 100644
index 0000000..823b88e
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-2-send.stderr
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-2-send.rs:21:5
+   |
+LL | fn is_send<T: Send>(t: T) { }
+   |    -------    ---- required by this bound in `is_send`
+...
+LL |     is_send(bar());
+   |     ^^^^^^^ future returned by `bar` is not `Send`
+   |
+   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-64130-2-send.rs:15:5
+   |
+LL |     let x = Foo;
+   |         - has type `Foo`
+LL |     baz().await;
+   |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs
new file mode 100644
index 0000000..901544e
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-3-other.rs
@@ -0,0 +1,25 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the unspecialized async-await-specific error when futures don't implement an
+// auto trait (which is not Send or Sync) due to some type that was captured.
+
+auto trait Qux { }
+
+struct Foo;
+
+impl !Qux for Foo {}
+
+fn is_qux<T: Qux>(t: T) { }
+
+async fn bar() {
+    let x = Foo;
+    baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+    is_qux(bar());
+    //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
+}
diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr
new file mode 100644
index 0000000..155c5cc
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-3-other.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
+  --> $DIR/issue-64130-3-other.rs:23:5
+   |
+LL | fn is_qux<T: Qux>(t: T) { }
+   |    ------    --- required by this bound in `is_qux`
+...
+LL |     is_qux(bar());
+   |     ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`
+   |
+   = help: the following implementations were found:
+             <Foo as Qux>
+note: future does not implement `Qux` as this value is used across an await
+  --> $DIR/issue-64130-3-other.rs:17:5
+   |
+LL |     let x = Foo;
+   |         - has type `Foo`
+LL |     baz().await;
+   |     ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.rs b/src/test/ui/async-await/issue-64130-4-async-move.rs
new file mode 100644
index 0000000..2538f34
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-4-async-move.rs
@@ -0,0 +1,28 @@
+// edition:2018
+use std::any::Any;
+use std::future::Future;
+
+struct Client(Box<dyn Any + Send>);
+
+impl Client {
+    fn status(&self) -> u16 {
+        200
+    }
+}
+
+async fn get() { }
+
+pub fn foo() -> impl Future + Send {
+    //~^ ERROR future cannot be sent between threads safely
+    let client = Client(Box::new(true));
+    async move {
+        match client.status() {
+            200 => {
+                let _x = get().await;
+            },
+            _ => (),
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr
new file mode 100644
index 0000000..ddbb469
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-4-async-move.rs:15:17
+   |
+LL | pub fn foo() -> impl Future + Send {
+   |                 ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-64130-4-async-move.rs:21:26
+   |
+LL |         match client.status() {
+   |               ------ has type `&Client`
+LL |             200 => {
+LL |                 let _x = get().await;
+   |                          ^^^^^^^^^^^ await occurs here, with `client` maybe used later
+...
+LL |     }
+   |     - `client` is later dropped here
+   = note: the return type of a function must have a statically known size
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
index 1936d1a..656ade6 100644
--- a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
@@ -1,10 +1,10 @@
 // edition:2018
 
+// This tests the basic example case for the async-await-specific error.
+
 use std::sync::Mutex;
 
-fn is_send<T: Send>(t: T) {
-
-}
+fn is_send<T: Send>(t: T) { }
 
 async fn foo() {
     bar(&Mutex::new(22)).await;
@@ -15,11 +15,9 @@
     baz().await;
 }
 
-async fn baz() {
-
-}
+async fn baz() { }
 
 fn main() {
     is_send(foo());
-    //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277]
+    //~^ ERROR future cannot be sent between threads safely
 }
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
index 9e9fc52..662407f 100644
--- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -1,14 +1,14 @@
-error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
-  --> $DIR/issue-64130-non-send-future-diags.rs:23:5
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-non-send-future-diags.rs:21:5
    |
-LL | fn is_send<T: Send>(t: T) {
+LL | fn is_send<T: Send>(t: T) { }
    |    -------    ---- required by this bound in `is_send`
 ...
 LL |     is_send(foo());
-   |     ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
+   |     ^^^^^^^ future returned by `foo` is not `Send`
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
-note: future does not implement `std::marker::Send` as this value is used across an await
+note: future is not `Send` as this value is used across an await
   --> $DIR/issue-64130-non-send-future-diags.rs:15:5
    |
 LL |     let g = x.lock().unwrap();
@@ -20,4 +20,3 @@
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
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 0000000..8f274cf
--- /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 0000000..57ce241
--- /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 0000000..778beef
--- /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 0000000..2a7b891
--- /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 ee6abf4..f9d3f6f 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 b34c03e..08134a2 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;
-   |          -- value moved here
-LL |     let [_y @ ..] = a;
-   |          ^^^^^^^ value used here after move
+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[..].0` has type `std::string::String`, which does not implement the `Copy` trait
 
-error: aborting due to 2 previous errors
+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 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::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+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 0000000..7d91a21
--- /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 0000000..f03a2ab
--- /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 0000000..e50e7eb
--- /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 0000000..e69071f
--- /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
similarity index 65%
rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs
rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
index a6b54f9..2ef9874 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_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_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 @@
         }
     }
     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_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_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 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
similarity index 89%
rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr
rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
index 2c019f4..b6f5ac6 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 @@
    |                          ------ 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 @@
    |                          ----- 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 @@
    |                                           --------- 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 @@
    |                                           --------- 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 @@
    |                                             ----------- 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 @@
    |                                ----------- 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 @@
    |                          ------ 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 @@
    |                          ------ 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/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
index 99006a2..33abfec 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_mut_refs)]
+#![feature(const_fn)]
 
 struct Foo {
     x: usize
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
index 8bd1929..b9ff040 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -4,6 +4,7 @@
 
 #![feature(const_panic)]
 #![feature(const_if_match)]
+#![feature(const_fn)]
 
 const X: u32 = 4;
 const Y: u32 = 5;
diff --git a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
index 6bbbdd9..7887fd1 100644
--- a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
+++ b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
@@ -3,6 +3,7 @@
 // check-pass
 
 #![feature(const_if_match)]
+#![feature(const_fn)]
 
 enum E {
     A,
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
index 21e3f2a..9509672 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate-const-if-match.rs:108:1
+  --> $DIR/feature-gate-const-if-match.rs:109:1
    |
 LL | / fn main() {
 LL | |     let _ = [0; {
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
index 00576d5..e4b6525 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
@@ -6,6 +6,7 @@
 
 #![feature(rustc_attrs)]
 #![cfg_attr(if_match, feature(const_if_match))]
+#![feature(const_fn)]
 
 const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
     5
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
index d3c6a51..e846ee4 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:10:16
+  --> $DIR/feature-gate-const-if-match.rs:11:16
    |
 LL |   const _: i32 = if true {
    |  ________________^
@@ -13,7 +13,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:16:16
+  --> $DIR/feature-gate-const-if-match.rs:17:16
    |
 LL |   const _: i32 = if let Some(true) = Some(false) {
    |  ________________^
@@ -27,7 +27,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:22:16
+  --> $DIR/feature-gate-const-if-match.rs:23:16
    |
 LL |   const _: i32 = match 1 {
    |  ________________^
@@ -41,7 +41,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:29:13
+  --> $DIR/feature-gate-const-if-match.rs:30:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:31:13
+  --> $DIR/feature-gate-const-if-match.rs:32:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:33:5
+  --> $DIR/feature-gate-const-if-match.rs:34:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:38:13
+  --> $DIR/feature-gate-const-if-match.rs:39:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:40:13
+  --> $DIR/feature-gate-const-if-match.rs:41:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:42:5
+  --> $DIR/feature-gate-const-if-match.rs:43:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:47:5
+  --> $DIR/feature-gate-const-if-match.rs:48:5
    |
 LL |     if true { 5 } else { 6 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:51:5
+  --> $DIR/feature-gate-const-if-match.rs:52:5
    |
 LL | /     if let Some(true) = a {
 LL | |         0
@@ -117,7 +117,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:59:5
+  --> $DIR/feature-gate-const-if-match.rs:60:5
    |
 LL | /     match i {
 LL | |         i if i > 10 => i,
@@ -130,7 +130,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:90:17
+  --> $DIR/feature-gate-const-if-match.rs:91:17
    |
 LL |         let x = if y { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:92:17
+  --> $DIR/feature-gate-const-if-match.rs:93:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:94:9
+  --> $DIR/feature-gate-const-if-match.rs:95:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:110:17
+  --> $DIR/feature-gate-const-if-match.rs:111:17
    |
 LL |         let x = if false { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:112:17
+  --> $DIR/feature-gate-const-if-match.rs:113:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:114:9
+  --> $DIR/feature-gate-const-if-match.rs:115:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:67:21
+  --> $DIR/feature-gate-const-if-match.rs:68:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:70:25
+  --> $DIR/feature-gate-const-if-match.rs:71:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +202,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:73:24
+  --> $DIR/feature-gate-const-if-match.rs:74:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:78:21
+  --> $DIR/feature-gate-const-if-match.rs:79:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:81:25
+  --> $DIR/feature-gate-const-if-match.rs:82:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:84:24
+  --> $DIR/feature-gate-const-if-match.rs:85:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -238,7 +238,7 @@
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/feature-gate-const-if-match.rs:114:21
+  --> $DIR/feature-gate-const-if-match.rs:115:21
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |                     ^
diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs
index 8cee2a5..4b20a21 100644
--- a/src/test/ui/consts/control-flow/short-circuit-let.rs
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -4,6 +4,7 @@
 
 #![feature(const_if_match)]
 #![feature(const_panic)]
+#![feature(const_fn)]
 
 const X: i32 = {
     let mut x = 0;
diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
index 823605f..bb0fce6 100644
--- a/src/test/ui/consts/control-flow/single_variant_match_ice.rs
+++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_if_match)]
+#![feature(const_if_match, const_fn)]
 
 enum Foo {
     Prob,
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 29dcbfe..0f0ec0b 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -269,6 +269,28 @@
     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 @@
     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);
     });
diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs
index ae0a288..0db01c6 100644
--- a/src/test/ui/generator/not-send-sync.rs
+++ b/src/test/ui/generator/not-send-sync.rs
@@ -7,7 +7,7 @@
     fn assert_send<T: Send>(_: T) {}
 
     assert_sync(|| {
-        //~^ ERROR: E0277
+        //~^ ERROR: future cannot be shared between threads safely
         let a = Cell::new(2);
         yield;
     });
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
index 620db24..0ac1d18 100644
--- a/src/test/ui/generator/not-send-sync.stderr
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -11,18 +11,25 @@
    = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell<i32>`
    = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell<i32> _]`
 
-error[E0277]: `std::cell::Cell<i32>` cannot be shared between threads safely
+error: future cannot be shared between threads safely
   --> $DIR/not-send-sync.rs:9:5
    |
 LL |     fn assert_sync<T: Sync>(_: T) {}
    |        -----------    ---- required by this bound in `main::assert_sync`
 ...
 LL |     assert_sync(|| {
-   |     ^^^^^^^^^^^ `std::cell::Cell<i32>` cannot be shared between threads safely
+   |     ^^^^^^^^^^^ future returned by `main` is not `Sync`
    |
    = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
-   = note: required because it appears within the type `{std::cell::Cell<i32>, ()}`
-   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, ()}]`
+note: future is not `Sync` as this value is used across an yield
+  --> $DIR/not-send-sync.rs:12:9
+   |
+LL |         let a = Cell::new(2);
+   |             - has type `std::cell::Cell<i32>`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |     });
+   |     - `a` is later dropped here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
index ab9baa7..0a951cf 100644
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
+++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
@@ -17,10 +17,7 @@
 
 macro_rules! and_the_heavens_reject_not {
     () => {
-        // ↓ But let's test that we still lint for unused parens around
-        // function args inside of simple, one-deep macros.
         #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
-        //~^ WARN unnecessary parentheses around function argument
     }
 }
 
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
deleted file mode 100644
index 57cdcd7..0000000
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: unnecessary parentheses around function argument
-  --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:22:83
-   |
-LL |         #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
-   |                                                                                   ^^^ help: remove these parentheses
-...
-LL | and_the_heavens_reject_not!();
-   | ------------------------------ in this macro invocation
-   |
-note: lint level defined here
-  --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:3:9
-   |
-LL | #![warn(unused_parens)]
-   |         ^^^^^^^^^^^^^
-
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index 9f42b85..12ffb6d 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -25,6 +25,12 @@
     panic!()
 }
 
+macro_rules! baz {
+    ($($foo:expr),+) => {
+        ($($foo),*)
+    }
+}
+
 fn main() {
     foo();
     bar((true)); //~ ERROR unnecessary parentheses around function argument
@@ -55,4 +61,7 @@
     let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value
     _a = (0); //~ ERROR unnecessary parentheses around assigned value
     _a += (1); //~ ERROR unnecessary parentheses around assigned value
+
+    let _a = baz!(3, 4);
+    let _b = baz!(3);
 }
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index adc1069..541ae7a 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -23,25 +23,25 @@
    |                                          ^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:30:9
+  --> $DIR/lint-unnecessary-parens.rs:36:9
    |
 LL |     bar((true));
    |         ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:32:8
+  --> $DIR/lint-unnecessary-parens.rs:38:8
    |
 LL |     if (true) {}
    |        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:33:11
+  --> $DIR/lint-unnecessary-parens.rs:39:11
    |
 LL |     while (true) {}
    |           ^^^^^^ help: remove these parentheses
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-unnecessary-parens.rs:33:5
+  --> $DIR/lint-unnecessary-parens.rs:39:5
    |
 LL |     while (true) {}
    |     ^^^^^^^^^^^^ help: use `loop`
@@ -49,43 +49,43 @@
    = note: `#[warn(while_true)]` on by default
 
 error: unnecessary parentheses around `match` head expression
-  --> $DIR/lint-unnecessary-parens.rs:35:11
+  --> $DIR/lint-unnecessary-parens.rs:41:11
    |
 LL |     match (true) {
    |           ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:38:16
+  --> $DIR/lint-unnecessary-parens.rs:44:16
    |
 LL |     if let 1 = (1) {}
    |                ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:39:19
+  --> $DIR/lint-unnecessary-parens.rs:45:19
    |
 LL |     while let 1 = (2) {}
    |                   ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:53:24
+  --> $DIR/lint-unnecessary-parens.rs:59:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:55:18
+  --> $DIR/lint-unnecessary-parens.rs:61:18
    |
 LL |     let mut _a = (0);
    |                  ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:56:10
+  --> $DIR/lint-unnecessary-parens.rs:62:10
    |
 LL |     _a = (0);
    |          ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:57:11
+  --> $DIR/lint-unnecessary-parens.rs:63:11
    |
 LL |     _a += (1);
    |           ^^^ help: remove these parentheses
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.rs b/src/test/ui/parser/lifetime-in-pattern-recover.rs
new file mode 100644
index 0000000..7fb14b8
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let &'a x = &0; //~ ERROR unexpected lifetime `'a` in pattern
+    let &'a mut y = &mut 0; //~ ERROR unexpected lifetime `'a` in pattern
+
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.stderr b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
new file mode 100644
index 0000000..4bf7f57
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
@@ -0,0 +1,23 @@
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:2:10
+   |
+LL |     let &'a x = &0;
+   |          ^^ help: remove the lifetime
+
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:3:10
+   |
+LL |     let &'a mut y = &mut 0;
+   |          ^^ help: remove the lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/lifetime-in-pattern-recover.rs:5:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/lifetime-in-pattern.rs b/src/test/ui/parser/lifetime-in-pattern.rs
index afee685..d3c638d 100644
--- a/src/test/ui/parser/lifetime-in-pattern.rs
+++ b/src/test/ui/parser/lifetime-in-pattern.rs
@@ -1,5 +1,6 @@
 fn test(&'a str) {
     //~^ ERROR unexpected lifetime `'a` in pattern
+    //~| ERROR expected one of `:`, `@`, or `|`, found `)`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index e525c7b..71fd3cd 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@
   --> $DIR/lifetime-in-pattern.rs:1:10
    |
 LL | fn test(&'a str) {
-   |          ^^ unexpected lifetime
+   |          ^^ help: remove the lifetime
 
-error: aborting due to previous error
+error: expected one of `:`, `@`, or `|`, found `)`
+  --> $DIR/lifetime-in-pattern.rs:1:16
+   |
+LL | fn test(&'a str) {
+   |                ^ expected one of `:`, `@`, or `|`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs
new file mode 100644
index 0000000..2ad488e
--- /dev/null
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs
@@ -0,0 +1,46 @@
+// compile-flags: -Z print-type-sizes
+// build-pass (FIXME(62277): could be check-pass?)
+
+// At one point, zero-sized fields such as those in this file were causing
+// incorrect output from `-Z print-type-sizes`.
+
+#![feature(start)]
+
+struct S1 {
+    x: u32,
+    y: u32,
+    tag: (),
+}
+
+struct Void();
+struct Empty {}
+
+struct S5<TagW, TagZ> {
+    tagw: TagW,
+    w: u32,
+    unit: (),
+    x: u32,
+    void: Void,
+    y: u32,
+    empty: Empty,
+    z: u32,
+    tagz: TagZ,
+}
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+    let _s1: S1 = S1 { x: 0, y: 0, tag: () };
+
+    let _s5: S5<(), Empty> = S5 {
+        tagw: (),
+        w: 1,
+        unit: (),
+        x: 2,
+        void: Void(),
+        y: 3,
+        empty: Empty {},
+        z: 4,
+        tagz: Empty {},
+    };
+    0
+}
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.stdout b/src/test/ui/print_type_sizes/zero-sized-fields.stdout
new file mode 100644
index 0000000..72f59c4
--- /dev/null
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.stdout
@@ -0,0 +1,16 @@
+print-type-size type: `S5<(), Empty>`: 16 bytes, alignment: 4 bytes
+print-type-size     field `.tagw`: 0 bytes
+print-type-size     field `.unit`: 0 bytes
+print-type-size     field `.void`: 0 bytes
+print-type-size     field `.empty`: 0 bytes
+print-type-size     field `.tagz`: 0 bytes
+print-type-size     field `.w`: 4 bytes
+print-type-size     field `.x`: 4 bytes
+print-type-size     field `.y`: 4 bytes
+print-type-size     field `.z`: 4 bytes
+print-type-size type: `S1`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.tag`: 0 bytes
+print-type-size     field `.x`: 4 bytes
+print-type-size     field `.y`: 4 bytes
+print-type-size type: `Empty`: 0 bytes, alignment: 1 bytes
+print-type-size type: `Void`: 0 bytes, alignment: 1 bytes
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.rs b/src/test/ui/resolve/impl-items-vis-unresolved.rs
new file mode 100644
index 0000000..9b4fe49
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.rs
@@ -0,0 +1,25 @@
+// Visibilities on impl items expanded from macros are resolved (issue #64705).
+
+macro_rules! perftools_inline {
+    ($($item:tt)*) => (
+        $($item)*
+    );
+}
+
+mod state {
+    pub struct RawFloatState;
+    impl RawFloatState {
+        perftools_inline! {
+            pub(super) fn new() {} // OK
+        }
+    }
+}
+
+pub struct RawFloatState;
+impl RawFloatState {
+    perftools_inline! {
+        pub(super) fn new() {} //~ ERROR failed to resolve: there are too many initial `super`s
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.stderr b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
new file mode 100644
index 0000000..8e285e5
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: there are too many initial `super`s.
+  --> $DIR/impl-items-vis-unresolved.rs:21:13
+   |
+LL |         pub(super) fn new() {}
+   |             ^^^^^ there are too many initial `super`s.
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 5ce6a81..2beef50 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,7 @@
   --> $DIR/self-vs-path-ambiguity.rs:9:11
    |
 LL |     fn i(&'a self::S: &S) {}
-   |           ^^ unexpected lifetime
+   |           ^^ help: remove the lifetime
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/option-content-move2.rs b/src/test/ui/suggestions/option-content-move2.rs
new file mode 100644
index 0000000..88e8a5b
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.rs
@@ -0,0 +1,16 @@
+struct NotCopyable;
+
+fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+
+fn parse() {
+    let mut var = None;
+    func(|| {
+        // Shouldn't suggest `move ||.as_ref()` here
+        move || {
+        //~^ ERROR: cannot move out of `var`
+            var = Some(NotCopyable);
+        }
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
new file mode 100644
index 0000000..71f7453
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+  --> $DIR/option-content-move2.rs:9:9
+   |
+LL |     let mut var = None;
+   |         ------- captured outer variable
+...
+LL |         move || {
+   |         ^^^^^^^ move out of `var` occurs here
+LL |
+LL |             var = Some(NotCopyable);
+   |             ---
+   |             |
+   |             move occurs because `var` has type `std::option::Option<NotCopyable>`, which does not implement the `Copy` trait
+   |             move occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
index 9194468..1becb1e 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
@@ -9,6 +9,7 @@
 
 type Foo<V> = impl Trait<V>;
 //~^ ERROR could not find defining uses
+//~| ERROR the trait bound `T: TraitWithAssoc` is not satisfied
 
 trait Trait<U> {}
 
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
index bb22d58..1eb4cf2 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
@@ -1,5 +1,14 @@
+error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied
+  --> $DIR/bound_reduction2.rs:10:1
+   |
+LL | type Foo<V> = impl Trait<V>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T`
+...
+LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
+   |                  -- help: consider further restricting this bound: `T: TraitWithAssoc +`
+
 error: defining opaque type use does not fully define opaque type: generic parameter `V` is specified as concrete type `<T as TraitWithAssoc>::Assoc`
-  --> $DIR/bound_reduction2.rs:17:1
+  --> $DIR/bound_reduction2.rs:18:1
    |
 LL | / fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
 LL | |     ()
@@ -12,5 +21,6 @@
 LL | type Foo<V> = impl Trait<V>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0277`.