Rollup merge of #64250 - Xanewok:save-analysis-assoc-nested, r=varkor

save-analysis: Nest typeck tables when processing functions/methods

Fixes an issue where we did not nest tables correctly when resolving
associated types in formal argument/return type positions.

This was the minimized reproduction case that I tested the fix on:
```rust
pub trait Trait {
    type Assoc;
}

pub struct A;

pub fn func() {
    fn _inner1<U: Trait>(_: U::Assoc) {}
    fn _inner2<U: Trait>() -> U::Assoc { unimplemented!() }

    impl A {
        fn _inner1<U: Trait>(self, _: U::Assoc) {}
        fn _inner2<U: Trait>(self) -> U::Assoc { unimplemented!() }
    }
}
```
using `debug_assertions`-enabled rustc and by additionally passing `-Zsave-analysis`.

Unfortunately the original assertion fired is a *debug* one and from what I can tell we don't run the tests with these on, so I'm not adding a test here. If I missed it and there is a way to run tests with these on, I'd love to add a test case for this.

Closes #63663
Closes #50328
Closes #43982
diff --git a/.mailmap b/.mailmap
index da8044d..9587aaa 100644
--- a/.mailmap
+++ b/.mailmap
@@ -184,6 +184,7 @@
 Nick Platt <platt.nicholas@gmail.com>
 Nicole Mazzuca <npmazzuca@gmail.com>
 Nif Ward <nif.ward@gmail.com>
+Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com>
 Oliver Scherer <oliver.schneider@kit.edu> <git-spam-no-reply9815368754983@oli-obk.de>
 Oliver Scherer <oliver.schneider@kit.edu> <git-spam9815368754983@oli-obk.de>
 Oliver Scherer <oliver.schneider@kit.edu> <github333195615777966@oli-obk.de>
diff --git a/Cargo.lock b/Cargo.lock
index f2eaf47..679a024 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3014,7 +3014,6 @@
  "fmt_macros",
  "graphviz",
  "jobserver",
- "lazy_static 1.3.0",
  "log",
  "measureme",
  "num_cpus",
@@ -3256,13 +3255,9 @@
 dependencies = [
  "byteorder",
  "crossbeam-utils 0.6.5",
- "parking_lot 0.7.1",
- "rand 0.6.1",
- "scopeguard 0.3.3",
  "serde",
  "serde_json",
  "smallvec",
- "syn 0.15.35",
  "winapi 0.3.6",
 ]
 
@@ -3374,6 +3369,7 @@
 dependencies = [
  "env_logger",
  "graphviz",
+ "lazy_static 1.3.0",
  "log",
  "rustc",
  "rustc_ast_borrowck",
diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs
index 9a6c57d..ecb5948 100644
--- a/src/liballoc/collections/linked_list/tests.rs
+++ b/src/liballoc/collections/linked_list/tests.rs
@@ -102,8 +102,8 @@
         assert_eq!(m.pop_front(), Some(elt))
     }
     assert_eq!(n.len(), 0);
-    // let's make sure it's working properly, since we
-    // did some direct changes to private members
+    // Let's make sure it's working properly, since we
+    // did some direct changes to private members.
     n.push_back(3);
     assert_eq!(n.len(), 1);
     assert_eq!(n.pop_front(), Some(3));
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index bc8a38f..cf025ee 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -19,26 +19,26 @@
 /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
 /// In particular:
 ///
-/// * Produces Unique::empty() on zero-sized types
-/// * Produces Unique::empty() on zero-length allocations
-/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics)
-/// * Guards against 32-bit systems allocating more than isize::MAX bytes
-/// * Guards against overflowing your length
-/// * Aborts on OOM or calls handle_alloc_error as applicable
-/// * Avoids freeing Unique::empty()
-/// * Contains a ptr::Unique and thus endows the user with all related benefits
+/// * Produces `Unique::empty()` on zero-sized types.
+/// * Produces `Unique::empty()` on zero-length allocations.
+/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics).
+/// * Guards against 32-bit systems allocating more than isize::MAX bytes.
+/// * Guards against overflowing your length.
+/// * Aborts on OOM or calls `handle_alloc_error` as applicable.
+/// * Avoids freeing `Unique::empty()`.
+/// * Contains a `ptr::Unique` and thus endows the user with all related benefits.
 ///
 /// This type does not in anyway inspect the memory that it manages. When dropped it *will*
-/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec
-/// to handle the actual things *stored* inside of a RawVec.
+/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec`
+/// to handle the actual things *stored* inside of a `RawVec`.
 ///
-/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types.
-/// This enables you to use capacity growing logic catch the overflows in your length
+/// Note that a `RawVec` always forces its capacity to be `usize::MAX` for zero-sized types.
+/// This enables you to use capacity-growing logic catch the overflows in your length
 /// that might occur with zero-sized types.
 ///
-/// However this means that you need to be careful when round-tripping this type
-/// with a `Box<[T]>`: `capacity()` won't yield the len. However `with_capacity`,
-/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
+/// The above means that you need to be careful when round-tripping this type with a
+/// `Box<[T]>`, since `capacity()` won't yield the length. However, `with_capacity`,
+/// `shrink_to_fit`, and `from_box` will actually set `RawVec`'s private capacity
 /// field. This allows zero-sized types to not be special-cased by consumers of
 /// this type.
 #[allow(missing_debug_implementations)]
@@ -49,14 +49,14 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Like `new` but parameterized over the choice of allocator for
-    /// the returned RawVec.
+    /// Like `new`, but parameterized over the choice of allocator for
+    /// the returned `RawVec`.
     pub const fn new_in(a: A) -> Self {
-        // !0 is usize::MAX. This branch should be stripped at compile time.
-        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`
+        // `!0` is `usize::MAX`. This branch should be stripped at compile time.
+        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
         //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
 
-        // Unique::empty() doubles as "unallocated" and "zero-sized allocation"
+        // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
         RawVec {
             ptr: Unique::empty(),
             // FIXME(mark-i-m): use `cap` when ifs are allowed in const
@@ -65,15 +65,15 @@
         }
     }
 
-    /// Like `with_capacity` but parameterized over the choice of
-    /// allocator for the returned RawVec.
+    /// Like `with_capacity`, but parameterized over the choice of
+    /// allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_in(capacity: usize, a: A) -> Self {
         RawVec::allocate_in(capacity, false, a)
     }
 
-    /// Like `with_capacity_zeroed` but parameterized over the choice
-    /// of allocator for the returned RawVec.
+    /// Like `with_capacity_zeroed`, but parameterized over the choice
+    /// of allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, a: A) -> Self {
         RawVec::allocate_in(capacity, true, a)
@@ -86,7 +86,7 @@
             let alloc_size = capacity.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow());
             alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow());
 
-            // handles ZSTs and `capacity = 0` alike
+            // Handles ZSTs and `capacity == 0` alike.
             let ptr = if alloc_size == 0 {
                 NonNull::<T>::dangling()
             } else {
@@ -113,20 +113,20 @@
 }
 
 impl<T> RawVec<T, Global> {
-    /// Creates the biggest possible RawVec (on the system heap)
-    /// without allocating. If T has positive size, then this makes a
-    /// RawVec with capacity 0. If T has 0 size, then it makes a
-    /// RawVec with capacity `usize::MAX`. Useful for implementing
+    /// Creates the biggest possible `RawVec` (on the system heap)
+    /// without allocating. If `T` has positive size, then this makes a
+    /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a
+    /// `RawVec` with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     pub const fn new() -> Self {
         Self::new_in(Global)
     }
 
-    /// Creates a RawVec (on the system heap) with exactly the
+    /// Creates a `RawVec` (on the system heap) with exactly the
     /// capacity and alignment requirements for a `[T; capacity]`. This is
-    /// equivalent to calling RawVec::new when `capacity` is 0 or T is
+    /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is
     /// zero-sized. Note that if `T` is zero-sized this means you will
-    /// *not* get a RawVec with the requested capacity!
+    /// *not* get a `RawVec` with the requested capacity.
     ///
     /// # Panics
     ///
@@ -136,13 +136,13 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         RawVec::allocate_in(capacity, false, Global)
     }
 
-    /// Like `with_capacity` but guarantees the buffer is zeroed.
+    /// Like `with_capacity`, but guarantees the buffer is zeroed.
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         RawVec::allocate_in(capacity, true, Global)
@@ -150,13 +150,13 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Reconstitutes a RawVec from a pointer, capacity, and allocator.
+    /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
     ///
     /// # Undefined Behavior
     ///
-    /// The ptr must be allocated (via the given allocator `a`), and with the given capacity. The
-    /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
-    /// If the ptr and capacity come from a RawVec created via `a`, then this is guaranteed.
+    /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
+    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
+    /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
         RawVec {
             ptr: Unique::new_unchecked(ptr),
@@ -167,13 +167,13 @@
 }
 
 impl<T> RawVec<T, Global> {
-    /// Reconstitutes a RawVec from a pointer, capacity.
+    /// Reconstitutes a `RawVec` from a pointer and capacity.
     ///
     /// # Undefined Behavior
     ///
-    /// The ptr must be allocated (on the system heap), and with the given capacity. The
-    /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
-    /// If the ptr and capacity come from a RawVec, then this is guaranteed.
+    /// The `ptr` must be allocated (on the system heap), and with the given `capacity`.
+    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
+    /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
     pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
         RawVec {
             ptr: Unique::new_unchecked(ptr),
@@ -194,7 +194,7 @@
 
 impl<T, A: Alloc> RawVec<T, A> {
     /// Gets a raw pointer to the start of the allocation. Note that this is
-    /// Unique::empty() if `capacity = 0` or T is zero-sized. In the former case, you must
+    /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
     pub fn ptr(&self) -> *mut T {
         self.ptr.as_ptr()
@@ -212,12 +212,12 @@
         }
     }
 
-    /// Returns a shared reference to the allocator backing this RawVec.
+    /// Returns a shared reference to the allocator backing this `RawVec`.
     pub fn alloc(&self) -> &A {
         &self.a
     }
 
-    /// Returns a mutable reference to the allocator backing this RawVec.
+    /// Returns a mutable reference to the allocator backing this `RawVec`.
     pub fn alloc_mut(&mut self) -> &mut A {
         &mut self.a
     }
@@ -247,7 +247,7 @@
     ///
     /// # Panics
     ///
-    /// * Panics if T is zero-sized on the assumption that you managed to exhaust
+    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
     ///   all `usize::MAX` slots in your imaginary buffer.
     /// * Panics on 32-bit platforms if the requested capacity exceeds
     ///   `isize::MAX` bytes.
@@ -290,20 +290,20 @@
         unsafe {
             let elem_size = mem::size_of::<T>();
 
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the RawVec is overfull.
+            // Since we set the capacity to `usize::MAX` when `elem_size` is
+            // 0, getting to here necessarily means the `RawVec` is overfull.
             assert!(elem_size != 0, "capacity overflow");
 
             let (new_cap, uniq) = match self.current_layout() {
                 Some(cur) => {
                     // Since we guarantee that we never allocate more than
-                    // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as
+                    // `isize::MAX` bytes, `elem_size * self.cap <= isize::MAX` as
                     // a precondition, so this can't overflow. Additionally the
                     // alignment will never be too large as to "not be
                     // satisfiable", so `Layout::from_size_align` will always
                     // return `Some`.
                     //
-                    // tl;dr; we bypass runtime checks due to dynamic assertions
+                    // TL;DR, we bypass runtime checks due to dynamic assertions
                     // in this module, allowing us to use
                     // `from_size_align_unchecked`.
                     let new_cap = 2 * self.cap;
@@ -320,8 +320,8 @@
                     }
                 }
                 None => {
-                    // skip to 4 because tiny Vec's are dumb; but not if that
-                    // would cause overflow
+                    // Skip to 4 because tiny `Vec`'s are dumb; but not if that
+                    // would cause overflow.
                     let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
                     match self.a.alloc_array::<T>(new_cap) {
                         Ok(ptr) => (new_cap, ptr.into()),
@@ -342,7 +342,7 @@
     ///
     /// # Panics
     ///
-    /// * Panics if T is zero-sized on the assumption that you managed to exhaust
+    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
     ///   all `usize::MAX` slots in your imaginary buffer.
     /// * Panics on 32-bit platforms if the requested capacity exceeds
     ///   `isize::MAX` bytes.
@@ -356,15 +356,15 @@
                 None => return false, // nothing to double
             };
 
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the RawVec is overfull.
+            // Since we set the capacity to `usize::MAX` when `elem_size` is
+            // 0, getting to here necessarily means the `RawVec` is overfull.
             assert!(elem_size != 0, "capacity overflow");
 
-            // Since we guarantee that we never allocate more than isize::MAX
+            // Since we guarantee that we never allocate more than `isize::MAX`
             // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so
             // this can't overflow.
             //
-            // Similarly like with `double` above we can go straight to
+            // Similarly to with `double` above, we can go straight to
             // `Layout::from_size_align_unchecked` as we know this won't
             // overflow and the alignment is sufficiently small.
             let new_cap = 2 * self.cap;
@@ -409,7 +409,7 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
         match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) {
             Err(CapacityOverflow) => capacity_overflow(),
@@ -424,7 +424,7 @@
     fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize)
         -> Result<usize, TryReserveError> {
 
-        // Nothing we can really do about these checks :(
+        // Nothing we can really do about these checks, sadly.
         let required_cap = used_capacity.checked_add(needed_extra_capacity)
             .ok_or(CapacityOverflow)?;
         // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
@@ -459,7 +459,7 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     ///
     /// # Examples
     ///
@@ -538,7 +538,7 @@
 
             // Here, `cap < used_capacity + needed_extra_capacity <= new_cap`
             // (regardless of whether `self.cap - used_capacity` wrapped).
-            // Therefore we can safely call grow_in_place.
+            // Therefore, we can safely call `grow_in_place`.
 
             let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
             // FIXME: may crash and burn on over-reserve
@@ -576,14 +576,14 @@
             return;
         }
 
-        // This check is my waterloo; it's the only thing Vec wouldn't have to do.
+        // This check is my waterloo; it's the only thing `Vec` wouldn't have to do.
         assert!(self.cap >= amount, "Tried to shrink to a larger capacity");
 
         if amount == 0 {
             // We want to create a new zero-length vector within the
-            // same allocator.  We use ptr::write to avoid an
+            // same allocator. We use `ptr::write` to avoid an
             // erroneous attempt to drop the contents, and we use
-            // ptr::read to sidestep condition against destructuring
+            // `ptr::read` to sidestep condition against destructuring
             // types that implement Drop.
 
             unsafe {
@@ -600,7 +600,7 @@
                 //
                 // We also know that `self.cap` is greater than `amount`, and
                 // consequently we don't need runtime checks for creating either
-                // layout
+                // layout.
                 let old_size = elem_size * self.cap;
                 let new_size = elem_size * amount;
                 let align = mem::align_of::<T>();
@@ -653,7 +653,7 @@
                 return Ok(());
             }
 
-            // Nothing we can really do about these checks :(
+            // Nothing we can really do about these checks, sadly.
             let new_cap = match strategy {
                 Exact => used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?,
                 Amortized => self.amortized_new_size(used_capacity, needed_extra_capacity)?,
@@ -692,7 +692,7 @@
     /// Converts the entire buffer into `Box<[T]>`.
     ///
     /// Note that this will correctly reconstitute any `cap` changes
-    /// that may have been performed. (see description of type for details)
+    /// that may have been performed. (See description of type for details.)
     ///
     /// # Undefined Behavior
     ///
@@ -700,7 +700,7 @@
     /// the rules around uninitialized boxed values are not finalized yet,
     /// but until they are, it is advisable to avoid them.
     pub unsafe fn into_box(self) -> Box<[T]> {
-        // NOTE: not calling `capacity()` here, actually using the real `cap` field!
+        // NOTE: not calling `capacity()` here; actually using the real `cap` field!
         let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
         let output: Box<[T]> = Box::from_raw(slice);
         mem::forget(self);
@@ -709,7 +709,7 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Frees the memory owned by the RawVec *without* trying to Drop its contents.
+    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
     pub unsafe fn dealloc_buffer(&mut self) {
         let elem_size = mem::size_of::<T>();
         if elem_size != 0 {
@@ -721,22 +721,20 @@
 }
 
 unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
-    /// Frees the memory owned by the RawVec *without* trying to Drop its contents.
+    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
     fn drop(&mut self) {
         unsafe { self.dealloc_buffer(); }
     }
 }
 
-
-
 // We need to guarantee the following:
-// * We don't ever allocate `> isize::MAX` byte-size objects
-// * We don't overflow `usize::MAX` and actually allocate too little
+// * We don't ever allocate `> isize::MAX` byte-size objects.
+// * We don't overflow `usize::MAX` and actually allocate too little.
 //
 // On 64-bit we just need to check for overflow since trying to allocate
 // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
 // an extra guard for this in case we're running on a platform which can use
-// all 4GB in user-space. e.g., PAE or x32
+// all 4GB in user-space, e.g., PAE or x32.
 
 #[inline]
 fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
@@ -751,5 +749,5 @@
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
 fn capacity_overflow() -> ! {
-    panic!("capacity overflow")
+    panic!("capacity overflow");
 }
diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs
index c389898..d35b62f 100644
--- a/src/liballoc/raw_vec/tests.rs
+++ b/src/liballoc/raw_vec/tests.rs
@@ -5,12 +5,12 @@
     use crate::alloc::AllocErr;
 
     // Writing a test of integration between third-party
-    // allocators and RawVec is a little tricky because the RawVec
+    // allocators and `RawVec` is a little tricky because the `RawVec`
     // API does not expose fallible allocation methods, so we
     // cannot check what happens when allocator is exhausted
     // (beyond detecting a panic).
     //
-    // Instead, this just checks that the RawVec methods do at
+    // Instead, this just checks that the `RawVec` methods do at
     // least go through the Allocator API when it reserves
     // storage.
 
@@ -44,7 +44,7 @@
 fn reserve_does_not_overallocate() {
     {
         let mut v: RawVec<u32> = RawVec::new();
-        // First `reserve` allocates like `reserve_exact`
+        // First, `reserve` allocates like `reserve_exact`.
         v.reserve(0, 9);
         assert_eq!(9, v.capacity());
     }
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 2b222ca..f234ac5 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -567,7 +567,7 @@
     ///     let x = Rc::from_raw(x_ptr);
     ///     assert_eq!(&*x, "hello");
     ///
-    ///     // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe.
+    ///     // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe.
     /// }
     ///
     /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
@@ -1832,8 +1832,9 @@
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just values
-    /// that compare as equal).
+    /// Returns `true` if the two `Weak`s point to the same value (not just
+    /// values that compare as equal), or if both don't point to any value
+    /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
@@ -1843,7 +1844,6 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::rc::Rc;
     ///
     /// let first_rc = Rc::new(5);
@@ -1861,7 +1861,6 @@
     /// Comparing `Weak::new`.
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::rc::{Rc, Weak};
     ///
     /// let first = Weak::new();
@@ -1873,7 +1872,7 @@
     /// assert!(!first.ptr_eq(&third));
     /// ```
     #[inline]
-    #[unstable(feature = "weak_ptr_eq", issue = "55981")]
+    #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
     }
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 9ffc167..45f9816 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -547,7 +547,7 @@
     ///     let x = Arc::from_raw(x_ptr);
     ///     assert_eq!(&*x, "hello");
     ///
-    ///     // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe.
+    ///     // Further calls to `Arc::from_raw(x_ptr)` would be memory-unsafe.
     /// }
     ///
     /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
@@ -1550,19 +1550,18 @@
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just values
-    /// that compare as equal).
+    /// Returns `true` if the two `Weak`s point to the same value (not just
+    /// values that compare as equal), or if both don't point to any value
+    /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
     /// Since this compares pointers it means that `Weak::new()` will equal each
     /// other, even though they don't point to any value.
     ///
-    ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::sync::Arc;
     ///
     /// let first_rc = Arc::new(5);
@@ -1580,7 +1579,6 @@
     /// Comparing `Weak::new`.
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::sync::{Arc, Weak};
     ///
     /// let first = Weak::new();
@@ -1592,7 +1590,7 @@
     /// assert!(!first.ptr_eq(&third));
     /// ```
     #[inline]
-    #[unstable(feature = "weak_ptr_eq", issue = "55981")]
+    #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
     }
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index d5dc2d4..c513658 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -685,21 +685,25 @@
     /// [`drain`]: #method.drain
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn truncate(&mut self, len: usize) {
-        let current_len = self.len;
-        unsafe {
-            let mut ptr = self.as_mut_ptr().add(self.len);
-            // Set the final length at the end, keeping in mind that
-            // dropping an element might panic. Works around a missed
-            // optimization, as seen in the following issue:
-            // https://github.com/rust-lang/rust/issues/51802
-            let mut local_len = SetLenOnDrop::new(&mut self.len);
+        if mem::needs_drop::<T>() {
+            let current_len = self.len;
+            unsafe {
+                let mut ptr = self.as_mut_ptr().add(self.len);
+                // Set the final length at the end, keeping in mind that
+                // dropping an element might panic. Works around a missed
+                // optimization, as seen in the following issue:
+                // https://github.com/rust-lang/rust/issues/51802
+                let mut local_len = SetLenOnDrop::new(&mut self.len);
 
-            // drop any extra elements
-            for _ in len..current_len {
-                local_len.decrement_len(1);
-                ptr = ptr.offset(-1);
-                ptr::drop_in_place(ptr);
+                // drop any extra elements
+                for _ in len..current_len {
+                    local_len.decrement_len(1);
+                    ptr = ptr.offset(-1);
+                    ptr::drop_in_place(ptr);
+                }
             }
+        } else if len <= self.len {
+            self.len = len;
         }
     }
 
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index e8a0a88..0afbf4f 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -153,13 +153,13 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn is<T: Any>(&self) -> bool {
-        // Get TypeId of the type this function is instantiated with
+        // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get TypeId of the type in the trait object
+        // Get `TypeId` of the type in the trait object.
         let concrete = self.type_id();
 
-        // Compare both TypeIds on equality
+        // Compare both `TypeId`s on equality.
         t == concrete
     }
 
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 89af252..347e7dc 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -602,10 +602,10 @@
 unsafe impl<T: ?Sized> Freeze for &T {}
 unsafe impl<T: ?Sized> Freeze for &mut T {}
 
-/// Types which can be safely moved after being pinned.
+/// Types that can be safely moved after being pinned.
 ///
 /// Since Rust itself has no notion of immovable types, and considers moves
-/// (e.g. through assignment or [`mem::replace`]) to always be safe,
+/// (e.g., through assignment or [`mem::replace`]) to always be safe,
 /// this trait cannot prevent types from moving by itself.
 ///
 /// Instead it is used to prevent moves through the type system,
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index f5fbd1a..13ccc9b 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -1042,7 +1042,7 @@
         (self as *const u8) == null()
     }
 
-    /// Cast to a pointer to a different type
+    /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *const U {
@@ -1726,7 +1726,7 @@
         (self as *mut u8) == null_mut()
     }
 
-    /// Cast to a pointer to a different type
+    /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *mut U {
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index ad3d1ce..7dcd57f 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -125,7 +125,7 @@
         &mut *self.as_ptr()
     }
 
-    /// Cast to a pointer of another type
+    /// Casts to a pointer of another type.
     #[stable(feature = "nonnull_cast", since = "1.27.0")]
     #[inline]
     pub const fn cast<U>(self) -> NonNull<U> {
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index a479fab..66071d6 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -15,7 +15,6 @@
 fmt_macros = { path = "../libfmt_macros" }
 graphviz = { path = "../libgraphviz" }
 jobserver = "0.1"
-lazy_static = "1.0.0"
 num_cpus = "1.0"
 scoped-tls = "1.0"
 log = { version = "0.4", features = ["release_max_level_info", "std"] }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b50cfa0..58789a1 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1316,7 +1316,7 @@
                             ImplTraitContext::Universal(in_band_ty_params),
                         );
                         // Set the name to `impl Bound1 + Bound2`.
-                        let ident = Ident::from_str(&pprust::ty_to_string(t)).with_span_pos(span);
+                        let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
                         in_band_ty_params.push(hir::GenericParam {
                             hir_id: self.lower_node_id(def_node_id),
                             name: ParamName::Plain(ident),
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index bffb4df..d1cc7a8 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -31,7 +31,7 @@
         self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
     }
 
-    pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
         f(self);
         self.parent_def = orig_parent_def;
@@ -74,6 +74,22 @@
         })
     }
 
+    fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
+        if field.is_placeholder {
+            self.visit_macro_invoc(field.id);
+        } else {
+            let name = field.ident.map(|ident| ident.name)
+                .or_else(|| index.map(sym::integer))
+                .unwrap_or_else(|| {
+                    let node_id = NodeId::placeholder_from_expn_id(self.expansion);
+                    sym::integer(self.definitions.placeholder_field_indices[&node_id])
+                })
+                .as_interned_str();
+            let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
+            self.with_parent(def, |this| visit::walk_struct_field(this, field));
+        }
+    }
+
     pub fn visit_macro_invoc(&mut self, id: NodeId) {
         self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
     }
@@ -170,17 +186,14 @@
     }
 
     fn visit_variant_data(&mut self, data: &'a VariantData) {
+        // The assumption here is that non-`cfg` macro expansion cannot change field indices.
+        // It currently holds because only inert attributes are accepted on fields,
+        // and every such attribute expands into a single field after it's resolved.
         for (index, field) in data.fields().iter().enumerate() {
-            if field.is_placeholder {
-                self.visit_macro_invoc(field.id);
-                continue;
+            self.collect_field(field, Some(index));
+            if field.is_placeholder && field.ident.is_none() {
+                self.definitions.placeholder_field_indices.insert(field.id, index);
             }
-            let name = field.ident.map(|ident| ident.name)
-                .unwrap_or_else(|| sym::integer(index));
-            let def = self.create_def(field.id,
-                                      DefPathData::ValueNs(name.as_interned_str()),
-                                      field.span);
-            self.with_parent(def, |this| visit::walk_struct_field(this, field));
         }
     }
 
@@ -338,16 +351,9 @@
         }
     }
 
-    fn visit_struct_field(&mut self, sf: &'a StructField) {
-        if sf.is_placeholder {
-            self.visit_macro_invoc(sf.id)
-        } else {
-            let name = sf.ident.map(|ident| ident.name)
-                .unwrap_or_else(|| panic!("don't know the field number in this context"));
-            let def = self.create_def(sf.id,
-                                        DefPathData::ValueNs(name.as_interned_str()),
-                                        sf.span);
-            self.with_parent(def, |this| visit::walk_struct_field(this, sf));
-        }
+    // This method is called only when we are visiting an individual field
+    // after expanding an attribute on it.
+    fn visit_struct_field(&mut self, field: &'a StructField) {
+        self.collect_field(field, None);
     }
 }
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 651fe84..187bc59 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -104,6 +104,8 @@
     /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
     /// we know what parent node that fragment should be attached to thanks to this table.
     invocation_parents: FxHashMap<ExpnId, DefIndex>,
+    /// Indices of unnamed struct or variant fields with unresolved attributes.
+    pub(super) placeholder_field_indices: NodeMap<usize>,
 }
 
 /// A unique identifier that we can use to lookup a definition
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f5e6446..2c8590a 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -190,7 +190,7 @@
     Fresh(usize),
 
     /// Indicates an illegal name was given and an error has been
-    /// repored (so we should squelch other derived errors). Occurs
+    /// reported (so we should squelch other derived errors). Occurs
     /// when, e.g., `'_` is used in the wrong place.
     Error,
 }
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 5883be6..ab24b3f 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -55,7 +55,8 @@
 use crate::hir::Node;
 use crate::infer::opaque_types;
 use crate::middle::region;
-use crate::traits::{ObligationCause, ObligationCauseCode};
+use crate::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use crate::traits::{ObligationCauseCode};
 use crate::ty::error::TypeError;
 use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable};
 use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
@@ -624,13 +625,13 @@
                     }
                 }
             }
-            ObligationCauseCode::MatchExpressionArm {
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
                 source,
                 ref prior_arms,
                 last_ty,
                 discrim_hir_id,
                 ..
-            } => match source {
+            }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arms have incompatible types";
                     err.span_label(cause.span, msg);
@@ -681,7 +682,7 @@
                     }
                 }
             },
-            ObligationCauseCode::IfExpression { then, outer, semicolon } => {
+            ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
                 err.span_label(then, "expected because of this");
                 outer.map(|sp| err.span_label(sp, "if and else have incompatible types"));
                 if let Some(sp) = semicolon {
@@ -1622,13 +1623,15 @@
         use crate::traits::ObligationCauseCode::*;
         match self.code {
             CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
-            MatchExpressionArm { source, .. } => Error0308(match source {
-                hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
-                hir::MatchSource::TryDesugar => {
-                    "try expression alternatives have incompatible types"
-                }
-                _ => "match arms have incompatible types",
-            }),
+            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) =>
+                Error0308(match source {
+                    hir::MatchSource::IfLetDesugar { .. } =>
+                        "`if let` arms have incompatible types",
+                    hir::MatchSource::TryDesugar => {
+                        "try expression alternatives have incompatible types"
+                    }
+                    _ => "match arms have incompatible types",
+                }),
             IfExpression { .. } => Error0308("if and else have incompatible types"),
             IfExpressionWithNoElse => Error0317("if may be missing an else clause"),
             MainFunctionType => Error0580("main function has wrong type"),
@@ -1656,7 +1659,7 @@
         match self.code {
             CompareImplMethodObligation { .. } => "method type is compatible with trait",
             ExprAssignable => "expression is assignable",
-            MatchExpressionArm { source, .. } => match source {
+            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
                 _ => "match arms have compatible types",
             },
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 63ef82a..7a01ae6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -67,7 +67,6 @@
 
 #[macro_use] extern crate bitflags;
 extern crate getopts;
-#[macro_use] extern crate lazy_static;
 #[macro_use] extern crate scoped_tls;
 #[cfg(windows)]
 extern crate libc;
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 93bb301..ba27d33 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -16,16 +16,16 @@
 
     map: &'a hir_map::Map<'tcx>,
 
-    /// The top-level function called 'main'.
+    /// The top-level function called `main`.
     main_fn: Option<(HirId, Span)>,
 
-    /// The function that has attribute named 'main'.
+    /// The function that has attribute named `main`.
     attr_main_fn: Option<(HirId, Span)>,
 
     /// The function that has the attribute 'start' on it.
     start_fn: Option<(HirId, Span)>,
 
-    /// The functions that one might think are 'main' but aren't, e.g.
+    /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
     non_main_fns: Vec<(HirId, Span)> ,
 }
@@ -88,7 +88,7 @@
                 EntryPointType::MainAttr
             } else if item.ident.name == sym::main {
                 if at_root {
-                    // This is a top-level function so can be 'main'.
+                    // This is a top-level function so can be `main`.
                     EntryPointType::MainNamed
                 } else {
                     EntryPointType::OtherMain
@@ -109,7 +109,7 @@
                 ctxt.main_fn = Some((item.hir_id, item.span));
             } else {
                 span_err!(ctxt.session, item.span, E0136,
-                          "multiple 'main' functions");
+                          "multiple `main` functions");
             }
         },
         EntryPointType::OtherMain => {
@@ -130,7 +130,7 @@
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((item.hir_id, item.span));
             } else {
-                struct_span_err!(ctxt.session, item.span, E0138, "multiple 'start' functions")
+                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
                     .span_label(item.span, "multiple `start` functions")
                     .emit();
@@ -148,34 +148,48 @@
     } else if let Some((hir_id, _)) = visitor.main_fn {
         Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
     } else {
-        // There is no main function.
-        let mut err = struct_err!(tcx.sess, E0601,
-            "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
-        if !visitor.non_main_fns.is_empty() {
-            // There were some functions named 'main' though. Try to give the user a hint.
-            err.note("the main function must be defined at the crate level \
-                      but you have one or more functions named 'main' that are not \
-                      defined at the crate level. Either move the definition or \
-                      attach the `#[main]` attribute to override this behavior.");
-            for &(_, span) in &visitor.non_main_fns {
-                err.span_note(span, "here is a function named 'main'");
-            }
-            err.emit();
-        } else {
-            if let Some(ref filename) = tcx.sess.local_crate_source_file {
-                err.note(&format!("consider adding a `main` function to `{}`", filename.display()));
-            }
-            if tcx.sess.teach(&err.get_code().unwrap()) {
-                err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
-                          to get started: https://doc.rust-lang.org/book/");
-            }
-            err.emit();
-        }
-
+        no_main_err(tcx, visitor);
         None
     }
 }
 
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+    // There is no main function.
+    let mut err = struct_err!(tcx.sess, E0601,
+        "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
+    let filename = &tcx.sess.local_crate_source_file;
+    let note = if !visitor.non_main_fns.is_empty() {
+        for &(_, span) in &visitor.non_main_fns {
+            err.span_note(span, "here is a function named `main`");
+        }
+        err.note("you have one or more functions named `main` not defined at the crate level");
+        err.help("either move the `main` function definitions or attach the `#[main]` attribute \
+                  to one of them");
+        // There were some functions named `main` though. Try to give the user a hint.
+        format!("the main function must be defined at the crate level{}",
+                 filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default())
+    } else if let Some(filename) = filename {
+        format!("consider adding a `main` function to `{}`", filename.display())
+    } else {
+        String::from("consider adding a `main` function at the crate level")
+    };
+    let sp = tcx.hir().krate().span;
+    // The file may be empty, which leads to the diagnostic machinery not emitting this
+    // note. This is a relatively simple way to detect that case and emit a span-less
+    // note instead.
+    if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) {
+        err.set_span(sp);
+        err.span_label(sp, &note);
+    } else {
+        err.note(&note);
+    }
+    if tcx.sess.teach(&err.get_code().unwrap()) {
+        err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
+                  to get started: https://doc.rust-lang.org/book/");
+    }
+    err.emit();
+}
+
 pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
     tcx.entry_fn(LOCAL_CRATE)
 }
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index d72d879..b8bc741 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -17,8 +17,8 @@
     pub ty: Ty<'tcx>,
 }
 
-/// Represents a constant value in Rust. `Scalar` and `ScalarPair` are optimizations that
-/// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`.
+/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
+/// array length computations, enum discriminants and the pattern matching logic.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord,
          RustcEncodable, RustcDecodable, Hash, HashStable)]
 pub enum ConstValue<'tcx> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 18a5142..0ebc707 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -32,7 +32,6 @@
 use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::iter::FusedIterator;
 use std::ops::{Index, IndexMut};
 use std::slice;
 use std::vec::IntoIter;
@@ -1548,7 +1547,7 @@
 
 // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(Statement<'_>, 56);
+static_assert_size!(Statement<'_>, 32);
 
 impl Statement<'_> {
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -1569,7 +1568,7 @@
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum StatementKind<'tcx> {
     /// Write the RHS Rvalue to the LHS Place.
-    Assign(Place<'tcx>, Box<Rvalue<'tcx>>),
+    Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
 
     /// This represents all the reading that a pattern match may do
     /// (e.g., inspecting constants and discriminant values), and the
@@ -1578,10 +1577,10 @@
     ///
     /// Note that this also is emitted for regular `let` bindings to ensure that locals that are
     /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
-    FakeRead(FakeReadCause, Place<'tcx>),
+    FakeRead(FakeReadCause, Box<Place<'tcx>>),
 
     /// Write the discriminant for a variant to the enum Place.
-    SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx },
+    SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
 
     /// Start a live range for the storage of the local.
     StorageLive(Local),
@@ -1598,7 +1597,7 @@
     /// by miri and only generated when "-Z mir-emit-retag" is passed.
     /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
     /// for more details.
-    Retag(RetagKind, Place<'tcx>),
+    Retag(RetagKind, Box<Place<'tcx>>),
 
     /// Encodes a user's type ascription. These need to be preserved
     /// intact so that NLL can respect them. For example:
@@ -1612,7 +1611,7 @@
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
-    AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>),
+    AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
@@ -1676,7 +1675,7 @@
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::StatementKind::*;
         match self.kind {
-            Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
+            Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
             FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
             Retag(ref kind, ref place) => write!(
                 fmt,
@@ -1697,7 +1696,7 @@
             InlineAsm(ref asm) => {
                 write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
             }
-            AscribeUserType(ref place, ref variance, ref c_ty) => {
+            AscribeUserType(box(ref place, ref c_ty), ref variance) => {
                 write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
             }
             Nop => write!(fmt, "nop"),
@@ -1717,7 +1716,7 @@
     pub base: PlaceBase<'tcx>,
 
     /// projection out of a place (access a field, deref a pointer, etc)
-    pub projection: Option<Box<Projection<'tcx>>>,
+    pub projection: Box<[PlaceElem<'tcx>]>,
 }
 
 #[derive(
@@ -1760,15 +1759,6 @@
     def_id
 });
 
-/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
-#[derive(
-    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
-)]
-pub struct Projection<'tcx> {
-    pub base: Option<Box<Projection<'tcx>>>,
-    pub elem: PlaceElem<'tcx>,
-}
-
 #[derive(
     Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
 )]
@@ -1850,14 +1840,22 @@
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct PlaceRef<'a, 'tcx> {
     pub base: &'a PlaceBase<'tcx>,
-    pub projection: &'a Option<Box<Projection<'tcx>>>,
+    pub projection: &'a [PlaceElem<'tcx>],
 }
 
 impl<'tcx> Place<'tcx> {
-    pub const RETURN_PLACE: Place<'tcx> = Place {
-        base: PlaceBase::Local(RETURN_PLACE),
-        projection: None,
-    };
+    // FIXME change this back to a const when projection is a shared slice.
+    //
+    // pub const RETURN_PLACE: Place<'tcx> = Place {
+    //     base: PlaceBase::Local(RETURN_PLACE),
+    //     projection: &[],
+    // };
+    pub fn return_place() -> Place<'tcx> {
+        Place {
+            base: PlaceBase::Local(RETURN_PLACE),
+            projection: Box::new([]),
+        }
+    }
 
     pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
         self.elem(ProjectionElem::Field(f, ty))
@@ -1883,9 +1881,13 @@
     }
 
     pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
+        // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
+        let mut projection = self.projection.into_vec();
+        projection.push(elem);
+
         Place {
             base: self.base,
-            projection: Some(Box::new(Projection { base: self.projection, elem })),
+            projection: projection.into_boxed_slice(),
         }
     }
 
@@ -1894,7 +1896,7 @@
     /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
     /// same region of memory as its base.
     pub fn is_indirect(&self) -> bool {
-        self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
+        self.projection.iter().any(|elem| elem.is_indirect())
     }
 
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@@ -1905,61 +1907,16 @@
         match self {
             Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             } |
             Place {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: box [ProjectionElem::Deref],
             } => Some(*local),
             _ => None,
         }
     }
 
-    /// Recursively "iterates" over place components, generating a `PlaceBase` and
-    /// `Projections` list and invoking `op` with a `ProjectionsIter`.
-    pub fn iterate<R>(
-        &self,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        Place::iterate_over(&self.base, &self.projection, op)
-    }
-
-    pub fn iterate_over<R>(
-        place_base: &PlaceBase<'tcx>,
-        place_projection: &Option<Box<Projection<'tcx>>>,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        fn iterate_over2<'tcx, R>(
-            place_base: &PlaceBase<'tcx>,
-            place_projection: &Option<Box<Projection<'tcx>>>,
-            next: &Projections<'_, 'tcx>,
-            op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-        ) -> R {
-            match place_projection {
-                None => {
-                    op(place_base, next.iter())
-                }
-
-                Some(interior) => {
-                    iterate_over2(
-                        place_base,
-                        &interior.base,
-                        &Projections::List {
-                            projection: interior,
-                            next,
-                        },
-                        op,
-                    )
-                }
-            }
-        }
-
-        iterate_over2(place_base, place_projection, &Projections::Empty, op)
-    }
-
     pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
         PlaceRef {
             base: &self.base,
@@ -1972,7 +1929,7 @@
     fn from(local: Local) -> Self {
         Place {
             base: local.into(),
-            projection: None,
+            projection: Box::new([]),
         }
     }
 }
@@ -1984,13 +1941,6 @@
 }
 
 impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
-    pub fn iterate<R>(
-        &self,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        Place::iterate_over(self.base, self.projection, op)
-    }
-
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
     /// a single deref of a local.
     //
@@ -1999,143 +1949,71 @@
         match self {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } |
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } => Some(*local),
             _ => None,
         }
     }
 }
 
-/// A linked list of projections running up the stack; begins with the
-/// innermost projection and extends to the outermost (e.g., `a.b.c`
-/// would have the place `b` with a "next" pointer to `b.c`).
-/// Created by `Place::iterate`.
-///
-/// N.B., this particular impl strategy is not the most obvious. It was
-/// chosen because it makes a measurable difference to NLL
-/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
-pub enum Projections<'p, 'tcx> {
-    Empty,
-
-    List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> },
-}
-
-impl<'p, 'tcx> Projections<'p, 'tcx> {
-    fn iter(&self) -> ProjectionsIter<'_, 'tcx> {
-        ProjectionsIter { value: self }
-    }
-}
-
-impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> {
-    type Item = &'p Projection<'tcx>;
-    type IntoIter = ProjectionsIter<'p, 'tcx>;
-
-    /// Converts a list of `Projection` components into an iterator;
-    /// this iterator yields up a never-ending stream of `Option<&Place>`.
-    /// These begin with the "innermost" projection and then with each
-    /// projection therefrom. So given a place like `a.b.c` it would
-    /// yield up:
-    ///
-    /// ```notrust
-    /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
-    /// ```
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}
-
-/// Iterator over components; see `Projections::iter` for more
-/// information.
-///
-/// N.B., this is not a *true* Rust iterator -- the code above just
-/// manually invokes `next`. This is because we (sometimes) want to
-/// keep executing even after `None` has been returned.
-pub struct ProjectionsIter<'p, 'tcx> {
-    pub value: &'p Projections<'p, 'tcx>,
-}
-
-impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> {
-    type Item = &'p Projection<'tcx>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let &Projections::List { projection, next } = self.value {
-            self.value = next;
-            Some(projection)
-        } else {
-            None
-        }
-    }
-}
-
-impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {}
-
 impl Debug for Place<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        self.iterate(|_place_base, place_projections| {
-            // FIXME: remove this collect once we have migrated to slices
-            let projs_vec: Vec<_> = place_projections.collect();
-            for projection in projs_vec.iter().rev() {
-                match projection.elem {
-                    ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
-                        write!(fmt, "(").unwrap();
-                    }
-                    ProjectionElem::Deref => {
-                        write!(fmt, "(*").unwrap();
-                    }
-                    ProjectionElem::Index(_)
-                    | ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. } => {}
+        for elem in self.projection.iter().rev() {
+            match elem {
+                ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
+                    write!(fmt, "(").unwrap();
+                }
+                ProjectionElem::Deref => {
+                    write!(fmt, "(*").unwrap();
+                }
+                ProjectionElem::Index(_)
+                | ProjectionElem::ConstantIndex { .. }
+                | ProjectionElem::Subslice { .. } => {}
+            }
+        }
+
+        write!(fmt, "{:?}", self.base)?;
+
+        for elem in self.projection.iter() {
+            match elem {
+                ProjectionElem::Downcast(Some(name), _index) => {
+                    write!(fmt, " as {})", name)?;
+                }
+                ProjectionElem::Downcast(None, index) => {
+                    write!(fmt, " as variant#{:?})", index)?;
+                }
+                ProjectionElem::Deref => {
+                    write!(fmt, ")")?;
+                }
+                ProjectionElem::Field(field, ty) => {
+                    write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
+                }
+                ProjectionElem::Index(ref index) => {
+                    write!(fmt, "[{:?}]", index)?;
+                }
+                ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
+                    write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
+                }
+                ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
+                    write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
+                }
+                ProjectionElem::Subslice { from, to } if *to == 0 => {
+                    write!(fmt, "[{:?}:]", from)?;
+                }
+                ProjectionElem::Subslice { from, to } if *from == 0 => {
+                    write!(fmt, "[:-{:?}]", to)?;
+                }
+                ProjectionElem::Subslice { from, to } => {
+                    write!(fmt, "[{:?}:-{:?}]", from, to)?;
                 }
             }
-        });
+        }
 
-        self.iterate(|place_base, place_projections| {
-            write!(fmt, "{:?}", place_base)?;
-
-            for projection in place_projections {
-                match projection.elem {
-                    ProjectionElem::Downcast(Some(name), _index) => {
-                        write!(fmt, " as {})", name)?;
-                    }
-                    ProjectionElem::Downcast(None, index) => {
-                        write!(fmt, " as variant#{:?})", index)?;
-                    }
-                    ProjectionElem::Deref => {
-                        write!(fmt, ")")?;
-                    }
-                    ProjectionElem::Field(field, ty) => {
-                        write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
-                    }
-                    ProjectionElem::Index(ref index) => {
-                        write!(fmt, "[{:?}]", index)?;
-                    }
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
-                        write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
-                    }
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
-                        write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
-                    }
-                    ProjectionElem::Subslice { from, to } if to == 0 => {
-                        write!(fmt, "[{:?}:]", from)?;
-                    }
-                    ProjectionElem::Subslice { from, to } if from == 0 => {
-                        write!(fmt, "[:-{:?}]", to)?;
-                    }
-                    ProjectionElem::Subslice { from, to } => {
-                        write!(fmt, "[{:?}:-{:?}]", from, to)?;
-                    }
-                }
-            }
-
-            Ok(())
-        })
+        Ok(())
     }
 }
 
@@ -3120,14 +2998,14 @@
 
 EnumTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
-        (StatementKind::Assign)(a, b),
+        (StatementKind::Assign)(a),
         (StatementKind::FakeRead)(cause, place),
         (StatementKind::SetDiscriminant) { place, variant_index },
         (StatementKind::StorageLive)(a),
         (StatementKind::StorageDead)(a),
         (StatementKind::InlineAsm)(a),
         (StatementKind::Retag)(kind, place),
-        (StatementKind::AscribeUserType)(a, v, b),
+        (StatementKind::AscribeUserType)(a, v),
         (StatementKind::Nop),
     }
 }
@@ -3409,30 +3287,26 @@
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         use crate::mir::ProjectionElem::*;
 
-        let base = self.base.fold_with(folder);
-        let elem = match self.elem {
+        match self {
             Deref => Deref,
-            Field(f, ref ty) => Field(f, ty.fold_with(folder)),
-            Index(ref v) => Index(v.fold_with(folder)),
-            ref elem => elem.clone(),
-        };
-
-        Projection { base, elem }
+            Field(f, ty) => Field(*f, ty.fold_with(folder)),
+            Index(v) => Index(v.fold_with(folder)),
+            elem => elem.clone(),
+        }
     }
 
     fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
         use crate::mir::ProjectionElem::*;
 
-        self.base.visit_with(visitor)
-            || match self.elem {
-                Field(_, ref ty) => ty.visit_with(visitor),
-                Index(ref v) => v.visit_with(visitor),
-                _ => false,
-            }
+        match self {
+            Field(_, ty) => ty.visit_with(visitor),
+            Index(v) => v.visit_with(visitor),
+            _ => false,
+        }
     }
 }
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index e9f7636..d776809 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -121,21 +121,16 @@
 impl<'tcx> Place<'tcx> {
     pub fn ty_from<D>(
         base: &PlaceBase<'tcx>,
-        projection: &Option<Box<Projection<'tcx>>>,
+        projection: &[PlaceElem<'tcx>],
         local_decls: &D,
         tcx: TyCtxt<'tcx>
     ) -> PlaceTy<'tcx>
         where D: HasLocalDecls<'tcx>
     {
-        Place::iterate_over(base, projection, |place_base, place_projections| {
-            let mut place_ty = place_base.ty(local_decls);
-
-            for proj in place_projections {
-                place_ty = place_ty.projection_ty(tcx, &proj.elem);
-            }
-
-            place_ty
-        })
+        projection.iter().fold(
+            base.ty(local_decls),
+            |place_ty, elem| place_ty.projection_ty(tcx, elem)
+        )
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 821367e..1e3b9eb 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -152,18 +152,18 @@
             }
 
             fn visit_place_base(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_place_base(place_base, context, location);
+                self.super_place_base(base, context, location);
             }
 
             fn visit_projection(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
-                                place: & $($mutability)? Projection<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
+                                projection: & $($mutability)? [PlaceElem<'tcx>],
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_projection(place_base, place, context, location);
+                self.super_projection(base, projection, context, location);
             }
 
             fn visit_constant(&mut self,
@@ -344,7 +344,9 @@
 
                 self.visit_source_info(source_info);
                 match kind {
-                    StatementKind::Assign(place, rvalue) => {
+                    StatementKind::Assign(
+                        box(ref $($mutability)? place, ref $($mutability)? rvalue)
+                    ) => {
                         self.visit_assign(place, rvalue, location);
                     }
                     StatementKind::FakeRead(_, place) => {
@@ -391,7 +393,10 @@
                     StatementKind::Retag(kind, place) => {
                         self.visit_retag(kind, place, location);
                     }
-                    StatementKind::AscribeUserType(place, variance, user_ty) => {
+                    StatementKind::AscribeUserType(
+                        box(ref $($mutability)? place, ref $($mutability)? user_ty),
+                        variance
+                    ) => {
                         self.visit_ascribe_user_ty(place, variance, user_ty, location);
                     }
                     StatementKind::Nop => {}
@@ -685,7 +690,7 @@
                             location: Location) {
                 let mut context = context;
 
-                if place.projection.is_some() {
+                if !place.projection.is_empty() {
                     context = if context.is_mutating_use() {
                         PlaceContext::MutatingUse(MutatingUseContext::Projection)
                     } else {
@@ -695,9 +700,10 @@
 
                 self.visit_place_base(& $($mutability)? place.base, context, location);
 
-                if let Some(box proj) = & $($mutability)? place.projection {
-                    self.visit_projection(& $($mutability)? place.base, proj, context, location);
-                }
+                self.visit_projection(& $($mutability)? place.base,
+                                      & $($mutability)? place.projection,
+                                      context,
+                                      location);
             }
 
             fn super_place_base(&mut self,
@@ -715,31 +721,31 @@
             }
 
             fn super_projection(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
-                                proj: & $($mutability)? Projection<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
+                                projection: & $($mutability)? [PlaceElem<'tcx>],
                                 context: PlaceContext,
                                 location: Location) {
-                if let Some(box proj_base) = & $($mutability)? proj.base {
-                    self.visit_projection(place_base, proj_base, context, location);
-                }
+                if let [proj_base @ .., elem] = projection {
+                    self.visit_projection(base, proj_base, context, location);
 
-                match & $($mutability)? proj.elem {
-                    ProjectionElem::Field(_field, ty) => {
-                        self.visit_ty(ty, TyContext::Location(location));
-                    }
-                    ProjectionElem::Index(local) => {
-                        self.visit_local(
-                            local,
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
-                            location
-                        );
-                    }
-                    ProjectionElem::Deref |
-                    ProjectionElem::Subslice { from: _, to: _ } |
-                    ProjectionElem::ConstantIndex { offset: _,
-                                                    min_length: _,
-                                                    from_end: _ } |
-                    ProjectionElem::Downcast(_, _) => {
+                    match elem {
+                        ProjectionElem::Field(_field, ty) => {
+                            self.visit_ty(ty, TyContext::Location(location));
+                        }
+                        ProjectionElem::Index(local) => {
+                            self.visit_local(
+                                local,
+                                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                                location
+                            );
+                        }
+                        ProjectionElem::Deref |
+                        ProjectionElem::Subslice { from: _, to: _ } |
+                        ProjectionElem::ConstantIndex { offset: _,
+                                                        min_length: _,
+                                                        from_end: _ } |
+                        ProjectionElem::Downcast(_, _) => {
+                        }
                     }
                 }
             }
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index c1de493..4494c03 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -68,6 +68,10 @@
     pub stalled_on: Vec<Ty<'tcx>>,
 }
 
+// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PendingPredicateObligation<'_>, 136);
+
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 1ca92d7..d268309 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -123,6 +123,10 @@
 pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
+// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateObligation<'_>, 112);
+
 /// The reason why we incurred this obligation; used for error reporting.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct ObligationCause<'tcx> {
@@ -147,7 +151,8 @@
             ObligationCauseCode::StartFunctionType => {
                 tcx.sess.source_map().def_span(self.span)
             }
-            ObligationCauseCode::MatchExpressionArm { arm_span, .. } => arm_span,
+            ObligationCauseCode::MatchExpressionArm(
+                box MatchExpressionArmCause { arm_span, .. }) => arm_span,
             _ => self.span,
         }
     }
@@ -223,23 +228,13 @@
     ExprAssignable,
 
     /// Computing common supertype in the arms of a match expression
-    MatchExpressionArm {
-        arm_span: Span,
-        source: hir::MatchSource,
-        prior_arms: Vec<Span>,
-        last_ty: Ty<'tcx>,
-        discrim_hir_id: hir::HirId,
-    },
+    MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
 
     /// Computing common supertype in the pattern guard for the arms of a match expression
     MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> },
 
     /// Computing common supertype in an if expression
-    IfExpression {
-        then: Span,
-        outer: Option<Span>,
-        semicolon: Option<Span>,
-    },
+    IfExpression(Box<IfExpressionCause>),
 
     /// Computing common supertype of an if expression with no else counter-part
     IfExpressionWithNoElse,
@@ -269,6 +264,26 @@
     TrivialBound,
 }
 
+// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(ObligationCauseCode<'_>, 32);
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct MatchExpressionArmCause<'tcx> {
+    pub arm_span: Span,
+    pub source: hir::MatchSource,
+    pub prior_arms: Vec<Span>,
+    pub last_ty: Ty<'tcx>,
+    pub discrim_hir_id: hir::HirId,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct IfExpressionCause {
+    pub then: Span,
+    pub outer: Option<Span>,
+    pub semicolon: Option<Span>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait reference of the parent obligation that led to the
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 05b698e..6930c93 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -508,31 +508,33 @@
                 trait_item_def_id,
             }),
             super::ExprAssignable => Some(super::ExprAssignable),
-            super::MatchExpressionArm {
+            super::MatchExpressionArm(box super::MatchExpressionArmCause {
                 arm_span,
                 source,
                 ref prior_arms,
                 last_ty,
                 discrim_hir_id,
-            } => {
+            }) => {
                 tcx.lift(&last_ty).map(|last_ty| {
-                    super::MatchExpressionArm {
+                    super::MatchExpressionArm(box super::MatchExpressionArmCause {
                         arm_span,
                         source,
                         prior_arms: prior_arms.clone(),
                         last_ty,
                         discrim_hir_id,
-                    }
+                    })
                 })
             }
             super::MatchExpressionArmPattern { span, ty } => {
                 tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty })
             }
-            super::IfExpression { then, outer, semicolon } => Some(super::IfExpression {
-                then,
-                outer,
-                semicolon,
-            }),
+            super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
+                Some(super::IfExpression(box super::IfExpressionCause {
+                    then,
+                    outer,
+                    semicolon,
+                }))
+            }
             super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
             super::MainFunctionType => Some(super::MainFunctionType),
             super::StartFunctionType => Some(super::StartFunctionType),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 7366037..0155803 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2394,9 +2394,9 @@
     }
 
     #[inline]
-    pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem)  -> Ty<'tcx> {
-        let def_id = self.require_lang_item(item, None);
-        self.mk_generic_adt(def_id, ty)
+    pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem)  -> Option<Ty<'tcx>> {
+        let def_id = self.lang_items().require(item).ok()?;
+        Some(self.mk_generic_adt(def_id, ty))
     }
 
     #[inline]
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 7118d05..2475b93 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -5,17 +5,13 @@
 use std::cell::{RefCell, Cell};
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::panic;
-use std::env;
 use std::time::{Duration, Instant};
 
 use std::sync::mpsc::{Sender};
 use syntax_pos::{SpanData};
 use syntax::symbol::{Symbol, sym};
 use rustc_macros::HashStable;
-use crate::ty::TyCtxt;
 use crate::dep_graph::{DepNode};
-use lazy_static;
 use crate::session::Session;
 
 #[cfg(test)]
@@ -31,39 +27,6 @@
 
 thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
 
-lazy_static! {
-    static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(panic_hook));
-        hook
-    };
-}
-
-fn panic_hook(info: &panic::PanicInfo<'_>) {
-    (*DEFAULT_HOOK)(info);
-
-    let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
-
-    if backtrace {
-        TyCtxt::try_print_query_stack();
-    }
-
-    #[cfg(windows)]
-    unsafe {
-        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-            extern "system" {
-                fn DebugBreak();
-            }
-            // Trigger a debugger if we crashed during bootstrap.
-            DebugBreak();
-        }
-    }
-}
-
-pub fn install_panic_hook() {
-    lazy_static::initialize(&DEFAULT_HOOK);
-}
-
 /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
 #[derive(Clone,Debug)]
 pub struct ProfQDumpParams {
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index ff87afe..2ca517d 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -229,7 +229,7 @@
                 // We instead thus allocate some scratch space...
                 let scratch_size = cast.size(bx);
                 let scratch_align = cast.align(bx);
-                let llscratch = bx.alloca(cast.llvm_type(bx), "abi_cast", scratch_align);
+                let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
                 bx.lifetime_start(llscratch, scratch_size);
 
                 // ...where we first store the value...
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index e13a5ec..423a01a 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -387,23 +387,17 @@
         )
     }
 
-    fn alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
+    fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
         let mut bx = Builder::with_cx(self.cx);
         bx.position_at_start(unsafe {
             llvm::LLVMGetFirstBasicBlock(self.llfn())
         });
-        bx.dynamic_alloca(ty, name, align)
+        bx.dynamic_alloca(ty, align)
     }
 
-    fn dynamic_alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
+    fn dynamic_alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
         unsafe {
-            let alloca = if name.is_empty() {
-                llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED)
-            } else {
-                let name = SmallCStr::new(name);
-                llvm::LLVMBuildAlloca(self.llbuilder, ty,
-                                      name.as_ptr())
-            };
+            let alloca = llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED);
             llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
             alloca
         }
@@ -412,16 +406,9 @@
     fn array_alloca(&mut self,
                         ty: &'ll Type,
                         len: &'ll Value,
-                        name: &str,
                         align: Align) -> &'ll Value {
         unsafe {
-            let alloca = if name.is_empty() {
-                llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED)
-            } else {
-                let name = SmallCStr::new(name);
-                llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len,
-                                           name.as_ptr())
-            };
+            let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED);
             llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
             alloca
         }
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index fc0b9ff..5fbfe91 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -871,7 +871,7 @@
         // More information can be found in libstd's seh.rs implementation.
         let i64p = bx.type_ptr_to(bx.type_i64());
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let slot = bx.alloca(i64p, "slot", ptr_align);
+        let slot = bx.alloca(i64p, ptr_align);
         bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
 
         normal.ret(bx.const_i32(0));
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 90bf964..1708d72 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -4,6 +4,7 @@
 #![feature(box_syntax)]
 #![feature(core_intrinsics)]
 #![feature(libc)]
+#![feature(slice_patterns)]
 #![feature(stmt_expr_attributes)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index e63f1b9..d192f2f 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -105,7 +105,7 @@
     ) {
         let cx = self.fx.cx;
 
-        if let Some(proj) = place_ref.projection {
+        if let [proj_base @ .., elem] = place_ref.projection {
             // Allow uses of projections that are ZSTs or from scalar fields.
             let is_consume = match context {
                 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
@@ -114,12 +114,12 @@
             };
             if is_consume {
                 let base_ty =
-                    mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx());
+                    mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
                 let elem_ty = base_ty
-                    .projection_ty(cx.tcx(), &proj.elem)
+                    .projection_ty(cx.tcx(), elem)
                     .ty;
                 let elem_ty = self.fx.monomorphize(&elem_ty);
                 let span = if let mir::PlaceBase::Local(index) = place_ref.base {
@@ -131,7 +131,7 @@
                     return;
                 }
 
-                if let mir::ProjectionElem::Field(..) = proj.elem {
+                if let mir::ProjectionElem::Field(..) = elem {
                     let layout = cx.spanned_layout_of(base_ty.ty, span);
                     if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                         // Recurse with the same context, instead of `Projection`,
@@ -140,7 +140,7 @@
                         self.process_place(
                             &mir::PlaceRef {
                                 base: place_ref.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             context,
                             location,
@@ -151,11 +151,11 @@
             }
 
             // A deref projection only reads the pointer, never needs the place.
-            if let mir::ProjectionElem::Deref = proj.elem {
+            if let mir::ProjectionElem::Deref = elem {
                 self.process_place(
                     &mir::PlaceRef {
                         base: place_ref.base,
-                        projection: &proj.base,
+                        projection: proj_base,
                     },
                     PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                     location
@@ -168,7 +168,7 @@
         // visit_place API
         let mut context = context;
 
-        if place_ref.projection.is_some() {
+        if !place_ref.projection.is_empty() {
             context = if context.is_mutating_use() {
                 PlaceContext::MutatingUse(MutatingUseContext::Projection)
             } else {
@@ -177,10 +177,7 @@
         }
 
         self.visit_place_base(place_ref.base, context, location);
-
-        if let Some(box proj) = place_ref.projection {
-            self.visit_projection(place_ref.base, proj, context, location);
-        }
+        self.visit_projection(place_ref.base, place_ref.projection, context, location);
     }
 
 }
@@ -196,7 +193,7 @@
 
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *place {
             self.assign(index, location);
             let decl_span = self.fx.mir.local_decls[index].source_info.span;
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index c41e463..8829a33 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -253,7 +253,7 @@
 
             PassMode::Direct(_) | PassMode::Pair(..) => {
                 let op =
-                    self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref());
+                    self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref());
                 if let Ref(llval, _, align) = op.val {
                     bx.load(llval, align)
                 } else {
@@ -276,7 +276,7 @@
                 let llslot = match op.val {
                     Immediate(_) | Pair(..) => {
                         let scratch =
-                            PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout, "ret");
+                            PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout);
                         op.val.store(&mut bx, scratch);
                         scratch.llval
                     }
@@ -612,7 +612,7 @@
                                     ty,
                                     def_id: _,
                                 }),
-                                projection: None,
+                                projection: box [],
                             }
                         ) |
                         mir::Operand::Move(
@@ -622,7 +622,7 @@
                                     ty,
                                     def_id: _,
                                 }),
-                                projection: None,
+                                projection: box [],
                             }
                         ) => {
                             let param_env = ty::ParamEnv::reveal_all();
@@ -767,7 +767,7 @@
             match (arg, op.val) {
                 (&mir::Operand::Copy(_), Ref(_, None, _)) |
                 (&mir::Operand::Constant(_), Ref(_, None, _)) => {
-                    let tmp = PlaceRef::alloca(&mut bx, op.layout, "const");
+                    let tmp = PlaceRef::alloca(&mut bx, op.layout);
                     op.val.store(&mut bx, tmp);
                     op.val = Ref(tmp.llval, None, tmp.align);
                 }
@@ -925,7 +925,7 @@
             Immediate(_) | Pair(..) => {
                 match arg.mode {
                     PassMode::Indirect(..) | PassMode::Cast(_) => {
-                        let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                        let scratch = PlaceRef::alloca(bx, arg.layout);
                         op.val.store(bx, scratch);
                         (scratch.llval, scratch.align, true)
                     }
@@ -940,7 +940,7 @@
                     // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
                     // have scary latent bugs around.
 
-                    let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                    let scratch = PlaceRef::alloca(bx, arg.layout);
                     base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
                                     op.layout, MemFlags::empty());
                     (scratch.llval, scratch.align, true)
@@ -1017,7 +1017,7 @@
                 cx.tcx().mk_mut_ptr(cx.tcx().types.u8),
                 cx.tcx().types.i32
             ]));
-            let slot = PlaceRef::alloca(bx, layout, "personalityslot");
+            let slot = PlaceRef::alloca(bx, layout);
             self.personality_slot = Some(slot);
             slot
         }
@@ -1105,7 +1105,7 @@
         }
         let dest = if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *dest {
             match self.locals[index] {
                 LocalRef::Place(dest) => dest,
@@ -1116,7 +1116,7 @@
                     return if fn_ret.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca(bx, fn_ret.layout);
                         tmp.storage_live(bx);
                         llargs.push(tmp.llval);
                         ReturnDest::IndirectOperand(tmp, index)
@@ -1124,7 +1124,7 @@
                         // Currently, intrinsics always need a location to store
                         // the result, so we create a temporary `alloca` for the
                         // result.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca(bx, fn_ret.layout);
                         tmp.storage_live(bx);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else {
@@ -1166,7 +1166,7 @@
     ) {
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *dst {
             match self.locals[index] {
                 LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
@@ -1174,7 +1174,7 @@
                 LocalRef::Operand(None) => {
                     let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_ref()));
                     assert!(!dst_layout.ty.has_erasable_regions());
-                    let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
+                    let place = PlaceRef::alloca(bx, dst_layout);
                     place.storage_live(bx);
                     self.codegen_transmute_into(bx, src, place);
                     let op = bx.load_operand(place);
@@ -1227,7 +1227,7 @@
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if let PassMode::Cast(_) = ret_ty.mode {
-                    let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret");
+                    let tmp = PlaceRef::alloca(bx, ret_ty.layout);
                     tmp.storage_live(bx);
                     bx.store_arg_ty(&ret_ty, llval, tmp);
                     let op = bx.load_operand(tmp);
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 00e9ca0..aa3971a 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -268,11 +268,13 @@
                 debug!("alloc: {:?} ({}) -> place", local, name);
                 if layout.is_unsized() {
                     let indirect_place =
-                        PlaceRef::alloca_unsized_indirect(&mut bx, layout, &name.as_str());
+                        PlaceRef::alloca_unsized_indirect(&mut bx, layout);
+                    bx.set_var_name(indirect_place.llval, name);
                     // FIXME: add an appropriate debuginfo
                     LocalRef::UnsizedPlace(indirect_place)
                 } else {
-                    let place = PlaceRef::alloca(&mut bx, layout, &name.as_str());
+                    let place = PlaceRef::alloca(&mut bx, layout);
+                    bx.set_var_name(place.llval, name);
                     if dbg {
                         let (scope, span) = fx.debug_loc(mir::SourceInfo {
                             span: decl.source_info.span,
@@ -293,14 +295,13 @@
                 } else if memory_locals.contains(local) {
                     debug!("alloc: {:?} -> place", local);
                     if layout.is_unsized() {
-                        let indirect_place = PlaceRef::alloca_unsized_indirect(
-                            &mut bx,
-                            layout,
-                            &format!("{:?}", local),
-                        );
+                        let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout);
+                        bx.set_var_name(indirect_place.llval, format_args!("{:?}", local));
                         LocalRef::UnsizedPlace(indirect_place)
                     } else {
-                        LocalRef::Place(PlaceRef::alloca(&mut bx, layout, &format!("{:?}", local)))
+                        let place = PlaceRef::alloca(&mut bx, layout);
+                        bx.set_var_name(place.llval, format_args!("{:?}", local));
+                        LocalRef::Place(place)
                     }
                 } else {
                     // If this is an immediate local, we do not create an
@@ -452,10 +453,11 @@
     mir.args_iter().enumerate().map(|(arg_index, local)| {
         let arg_decl = &mir.local_decls[local];
 
+        // FIXME(eddyb) don't allocate a `String` unless it gets used.
         let name = if let Some(name) = arg_decl.name {
             name.as_str().to_string()
         } else {
-            format!("arg{}", arg_index)
+            format!("{:?}", local)
         };
 
         if Some(local) == mir.spread_arg {
@@ -470,7 +472,8 @@
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty), &name);
+            let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+            bx.set_var_name(place.llval, name);
             for i in 0..tupled_arg_tys.len() {
                 let arg = &fx.fn_ty.args[idx];
                 idx += 1;
@@ -558,11 +561,13 @@
             llarg_idx += 1;
             let indirect_operand = OperandValue::Pair(llarg, llextra);
 
-            let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout, &name);
+            let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout);
+            bx.set_var_name(tmp.llval, name);
             indirect_operand.store(bx, tmp);
             tmp
         } else {
-            let tmp = PlaceRef::alloca(bx, arg.layout, &name);
+            let tmp = PlaceRef::alloca(bx, arg.layout);
+            bx.set_var_name(tmp.llval, name);
             if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) {
                 let va_list_did = match tcx.lang_items().va_list() {
                     Some(did) => did,
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index a8ab3ea..daa25b2 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -367,7 +367,7 @@
 
         // Allocate an appropriate region on the stack, and copy the value into it
         let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
-        let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, "unsized_tmp", max_align);
+        let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, max_align);
         bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
 
         // Store the allocated region and the extra to the indirect place.
@@ -384,47 +384,45 @@
     ) -> Option<OperandRef<'tcx, Bx::Value>> {
         debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
 
-        place_ref.iterate(|place_base, place_projection| {
-            if let mir::PlaceBase::Local(index) = place_base {
-                match self.locals[*index] {
-                    LocalRef::Operand(Some(mut o)) => {
-                        // Moves out of scalar and scalar pair fields are trivial.
-                        for proj in place_projection {
-                            match proj.elem {
-                                mir::ProjectionElem::Field(ref f, _) => {
-                                    o = o.extract_field(bx, f.index());
-                                }
-                                mir::ProjectionElem::Index(_) |
-                                mir::ProjectionElem::ConstantIndex { .. } => {
-                                    // ZSTs don't require any actual memory access.
-                                    // FIXME(eddyb) deduplicate this with the identical
-                                    // checks in `codegen_consume` and `extract_field`.
-                                    let elem = o.layout.field(bx.cx(), 0);
-                                    if elem.is_zst() {
-                                        o = OperandRef::new_zst(bx, elem);
-                                    } else {
-                                        return None;
-                                    }
-                                }
-                                _ => return None,
+        if let mir::PlaceBase::Local(index) = place_ref.base {
+            match self.locals[*index] {
+                LocalRef::Operand(Some(mut o)) => {
+                    // Moves out of scalar and scalar pair fields are trivial.
+                    for elem in place_ref.projection.iter() {
+                        match elem {
+                            mir::ProjectionElem::Field(ref f, _) => {
+                                o = o.extract_field(bx, f.index());
                             }
+                            mir::ProjectionElem::Index(_) |
+                            mir::ProjectionElem::ConstantIndex { .. } => {
+                                // ZSTs don't require any actual memory access.
+                                // FIXME(eddyb) deduplicate this with the identical
+                                // checks in `codegen_consume` and `extract_field`.
+                                let elem = o.layout.field(bx.cx(), 0);
+                                if elem.is_zst() {
+                                    o = OperandRef::new_zst(bx, elem);
+                                } else {
+                                    return None;
+                                }
+                            }
+                            _ => return None,
                         }
+                    }
 
-                        Some(o)
-                    }
-                    LocalRef::Operand(None) => {
-                        bug!("use of {:?} before def", place_ref);
-                    }
-                    LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
-                        // watch out for locals that do not have an
-                        // alloca; they are handled somewhat differently
-                        None
-                    }
+                    Some(o)
                 }
-            } else {
-                None
+                LocalRef::Operand(None) => {
+                    bug!("use of {:?} before def", place_ref);
+                }
+                LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+                    // watch out for locals that do not have an
+                    // alloca; they are handled somewhat differently
+                    None
+                }
             }
-        })
+        } else {
+            None
+        }
     }
 
     pub fn codegen_consume(
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index b8e10d3..a4b4cb5 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -71,11 +71,9 @@
     pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyLayout<'tcx>,
-        name: &str
     ) -> Self {
-        debug!("alloca({:?}: {:?})", name, layout);
         assert!(!layout.is_unsized(), "tried to statically allocate unsized place");
-        let tmp = bx.alloca(bx.cx().backend_type(layout), name, layout.align.abi);
+        let tmp = bx.alloca(bx.cx().backend_type(layout), layout.align.abi);
         Self::new_sized(tmp, layout)
     }
 
@@ -83,13 +81,11 @@
     pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyLayout<'tcx>,
-        name: &str,
     ) -> Self {
-        debug!("alloca_unsized_indirect({:?}: {:?})", name, layout);
         assert!(layout.is_unsized(), "tried to allocate indirect place for sized values");
         let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty);
         let ptr_layout = bx.cx().layout_of(ptr_ty);
-        Self::alloca(bx, ptr_layout, name)
+        Self::alloca(bx, ptr_layout)
     }
 
     pub fn len<Cx: ConstMethods<'tcx, Value = V>>(
@@ -449,7 +445,7 @@
         let result = match &place_ref {
             mir::PlaceRef {
                 base: mir::PlaceBase::Local(index),
-                projection: None,
+                projection: [],
             } => {
                 match self.locals[*index] {
                     LocalRef::Place(place) => {
@@ -469,7 +465,7 @@
                     kind: mir::StaticKind::Promoted(promoted, substs),
                     def_id,
                 }),
-                projection: None,
+                projection: [],
             } => {
                 let param_env = ty::ParamEnv::reveal_all();
                 let instance = Instance::new(*def_id, self.monomorphize(substs));
@@ -504,7 +500,7 @@
                     kind: mir::StaticKind::Static,
                     def_id,
                 }),
-                projection: None,
+                projection: [],
             } => {
                 // NB: The layout of a static may be unsized as is the case when working
                 // with a static that is an extern_type.
@@ -514,10 +510,7 @@
             },
             mir::PlaceRef {
                 base,
-                projection: Some(box mir::Projection {
-                    base: proj_base,
-                    elem: mir::ProjectionElem::Deref,
-                }),
+                projection: [proj_base @ .., mir::ProjectionElem::Deref],
             } => {
                 // Load the pointer from its location.
                 self.codegen_consume(bx, &mir::PlaceRef {
@@ -527,22 +520,22 @@
             }
             mir::PlaceRef {
                 base,
-                projection: Some(projection),
+                projection: [proj_base @ .., elem],
             } => {
                 // FIXME turn this recursion into iteration
                 let cg_base = self.codegen_place(bx, &mir::PlaceRef {
                     base,
-                    projection: &projection.base,
+                    projection: proj_base,
                 });
 
-                match projection.elem {
+                match elem {
                     mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
                         cg_base.project_field(bx, field.index())
                     }
                     mir::ProjectionElem::Index(index) => {
                         let index = &mir::Operand::Copy(
-                            mir::Place::from(index)
+                            mir::Place::from(*index)
                         );
                         let index = self.codegen_operand(bx, index);
                         let llindex = index.immediate();
@@ -551,27 +544,27 @@
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: false,
                                                          min_length: _ } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
+                        let lloffset = bx.cx().const_usize(*offset as u64);
                         cg_base.project_index(bx, lloffset)
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: true,
                                                          min_length: _ } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
+                        let lloffset = bx.cx().const_usize(*offset as u64);
                         let lllen = cg_base.len(bx.cx());
                         let llindex = bx.sub(lllen, lloffset);
                         cg_base.project_index(bx, llindex)
                     }
                     mir::ProjectionElem::Subslice { from, to } => {
                         let mut subslice = cg_base.project_index(bx,
-                            bx.cx().const_usize(from as u64));
+                            bx.cx().const_usize(*from as u64));
                         let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
-                            .projection_ty(tcx, &projection.elem).ty;
+                            .projection_ty(tcx, elem).ty;
                         subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
 
                         if subslice.layout.is_unsized() {
                             subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
-                                bx.cx().const_usize((from as u64) + (to as u64))));
+                                bx.cx().const_usize((*from as u64) + (*to as u64))));
                         }
 
                         // Cast the place pointer type to the new
@@ -582,7 +575,7 @@
                         subslice
                     }
                     mir::ProjectionElem::Downcast(_, v) => {
-                        cg_base.project_downcast(bx, v)
+                        cg_base.project_downcast(bx, *v)
                     }
                 }
             }
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index e0ad252..f21836a 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -64,7 +64,7 @@
                         // index into the struct, and this case isn't
                         // important enough for it.
                         debug!("codegen_rvalue: creating ugly alloca");
-                        let scratch = PlaceRef::alloca(&mut bx, operand.layout, "__unsize_temp");
+                        let scratch = PlaceRef::alloca(&mut bx, operand.layout);
                         scratch.storage_live(&mut bx);
                         operand.val.store(&mut bx, scratch);
                         base::coerce_unsized_into(&mut bx, scratch, dest);
@@ -522,7 +522,7 @@
         // because codegen_place() panics if Local is operand.
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::Array(_, n) = op.layout.ty.sty {
diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs
index 594f45c..dab7dfc 100644
--- a/src/librustc_codegen_ssa/mir/statement.rs
+++ b/src/librustc_codegen_ssa/mir/statement.rs
@@ -16,12 +16,12 @@
 
         self.set_debug_loc(&mut bx, statement.source_info);
         match statement.kind {
-            mir::StatementKind::Assign(ref place, ref rvalue) => {
+            mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
                 if let mir::Place {
                     base: mir::PlaceBase::Local(index),
-                    projection: None,
-                } = *place {
-                    match self.locals[index] {
+                    projection: box [],
+                } = place {
+                    match self.locals[*index] {
                         LocalRef::Place(cg_dest) => {
                             self.codegen_rvalue(bx, cg_dest, rvalue)
                         }
@@ -30,7 +30,7 @@
                         }
                         LocalRef::Operand(None) => {
                             let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
-                            if let Some(name) = self.mir.local_decls[index].name {
+                            if let Some(name) = self.mir.local_decls[*index].name {
                                 match operand.val {
                                     OperandValue::Ref(x, ..) |
                                     OperandValue::Immediate(x) => {
@@ -44,7 +44,7 @@
                                     }
                                 }
                             }
-                            self.locals[index] = LocalRef::Operand(Some(operand));
+                            self.locals[*index] = LocalRef::Operand(Some(operand));
                             bx
                         }
                         LocalRef::Operand(Some(op)) => {
@@ -64,7 +64,7 @@
                     self.codegen_rvalue(bx, cg_dest, rvalue)
                 }
             }
-            mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
+            mir::StatementKind::SetDiscriminant{box ref place, variant_index} => {
                 self.codegen_place(&mut bx, &place.as_ref())
                     .codegen_set_discr(&mut bx, variant_index);
                 bx
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index 3a144f0..1886701 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -109,13 +109,12 @@
         rhs: Self::Value,
     ) -> (Self::Value, Self::Value);
 
-    fn alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value;
-    fn dynamic_alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value;
+    fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
+    fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
     fn array_alloca(
         &mut self,
         ty: Self::Type,
         len: Self::Value,
-        name: &str,
         align: Align,
     ) -> Self::Value;
 
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 04d2b23..6c52e62 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -559,13 +559,20 @@
         trace
     }
 
-    #[inline]
-    fn mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+    // This always-inlined function is for the hot call site.
+    #[inline(always)]
+    fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
         for dependent in node.parent.iter().chain(node.dependents.iter()) {
             self.mark_as_waiting_from(&self.nodes[dependent.get()]);
         }
     }
 
+    // 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)
+    }
+
     /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
     fn mark_as_waiting(&self) {
         for node in &self.nodes {
@@ -576,7 +583,8 @@
 
         for node in &self.nodes {
             if node.state.get() == NodeState::Pending {
-                self.mark_neighbors_as_waiting_from(node);
+                // This call site is hot.
+                self.inlined_mark_neighbors_as_waiting_from(node);
             }
         }
     }
@@ -588,7 +596,8 @@
             NodeState::Pending | NodeState::Done => {},
         }
 
-        self.mark_neighbors_as_waiting_from(node);
+        // This call site is cold.
+        self.uninlined_mark_neighbors_as_waiting_from(node);
     }
 
     /// Compresses the vector, removing all popped nodes. This adjusts
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index a839ee5..25f67b3 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -11,6 +11,7 @@
 
 [dependencies]
 graphviz = { path = "../libgraphviz" }
+lazy_static = "1.0"
 log = "0.4"
 env_logger = { version = "0.6", default-features = false }
 rustc = { path = "../librustc" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index a912ea3..005cdcf 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -20,6 +20,8 @@
 extern crate libc;
 #[macro_use]
 extern crate log;
+#[macro_use]
+extern crate lazy_static;
 
 pub extern crate rustc_plugin_impl as plugin;
 
@@ -35,8 +37,8 @@
 use rustc::lint::Lint;
 use rustc::lint;
 use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry};
-use rustc::util::common::{set_time_depth, time};
+use rustc::ty::TyCtxt;
+use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported};
 use rustc_metadata::locator;
 use rustc_metadata::cstore::CStore;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -161,8 +163,6 @@
         None => return Ok(()),
     };
 
-    install_panic_hook();
-
     let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
 
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
@@ -1151,63 +1151,107 @@
     }
 }
 
-/// Runs a procedure which will detect panics in the compiler and print nicer
-/// error messages rather than just failing the test.
+/// Runs a closure and catches unwinds triggered by fatal errors.
 ///
-/// The diagnostic emitter yielded to the procedure should be used for reporting
-/// errors of the compiler.
-pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
+/// The compiler currently unwinds with a special sentinel value to abort
+/// compilation on fatal errors. This function catches that sentinel and turns
+/// the panic into a `Result` instead.
+pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
     catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
         if value.is::<errors::FatalErrorMarker>() {
             ErrorReported
         } else {
-            // Thread panicked without emitting a fatal diagnostic
-            eprintln!("");
-
-            let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
-                errors::ColorConfig::Auto,
-                None,
-                false,
-                false,
-                None,
-            ));
-            let handler = errors::Handler::with_emitter(true, None, emitter);
-
-            // a .span_bug or .bug call has already printed what
-            // it wants to print.
-            if !value.is::<errors::ExplicitBug>() {
-                handler.emit(&MultiSpan::new(),
-                             "unexpected panic",
-                             errors::Level::Bug);
-            }
-
-            let mut xs: Vec<Cow<'static, str>> = vec![
-                "the compiler unexpectedly panicked. this is a bug.".into(),
-                format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(),
-                format!("rustc {} running on {}",
-                        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
-                        config::host_triple()).into(),
-            ];
-
-            if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
-                xs.push(format!("compiler flags: {}", flags.join(" ")).into());
-
-                if excluded_cargo_defaults {
-                    xs.push("some of the compiler flags provided by cargo are hidden".into());
-                }
-            }
-
-            for note in &xs {
-                handler.emit(&MultiSpan::new(),
-                             note,
-                             errors::Level::Note);
-            }
-
-            panic::resume_unwind(Box::new(errors::FatalErrorMarker));
+            panic::resume_unwind(value);
         }
     })
 }
 
+lazy_static! {
+    static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
+        let hook = panic::take_hook();
+        panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL)));
+        hook
+    };
+}
+
+/// Prints the ICE message, including backtrace and query stack.
+///
+/// The message will point the user at `bug_report_url` to report the ICE.
+///
+/// When `install_ice_hook` is called, this function will be called as the panic
+/// hook.
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+    // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+    (*DEFAULT_HOOK)(info);
+
+    // Separate the output with an empty line
+    eprintln!();
+
+    let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
+        errors::ColorConfig::Auto,
+        None,
+        false,
+        false,
+        None,
+    ));
+    let handler = errors::Handler::with_emitter(true, None, emitter);
+
+    // a .span_bug or .bug call has already printed what
+    // it wants to print.
+    if !info.payload().is::<errors::ExplicitBug>() {
+        handler.emit(&MultiSpan::new(),
+                     "unexpected panic",
+                     errors::Level::Bug);
+    }
+
+    let mut xs: Vec<Cow<'static, str>> = vec![
+        "the compiler unexpectedly panicked. this is a bug.".into(),
+        format!("we would appreciate a bug report: {}", bug_report_url).into(),
+        format!("rustc {} running on {}",
+                option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+                config::host_triple()).into(),
+    ];
+
+    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
+        xs.push(format!("compiler flags: {}", flags.join(" ")).into());
+
+        if excluded_cargo_defaults {
+            xs.push("some of the compiler flags provided by cargo are hidden".into());
+        }
+    }
+
+    for note in &xs {
+        handler.emit(&MultiSpan::new(),
+                     note,
+                     errors::Level::Note);
+    }
+
+    // If backtraces are enabled, also print the query stack
+    let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
+
+    if backtrace {
+        TyCtxt::try_print_query_stack();
+    }
+
+    #[cfg(windows)]
+    unsafe {
+        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+            extern "system" {
+                fn DebugBreak();
+            }
+            // Trigger a debugger if we crashed during bootstrap
+            DebugBreak();
+        }
+    }
+}
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook() {
+    lazy_static::initialize(&DEFAULT_HOOK);
+}
+
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// log crate version
 pub fn init_rustc_env_logger() {
@@ -1218,7 +1262,8 @@
     let start = Instant::now();
     init_rustc_env_logger();
     let mut callbacks = TimePassesCallbacks::default();
-    let result = report_ices_to_stderr_if_any(|| {
+    install_ice_hook();
+    let result = catch_fatal_errors(|| {
         let args = env::args_os().enumerate()
             .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
                     early_error(ErrorOutputType::default(),
diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs
index 39b9061..c626dd0 100644
--- a/src/librustc_errors/annotate_snippet_emitter_writer.rs
+++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs
@@ -37,7 +37,7 @@
                                           &mut primary_span,
                                           &mut children,
                                           &db.level,
-                                          db.handler.flags.external_macro_backtrace);
+                                          db.handler().flags.external_macro_backtrace);
 
         self.emit_messages_default(&db.level,
                                    db.message(),
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 41d0638..7b8902f 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -18,8 +18,17 @@
 /// extending `HandlerFlags`, accessed via `self.handler.flags`.
 #[must_use]
 #[derive(Clone)]
-pub struct DiagnosticBuilder<'a> {
-    pub handler: &'a Handler,
+pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);
+
+/// This is a large type, and often used as a return value, especially within
+/// the frequently-used `PResult` type. In theory, return value optimization
+/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
+/// time of writing). The split between `DiagnosticBuilder` and
+/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
+#[must_use]
+#[derive(Clone)]
+struct DiagnosticBuilderInner<'a> {
+    handler: &'a Handler,
     diagnostic: Diagnostic,
     allow_suggestions: bool,
 }
@@ -52,7 +61,7 @@
     ) => {
         $(#[$attrs])*
         pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
-            self.diagnostic.$n($($name),*);
+            self.0.diagnostic.$n($($name),*);
             self
         }
     };
@@ -69,7 +78,7 @@
     ) => {
         $(#[$attrs])*
         pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
-            self.diagnostic.$n($($name),*);
+            self.0.diagnostic.$n($($name),*);
             self
         }
     };
@@ -79,24 +88,28 @@
     type Target = Diagnostic;
 
     fn deref(&self) -> &Diagnostic {
-        &self.diagnostic
+        &self.0.diagnostic
     }
 }
 
 impl<'a> DerefMut for DiagnosticBuilder<'a> {
     fn deref_mut(&mut self) -> &mut Diagnostic {
-        &mut self.diagnostic
+        &mut self.0.diagnostic
     }
 }
 
 impl<'a> DiagnosticBuilder<'a> {
+    pub fn handler(&self) -> &'a Handler{
+        self.0.handler
+    }
+
     /// Emit the diagnostic.
     pub fn emit(&mut self) {
         if self.cancelled() {
             return;
         }
 
-        self.handler.emit_db(&self);
+        self.0.handler.emit_db(&self);
         self.cancel();
     }
 
@@ -115,8 +128,8 @@
     /// Buffers the diagnostic for later emission, unless handler
     /// has disabled such buffering.
     pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
-        if self.handler.flags.dont_buffer_diagnostics ||
-            self.handler.flags.treat_err_as_bug.is_some()
+        if self.0.handler.flags.dont_buffer_diagnostics ||
+            self.0.handler.flags.treat_err_as_bug.is_some()
         {
             self.emit();
             return;
@@ -126,7 +139,7 @@
         // implements `Drop`.
         let diagnostic;
         unsafe {
-            diagnostic = std::ptr::read(&self.diagnostic);
+            diagnostic = std::ptr::read(&self.0.diagnostic);
             std::mem::forget(self);
         };
         // Logging here is useful to help track down where in logs an error was
@@ -144,7 +157,7 @@
         span: Option<S>,
     ) -> &mut Self {
         let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
-        self.diagnostic.sub(level, message, span, None);
+        self.0.diagnostic.sub(level, message, span, None);
         self
     }
 
@@ -160,7 +173,7 @@
     /// locally in whichever way makes the most sense.
     pub fn delay_as_bug(&mut self) {
         self.level = Level::Bug;
-        self.handler.delay_as_bug(self.diagnostic.clone());
+        self.0.handler.delay_as_bug(self.0.diagnostic.clone());
         self.cancel();
     }
 
@@ -171,7 +184,7 @@
     /// then the snippet will just include that `Span`, which is
     /// called the primary span.
     pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
-        self.diagnostic.span_label(span, label);
+        self.0.diagnostic.span_label(span, label);
         self
     }
 
@@ -208,10 +221,10 @@
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.multipart_suggestion(
+        self.0.diagnostic.multipart_suggestion(
             msg,
             suggestion,
             applicability,
@@ -225,10 +238,10 @@
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.tool_only_multipart_suggestion(
+        self.0.diagnostic.tool_only_multipart_suggestion(
             msg,
             suggestion,
             applicability,
@@ -236,7 +249,6 @@
         self
     }
 
-
     pub fn span_suggestion(
         &mut self,
         sp: Span,
@@ -244,10 +256,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion(
+        self.0.diagnostic.span_suggestion(
             sp,
             msg,
             suggestion,
@@ -263,10 +275,10 @@
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestions(
+        self.0.diagnostic.span_suggestions(
             sp,
             msg,
             suggestions,
@@ -282,10 +294,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion_short(
+        self.0.diagnostic.span_suggestion_short(
             sp,
             msg,
             suggestion,
@@ -301,10 +313,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion_hidden(
+        self.0.diagnostic.span_suggestion_hidden(
             sp,
             msg,
             suggestion,
@@ -320,10 +332,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.tool_only_span_suggestion(
+        self.0.diagnostic.tool_only_span_suggestion(
             sp,
             msg,
             suggestion,
@@ -336,7 +348,7 @@
     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
 
     pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
-        self.allow_suggestions = allow;
+        self.0.allow_suggestions = allow;
         self
     }
 
@@ -359,19 +371,18 @@
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
-    pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
-                         -> DiagnosticBuilder<'a> {
-        DiagnosticBuilder {
+    pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
+        DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
             handler,
             diagnostic,
             allow_suggestions: true,
-        }
+        }))
     }
 }
 
 impl<'a> Debug for DiagnosticBuilder<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.diagnostic.fmt(f)
+        self.0.diagnostic.fmt(f)
     }
 }
 
@@ -381,7 +392,7 @@
     fn drop(&mut self) {
         if !panicking() && !self.cancelled() {
             let mut db = DiagnosticBuilder::new(
-                self.handler,
+                self.0.handler,
                 Level::Bug,
                 "the following error was constructed but not emitted",
             );
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 0ce69ee..6660836 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -385,7 +385,7 @@
                                           &mut primary_span,
                                           &mut children,
                                           &db.level,
-                                          db.handler.flags.external_macro_backtrace);
+                                          db.handler().flags.external_macro_backtrace);
 
         self.emit_messages_default(&db.level,
                                    &db.styled_message(),
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 3cfae16..e8e8da6 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -41,7 +41,6 @@
 use syntax::parse::{self, PResult};
 use syntax::util::node_count::NodeCounter;
 use syntax::symbol::Symbol;
-use syntax::feature_gate::AttributeType;
 use syntax_pos::FileName;
 use syntax_ext;
 
@@ -219,7 +218,6 @@
 
 pub struct PluginInfo {
     syntax_exts: Vec<NamedSyntaxExtension>,
-    attributes: Vec<(Symbol, AttributeType)>,
 }
 
 pub fn register_plugins<'a>(
@@ -312,12 +310,9 @@
     }
 
     *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
-    *sess.plugin_attributes.borrow_mut() = attributes.clone();
+    *sess.plugin_attributes.borrow_mut() = attributes;
 
-    Ok((krate, PluginInfo {
-        syntax_exts,
-        attributes,
-    }))
+    Ok((krate, PluginInfo { syntax_exts }))
 }
 
 fn configure_and_expand_inner<'a>(
@@ -329,7 +324,6 @@
     crate_loader: &'a mut CrateLoader<'a>,
     plugin_info: PluginInfo,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
-    let attributes = plugin_info.attributes;
     time(sess, "pre ast expansion lint checks", || {
         lint::check_ast_crate(
             sess,
@@ -522,7 +516,6 @@
             &krate,
             &sess.parse_sess,
             &sess.features_untracked(),
-            &attributes,
             sess.opts.unstable_features,
         );
     });
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index aecf5c5..cf19a9e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -669,6 +669,22 @@
     }
 }
 
+fn lint_deprecated_attr(
+    cx: &EarlyContext<'_>,
+    attr: &ast::Attribute,
+    msg: &str,
+    suggestion: Option<&str>,
+) {
+    cx.struct_span_lint(DEPRECATED, attr.span, &msg)
+        .span_suggestion_short(
+            attr.span,
+            suggestion.unwrap_or("remove this attribute"),
+            String::new(),
+            Applicability::MachineApplicable
+        )
+        .emit();
+}
+
 impl EarlyLintPass for DeprecatedAttr {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         for &&(n, _, _, ref g) in &self.depr_attrs {
@@ -679,18 +695,15 @@
                                              _) = g {
                     let msg = format!("use of deprecated attribute `{}`: {}. See {}",
                                       name, reason, link);
-                    let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg);
-                    err.span_suggestion_short(
-                        attr.span,
-                        suggestion.unwrap_or("remove this attribute"),
-                        String::new(),
-                        Applicability::MachineApplicable
-                    );
-                    err.emit();
+                    lint_deprecated_attr(cx, attr, &msg, suggestion);
                 }
                 return;
             }
         }
+        if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
+            let msg = format!("use of deprecated attribute `{}`: no longer used.", attr.path);
+            lint_deprecated_attr(cx, attr, &msg, None);
+        }
     }
 }
 
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 561bf20..21ea476 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -618,24 +618,19 @@
             }
 
             // Trigger the lint if the nested item is a non-self single item
-            let node_ident;
-            match items[0].0.kind {
+            let node_name = match items[0].0.kind {
                 ast::UseTreeKind::Simple(rename, ..) => {
                     let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == kw::SelfLower {
                         return;
                     }
-                    node_ident = rename.unwrap_or(orig_ident);
+                    rename.unwrap_or(orig_ident).name
                 }
-                ast::UseTreeKind::Glob => {
-                    node_ident = ast::Ident::from_str("*");
-                }
-                ast::UseTreeKind::Nested(_) => {
-                    return;
-                }
-            }
+                ast::UseTreeKind::Glob => Symbol::intern("*"),
+                ast::UseTreeKind::Nested(_) => return,
+            };
 
-            let msg = format!("braces around {} is unnecessary", node_ident.name);
+            let msg = format!("braces around {} is unnecessary", node_name);
             cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
         }
     }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index d6450f0..a1e3bbc 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -444,7 +444,8 @@
             .insert(local_span, (name.to_string(), data.get_span(id.index, sess)));
 
         LoadedMacro::MacroDef(ast::Item {
-            ident: ast::Ident::from_str(&name.as_str()),
+            // FIXME: cross-crate hygiene
+            ident: ast::Ident::with_dummy_span(name.as_symbol()),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
             attrs: attrs.iter().cloned().collect(),
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index c9e6e7f..db19cbc 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -317,7 +317,7 @@
         // so extract `temp`.
         let temp = if let &mir::Place {
             base: mir::PlaceBase::Local(temp),
-            projection: None,
+            projection: box [],
         } = assigned_place {
             temp
         } else {
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index bfc7050..4b4516d 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -2,8 +2,8 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
-    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
-    ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
+    Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
@@ -244,7 +244,7 @@
                 }
                 let span = if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = place {
                     let decl = &self.body.local_decls[*local];
                     Some(decl.source_info.span)
@@ -614,17 +614,17 @@
                     projection,
                 } = first_borrowed_place;
 
-                let mut current = projection;
+                for (i, elem) in projection.iter().enumerate().rev() {
+                    let proj_base = &projection[..i];
 
-                while let Some(box Projection { base: base_proj, elem }) = current {
                     match elem {
-                        ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => {
+                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
                             return Some((PlaceRef {
                                 base: base,
-                                projection: base_proj,
+                                projection: proj_base,
                             }, field));
                         },
-                        _ => current = base_proj,
+                        _ => {},
                     }
                 }
                 None
@@ -637,9 +637,9 @@
                     projection,
                 } = second_borrowed_place;
 
-                let mut current = projection;
+                for (i, elem) in projection.iter().enumerate().rev() {
+                    let proj_base = &projection[..i];
 
-                while let Some(box Projection { base: proj_base, elem }) = current {
                     if let ProjectionElem::Field(field, _) = elem {
                         if let Some(union_ty) = union_ty(base, proj_base) {
                             if field != target_field
@@ -660,8 +660,6 @@
                             }
                         }
                     }
-
-                    current = proj_base;
                 }
                 None
             })
@@ -707,7 +705,7 @@
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.var_or_use();
 
-        assert!(root_place.projection.is_none());
+        assert!(root_place.projection.is_empty());
         let proper_span = match root_place.base {
             PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
             _ => drop_span,
@@ -716,7 +714,7 @@
         if self.access_place_error_reported
             .contains(&(Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.clone(),
+                projection: root_place.projection.to_vec().into_boxed_slice(),
             }, borrow_span))
         {
             debug!(
@@ -729,7 +727,7 @@
         self.access_place_error_reported
             .insert((Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.clone(),
+                projection: root_place.projection.to_vec().into_boxed_slice(),
             }, borrow_span));
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
@@ -1107,7 +1105,7 @@
             let local_kind = match borrow.borrowed_place {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } => {
                     match self.body.local_kind(local) {
                         LocalKind::ReturnPointer
@@ -1136,7 +1134,7 @@
                 .unwrap();
             let local = if let PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } = root_place {
                 local
             } else {
@@ -1446,7 +1444,7 @@
     ) {
         let (from_arg, local_decl) = if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = *err_place {
             if let LocalKind::Arg = self.body.local_kind(local) {
                 (true, Some(&self.body.local_decls[local]))
@@ -1519,20 +1517,21 @@
     fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
         let tcx = self.infcx.tcx;
         match place.projection {
-            None => {
+            [] => {
                 StorageDeadOrDrop::LocalStorageDead
             }
-            Some(box Projection { ref base, ref elem }) => {
+            [proj_base @ .., elem] => {
+                // FIXME(spastorino) make this iterate
                 let base_access = self.classify_drop_access_kind(PlaceRef {
                     base: place.base,
-                    projection: base,
+                    projection: proj_base,
                 });
                 match elem {
                     ProjectionElem::Deref => match base_access {
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(),
+                                Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1540,7 +1539,7 @@
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
+                        let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
                         match base_ty.sty {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
@@ -1598,7 +1597,7 @@
             "annotate_argument_and_return_for_borrow: location={:?}",
             location
         );
-        if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
+        if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
              = &self.body[location.block].statements.get(location.statement_index)
         {
             debug!(
@@ -1609,7 +1608,7 @@
             let mut target = *match reservation {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } if self.body.local_kind(*local) == LocalKind::Temp => local,
                 _ => return None,
             };
@@ -1623,11 +1622,13 @@
                     target, stmt
                 );
                 if let StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(assigned_to),
-                        projection: None,
-                    },
-                    box rvalue
+                    box(
+                        Place {
+                            base: PlaceBase::Local(assigned_to),
+                            projection: box [],
+                        },
+                        rvalue
+                    )
                 ) = &stmt.kind {
                     debug!(
                         "annotate_argument_and_return_for_borrow: assigned_to={:?} \
@@ -1753,7 +1754,7 @@
             if let TerminatorKind::Call {
                 destination: Some((Place {
                     base: PlaceBase::Local(assigned_to),
-                    projection: None,
+                    projection: box [],
                 }, _)),
                 args,
                 ..
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 9f25e98..5bccd28 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -41,7 +41,7 @@
         let mut target = place.local_or_deref_local();
         for stmt in &self.body[location.block].statements[location.statement_index..] {
             debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
-            if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
+            if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
                 match from {
                     Operand::Copy(ref place) |
@@ -152,7 +152,7 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 self.append_local_to_string(*local, buf)?;
             }
@@ -162,7 +162,7 @@
                         kind: StaticKind::Promoted(..),
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 buf.push_str("promoted");
             }
@@ -173,15 +173,15 @@
                         def_id,
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
             }
             PlaceRef {
                 base,
-                projection: Some(ref proj),
+                projection: [proj_base @ .., elem],
             } => {
-                match proj.elem {
+                match elem {
                     ProjectionElem::Deref => {
                         let upvar_field_projection =
                             self.is_upvar_field_projection(place);
@@ -199,20 +199,20 @@
                                 self.append_place_to_string(
                                     PlaceRef {
                                         base,
-                                        projection: &proj.base,
+                                        projection: proj_base,
                                     },
                                     buf,
                                     autoderef,
                                     &including_downcast,
                                 )?;
                             } else {
-                                match (&proj.base, base) {
-                                    (None, PlaceBase::Local(local)) => {
+                                match (proj_base, base) {
+                                    ([], PlaceBase::Local(local)) => {
                                         if self.body.local_decls[*local].is_ref_for_guard() {
                                             self.append_place_to_string(
                                                 PlaceRef {
                                                     base,
-                                                    projection: &proj.base,
+                                                    projection: proj_base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -224,7 +224,7 @@
                                             self.append_place_to_string(
                                                 PlaceRef {
                                                     base,
-                                                    projection: &proj.base,
+                                                    projection: proj_base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -238,7 +238,7 @@
                                         self.append_place_to_string(
                                             PlaceRef {
                                                 base,
-                                                projection: &proj.base,
+                                                projection: proj_base,
                                             },
                                             buf,
                                             autoderef,
@@ -253,7 +253,7 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
@@ -275,12 +275,12 @@
                         } else {
                             let field_name = self.describe_field(PlaceRef {
                                 base,
-                                projection: &proj.base,
-                            }, field);
+                                projection: proj_base,
+                            }, *field);
                             self.append_place_to_string(
                                 PlaceRef {
                                     base,
-                                    projection: &proj.base,
+                                    projection: proj_base,
                                 },
                                 buf,
                                 autoderef,
@@ -295,14 +295,14 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
                             &including_downcast,
                         )?;
                         buf.push_str("[");
-                        if self.append_local_to_string(index, buf).is_err() {
+                        if self.append_local_to_string(*index, buf).is_err() {
                             buf.push_str("_");
                         }
                         buf.push_str("]");
@@ -315,7 +315,7 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
@@ -349,28 +349,30 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 let local = &self.body.local_decls[*local];
                 self.describe_field_from_ty(&local.ty, field, None)
             }
             PlaceRef {
                 base: PlaceBase::Static(static_),
-                projection: None,
+                projection: [],
             } =>
                 self.describe_field_from_ty(&static_.ty, field, None),
             PlaceRef {
                 base,
-                projection: Some(proj),
-            } => match proj.elem {
-                ProjectionElem::Deref => self.describe_field(PlaceRef {
-                    base,
-                    projection: &proj.base,
-                }, field),
+                projection: [proj_base @ .., elem],
+            } => match elem {
+                ProjectionElem::Deref => {
+                    self.describe_field(PlaceRef {
+                        base,
+                        projection: proj_base,
+                    }, field)
+                }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty =
                         Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
-                    self.describe_field_from_ty(&base_ty, field, Some(variant_index))
+                    self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
                     self.describe_field_from_ty(&field_type, field, None)
@@ -380,7 +382,7 @@
                 | ProjectionElem::Subslice { .. } => {
                     self.describe_field(PlaceRef {
                         base,
-                        projection: &proj.base,
+                        projection: proj_base,
                     }, field)
                 }
             },
@@ -445,7 +447,7 @@
                 def_id,
                 ..
             }),
-            projection: None,
+            projection: [],
         } = place_ref {
             let attrs = self.infcx.tcx.get_attrs(*def_id);
             let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
@@ -790,8 +792,7 @@
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
         if let  StatementKind::Assign(
-            _,
-            box Rvalue::Aggregate(ref kind, ref places)
+            box(_, Rvalue::Aggregate(ref kind, ref places))
         ) = stmt.kind {
             let (def_id, is_generator) = match kind {
                 box AggregateKind::Closure(def_id, _) => (def_id, false),
@@ -828,10 +829,10 @@
             .get(location.statement_index)
         {
             Some(&Statement {
-                kind: StatementKind::Assign(Place {
+                kind: StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
-                }, _),
+                    projection: box [],
+                }, _)),
                 ..
             }) => local,
             _ => return OtherUse(use_span),
@@ -844,7 +845,7 @@
 
         for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
             if let StatementKind::Assign(
-                _, box Rvalue::Aggregate(ref kind, ref places)
+                box(_, Rvalue::Aggregate(ref kind, ref places))
             ) = stmt.kind {
                 let (def_id, is_generator) = match kind {
                     box AggregateKind::Closure(def_id, _) => (def_id, false),
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 9ad7cbc..5ef7046 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,10 +10,10 @@
 use rustc::middle::borrowck::SignalledError;
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{
-    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
-    Static, StaticKind
+    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
+    PlaceRef, Static, StaticKind
 };
-use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
+use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind};
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt};
@@ -546,7 +546,7 @@
         self.check_activations(location, span, flow_state);
 
         match stmt.kind {
-            StatementKind::Assign(ref lhs, ref rhs) => {
+            StatementKind::Assign(box(ref lhs, ref rhs)) => {
                 self.consume_rvalue(
                     location,
                     (rhs, span),
@@ -561,7 +561,7 @@
                     flow_state,
                 );
             }
-            StatementKind::FakeRead(_, ref place) => {
+            StatementKind::FakeRead(_, box ref place) => {
                 // Read for match doesn't access any memory and is used to
                 // assert that a place is safe and live. So we don't have to
                 // do any checks here.
@@ -905,7 +905,7 @@
 
 struct RootPlace<'d, 'tcx> {
     place_base: &'d PlaceBase<'tcx>,
-    place_projection: &'d Option<Box<Projection<'tcx>>>,
+    place_projection: &'d [PlaceElem<'tcx>],
     is_local_mutation_allowed: LocalMutationIsAllowed,
 }
 
@@ -1191,7 +1191,7 @@
         // before (at this point in the flow).
         if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = place_span.0 {
             if let Mutability::Not = self.body.local_decls[*local].mutability {
                 // check for reassignments to immutable local variables
@@ -1331,7 +1331,7 @@
 
     fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
-            if place.projection.is_some() {
+            if !place.projection.is_empty() {
                 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
                     this.used_mut_upvars.push(field);
                 }
@@ -1346,11 +1346,11 @@
         match *operand {
             Operand::Move(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) |
             Operand::Copy(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) if self.body.local_decls[local].is_user_variable.is_none() => {
                 if self.body.local_decls[local].ty.is_mutable_ptr() {
                     // The variable will be marked as mutable by the borrow.
@@ -1387,7 +1387,7 @@
                 let stmt = &bbd.statements[loc.statement_index];
                 debug!("temporary assigned in: stmt={:?}", stmt);
 
-                if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind {
+                if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
                     propagate_closure_used_mut_place(self, source);
                 } else {
                     bug!("closures should only capture user variables \
@@ -1468,7 +1468,7 @@
         //
         // FIXME: allow thread-locals to borrow other thread locals?
 
-        assert!(root_place.projection.is_none());
+        assert!(root_place.projection.is_empty());
         let (might_be_alive, will_be_dropped) = match root_place.base {
             PlaceBase::Static(box Static {
                 kind: StaticKind::Promoted(..),
@@ -1756,13 +1756,10 @@
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
-        // recur down place; dispatch to external checks when necessary
-        let mut place_projection = &place.projection;
 
         // None case => assigning to `x` does not require `x` be initialized.
-        while let Some(proj) = place_projection {
-            let Projection { ref base, ref elem } = **proj;
-            match *elem {
+        for (i, elem) in place.projection.iter().enumerate().rev() {
+            match elem {
                 ProjectionElem::Index(_/*operand*/) |
                 ProjectionElem::ConstantIndex { .. } |
                 // assigning to P[i] requires P to be valid.
@@ -1774,11 +1771,13 @@
 
                 // assigning to (*P) requires P to be initialized
                 ProjectionElem::Deref => {
+                    let proj_base = &place.projection[..i];
+
                     self.check_if_full_path_is_moved(
                         location, InitializationRequiringAction::Use,
                         (PlaceRef {
                             base: &place.base,
-                            projection: base,
+                            projection: proj_base,
                         }, span), flow_state);
                     // (base initialized; no need to
                     // recur further)
@@ -1791,18 +1790,19 @@
                 }
 
                 ProjectionElem::Field(..) => {
+                    let proj_base = &place.projection[..i];
                     // if type of `P` has a dtor, then
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
+                    let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
                     match base_ty.sty {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
                                 (PlaceRef {
                                     base: &place.base,
-                                    projection: base,
+                                    projection: proj_base,
                                 }, span), flow_state);
 
                             // (base initialized; no need to
@@ -1815,7 +1815,7 @@
                         ty::Adt(..) | ty::Tuple(..) => {
                             check_parent_of_field(self, location, PlaceRef {
                                 base: &place.base,
-                                projection: base,
+                                projection: proj_base,
                             }, span, flow_state);
 
                             if let PlaceBase::Local(local) = place.base {
@@ -1835,8 +1835,6 @@
                     }
                 }
             }
-
-            place_projection = base;
         }
 
         fn check_parent_of_field<'cx, 'tcx>(
@@ -2084,7 +2082,7 @@
         match root_place {
             RootPlace {
                 place_base: PlaceBase::Local(local),
-                place_projection: None,
+                place_projection: [],
                 is_local_mutation_allowed,
             } => {
                 // If the local may have been initialized, and it is now currently being
@@ -2103,7 +2101,7 @@
             } => {}
             RootPlace {
                 place_base,
-                place_projection: place_projection @ Some(_),
+                place_projection: place_projection @ [.., _],
                 is_local_mutation_allowed: _,
             } => {
                 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -2115,7 +2113,7 @@
             }
             RootPlace {
                 place_base: PlaceBase::Static(..),
-                place_projection: None,
+                place_projection: [],
                 is_local_mutation_allowed: _,
             } => {}
         }
@@ -2131,7 +2129,7 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 let local = &self.body.local_decls[*local];
                 match local.mutability {
@@ -2162,7 +2160,7 @@
                     kind: StaticKind::Promoted(..),
                     ..
                 }),
-                projection: None,
+                projection: [],
             } =>
                 Ok(RootPlace {
                     place_base: place.base,
@@ -2175,7 +2173,7 @@
                     def_id,
                     ..
                 }),
-                projection: None,
+                projection: [],
             } => {
                 if !self.infcx.tcx.is_mutable_static(*def_id) {
                     Err(place)
@@ -2189,12 +2187,12 @@
             }
             PlaceRef {
                 base: _,
-                projection: Some(proj),
+                projection: [proj_base @ .., elem],
             } => {
-                match proj.elem {
+                match elem {
                     ProjectionElem::Deref => {
                         let base_ty =
-                            Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).ty;
+                            Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.sty {
@@ -2216,7 +2214,7 @@
 
                                         self.is_mutable(PlaceRef {
                                             base: place.base,
-                                            projection: &proj.base,
+                                            projection: proj_base,
                                         }, mode)
                                     }
                                 }
@@ -2240,7 +2238,7 @@
                             _ if base_ty.is_box() => {
                                 self.is_mutable(PlaceRef {
                                     base: place.base,
-                                    projection: &proj.base,
+                                    projection: proj_base,
                                 }, is_local_mutation_allowed)
                             }
                             // Deref should only be for reference, pointers or boxes
@@ -2297,7 +2295,7 @@
                                     // ```
                                     let _ = self.is_mutable(PlaceRef {
                                         base: place.base,
-                                        projection: &proj.base,
+                                        projection: proj_base,
                                     }, is_local_mutation_allowed)?;
                                     Ok(RootPlace {
                                         place_base: place.base,
@@ -2309,7 +2307,7 @@
                         } else {
                             self.is_mutable(PlaceRef {
                                 base: place.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             }, is_local_mutation_allowed)
                         }
                     }
@@ -2326,21 +2324,15 @@
         let mut place_projection = place_ref.projection;
         let mut by_ref = false;
 
-        if let Some(box Projection {
-            base,
-            elem: ProjectionElem::Deref,
-        }) = place_projection {
-            place_projection = &base;
+        if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
+            place_projection = proj_base;
             by_ref = true;
         }
 
         match place_projection {
-            Some(box Projection {
-                base,
-                elem: ProjectionElem::Field(field, _ty),
-            }) => {
+            [base @ .., ProjectionElem::Field(field, _ty)] => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty;
+                let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty;
 
                 if (base_ty.is_closure() || base_ty.is_generator()) &&
                     (!by_ref || self.upvars[field.index()].by_ref) {
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index 0d13db2..aa732b0 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -89,11 +89,13 @@
                 // If that ever stops being the case, then the ever initialized
                 // flow could be used.
                 if let Some(StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(local),
-                        projection: None,
-                    },
-                    box Rvalue::Use(Operand::Move(move_from)),
+                    box(
+                        Place {
+                            base: PlaceBase::Local(local),
+                            projection: box [],
+                        },
+                        Rvalue::Use(Operand::Move(move_from))
+                    )
                 )) = self.body.basic_blocks()[location.block]
                     .statements
                     .get(location.statement_index)
@@ -274,16 +276,12 @@
         place: &Place<'tcx>,
         span: Span
     ) -> DiagnosticBuilder<'a> {
-        let description = if place.projection.is_none() {
+        let description = if place.projection.is_empty() {
             format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
         } else {
-            let mut base_static = &place.projection;
-            while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
-                base_static = &proj.base;
-            }
             let base_static = PlaceRef {
                 base: &place.base,
-                projection: base_static,
+                projection: &place.projection[..1],
             };
 
             format!(
@@ -309,17 +307,19 @@
         let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
             .find_map(|p| self.is_upvar_field_projection(p));
 
-        let deref_base = match deref_target_place.projection {
-            Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
-                base: &deref_target_place.base,
-                projection: base,
-            },
+        let deref_base = match &deref_target_place.projection {
+            box [proj_base @ .., ProjectionElem::Deref] => {
+                PlaceRef {
+                    base: &deref_target_place.base,
+                    projection: proj_base,
+                }
+            }
             _ => bug!("deref_target_place is not a deref projection"),
         };
 
         if let PlaceRef {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: [],
         } = deref_base {
             let decl = &self.body.local_decls[*local];
             if decl.is_ref_for_guard() {
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 8f2ce80..14b76d9 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -2,7 +2,7 @@
 use rustc::hir::Node;
 use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
 use rustc::mir::{
-    Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind
+    Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
 };
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::indexed_vec::Idx;
@@ -47,12 +47,12 @@
         match the_place_err {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 if let Place {
                     base: PlaceBase::Local(_),
-                    projection: None,
+                    projection: box [],
                 } = access_place {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
@@ -65,14 +65,10 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base,
-                        elem: ProjectionElem::Field(upvar_index, _),
-                    }),
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
@@ -86,14 +82,10 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base,
-                        elem: ProjectionElem::Deref,
-                    }),
+                projection: [proj_base @ .., ProjectionElem::Deref],
             } => {
                 if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
-                    base.is_none() &&
+                    proj_base.is_empty() &&
                     !self.upvars.is_empty() {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
                     debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
@@ -114,7 +106,7 @@
                             ", as `Fn` closures cannot mutate their captured variables".to_string()
                         }
                 } else if {
-                    if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) {
+                    if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) {
                         self.body.local_decls[*local].is_ref_for_guard()
                     } else {
                         false
@@ -125,7 +117,7 @@
                 } else {
                     let source = self.borrowed_content_source(PlaceRef {
                         base: the_place_err.base,
-                        projection: base,
+                        projection: proj_base,
                     });
                     let pointer_type = source.describe_for_immutable_place();
                     opt_source = Some(source);
@@ -151,7 +143,7 @@
                         kind: StaticKind::Promoted(..),
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => unreachable!(),
 
             PlaceRef {
@@ -161,11 +153,11 @@
                         def_id,
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 if let Place {
                     base: PlaceBase::Static(_),
-                    projection: None,
+                    projection: box [],
                 } = access_place {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
                     reason = String::new();
@@ -178,33 +170,19 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base: _,
-                        elem: ProjectionElem::Index(_),
-                    }),
+                projection: [.., ProjectionElem::Index(_)],
             }
             | PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base: _,
-                        elem: ProjectionElem::ConstantIndex { .. },
-                    }),
+                projection: [.., ProjectionElem::ConstantIndex { .. }],
             }
             | PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Subslice { .. },
-                }),
+                projection: [.., ProjectionElem::Subslice { .. }],
             }
             | PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Downcast(..),
-                }),
+                projection: [.., ProjectionElem::Downcast(..)],
             } => bug!("Unexpected immutable place."),
         }
 
@@ -262,22 +240,17 @@
             // after the field access).
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: Some(box Projection {
-                        base: Some(box Projection {
-                            base: base_proj,
-                            elem: ProjectionElem::Deref,
-                        }),
-                        elem: ProjectionElem::Field(field, _),
-                    }),
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [proj_base @ ..,
+                             ProjectionElem::Deref,
+                             ProjectionElem::Field(field, _),
+                             ProjectionElem::Deref,
+                ],
             } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
                 if let Some((span, message)) = annotate_struct_field(
                     self.infcx.tcx,
-                    Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty,
+                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
                     field,
                 ) {
                     err.span_suggestion(
@@ -292,7 +265,7 @@
             // Suggest removing a `&mut` from the use of a mutable reference.
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } if {
                 self.body.local_decls.get(*local).map(|local_decl| {
                     if let ClearCrossCrate::Set(
@@ -328,7 +301,7 @@
             // variable) mutations...
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } if self.body.local_decls[*local].can_be_made_mutable() => {
                 // ... but it doesn't make sense to suggest it on
                 // variables that are `ref x`, `ref mut x`, `&self`,
@@ -349,13 +322,10 @@
             // Also suggest adding mut for upvars
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: proj_base,
-                    elem: ProjectionElem::Field(upvar_index, _),
-                }),
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -385,7 +355,7 @@
             // a local variable, then just suggest the user remove it.
             PlaceRef {
                 base: PlaceBase::Local(_),
-                projection: None,
+                projection: [],
             } if {
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         snippet.starts_with("&mut ")
@@ -400,10 +370,7 @@
 
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } if {
                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
                     self.body.local_decls[*local].is_user_variable
@@ -427,10 +394,7 @@
             // arbitrary base for the projection?
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } if self.body.local_decls[*local].is_user_variable.is_some() =>
             {
                 let local_decl = &self.body.local_decls[*local];
@@ -510,10 +474,7 @@
 
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             // FIXME document what is this 1 magic number about
             } if *base == PlaceBase::Local(Local::new(1)) &&
                   !self.upvars.is_empty() =>
@@ -527,10 +488,7 @@
 
             PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [.., ProjectionElem::Deref],
             } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 5c23091..1e5f613 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -8,9 +8,8 @@
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
-    ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
-    UserTypeProjection,
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
@@ -229,14 +228,11 @@
             match place {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } |
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: Some(box Projection {
-                        base: None,
-                        elem: ProjectionElem::Deref,
-                    }),
+                    projection: box [ProjectionElem::Deref],
                 } => {
                     debug!(
                         "Recording `killed` facts for borrows of local={:?} at location={:?}",
@@ -261,7 +257,7 @@
 
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: Some(_),
+                    projection: box [.., _],
                 } => {
                     // Kill conflicting borrows of the innermost local.
                     debug!(
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index aba3ef1..eae2f83 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -274,7 +274,7 @@
                     if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
                         if let Place {
                             base: PlaceBase::Local(borrowed_local),
-                            projection: None,
+                            projection: box [],
                         } = place {
                              if body.local_decls[*borrowed_local].name.is_some()
                                 && local != *borrowed_local
@@ -495,11 +495,11 @@
                             Operand::Constant(c) => c.span,
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(l),
-                                projection: None,
+                                projection: box [],
                             }) |
                             Operand::Move(Place {
                                 base: PlaceBase::Local(l),
-                                projection: None,
+                                projection: box [],
                             }) => {
                                 let local_decl = &self.body.local_decls[*l];
                                 if local_decl.name.is_none() {
@@ -541,10 +541,10 @@
         // it which simplifies the termination logic.
         let mut queue = vec![location];
         let mut target = if let Some(&Statement {
-            kind: StatementKind::Assign(Place {
+            kind: StatementKind::Assign(box(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
-            }, _),
+                projection: box [],
+            }, _)),
             ..
         }) = stmt
         {
@@ -567,7 +567,7 @@
                 debug!("was_captured_by_trait_object: stmt={:?}", stmt);
 
                 // The only kind of statement that we care about is assignments...
-                if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
+                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
                     let into = match place.local_or_deref_local() {
                         Some(into) => into,
                         None => {
@@ -583,11 +583,11 @@
                         Rvalue::Use(operand) => match operand {
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                             | Operand::Move(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                                 if *from == target =>
                             {
@@ -602,11 +602,11 @@
                         ) => match operand {
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                             | Operand::Move(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                                 if *from == target =>
                             {
@@ -639,7 +639,7 @@
                 if let TerminatorKind::Call {
                     destination: Some((Place {
                         base: PlaceBase::Local(dest),
-                        projection: None,
+                        projection: box [],
                     }, block)),
                     args,
                     ..
@@ -653,7 +653,7 @@
                     let found_target = args.iter().any(|arg| {
                         if let Operand::Move(Place {
                             base: PlaceBase::Local(potential),
-                            projection: None,
+                            projection: box [],
                         }) = arg {
                             *potential == target
                         } else {
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index 71106af..1d429e3 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -66,7 +66,7 @@
         self.check_activations(location);
 
         match statement.kind {
-            StatementKind::Assign(ref lhs, ref rhs) => {
+            StatementKind::Assign(box(ref lhs, ref rhs)) => {
                 self.consume_rvalue(
                     location,
                     rhs,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index da1f64b..1d17bae 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -421,107 +421,104 @@
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
 
-        place.iterate(|place_base, place_projection| {
-            let mut place_ty = match place_base {
-                PlaceBase::Local(index) =>
-                    PlaceTy::from_ty(self.body.local_decls[*index].ty),
-                PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
-                    let sty = self.sanitize_type(place, sty);
-                    let check_err =
-                        |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
-                         place: &Place<'tcx>,
-                         ty,
-                         sty| {
-                            if let Err(terr) = verifier.cx.eq_types(
-                                sty,
-                                ty,
-                                location.to_locations(),
-                                ConstraintCategory::Boring,
-                            ) {
-                                span_mirbug!(
-                                verifier,
-                                place,
-                                "bad promoted type ({:?}: {:?}): {:?}",
-                                ty,
-                                sty,
-                                terr
-                            );
-                            };
+        let mut place_ty = match &place.base {
+            PlaceBase::Local(index) =>
+                PlaceTy::from_ty(self.body.local_decls[*index].ty),
+            PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
+                let sty = self.sanitize_type(place, sty);
+                let check_err =
+                    |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+                     place: &Place<'tcx>,
+                     ty,
+                     sty| {
+                        if let Err(terr) = verifier.cx.eq_types(
+                            sty,
+                            ty,
+                            location.to_locations(),
+                            ConstraintCategory::Boring,
+                        ) {
+                            span_mirbug!(
+                            verifier,
+                            place,
+                            "bad promoted type ({:?}: {:?}): {:?}",
+                            ty,
+                            sty,
+                            terr
+                        );
                         };
-                    match kind {
-                        StaticKind::Promoted(promoted, _) => {
-                            if !self.errors_reported {
-                                let promoted_body = &self.promoted[*promoted];
-                                self.sanitize_promoted(promoted_body, location);
+                    };
+                match kind {
+                    StaticKind::Promoted(promoted, _) => {
+                        if !self.errors_reported {
+                            let promoted_body = &self.promoted[*promoted];
+                            self.sanitize_promoted(promoted_body, location);
 
-                                let promoted_ty = promoted_body.return_ty();
-                                check_err(self, place, promoted_ty, sty);
-                            }
-                        }
-                        StaticKind::Static => {
-                            let ty = self.tcx().type_of(*def_id);
-                            let ty = self.cx.normalize(ty, location);
-
-                            check_err(self, place, ty, sty);
+                            let promoted_ty = promoted_body.return_ty();
+                            check_err(self, place, promoted_ty, sty);
                         }
                     }
-                    PlaceTy::from_ty(sty)
-                }
-            };
+                    StaticKind::Static => {
+                        let ty = self.tcx().type_of(*def_id);
+                        let ty = self.cx.normalize(ty, location);
 
-            // FIXME use place_projection.is_empty() when is available
-            if place.projection.is_none() {
-                if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                    let is_promoted = match place {
-                        Place {
-                            base: PlaceBase::Static(box Static {
-                                kind: StaticKind::Promoted(..),
-                                ..
-                            }),
-                            projection: None,
-                        } => true,
-                        _ => false,
+                        check_err(self, place, ty, sty);
+                    }
+                }
+                PlaceTy::from_ty(sty)
+            }
+        };
+
+        if place.projection.is_empty() {
+            if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
+                let is_promoted = match place {
+                    Place {
+                        base: PlaceBase::Static(box Static {
+                            kind: StaticKind::Promoted(..),
+                            ..
+                        }),
+                        projection: box [],
+                    } => true,
+                    _ => false,
+                };
+
+                if !is_promoted {
+                    let tcx = self.tcx();
+                    let trait_ref = ty::TraitRef {
+                        def_id: tcx.lang_items().copy_trait().unwrap(),
+                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
                     };
 
-                    if !is_promoted {
-                        let tcx = self.tcx();
-                        let trait_ref = ty::TraitRef {
-                            def_id: tcx.lang_items().copy_trait().unwrap(),
-                            substs: tcx.mk_substs_trait(place_ty.ty, &[]),
-                        };
-
-                        // In order to have a Copy operand, the type T of the
-                        // value must be Copy. Note that we prove that T: Copy,
-                        // rather than using the `is_copy_modulo_regions`
-                        // test. This is important because
-                        // `is_copy_modulo_regions` ignores the resulting region
-                        // obligations and assumes they pass. This can result in
-                        // bounds from Copy impls being unsoundly ignored (e.g.,
-                        // #29149). Note that we decide to use Copy before knowing
-                        // whether the bounds fully apply: in effect, the rule is
-                        // that if a value of some type could implement Copy, then
-                        // it must.
-                        self.cx.prove_trait_ref(
-                            trait_ref,
-                            location.to_locations(),
-                            ConstraintCategory::CopyBound,
-                        );
-                    }
+                    // To have a `Copy` operand, the type `T` of the
+                    // value must be `Copy`. Note that we prove that `T: Copy`,
+                    // rather than using the `is_copy_modulo_regions`
+                    // test. This is important because
+                    // `is_copy_modulo_regions` ignores the resulting region
+                    // obligations and assumes they pass. This can result in
+                    // bounds from `Copy` impls being unsoundly ignored (e.g.,
+                    // #29149). Note that we decide to use `Copy` before knowing
+                    // whether the bounds fully apply: in effect, the rule is
+                    // that if a value of some type could implement `Copy`, then
+                    // it must.
+                    self.cx.prove_trait_ref(
+                        trait_ref,
+                        location.to_locations(),
+                        ConstraintCategory::CopyBound,
+                    );
                 }
             }
+        }
 
-            for proj in place_projection {
-                if place_ty.variant_index.is_none() {
-                    if place_ty.ty.references_error() {
-                        assert!(self.errors_reported);
-                        return PlaceTy::from_ty(self.tcx().types.err);
-                    }
+        for elem in place.projection.iter() {
+            if place_ty.variant_index.is_none() {
+                if place_ty.ty.references_error() {
+                    assert!(self.errors_reported);
+                    return PlaceTy::from_ty(self.tcx().types.err);
                 }
-                place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
             }
+            place_ty = self.sanitize_projection(place_ty, elem, place, location)
+        }
 
-            place_ty
-        })
+        place_ty
     }
 
     fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
@@ -1346,7 +1343,7 @@
         debug!("check_stmt: {:?}", stmt);
         let tcx = self.tcx();
         match stmt.kind {
-            StatementKind::Assign(ref place, ref rv) => {
+            StatementKind::Assign(box(ref place, ref rv)) => {
                 // Assignments to temporaries are not "interesting";
                 // they are not caused by the user, but rather artifacts
                 // of lowering. Assignments to other sorts of places *are* interesting
@@ -1354,7 +1351,7 @@
                 let category = match *place {
                     Place {
                         base: PlaceBase::Local(RETURN_PLACE),
-                        projection: None,
+                        projection: box [],
                     } => if let BorrowCheckContext {
                         universal_regions:
                             UniversalRegions {
@@ -1373,7 +1370,7 @@
                     },
                     Place {
                         base: PlaceBase::Local(l),
-                        projection: None,
+                        projection: box [],
                     } if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -1453,7 +1450,7 @@
                     );
                 };
             }
-            StatementKind::AscribeUserType(ref place, variance, box ref projection) => {
+            StatementKind::AscribeUserType(box(ref place, ref projection), variance) => {
                 let place_ty = place.ty(body, tcx).ty;
                 if let Err(terr) = self.relate_type_and_user_type(
                     place_ty,
@@ -1660,7 +1657,7 @@
                 let category = match *dest {
                     Place {
                         base: PlaceBase::Local(RETURN_PLACE),
-                        projection: None,
+                        projection: box [],
                     } => {
                         if let BorrowCheckContext {
                             universal_regions:
@@ -1682,7 +1679,7 @@
                     }
                     Place {
                         base: PlaceBase::Local(l),
-                        projection: None,
+                        projection: box [],
                     } if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -2416,19 +2413,18 @@
         // *p`, where the `p` has type `&'b mut Foo`, for example, we
         // need to ensure that `'b: 'a`.
 
-        let mut borrowed_projection = &borrowed_place.projection;
-
         debug!(
             "add_reborrow_constraint({:?}, {:?}, {:?})",
             location, borrow_region, borrowed_place
         );
-        while let Some(box proj) = borrowed_projection {
-            debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
+        for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
+            debug!("add_reborrow_constraint - iteration {:?}", elem);
+            let proj_base = &borrowed_place.projection[..i];
 
-            match proj.elem {
+            match elem {
                 ProjectionElem::Deref => {
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty;
+                    let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.sty {
@@ -2490,10 +2486,6 @@
                     // other field access
                 }
             }
-
-            // The "propagate" case. We need to check that our base is valid
-            // for the borrow's lifetime.
-            borrowed_projection = &proj.base;
         }
     }
 
diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index 5caba63..411fa5b 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -25,55 +25,54 @@
         body: &Body<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
-        self.iterate(|place_base, place_projection| {
-            let ignore = match place_base {
-                // If a local variable is immutable, then we only need to track borrows to guard
-                // against two kinds of errors:
-                // * The variable being dropped while still borrowed (e.g., because the fn returns
-                //   a reference to a local variable)
-                // * The variable being moved while still borrowed
-                //
-                // In particular, the variable cannot be mutated -- the "access checks" will fail --
-                // so we don't have to worry about mutation while borrowed.
-                PlaceBase::Local(index) => {
-                    match locals_state_at_exit {
-                        LocalsStateAtExit::AllAreInvalidated => false,
-                        LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
-                            let ignore = !has_storage_dead_or_moved.contains(*index) &&
-                                body.local_decls[*index].mutability == Mutability::Not;
-                            debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
-                            ignore
-                        }
-                    }
-                }
-                PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
-                    false,
-                PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
-                    tcx.is_mutable_static(*def_id)
-                }
-            };
-
-            for proj in place_projection {
-                if proj.elem == ProjectionElem::Deref {
-                    let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
-                    match ty.sty {
-                        // For both derefs of raw pointers and `&T`
-                        // references, the original path is `Copy` and
-                        // therefore not significant.  In particular,
-                        // there is nothing the user can do to the
-                        // original path that would invalidate the
-                        // newly created reference -- and if there
-                        // were, then the user could have copied the
-                        // original path into a new variable and
-                        // borrowed *that* one, leaving the original
-                        // path unborrowed.
-                        ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
-                        _ => {}
+        let ignore = match self.base {
+            // If a local variable is immutable, then we only need to track borrows to guard
+            // against two kinds of errors:
+            // * The variable being dropped while still borrowed (e.g., because the fn returns
+            //   a reference to a local variable)
+            // * The variable being moved while still borrowed
+            //
+            // In particular, the variable cannot be mutated -- the "access checks" will fail --
+            // so we don't have to worry about mutation while borrowed.
+            PlaceBase::Local(index) => {
+                match locals_state_at_exit {
+                    LocalsStateAtExit::AllAreInvalidated => false,
+                    LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
+                        let ignore = !has_storage_dead_or_moved.contains(index) &&
+                            body.local_decls[index].mutability == Mutability::Not;
+                        debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
+                        ignore
                     }
                 }
             }
+            PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
+                false,
+            PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
+                tcx.is_mutable_static(def_id)
+            }
+        };
 
-            ignore
-        })
+        for (i, elem) in self.projection.iter().enumerate() {
+            let proj_base = &self.projection[..i];
+
+            if *elem == ProjectionElem::Deref {
+                let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
+                if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.sty {
+                    // For both derefs of raw pointers and `&T`
+                    // references, the original path is `Copy` and
+                    // therefore not significant.  In particular,
+                    // there is nothing the user can do to the
+                    // original path that would invalidate the
+                    // newly created reference -- and if there
+                    // were, then the user could have copied the
+                    // original path into a new variable and
+                    // borrowed *that* one, leaving the original
+                    // path unborrowed.
+                    return true;
+                }
+            }
+        }
+
+        ignore
     }
 }
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 4f46917..dafa0b6 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -3,8 +3,7 @@
 use crate::borrow_check::{Deep, Shallow, AccessDepth};
 use rustc::hir;
 use rustc::mir::{
-    Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
-    StaticKind,
+    Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
 };
 use rustc::ty::{self, TyCtxt};
 use std::cmp::max;
@@ -67,39 +66,35 @@
     // it's so common that it's a speed win to check for it first.
     if let Place {
         base: PlaceBase::Local(l1),
-        projection: None,
+        projection: box [],
     } = borrow_place {
         if let PlaceRef {
             base: PlaceBase::Local(l2),
-            projection: None,
+            projection: [],
         } = access_place {
             return l1 == l2;
         }
     }
 
-    borrow_place.iterate(|borrow_base, borrow_projections| {
-        access_place.iterate(|access_base, access_projections| {
-            place_components_conflict(
-                tcx,
-                param_env,
-                body,
-                (borrow_base, borrow_projections),
-                borrow_kind,
-                (access_base, access_projections),
-                access,
-                bias,
-            )
-        })
-    })
+    place_components_conflict(
+        tcx,
+        param_env,
+        body,
+        borrow_place,
+        borrow_kind,
+        access_place,
+        access,
+        bias,
+    )
 }
 
 fn place_components_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
-    borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
+    borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
-    access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
+    access_place: PlaceRef<'_, 'tcx>,
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
@@ -145,8 +140,8 @@
     //    and either equal or disjoint.
     //  - If we did run out of access, the borrow can access a part of it.
 
-    let borrow_base = borrow_projections.0;
-    let access_base = access_projections.0;
+    let borrow_base = &borrow_place.base;
+    let access_base = access_place.base;
 
     match place_base_conflict(tcx, param_env, borrow_base, access_base) {
         Overlap::Arbitrary => {
@@ -163,147 +158,157 @@
         }
     }
 
-    let mut borrow_projections = borrow_projections.1;
-    let mut access_projections = access_projections.1;
+    // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
+    for (i, (borrow_c, access_c)) in
+        borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
+    {
+        debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
+        let borrow_proj_base = &borrow_place.projection[..i];
 
-    loop {
-        // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
-        if let Some(borrow_c) = borrow_projections.next() {
-            debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
+        debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
 
-            if let Some(access_c) = access_projections.next() {
-                debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
-
-                // Borrow and access path both have more components.
+        // Borrow and access path both have more components.
+        //
+        // Examples:
+        //
+        // - borrow of `a.(...)`, access to `a.(...)`
+        // - borrow of `a.(...)`, access to `b.(...)`
+        //
+        // Here we only see the components we have checked so
+        // far (in our examples, just the first component). We
+        // check whether the components being borrowed vs
+        // accessed are disjoint (as in the second example,
+        // but not the first).
+        match place_projection_conflict(
+            tcx,
+            body,
+            borrow_base,
+            borrow_proj_base,
+            borrow_c,
+            access_c,
+            bias,
+        ) {
+            Overlap::Arbitrary => {
+                // We have encountered different fields of potentially
+                // the same union - the borrow now partially overlaps.
                 //
-                // Examples:
+                // There is no *easy* way of comparing the fields
+                // further on, because they might have different types
+                // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
+                // `.y` come from different structs).
                 //
-                // - borrow of `a.(...)`, access to `a.(...)`
-                // - borrow of `a.(...)`, access to `b.(...)`
-                //
-                // Here we only see the components we have checked so
-                // far (in our examples, just the first component). We
-                // check whether the components being borrowed vs
-                // accessed are disjoint (as in the second example,
-                // but not the first).
-                match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) {
-                    Overlap::Arbitrary => {
-                        // We have encountered different fields of potentially
-                        // the same union - the borrow now partially overlaps.
-                        //
-                        // There is no *easy* way of comparing the fields
-                        // further on, because they might have different types
-                        // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
-                        // `.y` come from different structs).
-                        //
-                        // We could try to do some things here - e.g., count
-                        // dereferences - but that's probably not a good
-                        // idea, at least for now, so just give up and
-                        // report a conflict. This is unsafe code anyway so
-                        // the user could always use raw pointers.
-                        debug!("borrow_conflicts_with_place: arbitrary -> conflict");
-                        return true;
-                    }
-                    Overlap::EqualOrDisjoint => {
-                        // This is the recursive case - proceed to the next element.
-                    }
-                    Overlap::Disjoint => {
-                        // We have proven the borrow disjoint - further
-                        // projections will remain disjoint.
-                        debug!("borrow_conflicts_with_place: disjoint");
-                        return false;
-                    }
-                }
-            } else {
-                // Borrow path is longer than the access path. Examples:
-                //
-                // - borrow of `a.b.c`, access to `a.b`
-                //
-                // Here, we know that the borrow can access a part of
-                // our place. This is a conflict if that is a part our
-                // access cares about.
-
-                let base = &borrow_c.base;
-                let elem = &borrow_c.elem;
-                let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty;
-
-                match (elem, &base_ty.sty, access) {
-                    (_, _, Shallow(Some(ArtificialField::ArrayLength)))
-                    | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
-                        // The array length is like  additional fields on the
-                        // type; it does not overlap any existing data there.
-                        // Furthermore, if cannot actually be a prefix of any
-                        // borrowed place (at least in MIR as it is currently.)
-                        //
-                        // e.g., a (mutable) borrow of `a[5]` while we read the
-                        // array length of `a`.
-                        debug!("borrow_conflicts_with_place: implicit field");
-                        return false;
-                    }
-
-                    (ProjectionElem::Deref, _, Shallow(None)) => {
-                        // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
-                        // prefix thereof - the shallow access can't touch anything behind
-                        // the pointer.
-                        debug!("borrow_conflicts_with_place: shallow access behind ptr");
-                        return false;
-                    }
-                    (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
-                        // Shouldn't be tracked
-                        bug!("Tracking borrow behind shared reference.");
-                    }
-                    (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
-                        // Values behind a mutable reference are not access either by dropping a
-                        // value, or by StorageDead
-                        debug!("borrow_conflicts_with_place: drop access behind ptr");
-                        return false;
-                    }
-
-                    (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
-                        // Drop can read/write arbitrary projections, so places
-                        // conflict regardless of further projections.
-                        if def.has_dtor(tcx) {
-                            return true;
-                        }
-                    }
-
-                    (ProjectionElem::Deref, _, Deep)
-                    | (ProjectionElem::Deref, _, AccessDepth::Drop)
-                    | (ProjectionElem::Field { .. }, _, _)
-                    | (ProjectionElem::Index { .. }, _, _)
-                    | (ProjectionElem::ConstantIndex { .. }, _, _)
-                    | (ProjectionElem::Subslice { .. }, _, _)
-                    | (ProjectionElem::Downcast { .. }, _, _) => {
-                        // Recursive case. This can still be disjoint on a
-                        // further iteration if this a shallow access and
-                        // there's a deref later on, e.g., a borrow
-                        // of `*x.y` while accessing `x`.
-                    }
-                }
-            }
-        } else {
-            // Borrow path ran out but access path may not
-            // have. Examples:
-            //
-            // - borrow of `a.b`, access to `a.b.c`
-            // - borrow of `a.b`, access to `a.b`
-            //
-            // In the first example, where we didn't run out of
-            // access, the borrow can access all of our place, so we
-            // have a conflict.
-            //
-            // If the second example, where we did, then we still know
-            // that the borrow can access a *part* of our place that
-            // our access cares about, so we still have a conflict.
-            if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() {
-                debug!("borrow_conflicts_with_place: shallow borrow");
-                return false;
-            } else {
-                debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
+                // We could try to do some things here - e.g., count
+                // dereferences - but that's probably not a good
+                // idea, at least for now, so just give up and
+                // report a conflict. This is unsafe code anyway so
+                // the user could always use raw pointers.
+                debug!("borrow_conflicts_with_place: arbitrary -> conflict");
                 return true;
             }
+            Overlap::EqualOrDisjoint => {
+                // This is the recursive case - proceed to the next element.
+            }
+            Overlap::Disjoint => {
+                // We have proven the borrow disjoint - further
+                // projections will remain disjoint.
+                debug!("borrow_conflicts_with_place: disjoint");
+                return false;
+            }
         }
     }
+
+    if borrow_place.projection.len() > access_place.projection.len() {
+        for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
+        {
+            // Borrow path is longer than the access path. Examples:
+            //
+            // - borrow of `a.b.c`, access to `a.b`
+            //
+            // Here, we know that the borrow can access a part of
+            // our place. This is a conflict if that is a part our
+            // access cares about.
+
+            let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
+            let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
+
+            match (elem, &base_ty.sty, access) {
+                (_, _, Shallow(Some(ArtificialField::ArrayLength)))
+                | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
+                    // The array length is like  additional fields on the
+                    // type; it does not overlap any existing data there.
+                    // Furthermore, if cannot actually be a prefix of any
+                    // borrowed place (at least in MIR as it is currently.)
+                    //
+                    // e.g., a (mutable) borrow of `a[5]` while we read the
+                    // array length of `a`.
+                    debug!("borrow_conflicts_with_place: implicit field");
+                    return false;
+                }
+
+                (ProjectionElem::Deref, _, Shallow(None)) => {
+                    // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
+                    // prefix thereof - the shallow access can't touch anything behind
+                    // the pointer.
+                    debug!("borrow_conflicts_with_place: shallow access behind ptr");
+                    return false;
+                }
+                (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
+                    // Shouldn't be tracked
+                    bug!("Tracking borrow behind shared reference.");
+                }
+                (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
+                    // Values behind a mutable reference are not access either by dropping a
+                    // value, or by StorageDead
+                    debug!("borrow_conflicts_with_place: drop access behind ptr");
+                    return false;
+                }
+
+                (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
+                    // Drop can read/write arbitrary projections, so places
+                    // conflict regardless of further projections.
+                    if def.has_dtor(tcx) {
+                        return true;
+                    }
+                }
+
+                (ProjectionElem::Deref, _, Deep)
+                | (ProjectionElem::Deref, _, AccessDepth::Drop)
+                | (ProjectionElem::Field { .. }, _, _)
+                | (ProjectionElem::Index { .. }, _, _)
+                | (ProjectionElem::ConstantIndex { .. }, _, _)
+                | (ProjectionElem::Subslice { .. }, _, _)
+                | (ProjectionElem::Downcast { .. }, _, _) => {
+                    // Recursive case. This can still be disjoint on a
+                    // further iteration if this a shallow access and
+                    // there's a deref later on, e.g., a borrow
+                    // of `*x.y` while accessing `x`.
+                }
+            }
+        }
+    }
+
+    // Borrow path ran out but access path may not
+    // have. Examples:
+    //
+    // - borrow of `a.b`, access to `a.b.c`
+    // - borrow of `a.b`, access to `a.b`
+    //
+    // In the first example, where we didn't run out of
+    // access, the borrow can access all of our place, so we
+    // have a conflict.
+    //
+    // If the second example, where we did, then we still know
+    // that the borrow can access a *part* of our place that
+    // our access cares about, so we still have a conflict.
+    if borrow_kind == BorrowKind::Shallow
+        && borrow_place.projection.len() < access_place.projection.len()
+    {
+        debug!("borrow_conflicts_with_place: shallow borrow");
+        false
+    } else {
+        debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
+        true
+    }
 }
 
 // Given that the bases of `elem1` and `elem2` are always either equal
@@ -381,11 +386,12 @@
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     pi1_base: &PlaceBase<'tcx>,
-    pi1: &Projection<'tcx>,
-    pi2: &Projection<'tcx>,
+    pi1_proj_base: &[PlaceElem<'tcx>],
+    pi1_elem: &PlaceElem<'tcx>,
+    pi2_elem: &PlaceElem<'tcx>,
     bias: PlaceConflictBias,
 ) -> Overlap {
-    match (&pi1.elem, &pi2.elem) {
+    match (pi1_elem, pi2_elem) {
         (ProjectionElem::Deref, ProjectionElem::Deref) => {
             // derefs (e.g., `*x` vs. `*x`) - recur.
             debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
@@ -397,7 +403,7 @@
                 debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
                 Overlap::EqualOrDisjoint
             } else {
-                let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
+                let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
                 match ty.sty {
                     ty::Adt(def, _) if def.is_union() => {
                         // Different fields of a union, we are basically stuck.
@@ -493,7 +499,7 @@
             // element (like -1 in Python) and `min_length` the first.
             // Therefore, `min_length - offset_from_end` gives the minimal possible
             // offset from the beginning
-            if *offset_from_begin >= min_length - offset_from_end {
+            if *offset_from_begin >= *min_length - *offset_from_end {
                 debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
                 Overlap::EqualOrDisjoint
             } else {
@@ -538,8 +544,8 @@
         | (ProjectionElem::Subslice { .. }, _)
         | (ProjectionElem::Downcast(..), _) => bug!(
             "mismatched projections in place_element_conflict: {:?} and {:?}",
-            pi1,
-            pi2
+            pi1_elem,
+            pi2_elem
         ),
     }
 }
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 4c6be23..0a268ec 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -19,17 +19,9 @@
 
 impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
-        let mut cursor = other.projection;
-        loop {
-            if self.projection == cursor {
-                return self.base == other.base;
-            }
-
-            match cursor {
-                None => return false,
-                Some(proj) => cursor = &proj.base,
-            }
-        }
+        self.base == other.base
+            && self.projection.len() <= other.projection.len()
+            && self.projection == &other.projection[..self.projection.len()]
     }
 }
 
@@ -81,112 +73,113 @@
         // downcasts here, but may return a base of a downcast).
 
         'cursor: loop {
-            let proj = match &cursor {
+            match &cursor {
                 PlaceRef {
                     base: PlaceBase::Local(_),
-                    projection: None,
+                    projection: [],
                 }
                 | // search yielded this leaf
                 PlaceRef {
                     base: PlaceBase::Static(_),
-                    projection: None,
+                    projection: [],
                 } => {
                     self.next = None;
                     return Some(cursor);
                 }
                 PlaceRef {
                     base: _,
-                    projection: Some(proj),
-                } => proj,
-            };
+                    projection: [proj_base @ .., elem],
+                } => {
+                    match elem {
+                        ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
+                            // FIXME: add union handling
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+                        ProjectionElem::Downcast(..) |
+                        ProjectionElem::Subslice { .. } |
+                        ProjectionElem::ConstantIndex { .. } |
+                        ProjectionElem::Index(_) => {
+                            cursor = PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            };
+                            continue 'cursor;
+                        }
+                        ProjectionElem::Deref => {
+                            // (handled below)
+                        }
+                    }
 
-            match proj.elem {
-                ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
-                    // FIXME: add union handling
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-                ProjectionElem::Downcast(..) |
-                ProjectionElem::Subslice { .. } |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Index(_) => {
-                    cursor = PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    };
-                    continue 'cursor;
-                }
-                ProjectionElem::Deref => {
-                    // (handled below)
-                }
-            }
+                    assert_eq!(*elem, ProjectionElem::Deref);
 
-            assert_eq!(proj.elem, ProjectionElem::Deref);
+                    match self.kind {
+                        PrefixSet::Shallow => {
+                            // Shallow prefixes are found by stripping away
+                            // fields, but stop at *any* dereference.
+                            // So we can just stop the traversal now.
+                            self.next = None;
+                            return Some(cursor);
+                        }
+                        PrefixSet::All => {
+                            // All prefixes: just blindly enqueue the base
+                            // of the projection.
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+                        PrefixSet::Supporting => {
+                            // Fall through!
+                        }
+                    }
 
-            match self.kind {
-                PrefixSet::Shallow => {
-                    // shallow prefixes are found by stripping away
-                    // fields, but stop at *any* dereference.
-                    // So we can just stop the traversal now.
-                    self.next = None;
-                    return Some(cursor);
-                }
-                PrefixSet::All => {
-                    // all prefixes: just blindly enqueue the base
-                    // of the projection.
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-                PrefixSet::Supporting => {
-                    // fall through!
-                }
-            }
+                    assert_eq!(self.kind, PrefixSet::Supporting);
+                    // Supporting prefixes: strip away fields and
+                    // derefs, except we stop at the deref of a shared
+                    // reference.
 
-            assert_eq!(self.kind, PrefixSet::Supporting);
-            // supporting prefixes: strip away fields and
-            // derefs, except we stop at the deref of a shared
-            // reference.
+                    let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
+                    match ty.sty {
+                        ty::RawPtr(_) |
+                        ty::Ref(
+                            _, /*rgn*/
+                            _, /*ty*/
+                            hir::MutImmutable
+                            ) => {
+                            // don't continue traversing over derefs of raw pointers or shared
+                            // borrows.
+                            self.next = None;
+                            return Some(cursor);
+                        }
 
-            let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
-            match ty.sty {
-                ty::RawPtr(_) |
-                ty::Ref(
-                    _, /*rgn*/
-                    _, /*ty*/
-                    hir::MutImmutable
-                    ) => {
-                    // don't continue traversing over derefs of raw pointers or shared borrows.
-                    self.next = None;
-                    return Some(cursor);
+                        ty::Ref(
+                            _, /*rgn*/
+                            _, /*ty*/
+                            hir::MutMutable,
+                            ) => {
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+
+                        ty::Adt(..) if ty.is_box() => {
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+
+                        _ => panic!("unknown type fed to Projection Deref."),
+                    }
                 }
-
-                ty::Ref(
-                    _, /*rgn*/
-                    _, /*ty*/
-                    hir::MutMutable,
-                    ) => {
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-
-                ty::Adt(..) if ty.is_box() => {
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-
-                _ => panic!("unknown type fed to Projection Deref."),
             }
         }
     }
diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs
index 2587d14..695080d 100644
--- a/src/librustc_mir/borrow_check/used_muts.rs
+++ b/src/librustc_mir/borrow_check/used_muts.rs
@@ -89,7 +89,7 @@
         _location: Location,
     ) {
         match &statement.kind {
-            StatementKind::Assign(into, _) => {
+            StatementKind::Assign(box(into, _)) => {
                 if let PlaceBase::Local(local) = into.base {
                     debug!(
                         "visit_statement: statement={:?} local={:?} \
@@ -120,7 +120,7 @@
                 );
                 if let Place {
                     base: PlaceBase::Local(user_local),
-                    projection: None,
+                    projection: box [],
                 } = path.place {
                     self.mbcx.used_mut.insert(user_local);
                 }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 778d1e7..3ed6b4f 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -37,7 +37,7 @@
                        rvalue: Rvalue<'tcx>) {
         self.push(block, Statement {
             source_info,
-            kind: StatementKind::Assign(place.clone(), box rvalue)
+            kind: StatementKind::Assign(box(place.clone(), rvalue))
         });
     }
 
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 98cf4bb..09b33c6 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -129,7 +129,7 @@
                     kind: StaticKind::Static,
                     def_id: id,
                 })),
-                projection: None,
+                projection: box [],
             }),
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
@@ -147,9 +147,11 @@
                         Statement {
                             source_info,
                             kind: StatementKind::AscribeUserType(
-                                place.clone(),
+                                box(
+                                    place.clone(),
+                                    UserTypeProjection { base: annotation_index, projs: vec![], }
+                                ),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
@@ -174,9 +176,11 @@
                         Statement {
                             source_info,
                             kind: StatementKind::AscribeUserType(
-                                Place::from(temp.clone()),
+                                box(
+                                    Place::from(temp.clone()),
+                                    UserTypeProjection { base: annotation_index, projs: vec![], },
+                                ),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 1a186fa..7dfe98c 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -500,14 +500,11 @@
         let mutability = match arg_place {
             Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             } => this.local_decls[local].mutability,
             Place {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                })
+                projection: box [ProjectionElem::Deref],
             } => {
                 debug_assert!(
                     this.local_decls[local].is_ref_for_guard(),
@@ -517,24 +514,19 @@
             }
             Place {
                 ref base,
-                projection: Some(box Projection {
-                    base: ref base_proj,
-                    elem: ProjectionElem::Field(upvar_index, _),
-                }),
+                projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             }
             | Place {
                 ref base,
-                projection: Some(box Projection {
-                    base: Some(box Projection {
-                        base: ref base_proj,
-                        elem: ProjectionElem::Field(upvar_index, _),
-                    }),
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: box [
+                    ref proj_base @ ..,
+                    ProjectionElem::Field(upvar_index, _),
+                    ProjectionElem::Deref
+                ],
             } => {
                 let place = PlaceRef {
                     base,
-                    projection: base_proj,
+                    projection: proj_base,
                 };
 
                 // Not projected from the implicit `self` in a closure.
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 889861b..45f4a16 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -301,7 +301,7 @@
                 // Create a "fake" temporary variable so that we check that the
                 // value is Sized. Usually, this is caught in type checking, but
                 // in the case of box expr there is no such check.
-                if destination.projection.is_some() {
+                if !destination.projection.is_empty() {
                     this.local_decls
                         .push(LocalDecl::new_temp(expr.ty, expr.span));
                 }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index f949b52..aa261f8 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -135,7 +135,7 @@
             source_info,
             kind: StatementKind::FakeRead(
                 FakeReadCause::ForMatchedPlace,
-                scrutinee_place.clone(),
+                box(scrutinee_place.clone()),
             ),
         });
 
@@ -320,7 +320,7 @@
                     block,
                     Statement {
                         source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
                     },
                 );
 
@@ -362,12 +362,12 @@
                     block,
                     Statement {
                         source_info: pattern_source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
                     },
                 );
 
                 let ty_source_info = self.source_info(user_ty_span);
-                let user_ty = box pat_ascription_ty.user_ty(
+                let user_ty = pat_ascription_ty.user_ty(
                     &mut self.canonical_user_type_annotations,
                     place.ty(&self.local_decls, self.hir.tcx()).ty,
                     ty_source_info.span,
@@ -377,7 +377,10 @@
                     Statement {
                         source_info: ty_source_info,
                         kind: StatementKind::AscribeUserType(
-                            place,
+                            box(
+                                place,
+                                user_ty,
+                            ),
                             // We always use invariant as the variance here. This is because the
                             // variance field from the ascription refers to the variance to use
                             // when applying the type to the value being matched, but this
@@ -393,7 +396,6 @@
                             // contrast, is intended to be used to relate `T` to the type of
                             // `<expr>`.
                             ty::Variance::Invariant,
-                            user_ty,
                         ),
                     },
                 );
@@ -942,16 +944,15 @@
             for Binding { source, .. }
                 in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
             {
-                let mut cursor = &source.projection;
-                while let Some(box Projection { base, elem }) = cursor {
-                    cursor = base;
-                    if let ProjectionElem::Deref = elem {
-                        fake_borrows.insert(Place {
-                            base: source.base.clone(),
-                            projection: cursor.clone(),
-                        });
-                        break;
-                    }
+                if let Some(i) =
+                    source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
+                {
+                    let proj_base = &source.projection[..i];
+
+                    fake_borrows.insert(Place {
+                        base: source.base.clone(),
+                        projection: proj_base.to_vec().into_boxed_slice(),
+                    });
                 }
             }
         }
@@ -1295,18 +1296,18 @@
         // Insert a Shallow borrow of the prefixes of any fake borrows.
         for place in fake_borrows
         {
-            let mut prefix_cursor = &place.projection;
-            while let Some(box Projection { base, elem }) = prefix_cursor {
+            for (i, elem) in place.projection.iter().enumerate().rev() {
+                let proj_base = &place.projection[..i];
+
                 if let ProjectionElem::Deref = elem {
                     // Insert a shallow borrow after a deref. For other
                     // projections the borrow of prefix_cursor will
                     // conflict with any mutation of base.
                     all_fake_borrows.push(PlaceRef {
                         base: &place.base,
-                        projection: base,
+                        projection: proj_base,
                     });
                 }
-                prefix_cursor = base;
             }
 
             all_fake_borrows.push(place.as_ref());
@@ -1489,7 +1490,7 @@
                     BorrowKind::Shallow,
                     Place {
                         base: place.base.clone(),
-                        projection: place.projection.clone(),
+                        projection: place.projection.to_vec().into_boxed_slice(),
                     },
                 );
                 self.cfg.push_assign(
@@ -1520,7 +1521,7 @@
                     source_info: guard_end,
                     kind: StatementKind::FakeRead(
                         FakeReadCause::ForMatchGuard,
-                        Place::from(temp),
+                        box(Place::from(temp)),
                     ),
                 });
             }
@@ -1570,7 +1571,7 @@
                     post_guard_block,
                     Statement {
                         source_info: guard_end,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
                     },
                 );
             }
@@ -1603,7 +1604,7 @@
                 ascription.user_ty,
             );
 
-            let user_ty = box ascription.user_ty.clone().user_ty(
+            let user_ty = ascription.user_ty.clone().user_ty(
                 &mut self.canonical_user_type_annotations,
                 ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
                 source_info.span
@@ -1613,9 +1614,11 @@
                 Statement {
                     source_info,
                     kind: StatementKind::AscribeUserType(
-                        ascription.source.clone(),
+                        box(
+                            ascription.source.clone(),
+                            user_ty,
+                        ),
                         ascription.variance,
-                        user_ty,
                     ),
                 },
             );
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 7ab0bf7..647d751 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -609,7 +609,7 @@
         unpack!(block = builder.in_breakable_scope(
             None,
             START_BLOCK,
-            Place::RETURN_PLACE,
+            Place::return_place(),
             |builder| {
                 builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
                     builder.args_and_body(block, &arguments, arg_scope, &body.value)
@@ -670,7 +670,7 @@
     let mut block = START_BLOCK;
     let ast_expr = &tcx.hir().body(body_id).value;
     let expr = builder.hir.mirror(ast_expr);
-    unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
+    unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -871,7 +871,7 @@
         }
 
         let body = self.hir.mirror(ast_body);
-        self.into(&Place::RETURN_PLACE, block, body)
+        self.into(&Place::return_place(), block, body)
     }
 
     fn set_correct_source_scope_for_arg(
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index a04c041..ee6d42d 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -314,7 +314,7 @@
         match target {
             BreakableTarget::Return => {
                 let scope = &self.breakable_scopes[0];
-                if scope.break_destination != Place::RETURN_PLACE {
+                if scope.break_destination != Place::return_place() {
                     span_bug!(span, "`return` in item with no return scope");
                 }
                 (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
@@ -853,11 +853,11 @@
             _ if self.local_scope().is_none() => (),
             Operand::Copy(Place {
                 base: PlaceBase::Local(cond_temp),
-                projection: None,
+                projection: box [],
             })
             | Operand::Move(Place {
                 base: PlaceBase::Local(cond_temp),
-                projection: None,
+                projection: box [],
             }) => {
                 // Manually drop the condition on both branches.
                 let top_scope = self.scopes.scopes.last_mut().unwrap();
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 3e02497..57ddaa4 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -589,7 +589,7 @@
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
-    // see comment in const_eval_provider for what we're doing here
+    // see comment in const_eval_raw_provider for what we're doing here
     if key.param_env.reveal == Reveal::All {
         let mut key = key.clone();
         key.param_env.reveal = Reveal::UserFacing;
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index c071b31..444cc00 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -10,19 +10,17 @@
                                         path: MovePathIndex,
                                         mut cond: F)
                                         -> Option<MovePathIndex>
-    where F: FnMut(&mir::Projection<'tcx>) -> bool
+    where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
 {
     let mut next_child = move_data.move_paths[path].first_child;
     while let Some(child_index) = next_child {
-        match move_data.move_paths[child_index].place.projection {
-            Some(ref proj) => {
-                if cond(proj) {
-                    return Some(child_index)
-                }
+        let move_path_children = &move_data.move_paths[child_index];
+        if let Some(elem) = move_path_children.place.projection.last() {
+            if cond(elem) {
+                return Some(child_index)
             }
-            _ => {}
         }
-        next_child = move_data.move_paths[child_index].next_sibling;
+        next_child = move_path_children.next_sibling;
     }
 
     None
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 2ea6c4a..a86fcb3 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -208,7 +208,7 @@
             // If the borrowed place is a local with no projections, all other borrows of this
             // local must conflict. This is purely an optimization so we don't have to call
             // `places_conflict` for every borrow.
-            if place.projection.is_none() {
+            if place.projection.is_empty() {
                 trans.kill_all(other_borrows_of_local);
                 return;
             }
@@ -268,8 +268,8 @@
 
         debug!("Borrows::statement_effect: stmt={:?}", stmt);
         match stmt.kind {
-            mir::StatementKind::Assign(ref lhs, ref rhs) => {
-                if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
+            mir::StatementKind::Assign(box(ref lhs, ref rhs)) => {
+                if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
                     if place.ignore_borrow(
                         self.tcx,
                         self.body,
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index 0e01701..0f66b13 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -119,8 +119,8 @@
         match stmt.kind {
             StatementKind::StorageLive(l) => sets.gen(l),
             StatementKind::StorageDead(l) => sets.kill(l),
-            StatementKind::Assign(ref place, _)
-            | StatementKind::SetDiscriminant { ref place, .. } => {
+            StatementKind::Assign(box(ref place, _))
+            | StatementKind::SetDiscriminant { box ref place, .. } => {
                 if let PlaceBase::Local(local) = place.base {
                     sets.gen(local);
                 }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 81451c2..698c501 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -94,72 +94,74 @@
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
         debug!("lookup({:?})", place);
-        place.iterate(|place_base, place_projection| {
-            let mut base = match place_base {
-                PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
-                PlaceBase::Static(..) => {
-                    return Err(MoveError::cannot_move_out_of(self.loc, Static));
+        let mut base = match place.base {
+            PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
+            PlaceBase::Static(..) => {
+                return Err(MoveError::cannot_move_out_of(self.loc, Static));
+            }
+        };
+
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+            let body = self.builder.body;
+            let tcx = self.builder.tcx;
+            let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
+            match place_ty.sty {
+                ty::Ref(..) | ty::RawPtr(..) => {
+                    let proj = &place.projection[..i+1];
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        BorrowedContent {
+                            target_place: Place {
+                                base: place.base.clone(),
+                                projection: proj.to_vec().into_boxed_slice(),
+                            },
+                        },
+                    ));
                 }
+                ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        InteriorOfTypeWithDestructor { container_ty: place_ty },
+                    ));
+                }
+                // move out of union - always move the entire union
+                ty::Adt(adt, _) if adt.is_union() => {
+                    return Err(MoveError::UnionMove { path: base });
+                }
+                ty::Slice(_) => {
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        InteriorOfSliceOrArray {
+                            ty: place_ty,
+                            is_index: match elem {
+                                ProjectionElem::Index(..) => true,
+                                _ => false,
+                            },
+                        },
+                    ));
+                }
+                ty::Array(..) => match elem {
+                    ProjectionElem::Index(..) => {
+                        return Err(MoveError::cannot_move_out_of(
+                            self.loc,
+                            InteriorOfSliceOrArray { ty: place_ty, is_index: true },
+                        ));
+                    }
+                    _ => {
+                        // FIXME: still badly broken
+                    }
+                },
+                _ => {}
             };
 
-            for proj in place_projection {
-                let body = self.builder.body;
-                let tcx = self.builder.tcx;
-                let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
-                match place_ty.sty {
-                    ty::Ref(..) | ty::RawPtr(..) => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            BorrowedContent {
-                                target_place: Place {
-                                    base: place_base.clone(),
-                                    projection: Some(Box::new(proj.clone())),
-                                },
-                            },
-                        ));
-                    }
-                    ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            InteriorOfTypeWithDestructor { container_ty: place_ty },
-                        ));
-                    }
-                    // move out of union - always move the entire union
-                    ty::Adt(adt, _) if adt.is_union() => {
-                        return Err(MoveError::UnionMove { path: base });
-                    }
-                    ty::Slice(_) => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            InteriorOfSliceOrArray {
-                                ty: place_ty,
-                                is_index: match proj.elem {
-                                    ProjectionElem::Index(..) => true,
-                                    _ => false,
-                                },
-                            },
-                        ));
-                    }
-                    ty::Array(..) => match proj.elem {
-                        ProjectionElem::Index(..) => {
-                            return Err(MoveError::cannot_move_out_of(
-                                self.loc,
-                                InteriorOfSliceOrArray { ty: place_ty, is_index: true },
-                            ));
-                        }
-                        _ => {
-                            // FIXME: still badly broken
-                        }
-                    },
-                    _ => {}
-                };
-
-                base = match self
-                    .builder
-                    .data
-                    .rev_lookup
-                    .projections
-                    .entry((base, proj.elem.lift()))
+            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) => {
@@ -169,18 +171,17 @@
                             &mut self.builder.data.init_path_map,
                             Some(base),
                             Place {
-                                base: place_base.clone(),
-                                projection: Some(Box::new(proj.clone())),
+                                base: place.base.clone(),
+                                projection: proj.to_vec().into_boxed_slice(),
                             },
                         );
                         ent.insert(path);
                         path
                     }
                 };
-            }
+        }
 
-            Ok(base)
-        })
+        Ok(base)
     }
 
     fn create_move_path(&mut self, place: &Place<'tcx>) {
@@ -267,7 +268,7 @@
 impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
         match stmt.kind {
-            StatementKind::Assign(ref place, ref rval) => {
+            StatementKind::Assign(box(ref place, ref rval)) => {
                 self.create_move_path(place);
                 if let RvalueInitializationState::Shallow = rval.initialization_state() {
                     // Box starts out uninitialized - need to create a separate
@@ -355,7 +356,7 @@
             | TerminatorKind::Unreachable => {}
 
             TerminatorKind::Return => {
-                self.gather_move(&Place::RETURN_PLACE);
+                self.gather_move(&Place::return_place());
             }
 
             TerminatorKind::Assert { ref cond, .. } => {
@@ -435,9 +436,7 @@
 
         // Check if we are assigning into a field of a union, if so, lookup the place
         // of the union so it is marked as initialized again.
-        if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) =
-            place.projection
-        {
+        if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
             if let ty::Adt(def, _) =
                 Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
             {
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 5028e96..156c19c 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -245,23 +245,21 @@
     // alternative will *not* create a MovePath on the fly for an
     // unknown place, but will rather return the nearest available
     // parent.
-    pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult {
-        place_ref.iterate(|place_base, place_projection| {
-            let mut result = match place_base {
-                PlaceBase::Local(local) => self.locals[*local],
-                PlaceBase::Static(..) => return LookupResult::Parent(None),
-            };
+    pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
+        let mut result = match place.base {
+            PlaceBase::Local(local) => self.locals[*local],
+            PlaceBase::Static(..) => return LookupResult::Parent(None),
+        };
 
-            for proj in place_projection {
-                if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
-                    result = subpath;
-                } else {
-                    return LookupResult::Parent(Some(result));
-                }
+        for elem in place.projection.iter() {
+            if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
+                result = subpath;
+            } else {
+                return LookupResult::Parent(Some(result));
             }
+        }
 
-            LookupResult::Exact(result)
-        })
+        LookupResult::Exact(result)
     }
 
     pub fn find_local(&self, local: Local) -> MovePathIndex {
@@ -329,7 +327,7 @@
     pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
         loop {
             let path = &self.move_paths[mpi];
-            if let Place { base: PlaceBase::Local(l), projection: None } = path.place {
+            if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
                 return Some(l);
             }
             if let Some(parent) = path.parent {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 6caccfd..4aaa5e8 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1229,7 +1229,13 @@
                 ty::RawPtr(..) => {
                     // `#[structural_match]` ignores substructure of
                     // `*const _`/`*mut _`, so skip super_visit_with
-
+                    //
+                    // (But still tell caller to continue search.)
+                    return false;
+                }
+                ty::FnDef(..) | ty::FnPtr(..) => {
+                    // types of formals and return in `fn(_) -> _` are also irrelevant
+                    //
                     // (But still tell caller to continue search.)
                     return false;
                 }
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index b5aab99..9ad1542 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -472,39 +472,38 @@
     // avoid allocations.
     pub(super) fn eval_place_to_op(
         &self,
-        mir_place: &mir::Place<'tcx>,
+        place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::PlaceBase;
 
-        mir_place.iterate(|place_base, place_projection| {
-            let mut op = match place_base {
-                PlaceBase::Local(mir::RETURN_PLACE) =>
-                    throw_unsup!(ReadFromReturnPointer),
-                PlaceBase::Local(local) => {
-                    // Do not use the layout passed in as argument if the base we are looking at
-                    // here is not the entire place.
-                    // FIXME use place_projection.is_empty() when is available
-                    let layout = if mir_place.projection.is_none() {
-                        layout
-                    } else {
-                        None
-                    };
+        let base_op = match &place.base {
+            PlaceBase::Local(mir::RETURN_PLACE) =>
+                throw_unsup!(ReadFromReturnPointer),
+            PlaceBase::Local(local) => {
+                // Do not use the layout passed in as argument if the base we are looking at
+                // here is not the entire place.
+                // FIXME use place_projection.is_empty() when is available
+                let layout = if place.projection.is_empty() {
+                    layout
+                } else {
+                    None
+                };
 
-                    self.access_local(self.frame(), *local, layout)?
-                }
-                PlaceBase::Static(place_static) => {
-                    self.eval_static_to_mplace(place_static)?.into()
-                }
-            };
-
-            for proj in place_projection {
-                op = self.operand_projection(op, &proj.elem)?
+                self.access_local(self.frame(), *local, layout)?
             }
+            PlaceBase::Static(place_static) => {
+                self.eval_static_to_mplace(&place_static)?.into()
+            }
+        };
 
-            trace!("eval_place_to_op: got {:?}", *op);
-            Ok(op)
-        })
+        let op = place.projection.iter().try_fold(
+            base_op,
+            |op, elem| self.operand_projection(op, elem)
+        )?;
+
+        trace!("eval_place_to_op: got {:?}", *op);
+        Ok(op)
     }
 
     /// Evaluate the operand, returning a place where you can then find the data.
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index f358bb0..1a28548 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -629,45 +629,43 @@
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
     pub fn eval_place(
         &mut self,
-        mir_place: &mir::Place<'tcx>,
+        place: &mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::PlaceBase;
 
-        mir_place.iterate(|place_base, place_projection| {
-            let mut place = match place_base {
-                PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
-                    Some(return_place) => {
-                        // We use our layout to verify our assumption; caller will validate
-                        // their layout on return.
-                        PlaceTy {
-                            place: *return_place,
-                            layout: self.layout_of(
-                                self.subst_from_frame_and_normalize_erasing_regions(
-                                    self.frame().body.return_ty()
-                                )
-                            )?,
-                        }
+        let mut place_ty = match &place.base {
+            PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
+                Some(return_place) => {
+                    // We use our layout to verify our assumption; caller will validate
+                    // their layout on return.
+                    PlaceTy {
+                        place: *return_place,
+                        layout: self.layout_of(
+                            self.subst_from_frame_and_normalize_erasing_regions(
+                                self.frame().body.return_ty()
+                            )
+                        )?,
                     }
-                    None => throw_unsup!(InvalidNullPointerUsage),
+                }
+                None => throw_unsup!(InvalidNullPointerUsage),
+            },
+            PlaceBase::Local(local) => PlaceTy {
+                // This works even for dead/uninitialized locals; we check further when writing
+                place: Place::Local {
+                    frame: self.cur_frame(),
+                    local: *local,
                 },
-                PlaceBase::Local(local) => PlaceTy {
-                    // This works even for dead/uninitialized locals; we check further when writing
-                    place: Place::Local {
-                        frame: self.cur_frame(),
-                        local: *local,
-                    },
-                    layout: self.layout_of_local(self.frame(), *local, None)?,
-                },
-                PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
-            };
+                layout: self.layout_of_local(self.frame(), *local, None)?,
+            },
+            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
+        };
 
-            for proj in place_projection {
-                place = self.place_projection(place, &proj.elem)?
-            }
+        for elem in place.projection.iter() {
+            place_ty = self.place_projection(place_ty, elem)?
+        }
 
-            self.dump_place(place.place);
-            Ok(place)
-        })
+        self.dump_place(place_ty.place);
+        Ok(place_ty)
     }
 
     /// Write a scalar to a place
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index ca4da45..affca10 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -82,7 +82,7 @@
         self.memory.tcx.span = stmt.source_info.span;
 
         match stmt.kind {
-            Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
+            Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
 
             SetDiscriminant {
                 ref place,
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 5de2979..8310ef0 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -391,7 +391,7 @@
                     // Don't forget to check the return type!
                     if let Some(caller_ret) = dest {
                         let callee_ret = self.eval_place(
-                            &mir::Place::RETURN_PLACE
+                            &mir::Place::return_place()
                         )?;
                         if !Self::check_argument_compat(
                             rust_abi,
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index aa83255..6daca5e 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -217,7 +217,7 @@
             // Function arguments should be retagged, and we make this one raw.
             body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
+                kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
             });
         }
         let patch = {
@@ -308,7 +308,7 @@
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
 
-    let dest = Place::RETURN_PLACE;
+    let dest = Place::return_place();
     let src = Place::from(Local::new(1+0)).deref();
 
     match self_ty.sty {
@@ -415,8 +415,10 @@
         let rcvr = Place::from(Local::new(1+0)).deref();
         let ret_statement = self.make_statement(
             StatementKind::Assign(
-                Place::RETURN_PLACE,
-                box Rvalue::Use(Operand::Copy(rcvr))
+                box(
+                    Place::return_place(),
+                    Rvalue::Use(Operand::Copy(rcvr))
+                )
             )
         );
         self.block(vec![ret_statement], TerminatorKind::Return, false);
@@ -458,8 +460,10 @@
         // `let ref_loc: &ty = &src;`
         let statement = self.make_statement(
             StatementKind::Assign(
-                ref_loc.clone(),
-                box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
+                box(
+                    ref_loc.clone(),
+                    Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
+                )
             )
         );
 
@@ -486,8 +490,10 @@
         let cond = self.make_place(Mutability::Mut, tcx.types.bool);
         let compute_cond = self.make_statement(
             StatementKind::Assign(
-                cond.clone(),
-                box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
+                box(
+                    cond.clone(),
+                    Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
+                )
             )
         );
 
@@ -521,14 +527,18 @@
         let inits = vec![
             self.make_statement(
                 StatementKind::Assign(
-                    Place::from(beg),
-                    box Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                    box(
+                        Place::from(beg),
+                        Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                    )
                 )
             ),
             self.make_statement(
                 StatementKind::Assign(
-                    end.clone(),
-                    box Rvalue::Use(Operand::Constant(self.make_usize(len)))
+                    box(
+                        end.clone(),
+                        Rvalue::Use(Operand::Constant(self.make_usize(len)))
+                    )
                 )
             )
         ];
@@ -559,11 +569,13 @@
         let statements = vec![
             self.make_statement(
                 StatementKind::Assign(
-                    Place::from(beg),
-                    box Rvalue::BinaryOp(
-                        BinOp::Add,
-                        Operand::Copy(Place::from(beg)),
-                        Operand::Constant(self.make_usize(1))
+                    box(
+                        Place::from(beg),
+                        Rvalue::BinaryOp(
+                            BinOp::Add,
+                            Operand::Copy(Place::from(beg)),
+                            Operand::Constant(self.make_usize(1))
+                        )
                     )
                 )
             )
@@ -582,8 +594,10 @@
         let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
         let init = self.make_statement(
             StatementKind::Assign(
-                Place::from(beg),
-                box Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                box(
+                    Place::from(beg),
+                    Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                )
             )
         );
         self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
@@ -609,11 +623,13 @@
         // `goto #6;`
         let statement = self.make_statement(
             StatementKind::Assign(
-                Place::from(beg),
-                box Rvalue::BinaryOp(
-                    BinOp::Add,
-                    Operand::Copy(Place::from(beg)),
-                    Operand::Constant(self.make_usize(1))
+                box(
+                    Place::from(beg),
+                    Rvalue::BinaryOp(
+                        BinOp::Add,
+                        Operand::Copy(Place::from(beg)),
+                        Operand::Constant(self.make_usize(1))
+                    )
                 )
             )
         );
@@ -727,8 +743,10 @@
             statements.push(Statement {
                 source_info,
                 kind: StatementKind::Assign(
-                    Place::from(ref_rcvr),
-                    box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
+                    box(
+                        Place::from(ref_rcvr),
+                        Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
+                    )
                 )
             });
             Operand::Move(Place::from(ref_rcvr))
@@ -773,7 +791,7 @@
     block(&mut blocks, statements, TerminatorKind::Call {
         func: callee,
         args,
-        destination: Some((Place::RETURN_PLACE,
+        destination: Some((Place::return_place(),
                            BasicBlock::new(1))),
         cleanup: if let Adjustment::RefMut = rcvr_adjustment {
             Some(BasicBlock::new(3))
@@ -868,7 +886,7 @@
     debug!("build_ctor: variant_index={:?}", variant_index);
 
     let statements = expand_aggregate(
-        Place::RETURN_PLACE,
+        Place::return_place(),
         adt_def
             .variants[variant_index]
             .fields
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index 0fd75cd..833c8b1 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -17,12 +17,11 @@
 fn is_stable(
     place: PlaceRef<'_, '_>,
 ) -> bool {
-    if let Some(proj) = &place.projection {
-        match proj.elem {
+    place.projection.iter().all(|elem| {
+        match elem {
             // Which place this evaluates to can change with any memory write,
             // so cannot assume this to be stable.
-            ProjectionElem::Deref =>
-                false,
+            ProjectionElem::Deref => false,
             // Array indices are intersting, but MIR building generates a *fresh*
             // temporary for every array access, so the index cannot be changed as
             // a side-effect.
@@ -31,15 +30,9 @@
             ProjectionElem::Field { .. } |
             ProjectionElem::ConstantIndex { .. } |
             ProjectionElem::Subslice { .. } |
-            ProjectionElem::Downcast { .. } =>
-                is_stable(PlaceRef {
-                    base: place.base,
-                    projection: &proj.base,
-                }),
+            ProjectionElem::Downcast { .. } => true,
         }
-    } else {
-        true
-    }
+    })
 }
 
 /// Determine whether this type may be a reference (or box), and thus needs retagging.
@@ -96,7 +89,7 @@
             basic_blocks[START_BLOCK].statements.splice(0..0,
                 places.into_iter().map(|place| Statement {
                     source_info,
-                    kind: StatementKind::Retag(RetagKind::FnEntry, place),
+                    kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
                 })
             );
         }
@@ -132,7 +125,7 @@
         for (source_info, dest_place, dest_block) in returns {
             basic_blocks[dest_block].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag(RetagKind::Default, dest_place),
+                kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
             });
         }
 
@@ -144,11 +137,11 @@
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
                     // If we are casting *from* a reference, we may have to retag-as-raw.
-                    StatementKind::Assign(ref place, box Rvalue::Cast(
+                    StatementKind::Assign(box(ref place, Rvalue::Cast(
                         CastKind::Misc,
                         ref src,
                         dest_ty,
-                    )) => {
+                    ))) => {
                         let src_ty = src.ty(&*local_decls, tcx);
                         if src_ty.is_region_ptr() {
                             // The only `Misc` casts on references are those creating raw pointers.
@@ -162,7 +155,7 @@
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
                     // we also retag after taking a reference!
-                    StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
+                    StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
                         let kind = match rvalue {
                             Rvalue::Ref(_, borrow_kind, _)
                                 if borrow_kind.allows_two_phase_borrow()
@@ -180,7 +173,7 @@
                 let source_info = block_data.statements[i].source_info;
                 block_data.statements.insert(i+1, Statement {
                     source_info,
-                    kind: StatementKind::Retag(retag_kind, place),
+                    kind: StatementKind::Retag(retag_kind, box(place)),
                 });
             }
         }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 539922c..f8af9b9 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -200,127 +200,127 @@
                     place: &Place<'tcx>,
                     context: PlaceContext,
                     _location: Location) {
-        place.iterate(|place_base, place_projections| {
-            match place_base {
-                PlaceBase::Local(..) => {
-                    // Locals are safe.
-                }
-                PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
-                    bug!("unsafety checking should happen before promotion")
-                }
-                PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
-                    if self.tcx.is_mutable_static(*def_id) {
-                        self.require_unsafe("use of mutable static",
-                            "mutable statics can be mutated by multiple threads: aliasing \
-                             violations or data races will cause undefined behavior",
-                             UnsafetyViolationKind::General);
-                    } else if self.tcx.is_foreign_item(*def_id) {
-                        let source_info = self.source_info;
-                        let lint_root =
-                            self.source_scope_local_data[source_info.scope].lint_root;
-                        self.register_violations(&[UnsafetyViolation {
-                            source_info,
-                            description: InternedString::intern("use of extern static"),
-                            details: InternedString::intern(
-                                "extern statics are not controlled by the Rust type system: \
-                                invalid data, aliasing violations or data races will cause \
-                                undefined behavior"),
-                            kind: UnsafetyViolationKind::ExternStatic(lint_root)
-                        }], &[]);
-                    }
+        match place.base {
+            PlaceBase::Local(..) => {
+                // Locals are safe.
+            }
+            PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
+                bug!("unsafety checking should happen before promotion")
+            }
+            PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
+                if self.tcx.is_mutable_static(def_id) {
+                    self.require_unsafe("use of mutable static",
+                        "mutable statics can be mutated by multiple threads: aliasing \
+                         violations or data races will cause undefined behavior",
+                         UnsafetyViolationKind::General);
+                } else if self.tcx.is_foreign_item(def_id) {
+                    let source_info = self.source_info;
+                    let lint_root =
+                        self.source_scope_local_data[source_info.scope].lint_root;
+                    self.register_violations(&[UnsafetyViolation {
+                        source_info,
+                        description: InternedString::intern("use of extern static"),
+                        details: InternedString::intern(
+                            "extern statics are not controlled by the Rust type system: \
+                            invalid data, aliasing violations or data races will cause \
+                            undefined behavior"),
+                        kind: UnsafetyViolationKind::ExternStatic(lint_root)
+                    }], &[]);
                 }
             }
+        }
 
-            for proj in place_projections {
-                if context.is_borrow() {
-                    if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
-                        let source_info = self.source_info;
-                        let lint_root =
-                            self.source_scope_local_data[source_info.scope].lint_root;
-                        self.register_violations(&[UnsafetyViolation {
-                            source_info,
-                            description: InternedString::intern("borrow of packed field"),
-                            details: InternedString::intern(
-                                "fields of packed structs might be misaligned: dereferencing a \
-                                misaligned pointer or even just creating a misaligned reference \
-                                is undefined behavior"),
-                            kind: UnsafetyViolationKind::BorrowPacked(lint_root)
-                        }], &[]);
-                    }
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+
+            if context.is_borrow() {
+                if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
+                    let source_info = self.source_info;
+                    let lint_root =
+                        self.source_scope_local_data[source_info.scope].lint_root;
+                    self.register_violations(&[UnsafetyViolation {
+                        source_info,
+                        description: InternedString::intern("borrow of packed field"),
+                        details: InternedString::intern(
+                            "fields of packed structs might be misaligned: dereferencing a \
+                            misaligned pointer or even just creating a misaligned reference \
+                            is undefined behavior"),
+                        kind: UnsafetyViolationKind::BorrowPacked(lint_root)
+                    }], &[]);
                 }
-                let is_borrow_of_interior_mut = context.is_borrow() &&
-                    !Place::ty_from(&place.base, &proj.base, self.body, self.tcx)
-                    .ty
-                    .is_freeze(self.tcx, self.param_env, self.source_info.span);
-                // prevent
-                // * `&mut x.field`
-                // * `x.field = y;`
-                // * `&x.field` if `field`'s type has interior mutability
-                // because either of these would allow modifying the layout constrained field and
-                // insert values that violate the layout constraints.
-                if context.is_mutating_use() || is_borrow_of_interior_mut {
-                    self.check_mut_borrowing_layout_constrained_field(
-                        place, context.is_mutating_use(),
-                    );
+            }
+            let is_borrow_of_interior_mut = context.is_borrow() &&
+                !Place::ty_from(&place.base, proj_base, self.body, self.tcx)
+                .ty
+                .is_freeze(self.tcx, self.param_env, self.source_info.span);
+            // prevent
+            // * `&mut x.field`
+            // * `x.field = y;`
+            // * `&x.field` if `field`'s type has interior mutability
+            // because either of these would allow modifying the layout constrained field and
+            // insert values that violate the layout constraints.
+            if context.is_mutating_use() || is_borrow_of_interior_mut {
+                self.check_mut_borrowing_layout_constrained_field(
+                    place, context.is_mutating_use(),
+                );
+            }
+            let old_source_info = self.source_info;
+            if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
+                if self.body.local_decls[*local].internal {
+                    // Internal locals are used in the `move_val_init` desugaring.
+                    // We want to check unsafety against the source info of the
+                    // desugaring, rather than the source info of the RHS.
+                    self.source_info = self.body.local_decls[*local].source_info;
                 }
-                let old_source_info = self.source_info;
-                if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) {
-                    if self.body.local_decls[*local].internal {
-                        // Internal locals are used in the `move_val_init` desugaring.
-                        // We want to check unsafety against the source info of the
-                        // desugaring, rather than the source info of the RHS.
-                        self.source_info = self.body.local_decls[*local].source_info;
-                    }
+            }
+            let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
+            match base_ty.sty {
+                ty::RawPtr(..) => {
+                    self.require_unsafe("dereference of raw pointer",
+                        "raw pointers may be NULL, dangling or unaligned; they can violate \
+                         aliasing rules and cause data races: all of these are undefined \
+                         behavior", UnsafetyViolationKind::General)
                 }
-                let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
-                match base_ty.sty {
-                    ty::RawPtr(..) => {
-                        self.require_unsafe("dereference of raw pointer",
-                            "raw pointers may be NULL, dangling or unaligned; they can violate \
-                             aliasing rules and cause data races: all of these are undefined \
-                             behavior", UnsafetyViolationKind::General)
-                    }
-                    ty::Adt(adt, _) => {
-                        if adt.is_union() {
-                            if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
-                                context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
-                                context == PlaceContext::MutatingUse(
-                                    MutatingUseContext::AsmOutput
-                                )
-                            {
-                                let elem_ty = match proj.elem {
-                                    ProjectionElem::Field(_, ty) => ty,
-                                    _ => span_bug!(
-                                        self.source_info.span,
-                                        "non-field projection {:?} from union?",
-                                        place)
-                                };
-                                if !elem_ty.is_copy_modulo_regions(
-                                    self.tcx,
-                                    self.param_env,
+                ty::Adt(adt, _) => {
+                    if adt.is_union() {
+                        if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
+                            context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
+                            context == PlaceContext::MutatingUse(
+                                MutatingUseContext::AsmOutput
+                            )
+                        {
+                            let elem_ty = match elem {
+                                ProjectionElem::Field(_, ty) => ty,
+                                _ => span_bug!(
                                     self.source_info.span,
-                                ) {
-                                    self.require_unsafe(
-                                        "assignment to non-`Copy` union field",
-                                        "the previous content of the field will be dropped, which \
-                                         causes undefined behavior if the field was not properly \
-                                         initialized", UnsafetyViolationKind::General)
-                                } else {
-                                    // write to non-move union, safe
-                                }
+                                    "non-field projection {:?} from union?",
+                                    place)
+                            };
+                            if !elem_ty.is_copy_modulo_regions(
+                                self.tcx,
+                                self.param_env,
+                                self.source_info.span,
+                            ) {
+                                self.require_unsafe(
+                                    "assignment to non-`Copy` union field",
+                                    "the previous content of the field will be dropped, which \
+                                     causes undefined behavior if the field was not properly \
+                                     initialized", UnsafetyViolationKind::General)
                             } else {
-                                self.require_unsafe("access to union field",
-                                    "the field may not be properly initialized: using \
-                                     uninitialized data will cause undefined behavior",
-                                     UnsafetyViolationKind::General)
+                                // write to non-move union, safe
                             }
+                        } else {
+                            self.require_unsafe("access to union field",
+                                "the field may not be properly initialized: using \
+                                 uninitialized data will cause undefined behavior",
+                                 UnsafetyViolationKind::General)
                         }
                     }
-                    _ => {}
                 }
-                self.source_info = old_source_info;
+                _ => {}
             }
-        });
+            self.source_info = old_source_info;
+        }
     }
 }
 
@@ -407,12 +407,13 @@
         place: &Place<'tcx>,
         is_mut_use: bool,
     ) {
-        let mut projection = &place.projection;
-        while let Some(proj) = projection {
-            match proj.elem {
+        for (i, elem) in place.projection.iter().enumerate().rev() {
+            let proj_base = &place.projection[..i];
+
+            match elem {
                 ProjectionElem::Field(..) => {
                     let ty =
-                        Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx)
+                        Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx)
                             .ty;
                     match ty.sty {
                         ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
@@ -447,7 +448,6 @@
                 }
                 _ => {}
             }
-            projection = &proj.base;
         }
     }
 }
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index ede1cb6..ea17327 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -39,7 +39,7 @@
                        location: Location) {
         match statement.kind {
             StatementKind::AscribeUserType(..)
-            | StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _))
+            | StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
             | StatementKind::FakeRead(..) => statement.make_nop(),
             _ => (),
         }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index e4b1867..614d5d2 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -282,53 +282,53 @@
 
     fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
         trace!("eval_place(place={:?})", place);
-        place.iterate(|place_base, place_projection| {
-            let mut eval = match place_base {
-                PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
-                PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
-                    let generics = self.tcx.generics_of(self.source.def_id());
-                    if generics.requires_monomorphization(self.tcx) {
-                        // FIXME: can't handle code with generics
-                        return None;
-                    }
-                    let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
-                    let instance = Instance::new(self.source.def_id(), substs);
-                    let cid = GlobalId {
-                        instance,
-                        promoted: Some(*promoted),
-                    };
-                    let res = self.use_ecx(source_info, |this| {
-                        this.ecx.const_eval_raw(cid)
-                    })?;
-                    trace!("evaluated promoted {:?} to {:?}", promoted, res);
-                    res.into()
+        let mut eval = match place.base {
+            PlaceBase::Local(loc) => self.get_const(loc).clone()?,
+            PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
+                let generics = self.tcx.generics_of(self.source.def_id());
+                if generics.requires_monomorphization(self.tcx) {
+                    // FIXME: can't handle code with generics
+                    return None;
                 }
-                _ => return None,
-            };
-
-            for proj in place_projection {
-                match proj.elem {
-                    ProjectionElem::Field(field, _) => {
-                        trace!("field proj on {:?}", proj.base);
-                        eval = self.use_ecx(source_info, |this| {
-                            this.ecx.operand_field(eval, field.index() as u64)
-                        })?;
-                    },
-                    ProjectionElem::Deref => {
-                        trace!("processing deref");
-                        eval = self.use_ecx(source_info, |this| {
-                            this.ecx.deref_operand(eval)
-                        })?.into();
-                    }
-                    // We could get more projections by using e.g., `operand_projection`,
-                    // but we do not even have the stack frame set up properly so
-                    // an `Index` projection would throw us off-track.
-                    _ => return None,
-                }
+                let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
+                let instance = Instance::new(self.source.def_id(), substs);
+                let cid = GlobalId {
+                    instance,
+                    promoted: Some(promoted),
+                };
+                let res = self.use_ecx(source_info, |this| {
+                    this.ecx.const_eval_raw(cid)
+                })?;
+                trace!("evaluated promoted {:?} to {:?}", promoted, res);
+                res.into()
             }
+            _ => return None,
+        };
 
-            Some(eval)
-        })
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+
+            match elem {
+                ProjectionElem::Field(field, _) => {
+                    trace!("field proj on {:?}", proj_base);
+                    eval = self.use_ecx(source_info, |this| {
+                        this.ecx.operand_field(eval, field.index() as u64)
+                    })?;
+                },
+                ProjectionElem::Deref => {
+                    trace!("processing deref");
+                    eval = self.use_ecx(source_info, |this| {
+                        this.ecx.deref_operand(eval)
+                    })?.into();
+                }
+                // We could get more projections by using e.g., `operand_projection`,
+                // but we do not even have the stack frame set up properly so
+                // an `Index` projection would throw us off-track.
+                _ => return None,
+            }
+        }
+
+        Some(eval)
     }
 
     fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
@@ -665,7 +665,7 @@
         location: Location,
     ) {
         trace!("visit_statement: {:?}", statement);
-        if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
+        if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place
                 .ty(&self.local_decls, self.tcx)
                 .ty;
@@ -673,7 +673,7 @@
                 if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
                     if let Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
+                        projection: box [],
                     } = *place {
                         trace!("checking whether {:?} can be stored to {:?}", value, local);
                         if self.can_const_prop[local] {
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index f3a523a..28f97f4 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -94,11 +94,13 @@
                     // That use of the source must be an assignment.
                     match statement.kind {
                         StatementKind::Assign(
-                            Place {
-                                base: PlaceBase::Local(local),
-                                projection: None,
-                            },
-                            box Rvalue::Use(ref operand)
+                            box(
+                                Place {
+                                    base: PlaceBase::Local(local),
+                                    projection: box [],
+                                },
+                                Rvalue::Use(ref operand)
+                            )
                         ) if local == dest_local => {
                             let maybe_action = match *operand {
                                 Operand::Copy(ref src_place) |
@@ -148,24 +150,28 @@
             if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
                 match stmt.kind {
                     StatementKind::Assign(
-                        Place {
-                            base: PlaceBase::Local(local),
-                            projection: None,
-                        },
-                        box Rvalue::Use(Operand::Copy(Place {
-                            base: PlaceBase::Local(src_local),
-                            projection: None,
-                        })),
+                        box(
+                            Place {
+                                base: PlaceBase::Local(local),
+                                projection: box [],
+                            },
+                            Rvalue::Use(Operand::Copy(Place {
+                                base: PlaceBase::Local(src_local),
+                                projection: box [],
+                            })),
+                        )
                     ) |
                     StatementKind::Assign(
-                        Place {
-                            base: PlaceBase::Local(local),
-                            projection: None,
-                        },
-                        box Rvalue::Use(Operand::Move(Place {
-                            base: PlaceBase::Local(src_local),
-                            projection: None,
-                        })),
+                        box(
+                            Place {
+                                base: PlaceBase::Local(local),
+                                projection: box [],
+                            },
+                            Rvalue::Use(Operand::Move(Place {
+                                base: PlaceBase::Local(src_local),
+                                projection: box [],
+                            })),
+                        )
                     ) if local == dest_local && dest_local == src_local => {}
                     _ => {
                         continue;
@@ -194,7 +200,7 @@
         // The source must be a local.
         let src_local = if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = *src_place {
             local
         } else {
@@ -351,11 +357,11 @@
         match *operand {
             Operand::Copy(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) |
             Operand::Move(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) if local == self.dest_local => {}
             _ => return,
         }
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 1fc7ce0..c1224be 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -12,8 +12,8 @@
         for bb in basic_blocks {
             bb.expand_statements(|stmt| {
                 // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
-                if let StatementKind::Assign(_, ref rhs) = stmt.kind {
-                    if let Rvalue::Aggregate(ref kind, _) = **rhs {
+                if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind {
+                    if let Rvalue::Aggregate(ref kind, _) = *rhs {
                         // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
                         if let AggregateKind::Array(_) = **kind {
                             return None;
@@ -28,7 +28,7 @@
                 let stmt = stmt.replace_nop();
                 let source_info = stmt.source_info;
                 let (lhs, kind, operands) = match stmt.kind {
-                    StatementKind::Assign(lhs, box rvalue) => {
+                    StatementKind::Assign(box(lhs, rvalue)) => {
                         match rvalue {
                             Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
                             _ => bug!()
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 7a5c00c..a9c66b3 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -236,47 +236,34 @@
     }
 
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::Field(idx, _), ..
-                } => idx == field,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::Field(idx, _) => *idx == field,
+            _ => false,
         })
     }
 
     fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
-                } => offset == index,
-                &Projection {
-                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
-                } => size - offset == index,
-                _ => false
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
+                *offset == index
             }
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
+                size - offset == index
+            }
+            _ => false,
         })
     }
 
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection { elem: ProjectionElem::Deref, .. } => true,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
+            *e == ProjectionElem::Deref
         })
     }
 
     fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::Downcast(_, idx), ..
-                } => idx == variant,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::Downcast(_, idx) => *idx == variant,
+            _ => false
         })
     }
 
@@ -465,7 +452,7 @@
         assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
 
         let assign = Statement {
-            kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())),
+            kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))),
             source_info: terminator.source_info
         };
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index d873311..0ce2db9 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -107,10 +107,7 @@
         if place.base == PlaceBase::Local(self_arg()) {
             replace_base(place, Place {
                 base: PlaceBase::Local(self_arg()),
-                projection: Some(Box::new(Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                })),
+                projection: Box::new([ProjectionElem::Deref]),
             });
         } else {
             self.super_place(place, context, location);
@@ -137,10 +134,7 @@
         if place.base == PlaceBase::Local(self_arg()) {
             replace_base(place, Place {
                 base: PlaceBase::Local(self_arg()),
-                projection: Some(Box::new(Projection {
-                    base: None,
-                    elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
-                })),
+                projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
             });
         } else {
             self.super_place(place, context, location);
@@ -149,13 +143,12 @@
 }
 
 fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
-    let mut projection = &mut place.projection;
-    while let Some(box proj) = projection {
-        projection = &mut proj.base;
-    }
-
     place.base = new_base.base;
-    *projection = new_base.projection;
+
+    let mut new_projection = new_base.projection.to_vec();
+    new_projection.append(&mut place.projection.to_vec());
+
+    place.projection = new_projection.into_boxed_slice();
 }
 
 fn self_arg() -> Local {
@@ -210,13 +203,12 @@
     fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
         let self_place = Place::from(self_arg());
         let base = self_place.downcast_unnamed(variant_index);
-        let field = Projection {
-            base: base.projection,
-            elem: ProjectionElem::Field(Field::new(idx), ty),
-        };
+        let mut projection = base.projection.to_vec();
+        projection.push(ProjectionElem::Field(Field::new(idx), ty));
+
         Place {
             base: base.base,
-            projection: Some(Box::new(field)),
+            projection: projection.into_boxed_slice(),
         }
     }
 
@@ -225,7 +217,10 @@
         let self_place = Place::from(self_arg());
         Statement {
             source_info,
-            kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc },
+            kind: StatementKind::SetDiscriminant {
+                place: box self_place,
+                variant_index: state_disc,
+            },
         }
     }
 
@@ -238,7 +233,7 @@
         let self_place = Place::from(self_arg());
         let assign = Statement {
             source_info: source_info(body),
-            kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)),
+            kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))),
         };
         (assign, temp)
     }
@@ -296,8 +291,12 @@
             // We must assign the value first in case it gets declared dead below
             data.statements.push(Statement {
                 source_info,
-                kind: StatementKind::Assign(Place::RETURN_PLACE,
-                                            box self.make_state(state_idx, v)),
+                kind: StatementKind::Assign(
+                    box(
+                        Place::return_place(),
+                        self.make_state(state_idx, v)
+                    )
+                ),
             });
             let state = if let Some(resume) = resume { // Yield
                 let state = 3 + self.suspension_points.len();
@@ -848,7 +847,7 @@
                 kind: TerminatorKind::Drop {
                     location: Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
+                        projection: box [],
                     },
                     target,
                     unwind
@@ -937,7 +936,7 @@
         // Alias tracking must know we changed the type
         body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
             source_info,
-            kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())),
+            kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())),
         })
     }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index f31303c..5ad026d 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -425,22 +425,20 @@
                 // writes to `i`. To prevent this we need to create a temporary
                 // borrow of the place and pass the destination as `*temp` instead.
                 fn dest_needs_borrow(place: &Place<'_>) -> bool {
-                    place.iterate(|place_base, place_projection| {
-                        for proj in place_projection {
-                            match proj.elem {
-                                ProjectionElem::Deref |
-                                ProjectionElem::Index(_) => return true,
-                                _ => {}
-                            }
+                    for elem in place.projection.iter() {
+                        match elem {
+                            ProjectionElem::Deref |
+                            ProjectionElem::Index(_) => return true,
+                            _ => {}
                         }
+                    }
 
-                        match place_base {
-                            // Static variables need a borrow because the callee
-                            // might modify the same static.
-                            PlaceBase::Static(_) => true,
-                            _ => false
-                        }
-                    })
+                    match place.base {
+                        // Static variables need a borrow because the callee
+                        // might modify the same static.
+                        PlaceBase::Static(_) => true,
+                        _ => false
+                    }
                 }
 
                 let dest = if dest_needs_borrow(&destination.0) {
@@ -459,7 +457,7 @@
 
                     let stmt = Statement {
                         source_info: callsite.location,
-                        kind: StatementKind::Assign(tmp.clone(), box dest)
+                        kind: StatementKind::Assign(box(tmp.clone(), dest))
                     };
                     caller_body[callsite.bb]
                         .statements.push(stmt);
@@ -591,7 +589,7 @@
 
         if let Operand::Move(Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         }) = arg {
             if caller_body.local_kind(local) == LocalKind::Temp {
                 // Reuse the operand if it's a temporary already
@@ -610,7 +608,7 @@
 
         let stmt = Statement {
             source_info: callsite.location,
-            kind: StatementKind::Assign(Place::from(arg_tmp), box arg),
+            kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
         };
         caller_body[callsite.bb].statements.push(stmt);
         arg_tmp
@@ -660,7 +658,7 @@
             match self.destination {
                 Place {
                     base: PlaceBase::Local(l),
-                    projection: None,
+                    projection: box [],
                 } => {
                     *local = l;
                     return;
@@ -684,7 +682,7 @@
         match place {
             Place {
                 base: PlaceBase::Local(RETURN_PLACE),
-                projection: None,
+                projection: box [],
             } => {
                 // Return pointer; update the place itself
                 *place = self.destination.clone();
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index abe4160..0e04e63 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -43,12 +43,21 @@
             let new_place = match *rvalue {
                 Rvalue::Ref(_, _, Place {
                     ref mut base,
-                    projection: Some(ref mut projection),
-                }) => Place {
-                    // Replace with dummy
-                    base: mem::replace(base, PlaceBase::Local(Local::new(0))),
-                    projection: projection.base.take(),
-                },
+                    projection: ref mut projection @ box [.., _],
+                }) => {
+                    if let box [proj_l @ .., proj_r] = projection {
+                        let place = Place {
+                            // Replace with dummy
+                            base: mem::replace(base, PlaceBase::Local(Local::new(0))),
+                            projection: proj_l.to_vec().into_boxed_slice(),
+                        };
+                        *projection = vec![proj_r.clone()].into_boxed_slice();
+
+                        place
+                    } else {
+                        unreachable!();
+                    }
+                }
                 _ => bug!("Detected `&*` but didn't find `&*`!"),
             };
             *rvalue = Rvalue::Use(Operand::Copy(new_place))
@@ -83,13 +92,11 @@
 impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         if let Rvalue::Ref(_, _, Place {
-            ref base,
-            projection: Some(ref projection),
-        }) = *rvalue {
-            if let ProjectionElem::Deref = projection.elem {
-                if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() {
-                    self.optimizations.and_stars.insert(location);
-                }
+            base,
+            projection: box [proj_base @ .., ProjectionElem::Deref],
+        }) = rvalue {
+            if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+                self.optimizations.and_stars.insert(location);
             }
         }
 
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index cdccdfe..7d1b96b 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -187,7 +187,7 @@
                 span,
                 scope: OUTERMOST_SOURCE_SCOPE
             },
-            kind: StatementKind::Assign(Place::from(dest), box rvalue)
+            kind: StatementKind::Assign(box(Place::from(dest), rvalue))
         });
     }
 
@@ -222,10 +222,10 @@
         // First, take the Rvalue or Call out of the source MIR,
         // or duplicate it, depending on keep_original.
         if loc.statement_index < no_stmts {
-            let (rvalue, source_info) = {
+            let (mut rvalue, source_info) = {
                 let statement = &mut self.source[loc.block].statements[loc.statement_index];
                 let rhs = match statement.kind {
-                    StatementKind::Assign(_, ref mut rhs) => rhs,
+                    StatementKind::Assign(box(_, ref mut rhs)) => rhs,
                     _ => {
                         span_bug!(statement.source_info.span, "{:?} is not an assignment",
                                   statement);
@@ -235,12 +235,11 @@
                 (if self.keep_original {
                     rhs.clone()
                 } else {
-                    let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
+                    let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
                     mem::replace(rhs, unit)
                 }, statement.source_info)
             };
 
-            let mut rvalue = *rvalue;
             self.visit_rvalue(&mut rvalue, loc);
             self.assign(new_temp, rvalue, source_info.span);
         } else {
@@ -318,7 +317,7 @@
                         ty,
                         def_id,
                     }),
-                    projection: None,
+                    projection: box [],
                 }
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
@@ -326,7 +325,7 @@
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
+                        StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
                             // Use the underlying local for this (necessarily interior) borrow.
                             let ty = place.base.ty(local_decls).ty;
                             let span = statement.source_info.span;
@@ -334,9 +333,9 @@
                             Operand::Move(Place {
                                 base: mem::replace(
                                     &mut place.base,
-                                    promoted_place(ty, span).base
+                                    promoted_place(ty, span).base,
                                 ),
-                                projection: None,
+                                projection: box [],
                             })
                         }
                         _ => bug!()
@@ -345,7 +344,7 @@
                 Candidate::Repeat(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
+                        StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => {
                             let ty = operand.ty(local_decls, self.tcx);
                             let span = statement.source_info.span;
                             mem::replace(
@@ -420,10 +419,10 @@
             Candidate::Repeat(Location { block, statement_index }) |
             Candidate::Ref(Location { block, statement_index }) => {
                 match body[block].statements[statement_index].kind {
-                    StatementKind::Assign(Place {
+                    StatementKind::Assign(box(Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
-                    }, _) => {
+                        projection: box [],
+                    }, _)) => {
                         if temps[local] == TempState::PromotedOut {
                             // Already promoted.
                             continue;
@@ -473,10 +472,10 @@
     for block in body.basic_blocks_mut() {
         block.statements.retain(|statement| {
             match statement.kind {
-                StatementKind::Assign(Place {
+                StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(index),
-                    projection: None,
-                }, _) |
+                    projection: box [],
+                }, _)) |
                 StatementKind::StorageLive(index) |
                 StatementKind::StorageDead(index) => {
                     !promoted(index)
@@ -488,7 +487,7 @@
         match terminator.kind {
             TerminatorKind::Drop { location: Place {
                 base: PlaceBase::Local(index),
-                projection: None,
+                projection: box [],
             }, target, .. } => {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 32b49ee..7cc1e63 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -187,26 +187,28 @@
         cx: &ConstCx<'_, 'tcx>,
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
-        let proj = place.projection.as_ref().unwrap();
+        if let [proj_base @ .., elem] = place.projection {
+            let base_qualif = Self::in_place(cx, PlaceRef {
+                base: place.base,
+                projection: proj_base,
+            });
+            let qualif = base_qualif && Self::mask_for_ty(
+                cx,
+                Place::ty_from(place.base, proj_base, cx.body, cx.tcx)
+                    .projection_ty(cx.tcx, elem)
+                    .ty,
+            );
+            match elem {
+                ProjectionElem::Deref |
+                ProjectionElem::Subslice { .. } |
+                ProjectionElem::Field(..) |
+                ProjectionElem::ConstantIndex { .. } |
+                ProjectionElem::Downcast(..) => qualif,
 
-        let base_qualif = Self::in_place(cx, PlaceRef {
-            base: place.base,
-            projection: &proj.base,
-        });
-        let qualif = base_qualif && Self::mask_for_ty(
-            cx,
-            Place::ty_from(place.base, &proj.base, cx.body, cx.tcx)
-                .projection_ty(cx.tcx, &proj.elem)
-                .ty,
-        );
-        match proj.elem {
-            ProjectionElem::Deref |
-            ProjectionElem::Subslice { .. } |
-            ProjectionElem::Field(..) |
-            ProjectionElem::ConstantIndex { .. } |
-            ProjectionElem::Downcast(..) => qualif,
-
-            ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
+                ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local),
+            }
+        } else {
+            bug!("This should be called if projection is not empty");
         }
     }
 
@@ -221,24 +223,24 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => Self::in_local(cx, *local),
             PlaceRef {
                 base: PlaceBase::Static(box Static {
                     kind: StaticKind::Promoted(..),
                     ..
                 }),
-                projection: None,
+                projection: [],
             } => bug!("qualifying already promoted MIR"),
             PlaceRef {
                 base: PlaceBase::Static(static_),
-                projection: None,
+                projection: [],
             } => {
                 Self::in_static(cx, static_)
             },
             PlaceRef {
                 base: _,
-                projection: Some(_),
+                projection: [.., _],
             } => Self::in_projection(cx, place),
         }
     }
@@ -289,13 +291,13 @@
 
             Rvalue::Ref(_, _, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let Some(ref proj) = place.projection {
-                    if let ProjectionElem::Deref = proj.elem {
-                        let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty;
+                if let box [proj_base @ .., elem] = &place.projection {
+                    if ProjectionElem::Deref == *elem {
+                        let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
                         if let ty::Ref(..) = base_ty.sty {
                             return Self::in_place(cx, PlaceRef {
                                 base: &place.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             });
                         }
                     }
@@ -453,30 +455,32 @@
         cx: &ConstCx<'_, 'tcx>,
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
-        let proj = place.projection.as_ref().unwrap();
+        if let [proj_base @ .., elem] = place.projection {
+            match elem {
+                ProjectionElem::Deref |
+                ProjectionElem::Downcast(..) => return true,
 
-        match proj.elem {
-            ProjectionElem::Deref |
-            ProjectionElem::Downcast(..) => return true,
+                ProjectionElem::ConstantIndex {..} |
+                ProjectionElem::Subslice {..} |
+                ProjectionElem::Index(_) => {}
 
-            ProjectionElem::ConstantIndex {..} |
-            ProjectionElem::Subslice {..} |
-            ProjectionElem::Index(_) => {}
-
-            ProjectionElem::Field(..) => {
-                if cx.mode == Mode::NonConstFn {
-                    let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty;
-                    if let Some(def) = base_ty.ty_adt_def() {
-                        // No promotion of union field accesses.
-                        if def.is_union() {
-                            return true;
+                ProjectionElem::Field(..) => {
+                    if cx.mode == Mode::NonConstFn {
+                        let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty;
+                        if let Some(def) = base_ty.ty_adt_def() {
+                            // No promotion of union field accesses.
+                            if def.is_union() {
+                                return true;
+                            }
                         }
                     }
                 }
             }
-        }
 
-        Self::in_projection_structurally(cx, place)
+            Self::in_projection_structurally(cx, place)
+        } else {
+            bug!("This should be called if projection is not empty");
+        }
     }
 
     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
@@ -806,23 +810,18 @@
                     // We might have a candidate for promotion.
                     let candidate = Candidate::Ref(location);
                     // Start by traversing to the "base", with non-deref projections removed.
-                    let mut place_projection = &place.projection;
-                    while let Some(proj) = place_projection {
-                        if proj.elem == ProjectionElem::Deref {
-                            break;
-                        }
-                        place_projection = &proj.base;
-                    }
+                    let deref_proj =
+                        place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref);
 
                     debug!(
                         "qualify_consts: promotion candidate: place={:?} {:?}",
-                        place.base, place_projection
+                        place.base, deref_proj
                     );
                     // We can only promote interior borrows of promotable temps (non-temps
                     // don't get promoted anyway).
                     // (If we bailed out of the loop due to a `Deref` above, we will definitely
                     // not enter the conditional here.)
-                    if let (PlaceBase::Local(local), None) = (&place.base, place_projection) {
+                    if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) {
                         if self.body.local_kind(*local) == LocalKind::Temp {
                             debug!("qualify_consts: promotion candidate: local={:?}", local);
                             // The borrowed place doesn't have `HasMutInterior`
@@ -858,27 +857,27 @@
             _ => {},
         }
 
-        let mut dest_projection = &dest.projection;
+        let mut dest_projection = &dest.projection[..];
         let index = loop {
             match (&dest.base, dest_projection) {
                 // We treat all locals equal in constants
-                (&PlaceBase::Local(index), None) => break index,
+                (&PlaceBase::Local(index), []) => break index,
                 // projections are transparent for assignments
                 // we qualify the entire destination at once, even if just a field would have
                 // stricter qualification
-                (base, Some(proj)) => {
+                (base, [proj_base @ .., _]) => {
                     // Catch more errors in the destination. `visit_place` also checks various
                     // projection rules like union field access and raw pointer deref
                     let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
                     self.visit_place_base(base, context, location);
-                    self.visit_projection(base, proj, context, location);
-                    dest_projection = &proj.base;
+                    self.visit_projection(base, dest_projection, context, location);
+                    dest_projection = proj_base;
                 },
                 (&PlaceBase::Static(box Static {
                     kind: StaticKind::Promoted(..),
                     ..
-                }), None) => bug!("promoteds don't exist yet during promotion"),
-                (&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
+                }), []) => bug!("promoteds don't exist yet during promotion"),
+                (&PlaceBase::Static(box Static{ kind: _, .. }), []) => {
                     // Catch more errors in the destination. `visit_place` also checks that we
                     // do not try to access statics from constants or try to mutate statics
                     let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
@@ -983,23 +982,25 @@
         for candidate in &self.promotion_candidates {
             match *candidate {
                 Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
-                    if let StatementKind::Assign(_, box Rvalue::Repeat(
+                    if let StatementKind::Assign(box(_, Rvalue::Repeat(
                         Operand::Move(Place {
                             base: PlaceBase::Local(index),
-                            projection: None,
+                            projection: box [],
                         }),
                         _
-                    )) = self.body[bb].statements[stmt_idx].kind {
+                    ))) = self.body[bb].statements[stmt_idx].kind {
                         promoted_temps.insert(index);
                     }
                 }
                 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
                     if let StatementKind::Assign(
-                        _,
-                        box Rvalue::Ref(_, _, Place {
-                            base: PlaceBase::Local(index),
-                            projection: None,
-                        })
+                        box(
+                            _,
+                            Rvalue::Ref(_, _, Place {
+                                base: PlaceBase::Local(index),
+                                projection: box [],
+                            })
+                        )
                     ) = self.body[bb].statements[stmt_idx].kind {
                         promoted_temps.insert(index);
                     }
@@ -1084,7 +1085,7 @@
     fn visit_projection(
         &mut self,
         place_base: &PlaceBase<'tcx>,
-        proj: &Projection<'tcx>,
+        proj: &[PlaceElem<'tcx>],
         context: PlaceContext,
         location: Location,
     ) {
@@ -1093,62 +1094,65 @@
             proj, context, location,
         );
         self.super_projection(place_base, proj, context, location);
-        match proj.elem {
-            ProjectionElem::Deref => {
-                if context.is_mutating_use() {
-                    // `not_const` errors out in const contexts
-                    self.not_const()
-                }
-                let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
-                match self.mode {
-                    Mode::NonConstFn => {},
-                    _ => {
-                        if let ty::RawPtr(_) = base_ty.sty {
-                            if !self.tcx.features().const_raw_ptr_deref {
-                                emit_feature_err(
-                                    &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
-                                    self.span, GateIssue::Language,
-                                    &format!(
-                                        "dereferencing raw pointers in {}s is unstable",
-                                        self.mode,
-                                    ),
-                                );
+
+        if let [proj_base @ .., elem] = proj {
+            match elem {
+                ProjectionElem::Deref => {
+                    if context.is_mutating_use() {
+                        // `not_const` errors out in const contexts
+                        self.not_const()
+                    }
+                    let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
+                    match self.mode {
+                        Mode::NonConstFn => {},
+                        _ => {
+                            if let ty::RawPtr(_) = base_ty.sty {
+                                if !self.tcx.features().const_raw_ptr_deref {
+                                    emit_feature_err(
+                                        &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
+                                        self.span, GateIssue::Language,
+                                        &format!(
+                                            "dereferencing raw pointers in {}s is unstable",
+                                            self.mode,
+                                        ),
+                                    );
+                                }
                             }
                         }
                     }
                 }
-            }
 
-            ProjectionElem::ConstantIndex {..} |
-            ProjectionElem::Subslice {..} |
-            ProjectionElem::Field(..) |
-            ProjectionElem::Index(_) => {
-                let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
-                if let Some(def) = base_ty.ty_adt_def() {
-                    if def.is_union() {
-                        match self.mode {
-                            Mode::ConstFn => {
-                                if !self.tcx.features().const_fn_union {
-                                    emit_feature_err(
-                                        &self.tcx.sess.parse_sess, sym::const_fn_union,
-                                        self.span, GateIssue::Language,
-                                        "unions in const fn are unstable",
-                                    );
-                                }
-                            },
+                ProjectionElem::ConstantIndex {..} |
+                ProjectionElem::Subslice {..} |
+                ProjectionElem::Field(..) |
+                ProjectionElem::Index(_) => {
+                    let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
+                    if let Some(def) = base_ty.ty_adt_def() {
+                        if def.is_union() {
+                            match self.mode {
+                                Mode::ConstFn => {
+                                    if !self.tcx.features().const_fn_union {
+                                        emit_feature_err(
+                                            &self.tcx.sess.parse_sess, sym::const_fn_union,
+                                            self.span, GateIssue::Language,
+                                            "unions in const fn are unstable",
+                                        );
+                                    }
+                                },
 
-                            | Mode::NonConstFn
-                            | Mode::Static
-                            | Mode::StaticMut
-                            | Mode::Const
-                            => {},
+                                | Mode::NonConstFn
+                                | Mode::Static
+                                | Mode::StaticMut
+                                | Mode::Const
+                                => {},
+                            }
                         }
                     }
                 }
-            }
 
-            ProjectionElem::Downcast(..) => {
-                self.not_const()
+                ProjectionElem::Downcast(..) => {
+                    self.not_const()
+                }
             }
         }
     }
@@ -1162,7 +1166,7 @@
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = *place {
                     self.cx.per_local[NeedsDrop].remove(local);
                 }
@@ -1179,11 +1183,11 @@
         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
             // Special-case reborrows.
             let mut reborrow_place = None;
-            if let Some(ref proj) = place.projection {
-                if let ProjectionElem::Deref = proj.elem {
-                    let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
+            if let box [proj_base @ .., elem] = &place.projection {
+                if *elem == ProjectionElem::Deref {
+                    let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.sty {
-                        reborrow_place = Some(&proj.base);
+                        reborrow_place = Some(proj_base);
                     }
                 }
             }
@@ -1204,9 +1208,7 @@
                     ),
                 };
                 self.visit_place_base(&place.base, ctx, location);
-                if let Some(proj) = proj {
-                    self.visit_projection(&place.base, proj, ctx, location);
-                }
+                self.visit_projection(&place.base, proj, ctx, location);
             } else {
                 self.super_rvalue(rvalue, location);
             }
@@ -1477,7 +1479,7 @@
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = *place {
                     if NeedsDrop::in_local(self, local) {
                         Some(self.body.local_decls[local].source_info.span)
@@ -1727,7 +1729,7 @@
             TerminatorKind::Drop {
                 location: Place {
                     base: PlaceBase::Local(index),
-                    projection: None,
+                    projection: box [],
                 },
                 target,
                 ..
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5609352..80e020a 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -206,7 +206,7 @@
 ) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
-        StatementKind::Assign(place, rval) => {
+        StatementKind::Assign(box(place, rval)) => {
             check_place(place, span)?;
             check_rvalue(tcx, body, rval, span)
         }
@@ -249,28 +249,26 @@
     place: &Place<'tcx>,
     span: Span,
 ) -> McfResult {
-    place.iterate(|place_base, place_projection| {
-        for proj in place_projection {
-            match proj.elem {
-                ProjectionElem::Downcast(..) => {
-                    return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
-                }
-                ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. }
-                | ProjectionElem::Deref
-                | ProjectionElem::Field(..)
-                | ProjectionElem::Index(_) => {}
+    for elem in place.projection.iter() {
+        match elem {
+            ProjectionElem::Downcast(..) => {
+                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
             }
+            ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Deref
+            | ProjectionElem::Field(..)
+            | ProjectionElem::Index(_) => {}
         }
+    }
 
-        match place_base {
-            PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
-                Err((span, "cannot access `static` items in const fn".into()))
-            }
-            PlaceBase::Local(_)
-            | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
+    match place.base {
+        PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
+            Err((span, "cannot access `static` items in const fn".into()))
         }
-    })
+        PlaceBase::Local(_)
+        | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
+    }
 }
 
 fn check_terminator(
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index 73089a2..70b1194 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -41,10 +41,10 @@
                     // These are all nops in a landing pad
                 }
 
-                StatementKind::Assign(Place {
+                StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(_),
-                    projection: None,
-                }, box Rvalue::Use(_)) => {
+                    projection: box [],
+                }, Rvalue::Use(_))) => {
                     // Writing to a local (e.g., a drop flag) does not
                     // turn a landing pad to a non-nop
                 }
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 1d3bf24..68fa082 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -120,11 +120,11 @@
     let peek_arg_place = match args[0] {
         mir::Operand::Copy(ref place @ mir::Place {
             base: mir::PlaceBase::Local(_),
-            projection: None,
+            projection: box [],
         }) |
         mir::Operand::Move(ref place @ mir::Place {
             base: mir::PlaceBase::Local(_),
-            projection: None,
+            projection: box [],
         }) => Some(place),
         _ => None,
     };
@@ -150,7 +150,7 @@
     for (j, stmt) in statements.iter().enumerate() {
         debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
         let (place, rvalue) = match stmt.kind {
-            mir::StatementKind::Assign(ref place, ref rvalue) => {
+            mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
                 (place, rvalue)
             }
             mir::StatementKind::FakeRead(..) |
@@ -166,7 +166,7 @@
         };
 
         if place == peek_arg_place {
-            if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
+            if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
                 // Okay, our search is over.
                 match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
                     LookupResult::Exact(peek_mpi) => {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 8199a25..34ad5cb 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -61,14 +61,14 @@
                     rvalue: &Rvalue<'tcx>,
                     location: Location) {
         if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
-            if let Some(ref proj) = src_place.projection {
+            if let box [proj_base @ .., elem] = &src_place.projection {
                 if let ProjectionElem::ConstantIndex{offset: _,
                                                      min_length: _,
-                                                     from_end: false} = proj.elem {
+                                                     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;
+                        Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Array(item_ty, const_size) = place_ty.sty {
                         if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
                             assert!(size <= u32::max_value() as u64,
@@ -78,7 +78,7 @@
                                 location,
                                 dst_place,
                                 &src_place.base,
-                                proj,
+                                &src_place.projection,
                                 item_ty,
                                 size as u32,
                             );
@@ -97,73 +97,76 @@
                location: Location,
                dst_place: &Place<'tcx>,
                base: &PlaceBase<'tcx>,
-               proj: &Projection<'tcx>,
+               proj: &[PlaceElem<'tcx>],
                item_ty: &'tcx ty::TyS<'tcx>,
                size: u32) {
-        match proj.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));
+        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: projection.into_boxed_slice(),
+                                                      }
+                                                  )
+                                              )
+                        );
+                        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,
-                                          Place::from(temp),
+                                          dst_place.clone(),
                                           Rvalue::Use(
                                               Operand::Move(
                                                   Place {
                                                       base: base.clone(),
-                                                      projection: Some(box Projection {
-                                                          base: proj.base.clone(),
-                                                          elem: ProjectionElem::ConstantIndex {
-                                                              offset: i,
-                                                              min_length: size,
-                                                              from_end: false,
-                                                          }
-                                                      }),
+                                                      projection: projection.into_boxed_slice(),
                                                   }
                                               )
                                           )
                     );
-                    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);
-                self.patch.add_assign(location,
-                                      dst_place.clone(),
-                                      Rvalue::Use(
-                                          Operand::Move(
-                                              Place {
-                                                  base: base.clone(),
-                                                  projection: Some(box Projection {
-                                                      base: proj.base.clone(),
-                                                      elem: ProjectionElem::ConstantIndex {
-                                                          offset: size - offset,
-                                                          min_length: size,
-                                                          from_end: false,
-                                                      },
-                                                  }),
-                                              }
-                                          )
-                                      )
-                );
-            }
-            _ => {}
         }
     }
 }
@@ -197,12 +200,12 @@
 
             for candidate in &visitor.candidates {
                 let statement = &body[candidate.block].statements[candidate.statement_index];
-                if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
-                    if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval {
+                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 {
                                 base: PlaceBase::Local(local),
-                                projection: None,
+                                projection: box [],
                             }) = item {
                                 let local_use = &visitor.locals_use[*local];
                                 let opt_index_and_place =
@@ -269,16 +272,17 @@
             }
             patch.make_nop(candidate);
             let size = opt_size.unwrap() as u32;
-            patch.add_assign(candidate,
-                             dst_place.clone(),
-                             Rvalue::Use(
-                                 Operand::Move(
-                                     Place {
-                                         base: src_place.base.clone(),
-                                         projection: Some(box Projection {
-                                             base: src_place.projection.clone(),
-                                             elem: ProjectionElem::Subslice{
-                                                 from: min, to: size - max - 1}})})));
+
+            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: projection.into_boxed_slice(),
+                })),
+            );
         }
     }
 
@@ -289,23 +293,34 @@
             if block.statements.len() > location.statement_index {
                 let statement = &block.statements[location.statement_index];
                 if let StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(_),
-                        projection: None,
-                    },
-                    box Rvalue::Use(Operand::Move(Place {
-                        base,
-                        projection: Some(box Projection {
-                            base: proj_base,
-                            elem: ProjectionElem::ConstantIndex {
+                    box(
+                        Place {
+                            base: PlaceBase::Local(_),
+                            projection: box [],
+                        },
+                        Rvalue::Use(Operand::Move(Place {
+                            base: _,
+                            projection: box [.., ProjectionElem::ConstantIndex {
                                 offset, min_length: _, from_end: false
-                            }
-                        }),
-                    }))) = &statement.kind {
-                    return Some((*offset, PlaceRef {
-                        base,
-                        projection: proj_base,
-                    }))
+                            }],
+                        })),
+                    )
+                ) = &statement.kind {
+                    // FIXME remove once we can use slices patterns
+                    if let StatementKind::Assign(
+                        box(
+                            _,
+                            Rvalue::Use(Operand::Move(Place {
+                                base,
+                                projection: box [proj_base @ .., _],
+                            })),
+                        )
+                    ) = &statement.kind {
+                        return Some((*offset, PlaceRef {
+                            base,
+                            projection: proj_base,
+                        }))
+                    }
                 }
             }
         }
diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs
index 98e7067..b3565d4 100644
--- a/src/librustc_mir/util/aggregate.rs
+++ b/src/librustc_mir/util/aggregate.rs
@@ -24,7 +24,7 @@
             if adt_def.is_enum() {
                 set_discriminant = Some(Statement {
                     kind: StatementKind::SetDiscriminant {
-                        place: lhs.clone(),
+                        place: box(lhs.clone()),
                         variant_index,
                     },
                     source_info,
@@ -39,7 +39,7 @@
             let variant_index = VariantIdx::new(0);
             set_discriminant = Some(Statement {
                 kind: StatementKind::SetDiscriminant {
-                    place: lhs.clone(),
+                    place: box(lhs.clone()),
                     variant_index,
                 },
                 source_info,
@@ -70,7 +70,7 @@
         };
         Statement {
             source_info,
-            kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
+            kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))),
         }
     }).chain(set_discriminant)
 }
diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs
index b8ef77d..b4c97f9 100644
--- a/src/librustc_mir/util/alignment.rs
+++ b/src/librustc_mir/util/alignment.rs
@@ -38,14 +38,14 @@
 where
     L: HasLocalDecls<'tcx>,
 {
-    let mut place_projection = &place.projection;
+    for (i, elem) in place.projection.iter().enumerate().rev() {
+        let proj_base = &place.projection[..i];
 
-    while let Some(proj) = place_projection {
-        match proj.elem {
+        match elem {
             // encountered a Deref, which is ABI-aligned
             ProjectionElem::Deref => break,
             ProjectionElem::Field(..) => {
-                let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty;
+                let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
                 match ty.sty {
                     ty::Adt(def, _) if def.repr.packed() => {
                         return true
@@ -55,7 +55,6 @@
             }
             _ => {}
         }
-        place_projection = &proj.base;
     }
 
     false
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index f3e03e7..52ad97b 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -586,10 +586,7 @@
                 BorrowKind::Mut { allow_two_phase_borrow: false },
                 Place {
                     base: PlaceBase::Local(cur),
-                    projection: Some(Box::new(Projection {
-                        base: None,
-                        elem: ProjectionElem::Deref,
-                    })),
+                    projection: Box::new([ProjectionElem::Deref]),
                 }
              ),
              Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
@@ -981,7 +978,7 @@
     fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
         Statement {
             source_info: self.source_info,
-            kind: StatementKind::Assign(lhs.clone(), box rhs)
+            kind: StatementKind::Assign(box(lhs.clone(), rhs))
         }
     }
 }
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index eb457da..2ea9924 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -120,7 +120,7 @@
     }
 
     pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
-        self.add_statement(loc, StatementKind::Assign(place, box rv));
+        self.add_statement(loc, StatementKind::Assign(box(place, rv)));
     }
 
     pub fn make_nop(&mut self, loc: Location) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index f97fcb0..74f68e5 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -40,7 +40,7 @@
 use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
 use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
-use syntax::symbol::{Symbol, kw, sym};
+use syntax::symbol::{kw, sym};
 
 use syntax::visit::{self, Visitor};
 use syntax::attr;
@@ -241,7 +241,7 @@
 
     fn names_to_string(segments: &[Segment]) -> String {
         names_to_string(&segments.iter()
-                            .map(|seg| seg.ident)
+                            .map(|seg| seg.ident.name)
                             .collect::<Vec<_>>())
     }
 }
@@ -951,7 +951,7 @@
     struct_constructors: DefIdMap<(Res, ty::Visibility)>,
 
     /// Features enabled for this crate.
-    active_features: FxHashSet<Symbol>,
+    active_features: FxHashSet<Name>,
 
     /// Stores enum visibilities to properly build a reduced graph
     /// when visiting the correspondent variants.
@@ -1018,8 +1018,8 @@
     fn resolve_str_path(
         &mut self,
         span: Span,
-        crate_root: Option<Symbol>,
-        components: &[Symbol],
+        crate_root: Option<Name>,
+        components: &[Name],
         ns: Namespace,
     ) -> (ast::Path, Res) {
         let root = if crate_root.is_some() {
@@ -2555,7 +2555,7 @@
     fn add_suggestion_for_rename_of_use(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        name: Symbol,
+        name: Name,
         directive: &ImportDirective<'_>,
         binding_span: Span,
     ) {
@@ -2770,22 +2770,22 @@
     }
 }
 
-fn names_to_string(idents: &[Ident]) -> String {
+fn names_to_string(names: &[Name]) -> String {
     let mut result = String::new();
-    for (i, ident) in idents.iter()
-                            .filter(|ident| ident.name != kw::PathRoot)
+    for (i, name) in names.iter()
+                            .filter(|name| **name != kw::PathRoot)
                             .enumerate() {
         if i > 0 {
             result.push_str("::");
         }
-        result.push_str(&ident.as_str());
+        result.push_str(&name.as_str());
     }
     result
 }
 
 fn path_names_to_string(path: &Path) -> String {
     names_to_string(&path.segments.iter()
-                        .map(|seg| seg.ident)
+                        .map(|seg| seg.ident.name)
                         .collect::<Vec<_>>())
 }
 
@@ -2793,15 +2793,14 @@
 fn module_to_string(module: Module<'_>) -> Option<String> {
     let mut names = Vec::new();
 
-    fn collect_mod(names: &mut Vec<Ident>, module: Module<'_>) {
+    fn collect_mod(names: &mut Vec<Name>, module: Module<'_>) {
         if let ModuleKind::Def(.., name) = module.kind {
             if let Some(parent) = module.parent {
-                names.push(Ident::with_dummy_span(name));
+                names.push(name);
                 collect_mod(names, parent);
             }
         } else {
-            // danger, shouldn't be ident?
-            names.push(Ident::from_str("<opaque>"));
+            names.push(Name::intern("<opaque>"));
             collect_mod(names, module.parent.unwrap());
         }
     }
@@ -2810,9 +2809,8 @@
     if names.is_empty() {
         return None;
     }
-    Some(names_to_string(&names.into_iter()
-                        .rev()
-                        .collect::<Vec<_>>()))
+    names.reverse();
+    Some(names_to_string(&names))
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index bd8b5e1..3900a3d 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -237,7 +237,8 @@
                 if let Res::Def(..) = res {
                     self.session.span_err(
                         span,
-                        "expected an inert attribute, found an attribute macro"
+                        &format!("expected an inert attribute, found {} {}",
+                                 res.article(), res.descr()),
                     );
                     return Ok(InvocationRes::Single(self.dummy_ext(kind)));
                 }
@@ -322,7 +323,7 @@
         self.check_stability_and_deprecation(&ext, path);
 
         Ok(if ext.macro_kind() != kind {
-            let expected = if kind == MacroKind::Attr { "attribute" } else  { kind.descr() };
+            let expected = kind.descr_expected();
             let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path);
             self.session.struct_span_err(path.span, &msg)
                         .span_label(path.span, format!("not {} {}", kind.article(), expected))
@@ -773,9 +774,8 @@
                 }
                 Err(..) => {
                     assert!(initial_binding.is_none());
-                    let bang = if kind == MacroKind::Bang { "!" } else { "" };
-                    let msg =
-                        format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
+                    let expected = kind.descr_expected();
+                    let msg = format!("cannot find {} `{}` in this scope", expected, ident);
                     let mut err = self.session.struct_span_err(ident.span, &msg);
                     self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
                     err.emit();
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index eb509f1..e77e829 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -1433,15 +1433,17 @@
     let global = !names.is_empty() && names[0].name == kw::PathRoot;
     if let Some(pos) = pos {
         let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] };
-        names_to_string(names)
+        names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>())
     } else {
         let names = if global { &names[1..] } else { names };
         if names.is_empty() {
             import_directive_subclass_to_string(subclass)
         } else {
-            format!("{}::{}",
-                    names_to_string(names),
-                    import_directive_subclass_to_string(subclass))
+            format!(
+                "{}::{}",
+                names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>()),
+                import_directive_subclass_to_string(subclass),
+            )
         }
     }
 }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 7427ae9..308a3d8 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -2,7 +2,8 @@
 use crate::check::coercion::CoerceMany;
 use rustc::hir::{self, ExprKind};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::traits::{ObligationCause, ObligationCauseCode};
+use rustc::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use rustc::traits::{ObligationCauseCode};
 use rustc::ty::Ty;
 use syntax_pos::Span;
 
@@ -146,13 +147,15 @@
                     // The reason for the first arm to fail is not that the match arms diverge,
                     // but rather that there's a prior obligation that doesn't hold.
                     0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
-                    _ => (expr.span, ObligationCauseCode::MatchExpressionArm {
-                        arm_span,
-                        source: match_src,
-                        prior_arms: other_arms.clone(),
-                        last_ty: prior_arm_ty.unwrap(),
-                        discrim_hir_id: discrim.hir_id,
-                    }),
+                    _ => (expr.span,
+                          ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                            arm_span,
+                            source: match_src,
+                            prior_arms: other_arms.clone(),
+                            last_ty: prior_arm_ty.unwrap(),
+                            discrim_hir_id: discrim.hir_id,
+                          })
+                         ),
                 };
                 let cause = self.cause(span, code);
                 coercion.coerce(self, &cause, &arm.body, arm_ty);
@@ -345,11 +348,11 @@
         };
 
         // Finally construct the cause:
-        self.cause(error_sp, ObligationCauseCode::IfExpression {
+        self.cause(error_sp, ObligationCauseCode::IfExpression(box IfExpressionCause {
             then: then_sp,
             outer: outer_sp,
             semicolon: remove_semicolon,
-        })
+        }))
     }
 
     fn demand_discriminant_type(
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index e937042..d626bff 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -529,11 +529,11 @@
                 ); // recreated from (*) above
 
                 // Check that E' = S'.
-                let cause = &self.misc(hir_ty.span);
+                let cause = self.misc(hir_ty.span);
                 let InferOk {
                     value: (),
                     obligations,
-                } = self.at(cause, self.param_env)
+                } = self.at(&cause, self.param_env)
                     .eq(*expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
 
@@ -549,7 +549,7 @@
                 );
                 all_obligations.push(
                     Obligation::new(
-                        cause.clone(),
+                        cause,
                         self.param_env,
                         ty::Predicate::TypeOutlives(
                             ty::Binder::dummy(
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index f22499f..51adf50 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -309,7 +309,7 @@
 
             let cause = ObligationCause {
                 span: impl_err_span,
-                ..cause.clone()
+                ..cause
             };
 
             let mut diag = struct_span_err!(tcx.sess,
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index da72dfd..56bd903 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -813,18 +813,20 @@
         error: MethodError<'tcx>
     ) {
         let rcvr = &args[0];
-        let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
-            if let Ok(pick) = self.lookup_probe(
-                span,
-                segment.ident,
-                new_rcvr_t,
-                rcvr,
-                probe::ProbeScope::AllTraits,
-            ) {
-                err.span_label(
-                    pick.item.ident.span,
-                    &format!("the method is available for `{}` here", new_rcvr_t),
-                );
+        let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, rcvr_t, lang_item| {
+            if let Some(new_rcvr_t) = self.tcx.mk_lang_item(rcvr_t, lang_item) {
+                if let Ok(pick) = self.lookup_probe(
+                    span,
+                    segment.ident,
+                    new_rcvr_t,
+                    rcvr,
+                    probe::ProbeScope::AllTraits,
+                ) {
+                    err.span_label(
+                        pick.item.ident.span,
+                        &format!("the method is available for `{}` here", new_rcvr_t),
+                    );
+                }
             }
         };
 
@@ -840,17 +842,10 @@
                 // Try alternative arbitrary self types that could fulfill this call.
                 // FIXME: probe for all types that *could* be arbitrary self-types, not
                 // just this whitelist.
-                let box_rcvr_t = self.tcx.mk_box(rcvr_t);
-                try_alt_rcvr(&mut err, box_rcvr_t);
-                let pin_rcvr_t = self.tcx.mk_lang_item(
-                    rcvr_t,
-                    lang_items::PinTypeLangItem,
-                );
-                try_alt_rcvr(&mut err, pin_rcvr_t);
-                let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
-                try_alt_rcvr(&mut err, arc_rcvr_t);
-                let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
-                try_alt_rcvr(&mut err, rc_rcvr_t);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::OwnedBoxLangItem);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::PinTypeLangItem);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::Arc);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::Rc);
             }
             err.emit();
         }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 02e7d97..1197160 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -400,7 +400,7 @@
 
 impl UnsafetyState {
     pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
-        UnsafetyState { def: def, unsafety: unsafety, unsafe_push_count: 0, from_fn: true }
+        UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true }
     }
 
     pub fn recurse(&mut self, blk: &hir::Block) -> UnsafetyState {
@@ -1088,6 +1088,8 @@
 
     let span = body.value.span;
 
+    fn_maybe_err(fcx.tcx, span, fn_sig.abi);
+
     if body.generator_kind.is_some() && can_be_generator.is_some() {
         let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::TypeInference,
@@ -1439,6 +1441,14 @@
     }
 }
 
+// Forbid defining intrinsics in Rust code,
+// as they must always be defined by the compiler.
+fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+    if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+        tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
+    }
+}
+
 pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
     debug!(
         "check_item_type(it.hir_id={}, it.name={})",
@@ -1475,9 +1485,17 @@
                 check_on_unimplemented(tcx, trait_def_id, it);
             }
         }
-        hir::ItemKind::Trait(..) => {
+        hir::ItemKind::Trait(_, _, _, _, ref items) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
             check_on_unimplemented(tcx, def_id, it);
+
+            for item in items.iter() {
+                let item = tcx.hir().trait_item(item.id);
+                if let hir::TraitItemKind::Method(sig, _) = &item.node {
+                    let abi = sig.header.abi;
+                    fn_maybe_err(tcx, item.ident.span, abi);
+                }
+            }
         }
         hir::ItemKind::Struct(..) => {
             check_struct(tcx, it.hir_id, it.span);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d77e790..0b9e717 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -473,7 +473,7 @@
     // First, parse the crate and extract all relevant information.
     info!("starting to run rustc");
 
-    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
+    let result = rustc_driver::catch_fatal_errors(move || {
         let crate_name = options.crate_name.clone();
         let crate_version = options.crate_version.clone();
         let (mut krate, renderinfo, renderopts) = core::run_core(options);
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index eca9339..b898936 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -290,7 +290,7 @@
 ///
 /// Note that while concurrent access to environment variables is safe in Rust,
 /// some platforms only expose inherently unsafe non-threadsafe APIs for
-/// inspecting the environment. As a result extra care needs to be taken when
+/// inspecting the environment. As a result, extra care needs to be taken when
 /// auditing calls to unsafe external FFI functions to ensure that any external
 /// environment accesses are properly synchronized with accesses in Rust.
 ///
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 998d59f..4a1bb75 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -197,10 +197,10 @@
     #[stable(feature = "error_source", since = "1.30.0")]
     fn source(&self) -> Option<&(dyn Error + 'static)> { None }
 
-    /// Gets the `TypeId` of `self`
+    /// Gets the `TypeId` of `self`.
     #[doc(hidden)]
     #[unstable(feature = "error_type_id",
-               reason = "this is memory unsafe to override in user code",
+               reason = "this is memory-unsafe to override in user code",
                issue = "60784")]
     fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static {
         TypeId::of::<Self>()
@@ -616,19 +616,19 @@
     }
 }
 
-// copied from any.rs
+// Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the boxed type is the same as `T`
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
-        // Get TypeId of the type this function is instantiated with
+        // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get TypeId of the type in the trait object
+        // Get `TypeId` of the type in the trait object.
         let boxed = self.type_id(private::Internal);
 
-        // Compare both TypeIds on equality
+        // Compare both `TypeId`s on equality.
         t == boxed
     }
 
@@ -662,21 +662,21 @@
 }
 
 impl dyn Error + 'static + Send {
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         <dyn Error + 'static>::is::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         <dyn Error + 'static>::downcast_ref::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
@@ -685,21 +685,21 @@
 }
 
 impl dyn Error + 'static + Send + Sync {
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         <dyn Error + 'static>::is::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         <dyn Error + 'static>::downcast_ref::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
@@ -710,7 +710,7 @@
 impl dyn Error {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
         if self.is::<T>() {
             unsafe {
@@ -878,12 +878,12 @@
 impl dyn Error + Send {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>)
                                         -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // reapply the Send marker
+            // Reapply the `Send` marker.
             transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
         })
     }
@@ -892,12 +892,12 @@
 impl dyn Error + Send + Sync {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>)
                                         -> Result<Box<T>, Box<Self>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // reapply the Send+Sync marker
+            // Reapply the `Send + Sync` marker.
             transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
         })
     }
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index bb346fb..d7f4cc5 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -615,7 +615,7 @@
 }
 
 // Turns this `CString` into an empty string to prevent
-// memory unsafe code from working by accident. Inline
+// memory-unsafe code from working by accident. Inline
 // to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
 impl Drop for CString {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index b14e02a..b5265fe 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1956,7 +1956,8 @@
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `opendir` function on Unix
-/// and the `FindFirstFile` function on Windows.
+/// and the `FindFirstFile` function on Windows. Advancing the iterator
+/// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: ../io/index.html#platform-specific-behavior
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 990c0eb..c798ee0 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -201,9 +201,9 @@
 ///
 /// Each handle returned is a reference to a shared global buffer whose access
 /// is synchronized via a mutex. If you need more explicit control over
-/// locking, see the [`lock() method`][lock].
+/// locking, see the [`Stdin::lock`] method.
 ///
-/// [lock]: struct.Stdin.html#method.lock
+/// [`Stdin::lock`]: struct.Stdin.html#method.lock
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
@@ -425,9 +425,9 @@
 ///
 /// Each handle returned is a reference to a shared global buffer whose access
 /// is synchronized via a mutex. If you need more explicit control over
-/// locking, see the [Stdout::lock] method.
+/// locking, see the [`Stdout::lock`] method.
 ///
-/// [Stdout::lock]: struct.Stdout.html#method.lock
+/// [`Stdout::lock`]: struct.Stdout.html#method.lock
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 000f80f..c50025a 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1595,7 +1595,7 @@
 
 /// A trait for implementing arbitrary return types in the `main` function.
 ///
-/// The c-main function only supports to return integers as return type.
+/// The C-main function only supports to return integers as return type.
 /// So, every type implementing the `Termination` trait has to be converted
 /// to an integer.
 ///
diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs
index 4dc7060..1fc88fb 100644
--- a/src/libstd/sys/vxworks/process/mod.rs
+++ b/src/libstd/sys/vxworks/process/mod.rs
@@ -1,5 +1,6 @@
 pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
 pub use self::process_inner::Process;
+pub use crate::ffi::OsString as EnvKey;
 
 mod process_common;
 #[path = "process_vxworks.rs"]
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
index 5091402..13648ab 100644
--- a/src/libstd/sys/vxworks/process/process_common.rs
+++ b/src/libstd/sys/vxworks/process/process_common.rs
@@ -12,8 +12,6 @@
 
 use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
 
-pub use crate::ffi::OsString as EnvKey;
-
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs
index 1ec0cbe..c22880d 100644
--- a/src/libstd/sys/vxworks/rand.rs
+++ b/src/libstd/sys/vxworks/rand.rs
@@ -14,17 +14,24 @@
 mod imp {
     use libc;
     use crate::io;
-
-    extern "C" {
-        fn randBytes (randBuf: *mut libc::c_uchar,
-                      numOfBytes: libc::c_int) -> libc::c_int;
-    }
+    use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
 
     pub fn fill_bytes(v: &mut [u8]) {
+        static RNG_INIT: AtomicBool = AtomicBool::new(false);
+        while !RNG_INIT.load(Relaxed) {
+            let ret = unsafe { libc::randSecure() };
+            if ret < 0 {
+                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
+            } else if ret > 0 {
+                RNG_INIT.store(true, Relaxed);
+                break;
+            }
+            unsafe { libc::usleep(10) };
+        }
         let ret = unsafe {
-            randBytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
+            libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
         };
-        if ret == -1 {
+        if ret < 0 {
             panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
         }
     }
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index dbec4da..3bf2b8b 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -59,6 +59,30 @@
 ///    println!("{}", now.elapsed().as_secs());
 /// }
 /// ```
+///
+/// # Underlying System calls
+/// Currently, the following system calls are being used to get the current time using `now()`:
+///
+/// |  Platform |               System call                                            |
+/// |:---------:|:--------------------------------------------------------------------:|
+/// | Cloud ABI | [clock_time_get (Monotonic Clock)]                                   |
+/// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
+/// | UNIX      | [clock_time_get (Monotonic Clock)]                                   |
+/// | Darwin    | [mach_absolute_time]                                                 |
+/// | VXWorks   | [clock_gettime (Monotonic Clock)]                                    |
+/// | WASI      | [__wasi_clock_time_get (Monotonic Clock)]                            |
+/// | Windows   | [QueryPerformanceCounter]                                            |
+///
+/// [QueryPerformanceCounter]: https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
+/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
+/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
+/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get
+/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
+/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
+/// [clock_time_get (Monotonic Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt
+///
+/// **Disclaimer:** These system calls might change over time.
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -114,6 +138,28 @@
 ///    }
 /// }
 /// ```
+///
+/// # Underlying System calls
+/// Currently, the following system calls are being used to get the current time using `now()`:
+///
+/// |  Platform |               System call                                            |
+/// |:---------:|:--------------------------------------------------------------------:|
+/// | Cloud ABI | [clock_time_get (Realtime Clock)]                                    |
+/// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
+/// | UNIX      | [clock_gettime (Realtime Clock)]                                     |
+/// | DARWIN    | [gettimeofday]                                                       |
+/// | VXWorks   | [clock_gettime (Realtime Clock)]                                     |
+/// | WASI      | [__wasi_clock_time_get (Realtime Clock)]                             |
+/// | Windows   | [GetSystemTimeAsFileTime]                                            |
+///
+/// [clock_time_get (Realtime Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt
+/// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html
+/// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime
+/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get
+/// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
+///
+/// **Disclaimer:** These system calls might change over time.
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTime(time::SystemTime);
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 7759a98..384c055 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -977,13 +977,6 @@
         span.with_call_site_ctxt(self.current_expansion.id)
     }
 
-    /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
-    /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
-    /// or with `with_call_site_ctxt` (where necessary).
-    pub fn with_legacy_ctxt(&self, span: Span) -> Span {
-        span.with_legacy_ctxt(self.current_expansion.id)
-    }
-
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
@@ -1081,8 +1074,8 @@
     pub fn set_trace_macros(&mut self, x: bool) {
         self.ecfg.trace_mac = x
     }
-    pub fn ident_of(&self, st: &str) -> ast::Ident {
-        ast::Ident::from_str(st)
+    pub fn ident_of(&self, st: &str, sp: Span) -> ast::Ident {
+        ast::Ident::from_str_and_span(st, sp)
     }
     pub fn std_path(&self, components: &[Symbol]) -> Vec<ast::Ident> {
         let def_site = self.with_def_site_ctxt(DUMMY_SP);
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 06a5531..f1d0e0b 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -363,7 +363,7 @@
         self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp)))
     }
     pub fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp);
+        let ident = Ident::new(sym::integer(idx), sp);
         self.expr(sp, ast::ExprKind::Field(expr, ident))
     }
     pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
@@ -525,7 +525,7 @@
         let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
         let err_path = self.path_global(sp, err);
 
-        let binding_variable = self.ident_of("__try_var");
+        let binding_variable = self.ident_of("__try_var", sp);
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 87e2d72..b80c530 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -26,7 +26,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use std::io::ErrorKind;
-use std::{iter, mem};
+use std::{iter, mem, slice};
 use std::ops::DerefMut;
 use std::rc::Rc;
 use std::path::PathBuf;
@@ -1019,7 +1019,7 @@
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            self.check_attribute_inner(attr, features);
+            feature_gate::check_attribute(attr, self.cx.parse_sess, features);
 
             // macros are expanded before any lint passes so this warning has to be hardcoded
             if attr.path == sym::derive {
@@ -1029,15 +1029,6 @@
             }
         }
     }
-
-    fn check_attribute(&mut self, at: &ast::Attribute) {
-        let features = self.cx.ecfg.features.unwrap();
-        self.check_attribute_inner(at, features);
-    }
-
-    fn check_attribute_inner(&mut self, at: &ast::Attribute, features: &Features) {
-        feature_gate::check_attribute(at, self.cx.parse_sess, features);
-    }
 }
 
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
@@ -1445,7 +1436,7 @@
 
                 if let Some(file) = it.value_str() {
                     let err_count = self.cx.parse_sess.span_diagnostic.err_count();
-                    self.check_attribute(&at);
+                    self.check_attributes(slice::from_ref(at));
                     if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
                         // avoid loading the file if they haven't enabled the feature
                         return noop_visit_attribute(at, self);
diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs
index 763c3ff..b6e1320 100644
--- a/src/libsyntax/feature_gate/builtin_attrs.rs
+++ b/src/libsyntax/feature_gate/builtin_attrs.rs
@@ -79,6 +79,7 @@
     CrateLevel,
 }
 
+#[derive(Clone, Copy)]
 pub enum AttributeGate {
     /// Is gated by a given feature gate, reason
     /// and function to check if enabled
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 5711b26..b4491a8 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -1,7 +1,7 @@
 use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState};
 use super::accepted::ACCEPTED_FEATURES;
 use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
-use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
+use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 
 use crate::ast::{
     self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
@@ -32,16 +32,10 @@
     Deprecated(&'static str, Option<&'static str>),
 }
 
-struct Context<'a> {
-    features: &'a Features,
-    parse_sess: &'a ParseSess,
-    plugin_attributes: &'a [(Symbol, AttributeType)],
-}
-
 macro_rules! gate_feature_fn {
     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
         let (cx, has_feature, span,
-             name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
+             name, explain, level) = (&*$cx, $has_feature, $span, $name, $explain, $level);
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !span.allows_unstable($name) {
@@ -62,68 +56,8 @@
     };
 }
 
-impl<'a> Context<'a> {
-    fn check_attribute(
-        &self,
-        attr: &ast::Attribute,
-        attr_info: Option<&BuiltinAttribute>,
-        is_macro: bool
-    ) {
-        debug!("check_attribute(attr = {:?})", attr);
-        if let Some(&(name, ty, _template, ref gateage)) = attr_info {
-            if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage {
-                if !attr.span.allows_unstable(name) {
-                    gate_feature_fn!(
-                        self, has_feature, attr.span, name, desc, GateStrength::Hard
-                    );
-                }
-            } else if name == sym::doc {
-                if let Some(content) = attr.meta_item_list() {
-                    if content.iter().any(|c| c.check_name(sym::include)) {
-                        gate_feature!(self, external_doc, attr.span,
-                            "`#[doc(include = \"...\")]` is experimental"
-                        );
-                    }
-                }
-            }
-            debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
-            return;
-        } else {
-            for segment in &attr.path.segments {
-                if segment.ident.as_str().starts_with("rustc") {
-                    let msg = "attributes starting with `rustc` are \
-                               reserved for use by the `rustc` compiler";
-                    gate_feature!(self, rustc_attrs, segment.ident.span, msg);
-                }
-            }
-        }
-        for &(n, ty) in self.plugin_attributes {
-            if attr.path == n {
-                // Plugins can't gate attributes, so we don't check for it
-                // unlike the code above; we only use this loop to
-                // short-circuit to avoid the checks below.
-                debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
-                return;
-            }
-        }
-        if !is_macro && !attr::is_known(attr) {
-            // Only run the custom attribute lint during regular feature gate
-            // checking. Macro gating runs before the plugin attributes are
-            // registered, so we skip this in that case.
-            let msg = format!("the attribute `{}` is currently unknown to the compiler and \
-                               may have meaning added to it in the future", attr.path);
-            gate_feature!(self, custom_attribute, attr.span, &msg);
-        }
-    }
-}
-
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
-    let cx = Context { features, parse_sess, plugin_attributes: &[] };
-    cx.check_attribute(
-        attr,
-        attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)),
-        true
-    );
+crate fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+    PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
@@ -238,21 +172,21 @@
     "unsized tuple coercion is not stable enough for use and is subject to change";
 
 struct PostExpansionVisitor<'a> {
-    context: &'a Context<'a>,
-    builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
+    parse_sess: &'a ParseSess,
+    features: &'a Features,
 }
 
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
         if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx.context, $feature, span, $explain)
+            gate_feature!(cx, $feature, span, $explain)
         }
     }};
     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
         let (cx, span) = ($cx, $span);
         if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx.context, $feature, span, $explain, $level)
+            gate_feature!(cx, $feature, span, $explain, $level)
         }
     }}
 }
@@ -316,50 +250,44 @@
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        let attr_info = attr.ident().and_then(|ident| {
-            self.builtin_attributes.get(&ident.name).map(|a| *a)
-        });
-
-        // Check for gated attributes.
-        self.context.check_attribute(attr, attr_info, false);
-
-        if attr.check_name(sym::doc) {
-            if let Some(content) = attr.meta_item_list() {
-                if content.len() == 1 && content[0].check_name(sym::cfg) {
-                    gate_feature_post!(&self, doc_cfg, attr.span,
-                        "`#[doc(cfg(...))]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::masked)) {
-                    gate_feature_post!(&self, doc_masked, attr.span,
-                        "`#[doc(masked)]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::spotlight)) {
-                    gate_feature_post!(&self, doc_spotlight, attr.span,
-                        "`#[doc(spotlight)]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::alias)) {
-                    gate_feature_post!(&self, doc_alias, attr.span,
-                        "`#[doc(alias = \"...\")]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::keyword)) {
-                    gate_feature_post!(&self, doc_keyword, attr.span,
-                        "`#[doc(keyword = \"...\")]` is experimental"
-                    );
-                }
-            }
+        let attr_info =
+            attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+        // Check feature gates for built-in attributes.
+        if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
+            gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
         }
-
+        // Check input tokens for built-in and key-value attributes.
         match attr_info {
             // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
-            Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
-                check_builtin_attribute(self.context.parse_sess, attr, name, template),
+            Some((name, _, template, _)) if name != sym::rustc_dummy =>
+                check_builtin_attribute(self.parse_sess, attr, name, template),
             _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
                 if token == token::Eq {
                     // All key-value attributes are restricted to meta-item syntax.
-                    attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
+                    attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok();
                 }
             }
         }
+        // Check unstable flavors of the `#[doc]` attribute.
+        if attr.check_name(sym::doc) {
+            for nested_meta in attr.meta_item_list().unwrap_or_default() {
+                macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
+                    $(if nested_meta.check_name(sym::$name) {
+                        let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
+                        gate_feature!(self, $feature, attr.span, msg);
+                    })*
+                }}
+
+                gate_doc!(
+                    include => external_doc
+                    cfg => doc_cfg
+                    masked => doc_masked
+                    spotlight => doc_spotlight
+                    alias => doc_alias
+                    keyword => doc_keyword
+                );
+            }
+        }
     }
 
     fn visit_name(&mut self, sp: Span, name: ast::Name) {
@@ -367,7 +295,7 @@
             gate_feature_post!(
                 &self,
                 non_ascii_idents,
-                self.context.parse_sess.source_map().def_span(sp),
+                self.parse_sess.source_map().def_span(sp),
                 "non-ascii idents are not fully supported"
             );
         }
@@ -423,12 +351,9 @@
                     }
                 }
 
-                let has_feature = self.context.features.arbitrary_enum_discriminant;
+                let has_feature = self.features.arbitrary_enum_discriminant;
                 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
-                    Parser::maybe_report_invalid_custom_discriminants(
-                        self.context.parse_sess,
-                        &variants,
-                    );
+                    Parser::maybe_report_invalid_custom_discriminants(self.parse_sess, &variants);
                 }
             }
 
@@ -538,7 +463,7 @@
             ast::ExprKind::Type(..) => {
                 // To avoid noise about type ascription in common syntax errors, only emit if it
                 // is the *only* error.
-                if self.context.parse_sess.span_diagnostic.err_count() == 0 {
+                if self.parse_sess.span_diagnostic.err_count() == 0 {
                     gate_feature_post!(&self, type_ascription, e.span,
                                        "type ascription is experimental");
                 }
@@ -872,22 +797,17 @@
 }
 
 pub fn check_crate(krate: &ast::Crate,
-                   sess: &ParseSess,
+                   parse_sess: &ParseSess,
                    features: &Features,
-                   plugin_attributes: &[(Symbol, AttributeType)],
                    unstable: UnstableFeatures) {
-    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
-    let ctx = Context {
-        features,
-        parse_sess: sess,
-        plugin_attributes,
-    };
+    maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
+    let mut visitor = PostExpansionVisitor { parse_sess, features };
 
     macro_rules! gate_all {
         ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); };
         ($spans:ident, $gate:ident, $msg:literal) => {
-            for span in &*sess.gated_spans.$spans.borrow() {
-                gate_feature!(&ctx, $gate, *span, $msg);
+            for span in &*parse_sess.gated_spans.$spans.borrow() {
+                gate_feature!(&visitor, $gate, *span, $msg);
             }
         }
     }
@@ -898,11 +818,7 @@
     gate_all!(yields, generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
 
-    let visitor = &mut PostExpansionVisitor {
-        context: &ctx,
-        builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
-    };
-    visit::walk_crate(visitor, krate);
+    visit::walk_crate(&mut visitor, krate);
 }
 
 #[derive(Clone, Copy, Hash)]
diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs
index 1e41667..ca13ab3 100644
--- a/src/libsyntax/feature_gate/mod.rs
+++ b/src/libsyntax/feature_gate/mod.rs
@@ -58,7 +58,8 @@
     deprecated_attributes, is_builtin_attr,  is_builtin_attr_name,
 };
 pub use check::{
-    check_attribute, check_crate, get_features, feature_err, emit_feature_err,
+    check_crate, get_features, feature_err, emit_feature_err,
     Stability, GateIssue, UnstableFeatures,
     EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
 };
+crate use check::check_attribute;
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index bc1bc00..2441a02 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -13,6 +13,8 @@
 
 use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+#[cfg(target_arch = "x86_64")]
+use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::{Lrc, Lock, Once};
 use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
 use syntax_pos::edition::Edition;
@@ -38,6 +40,11 @@
 
 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
 
+// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
+// (See also the comment on `DiagnosticBuilderInner`.)
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PResult<'_, bool>, 16);
+
 /// Collected spans during parsing for places where a certain feature was
 /// used and should be feature gated accordingly in `check_crate`.
 #[derive(Default)]
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index baae615..cf19664 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -1256,7 +1256,7 @@
             for part in idents {
                 fixed_name.push_str(&format!("_{}", part.name));
             }
-            ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp);
+            ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp);
 
             self.struct_span_err(fixed_name_sp, error_msg)
                 .span_label(fixed_name_sp, "dash-separated idents are not valid")
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 328b307..75d727b 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -62,7 +62,7 @@
     MacEager::expr(P(ast::Expr {
         id: ast::DUMMY_NODE_ID,
         node: ast::ExprKind::InlineAsm(P(inline_asm)),
-        span: cx.with_legacy_ctxt(sp),
+        span: cx.with_def_site_ctxt(sp),
         attrs: ThinVec::new(),
     }))
 }
diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs
index 001996e..cbfe14f 100644
--- a/src/libsyntax_ext/assert.rs
+++ b/src/libsyntax_ext/assert.rs
@@ -23,7 +23,9 @@
         }
     };
 
-    let sp = cx.with_legacy_ctxt(sp);
+    // `core::panic` and `std::panic` are different macros, so we use call-site
+    // context to pick up whichever is currently in scope.
+    let sp = cx.with_call_site_ctxt(sp);
     let panic_call = Mac {
         path: Path::from_ident(Ident::new(sym::panic, sp)),
         tts: custom_message.unwrap_or_else(|| {
diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs
index 0342e44..3c33baf 100644
--- a/src/libsyntax_ext/cfg.rs
+++ b/src/libsyntax_ext/cfg.rs
@@ -16,7 +16,7 @@
     sp: Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'static> {
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
 
     match parse_cfg(cx, sp, tts) {
         Ok(cfg) => {
diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs
index fc56dff..16f0160 100644
--- a/src/libsyntax_ext/concat.rs
+++ b/src/libsyntax_ext/concat.rs
@@ -59,6 +59,6 @@
     } else if has_errors {
         return DummyResult::any(sp);
     }
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
     base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
 }
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index 6391b62..f344706 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -39,7 +39,7 @@
         }
     }
 
-    let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_legacy_ctxt(sp));
+    let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp));
 
     struct ConcatIdentsResult { ident: ast::Ident }
 
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
index debdc30..13d63aa 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -109,7 +109,7 @@
         GtOp => "gt",
         GeOp => "ge",
     };
-    cx.expr_method_call(span, lft, ast::Ident::from_str_and_span(op_str, span), vec![rgt])
+    cx.expr_method_call(span, lft, cx.ident_of(op_str, span), vec![rgt])
 }
 
 pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 781645a..088b61b 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -62,7 +62,7 @@
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
-    let builder = Ident::from_str_and_span("debug_trait_builder", span);
+    let builder = cx.ident_of("debug_trait_builder", span);
     let builder_expr = cx.expr_ident(span, builder.clone());
 
     let fmt = substr.nonself_args[0].clone();
@@ -72,7 +72,7 @@
         ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
             // tuple struct/"normal" variant
             let expr =
-                cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]);
+                cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
             stmts.push(cx.stmt_let(span, true, builder, expr));
 
             for field in fields {
@@ -93,7 +93,7 @@
         ast::VariantData::Struct(..) => {
             // normal struct/struct variant
             let expr =
-                cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]);
+                cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]);
             stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
 
             for field in fields {
@@ -113,7 +113,7 @@
         }
     }
 
-    let expr = cx.expr_method_call(span, builder_expr, Ident::from_str("finish"), vec![]);
+    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);
 
     stmts.push(cx.stmt_expr(expr));
     let block = cx.block(span, stmts);
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index d3d604b..cde72ab 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -66,10 +66,14 @@
                           krate: &str)
                           -> P<Expr> {
     let decoder = substr.nonself_args[0].clone();
-    let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")];
+    let recurse = vec![
+        cx.ident_of(krate, trait_span),
+        cx.ident_of("Decodable", trait_span),
+        cx.ident_of("decode", trait_span),
+    ];
     let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_d");
+    let blkarg = cx.ident_of("_d", trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
     return match *substr.fields {
@@ -78,7 +82,7 @@
                 Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
-            let read_struct_field = cx.ident_of("read_struct_field");
+            let read_struct_field = cx.ident_of("read_struct_field", trait_span);
 
             let path = cx.path_ident(trait_span, substr.type_ident);
             let result =
@@ -94,17 +98,17 @@
             let result = cx.expr_ok(trait_span, result);
             cx.expr_method_call(trait_span,
                                 decoder,
-                                cx.ident_of("read_struct"),
+                                cx.ident_of("read_struct", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.expr_usize(trait_span, nfields),
                                      cx.lambda1(trait_span, result, blkarg)])
         }
         StaticEnum(_, ref fields) => {
-            let variant = cx.ident_of("i");
+            let variant = cx.ident_of("i", trait_span);
 
             let mut arms = Vec::with_capacity(fields.len() + 1);
             let mut variants = Vec::with_capacity(fields.len());
-            let rvariant_arg = cx.ident_of("read_enum_variant_arg");
+            let rvariant_arg = cx.ident_of("read_enum_variant_arg", trait_span);
 
             for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
                 variants.push(cx.expr_str(v_span, ident.name));
@@ -132,11 +136,11 @@
             let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
             let result = cx.expr_method_call(trait_span,
                                              blkdecoder,
-                                             cx.ident_of("read_enum_variant"),
+                                             cx.ident_of("read_enum_variant", trait_span),
                                              vec![variant_vec, lambda]);
             cx.expr_method_call(trait_span,
                                 decoder,
-                                cx.ident_of("read_enum"),
+                                cx.ident_of("read_enum", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.lambda1(trait_span, result, blkarg)])
         }
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index 8b18fb2..655d3bb 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -153,16 +153,16 @@
                           -> P<Expr> {
     let encoder = substr.nonself_args[0].clone();
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_e");
+    let blkarg = cx.ident_of("_e", trait_span);
     let blkencoder = cx.expr_ident(trait_span, blkarg);
     let fn_path = cx.expr_path(cx.path_global(trait_span,
-                                              vec![cx.ident_of(krate),
-                                                   cx.ident_of("Encodable"),
-                                                   cx.ident_of("encode")]));
+                                              vec![cx.ident_of(krate, trait_span),
+                                                   cx.ident_of("Encodable", trait_span),
+                                                   cx.ident_of("encode", trait_span)]));
 
     return match *substr.fields {
         Struct(_, ref fields) => {
-            let emit_struct_field = cx.ident_of("emit_struct_field");
+            let emit_struct_field = cx.ident_of("emit_struct_field", trait_span);
             let mut stmts = Vec::new();
             for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
@@ -201,7 +201,7 @@
 
             cx.expr_method_call(trait_span,
                                 encoder,
-                                cx.ident_of("emit_struct"),
+                                cx.ident_of("emit_struct", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.expr_usize(trait_span, fields.len()),
                                      blk])
@@ -214,7 +214,7 @@
             // actually exist.
             let me = cx.stmt_let(trait_span, false, blkarg, encoder);
             let encoder = cx.expr_ident(trait_span, blkarg);
-            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
+            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg", trait_span);
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
@@ -244,7 +244,7 @@
             let name = cx.expr_str(trait_span, variant.ident.name);
             let call = cx.expr_method_call(trait_span,
                                            blkencoder,
-                                           cx.ident_of("emit_enum_variant"),
+                                           cx.ident_of("emit_enum_variant", trait_span),
                                            vec![name,
                                                 cx.expr_usize(trait_span, idx),
                                                 cx.expr_usize(trait_span, fields.len()),
@@ -252,7 +252,7 @@
             let blk = cx.lambda1(trait_span, call, blkarg);
             let ret = cx.expr_method_call(trait_span,
                                           encoder,
-                                          cx.ident_of("emit_enum"),
+                                          cx.ident_of("emit_enum", trait_span),
                                           vec![cx.expr_str(trait_span ,substr.type_ident.name),
                                                blk]);
             cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index c53fa7d..aceee62 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -237,7 +237,7 @@
     /// Whether there is a self argument (outer Option) i.e., whether
     /// this is a static function, and whether it is a pointer (inner
     /// Option)
-    pub explicit_self: Option<Option<PtrTy<'a>>>,
+    pub explicit_self: Option<Option<PtrTy>>,
 
     /// Arguments other than the self argument
     pub args: Vec<(Ty<'a>, &'a str)>,
@@ -843,7 +843,7 @@
                                 -> P<Expr> {
         let substructure = Substructure {
             type_ident,
-            method_ident: cx.ident_of(self.name),
+            method_ident: cx.ident_of(self.name, trait_.span),
             self_args,
             nonself_args,
             fields,
@@ -890,7 +890,7 @@
 
         for (ty, name) in self.args.iter() {
             let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
-            let ident = ast::Ident::from_str_and_span(name, trait_.span);
+            let ident = cx.ident_of(name, trait_.span);
             arg_tys.push((ident, ast_ty));
 
             let arg_expr = cx.expr_ident(trait_.span, ident);
@@ -938,7 +938,7 @@
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = cx.ident_of(self.name);
+        let method_ident = cx.ident_of(self.name, trait_.span);
         let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
@@ -1201,7 +1201,7 @@
             ).collect::<Vec<String>>();
 
         let self_arg_idents = self_arg_names.iter()
-            .map(|name| cx.ident_of(&name[..]))
+            .map(|name| cx.ident_of(name, sp))
             .collect::<Vec<ast::Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
@@ -1210,7 +1210,7 @@
         let vi_idents = self_arg_names.iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", &name[..]);
-                ast::Ident::from_str_and_span(&vi_suffix[..], trait_.span)
+                cx.ident_of(&vi_suffix[..], trait_.span)
             })
             .collect::<Vec<ast::Ident>>();
 
@@ -1389,7 +1389,7 @@
 
                 let target_ty = cx.ty_ident(
                     sp,
-                    ast::Ident::from_str_and_span(target_type_name, sp),
+                    cx.ident_of(target_type_name, sp),
                 );
                 let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
                 let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
@@ -1591,7 +1591,7 @@
         let mut ident_exprs = Vec::new();
         for (i, struct_field) in struct_def.fields().iter().enumerate() {
             let sp = struct_field.span.with_ctxt(self.span.ctxt());
-            let ident = ast::Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
+            let ident = cx.ident_of(&format!("{}_{}", prefix, i), self.span);
             paths.push(ident.with_span_pos(sp));
             let val = cx.expr_path(cx.path_ident(sp, ident));
             let val = if use_temporaries {
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index cb1c7b2..b341a07 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -13,9 +13,9 @@
 
 /// The types of pointers
 #[derive(Clone)]
-pub enum PtrTy<'a> {
+pub enum PtrTy {
     /// &'lifetime mut
-    Borrowed(Option<&'a str>, ast::Mutability),
+    Borrowed(Option<Ident>, ast::Mutability),
     /// *mut
     #[allow(dead_code)]
     Raw(ast::Mutability),
@@ -26,7 +26,7 @@
 #[derive(Clone)]
 pub struct Path<'a> {
     path: Vec<&'a str>,
-    lifetime: Option<&'a str>,
+    lifetime: Option<Ident>,
     params: Vec<Box<Ty<'a>>>,
     kind: PathKind,
 }
@@ -46,7 +46,7 @@
         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
     }
     pub fn new_<'r>(path: Vec<&'r str>,
-                    lifetime: Option<&'r str>,
+                    lifetime: Option<Ident>,
                     params: Vec<Box<Ty<'r>>>,
                     kind: PathKind)
                     -> Path<'r> {
@@ -72,7 +72,7 @@
                    self_ty: Ident,
                    self_generics: &Generics)
                    -> ast::Path {
-        let mut idents = self.path.iter().map(|s| Ident::from_str_and_span(*s, span)).collect();
+        let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect();
         let lt = mk_lifetimes(cx, span, &self.lifetime);
         let tys: Vec<P<ast::Ty>> =
             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
@@ -99,7 +99,7 @@
 pub enum Ty<'a> {
     Self_,
     /// &/Box/ Ty
-    Ptr(Box<Ty<'a>>, PtrTy<'a>),
+    Ptr(Box<Ty<'a>>, PtrTy),
     /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
     /// parameter, and things like `i32`
     Literal(Path<'a>),
@@ -107,14 +107,14 @@
     Tuple(Vec<Ty<'a>>),
 }
 
-pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
+pub fn borrowed_ptrty() -> PtrTy {
     Borrowed(None, ast::Mutability::Immutable)
 }
 pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
     Ptr(ty, borrowed_ptrty())
 }
 
-pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
+pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
     Some(Some(borrowed_ptrty()))
 }
 
@@ -126,13 +126,11 @@
     Tuple(Vec::new())
 }
 
-fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
-    lt.map(|s|
-        cx.lifetime(span, Ident::from_str(s))
-    )
+fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
+    lt.map(|ident| cx.lifetime(span, ident))
 }
 
-fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
+fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
     mk_lifetime(cx, span, lt).into_iter().collect()
 }
 
@@ -209,7 +207,7 @@
             cx.trait_bound(path)
         })
         .collect();
-    cx.typaram(span, ast::Ident::from_str_and_span(name, span), attrs.to_owned(), bounds, None)
+    cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None)
 }
 
 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
@@ -265,7 +263,7 @@
 
 pub fn get_explicit_self(cx: &ExtCtxt<'_>,
                          span: Span,
-                         self_ptr: &Option<PtrTy<'_>>)
+                         self_ptr: &Option<PtrTy>)
                          -> (P<Expr>, ast::ExplicitSelf) {
     // this constructs a fresh `self` path
     let self_path = cx.expr_self(span);
@@ -276,7 +274,7 @@
                 respan(span,
                        match *ptr {
                            Borrowed(ref lt, mutbl) => {
-                               let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
+                               let lt = lt.map(|s| cx.lifetime(span, s));
                                SelfKind::Region(lt, mutbl)
                            }
                            Raw(_) => {
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index 179b7fe..70e1fbe 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -20,16 +20,16 @@
         Some(v) => v,
     };
 
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
     let e = match env::var(&*var.as_str()) {
         Err(..) => {
-            let lt = cx.lifetime(sp, Ident::with_dummy_span(kw::StaticLifetime));
+            let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
             cx.expr_path(cx.path_all(sp,
                                      true,
                                      cx.std_path(&[sym::option, sym::Option, sym::None]),
                                      vec![GenericArg::Type(cx.ty_rptr(sp,
                                                      cx.ty_ident(sp,
-                                                                 Ident::with_dummy_span(sym::str)),
+                                                                 Ident::new(sym::str, sp)),
                                                      Some(lt),
                                                      ast::Mutability::Immutable))],
                                      vec![]))
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index dec84c8..46c7cbb 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -138,15 +138,23 @@
     }
 
     let fmtstr = p.parse_expr()?;
+    let mut first = true;
     let mut named = false;
 
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
-            let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
-            err.span_label(p.token.span, "expected `,`");
-            p.maybe_annotate_with_ascription(&mut err, false);
-            return Err(err);
+            if first {
+                // After `format!(""` we always expect *only* a comma...
+                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+                err.span_label(p.token.span, "expected `,`");
+                p.maybe_annotate_with_ascription(&mut err, false);
+                return Err(err);
+            } else {
+                // ...after that delegate to `expect` to also include the other expected tokens.
+                return Err(p.expect(&token::Comma).err().unwrap());
+            }
         }
+        first = false;
         if p.token == token::Eof {
             break;
         } // accept trailing commas
@@ -478,7 +486,7 @@
         let sp = self.macsp;
         let count = |c, arg| {
             let mut path = Context::rtpath(self.ecx, "Count");
-            path.push(self.ecx.ident_of(c));
+            path.push(self.ecx.ident_of(c, sp));
             match arg {
                 Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
                 None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
@@ -526,7 +534,7 @@
                 let pos = {
                     let pos = |c, arg| {
                         let mut path = Context::rtpath(self.ecx, "Position");
-                        path.push(self.ecx.ident_of(c));
+                        path.push(self.ecx.ident_of(c, sp));
                         match arg {
                             Some(i) => {
                                 let arg = self.ecx.expr_usize(sp, i);
@@ -595,7 +603,7 @@
                 let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
                 let align = |name| {
                     let mut p = Context::rtpath(self.ecx, "Alignment");
-                    p.push(self.ecx.ident_of(name));
+                    p.push(self.ecx.ident_of(name, sp));
                     self.ecx.path_global(sp, p)
                 };
                 let align = match arg.format.align {
@@ -613,11 +621,11 @@
                     sp,
                     path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("fill", sp), fill),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("align", sp), align),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("flags", sp), flags),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("precision", sp), prec),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("width", sp), width),
                     ],
                 );
 
@@ -626,8 +634,8 @@
                     sp,
                                           path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt),
                     ],
                 ))
             }
@@ -645,7 +653,7 @@
         let mut heads = Vec::with_capacity(self.args.len());
 
         let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| ast::Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
+            .map(|i| self.ecx.ident_of(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs
index f4af169..19a87e6 100644
--- a/src/libsyntax_ext/global_allocator.rs
+++ b/src/libsyntax_ext/global_allocator.rs
@@ -28,7 +28,7 @@
     };
 
     // Generate a bunch of new items using the AllocFnFactory
-    let span = ecx.with_legacy_ctxt(item.span);
+    let span = ecx.with_def_site_ctxt(item.span);
     let f = AllocFnFactory {
         span,
         kind: AllocatorKind::Global,
@@ -43,7 +43,7 @@
     let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
     let const_body = ecx.expr_block(ecx.block(span, stmts));
     let const_item =
-        ecx.item_const(span, Ident::with_dummy_span(kw::Underscore), const_ty, const_body);
+        ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
 
     // Return the original item and the new methods.
     vec![Annotatable::Item(item), Annotatable::Item(const_item)]
@@ -61,7 +61,7 @@
         let mut abi_args = Vec::new();
         let mut i = 0;
         let ref mut mk = || {
-            let name = Ident::from_str(&format!("arg{}", i));
+            let name = self.cx.ident_of(&format!("arg{}", i), self.span);
             i += 1;
             name
         };
@@ -83,7 +83,7 @@
         );
         let item = self.cx.item(
             self.span,
-            Ident::from_str(&self.kind.fn_name(method.name)),
+            self.cx.ident_of(&self.kind.fn_name(method.name), self.span),
             self.attrs(),
             kind,
         );
@@ -119,7 +119,7 @@
     ) -> P<Expr> {
         match *ty {
             AllocatorTy::Layout => {
-                let usize = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::usize));
+                let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
                 let ty_usize = self.cx.ty_path(usize);
                 let size = ident();
                 let align = ident();
@@ -177,12 +177,12 @@
     }
 
     fn usize(&self) -> P<Ty> {
-        let usize = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::usize));
+        let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
         self.cx.ty_path(usize)
     }
 
     fn ptr_u8(&self) -> P<Ty> {
-        let u8 = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::u8));
+        let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span));
         let ty_u8 = self.cx.ty_path(u8);
         self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
     }
diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs
index 6140f0d..c56b3f3 100644
--- a/src/libsyntax_ext/global_asm.rs
+++ b/src/libsyntax_ext/global_asm.rs
@@ -30,7 +30,7 @@
                 id: ast::DUMMY_NODE_ID,
                 node: ast::ItemKind::GlobalAsm(P(global_asm)),
                 vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                span: cx.with_legacy_ctxt(sp),
+                span: cx.with_def_site_ctxt(sp),
                 tokens: None,
             })])
         }
diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs
index 31d32d2..a5dcfb9 100644
--- a/src/libsyntax_ext/proc_macro_harness.rs
+++ b/src/libsyntax_ext/proc_macro_harness.rs
@@ -340,12 +340,12 @@
                         Vec::new(),
                         ast::ItemKind::ExternCrate(None));
 
-    let bridge = Ident::from_str_and_span("bridge", span);
-    let client = Ident::from_str_and_span("client", span);
-    let proc_macro_ty = Ident::from_str_and_span("ProcMacro", span);
-    let custom_derive = Ident::from_str_and_span("custom_derive", span);
-    let attr = Ident::from_str_and_span("attr", span);
-    let bang = Ident::from_str_and_span("bang", span);
+    let bridge = cx.ident_of("bridge", span);
+    let client = cx.ident_of("client", span);
+    let proc_macro_ty = cx.ident_of("ProcMacro", span);
+    let custom_derive = cx.ident_of("custom_derive", span);
+    let attr = cx.ident_of("attr", span);
+    let bang = cx.ident_of("bang", span);
 
     let decls = {
         let local_path = |sp: Span, name| {
@@ -378,7 +378,7 @@
 
     let decls_static = cx.item_static(
         span,
-        Ident::from_str_and_span("_DECLS", span),
+        cx.ident_of("_DECLS", span),
         cx.ty_rptr(span,
             cx.ty(span, ast::TyKind::Slice(
                 cx.ty_path(cx.path(span,
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index be5aca7..0910c00 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -98,20 +98,20 @@
 
     // creates test::$name
     let test_path = |name| {
-        cx.path(sp, vec![test_id, cx.ident_of(name)])
+        cx.path(sp, vec![test_id, cx.ident_of(name, sp)])
     };
 
     // creates test::ShouldPanic::$name
     let should_panic_path = |name| {
-        cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic"), cx.ident_of(name)])
+        cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)])
     };
 
     // creates $name: $expr
-    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name), expr);
+    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr);
 
     let test_fn = if is_bench {
         // A simple ident for a lambda
-        let b = ast::Ident::from_str_and_span("b", attr_sp);
+        let b = cx.ident_of("b", attr_sp);
 
         cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), vec![
             // |b| self::test::assert_test_result(
diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs
index b93c11f..56de0c9 100644
--- a/src/libsyntax_ext/test_harness.rs
+++ b/src/libsyntax_ext/test_harness.rs
@@ -250,7 +250,7 @@
 
     // test::test_main_static(...)
     let mut test_runner = cx.test_runner.clone().unwrap_or(
-        ecx.path(sp, vec![test_id, Ident::from_str_and_span("test_main_static", sp)]));
+        ecx.path(sp, vec![test_id, ecx.ident_of("test_main_static", sp)]));
 
     test_runner.span = sp;
 
@@ -288,7 +288,7 @@
     // Honor the reexport_test_harness_main attribute
     let main_id = match cx.reexport_test_harness_main {
         Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())),
-        None => Ident::from_str_and_span("main", sp),
+        None => Ident::new(sym::main, sp),
     };
 
     let main = P(ast::Item {
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index f0e7344..8971638 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -677,6 +677,13 @@
         }
     }
 
+    pub fn descr_expected(self) -> &'static str {
+        match self {
+            MacroKind::Attr => "attribute",
+            _ => self.descr(),
+        }
+    }
+
     pub fn article(self) -> &'static str {
         match self {
             MacroKind::Attr => "an",
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 9a296f1..ca177eb 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -526,13 +526,6 @@
         self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
     }
 
-    /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
-    /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
-    /// or with `with_call_site_ctxt` (where necessary).
-    pub fn with_legacy_ctxt(&self, expn_id: ExpnId) -> Span {
-        self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
-    }
-
     /// Produces a span with the same location as `self` and context produced by a macro with the
     /// given ID and transparency, assuming that macro was defined directly and not produced by
     /// some other macro (which is the case for built-in and procedural macros).
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index ab32d44..597ae83 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -765,7 +765,7 @@
         Ident::with_dummy_span(string.as_symbol())
     }
 
-    /// Maps a string to an identifier with an empty span.
+    /// Maps a string to an identifier with a dummy span.
     pub fn from_str(string: &str) -> Ident {
         Ident::with_dummy_span(Symbol::intern(string))
     }
diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs
index ae2ff99..ded310d 100644
--- a/src/test/codegen/adjustments.rs
+++ b/src/test/codegen/adjustments.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs
index e152e6e..f67487c 100644
--- a/src/test/codegen/fastcall-inreg.rs
+++ b/src/test/codegen/fastcall-inreg.rs
@@ -49,27 +49,27 @@
 #![crate_type = "lib"]
 
 pub mod tests {
-    // CHECK: @f1(i32 inreg %arg0, i32 inreg %arg1, i32 %arg2)
+    // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3)
     #[no_mangle]
     pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
 
-    // CHECK: @f2(i32* inreg %arg0, i32* inreg %arg1, i32* %arg2)
+    // CHECK: @f2(i32* inreg %_1, i32* inreg %_2, i32* %_3)
     #[no_mangle]
     pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
 
-    // CHECK: @f3(float %arg0, i32 inreg %arg1, i32 inreg %arg2, i32 %arg3)
+    // CHECK: @f3(float %_1, i32 inreg %_2, i32 inreg %_3, i32 %_4)
     #[no_mangle]
     pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
 
-    // CHECK: @f4(i32 inreg %arg0, float %arg1, i32 inreg %arg2, i32 %arg3)
+    // CHECK: @f4(i32 inreg %_1, float %_2, i32 inreg %_3, i32 %_4)
     #[no_mangle]
     pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
 
-    // CHECK: @f5(i64 %arg0, i32 %arg1)
+    // CHECK: @f5(i64 %_1, i32 %_2)
     #[no_mangle]
     pub extern "fastcall" fn f5(_: i64, _: i32) {}
 
-    // CHECK: @f6(i1 inreg zeroext %arg0, i32 inreg %arg1, i32 %arg2)
+    // CHECK: @f6(i1 inreg zeroext %_1, i32 inreg %_2, i32 %_3)
     #[no_mangle]
     pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
 }
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index bd121ef2..7e1791c 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -18,48 +18,48 @@
   x
 }
 
-// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {
 }
 
-// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
 pub fn static_borrow(_: &'static i32) {
 }
 
-// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // borrow with named lifetime may be captured
 #[no_mangle]
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
+// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
+// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %_1)
 // ... unless this is a mutable borrow, those never alias
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %arg0)
+// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
 
-// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %arg0)
+// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
 
-// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %arg0)
+// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {
@@ -80,36 +80,36 @@
 }
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
 
-// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
 
-// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %_1.0, [[USIZE]] %_1.1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_slice(_: &[UnsafeInner]) {
 }
 
-// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow({}* nonnull align 1 %arg0.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %arg0.1)
+// CHECK: @trait_borrow({}* nonnull align 1 %_1.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn trait_borrow(_: &Drop) {
diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs
index 0d3d537..05888c0 100644
--- a/src/test/codegen/personality_lifetimes.rs
+++ b/src/test/codegen/personality_lifetimes.rs
@@ -20,12 +20,13 @@
     let _s = S;
     // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
     // in the first one.
+    // CHECK: [[SLOT:%[0-9]+]] = alloca { i8*, i32 }
     // CHECK-LABEL: cleanup:
-    // CHECK: bitcast{{.*}}personalityslot
-    // CHECK-NEXT: call void @llvm.lifetime.start
+    // CHECK: [[BITCAST:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8*
+    // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST]])
     // CHECK-LABEL: cleanup1:
-    // CHECK: bitcast{{.*}}personalityslot
-    // CHECK-NEXT: call void @llvm.lifetime.start
+    // CHECK: [[BITCAST1:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8*
+    // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST1]])
     might_unwind();
     let _t = S;
     might_unwind();
diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs
index cbb9942..15f99fd 100644
--- a/src/test/codegen/refs.rs
+++ b/src/test/codegen/refs.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs
index c348a8f..87f29f6 100644
--- a/src/test/codegen/repeat-trusted-len.rs
+++ b/src/test/codegen/repeat-trusted-len.rs
@@ -6,7 +6,7 @@
 
 use std::iter;
 
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs
index c9f3837..e705d5c 100644
--- a/src/test/codegen/repr-transparent.rs
+++ b/src/test/codegen/repr-transparent.rs
@@ -14,21 +14,21 @@
 #[repr(transparent)]
 pub struct F32(f32);
 
-// CHECK: define float @test_F32(float %arg0)
+// CHECK: define float @test_F32(float %_1)
 #[no_mangle]
 pub extern fn test_F32(_: F32) -> F32 { loop {} }
 
 #[repr(transparent)]
 pub struct Ptr(*mut u8);
 
-// CHECK: define i8* @test_Ptr(i8* %arg0)
+// CHECK: define i8* @test_Ptr(i8* %_1)
 #[no_mangle]
 pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} }
 
 #[repr(transparent)]
 pub struct WithZst(u64, Zst1);
 
-// CHECK: define i64 @test_WithZst(i64 %arg0)
+// CHECK: define i64 @test_WithZst(i64 %_1)
 #[no_mangle]
 pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 
@@ -36,14 +36,14 @@
 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
 
 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
-// CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0)
+// CHECK: define i32* @test_WithZeroSizedArray(i32* %_1)
 #[no_mangle]
 pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
 
 #[repr(transparent)]
 pub struct Generic<T>(T);
 
-// CHECK: define double @test_Generic(double %arg0)
+// CHECK: define double @test_Generic(double %_1)
 #[no_mangle]
 pub extern fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
 
@@ -53,14 +53,14 @@
 #[repr(u8)]
 pub enum Bool { True, False, FileNotFound }
 
-// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0)
+// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %_1)
 #[no_mangle]
 pub extern fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }
 
 #[repr(transparent)]
 pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
 
-// CHECK: define i16* @test_LifetimePhantom(i16* %arg0)
+// CHECK: define i16* @test_LifetimePhantom(i16* %_1)
 #[no_mangle]
 pub extern fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
 
@@ -70,28 +70,28 @@
 
 pub struct Px;
 
-// CHECK: define float @test_UnitPhantom(float %arg0)
+// CHECK: define float @test_UnitPhantom(float %_1)
 #[no_mangle]
 pub extern fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
 
 #[repr(transparent)]
 pub struct TwoZsts(Zst1, i8, Zst2);
 
-// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0)
+// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1)
 #[no_mangle]
 pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
 
 #[repr(transparent)]
 pub struct Nested1(Zst2, Generic<f64>);
 
-// CHECK: define double @test_Nested1(double %arg0)
+// CHECK: define double @test_Nested1(double %_1)
 #[no_mangle]
 pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
 
 #[repr(transparent)]
 pub struct Nested2(Nested1, Zst1);
 
-// CHECK: define double @test_Nested2(double %arg0)
+// CHECK: define double @test_Nested2(double %_1)
 #[no_mangle]
 pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
 
@@ -101,7 +101,7 @@
 #[repr(transparent)]
 pub struct Vector(f32x4);
 
-// CHECK: define <4 x float> @test_Vector(<4 x float> %arg0)
+// CHECK: define <4 x float> @test_Vector(<4 x float> %_1)
 #[no_mangle]
 pub extern fn test_Vector(_: Vector) -> Vector { loop {} }
 
@@ -111,7 +111,7 @@
 #[repr(transparent)]
 pub struct StructWithProjection(<f32 as Mirror>::It);
 
-// CHECK: define float @test_Projection(float %arg0)
+// CHECK: define float @test_Projection(float %_1)
 #[no_mangle]
 pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
 
@@ -120,7 +120,7 @@
     Variant(F32)
 }
 
-// CHECK: define float @test_EnumF32(float %arg0)
+// CHECK: define float @test_EnumF32(float %_1)
 #[no_mangle]
 pub extern fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
 
@@ -129,7 +129,7 @@
     Variant(Zst1, F32, Zst2)
 }
 
-// CHECK: define float @test_EnumF32WithZsts(float %arg0)
+// CHECK: define float @test_EnumF32WithZsts(float %_1)
 #[no_mangle]
 pub extern fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
 
@@ -138,7 +138,7 @@
     field: F32,
 }
 
-// CHECK: define float @test_UnionF32(float %arg0)
+// CHECK: define float @test_UnionF32(float %_1)
 #[no_mangle]
 pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
@@ -149,7 +149,7 @@
     zst2: Zst2,
 }
 
-// CHECK: define float @test_UnionF32WithZsts(float %arg0)
+// CHECK: define float @test_UnionF32WithZsts(float %_1)
 #[no_mangle]
 pub extern fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
 
diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs
index 78d1025..d91ee7f 100644
--- a/src/test/codegen/scalar-pair-bool.rs
+++ b/src/test/codegen/scalar-pair-bool.rs
@@ -20,24 +20,24 @@
     pair
 }
 
-// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %_1.0, i1 zeroext %_1.1)
 #[no_mangle]
 pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
     // Make sure it can operate directly on the unpacked args
-    // CHECK: and i1 %arg0.0, %arg0.1
-    // CHECK: or i1 %arg0.0, %arg0.1
+    // CHECK: and i1 %_1.0, %_1.1
+    // CHECK: or i1 %_1.0, %_1.1
     (a && b, a || b)
 }
 
-// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+// CHECK: define void @pair_branches(i1 zeroext %_1.0, i1 zeroext %_1.1)
 #[no_mangle]
 pub fn pair_branches((a, b): (bool, bool)) {
     // Make sure it can branch directly on the unpacked bool args
-    // CHECK: br i1 %arg0.0
+    // CHECK: br i1 %_1.0
     if a {
         println!("Hello!");
     }
-    // CHECK: br i1 %arg0.1
+    // CHECK: br i1 %_1.1
     if b {
         println!("Goodbye!");
     }
diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs
index b7baffe..7339df1 100644
--- a/src/test/codegen/union-abi.rs
+++ b/src/test/codegen/union-abi.rs
@@ -16,38 +16,38 @@
 #[derive(Copy, Clone)]
 pub union UnionI64x4{ a:(), b: i64x4 }
 
-// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4(_: UnionI64x4) { loop {} }
 
 pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 }
 
-// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} }
 
 pub union UnionI64x4I64{ a: i64x4, b: i64 }
 
-// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} }
 
 pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) }
 
-// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} }
 
 
 pub union UnionF32{a:f32}
 
-// CHECK: define float @test_UnionF32(float %arg0)
+// CHECK: define float @test_UnionF32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
 pub union UnionF32F32{a:f32, b:f32}
 
-// CHECK: define float @test_UnionF32F32(float %arg0)
+// CHECK: define float @test_UnionF32F32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} }
 
@@ -58,13 +58,13 @@
 pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} }
 
 pub union UnionU128{a:u128}
-// CHECK: define i128 @test_UnionU128(i128 %arg0)
+// CHECK: define i128 @test_UnionU128(i128 %_1)
 #[no_mangle]
 pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
 
 #[repr(C)]
 pub union CUnionU128{a:u128}
-// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0)
+// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1)
 #[no_mangle]
 pub fn test_CUnionU128(_: CUnionU128) { loop {} }
 
diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs
index 4515e36..9cc2d3b 100644
--- a/src/test/incremental/hashes/function_interfaces.rs
+++ b/src/test/incremental/hashes/function_interfaces.rs
@@ -11,7 +11,6 @@
 
 
 #![allow(warnings)]
-#![feature(intrinsics)]
 #![feature(linkage)]
 #![feature(rustc_attrs)]
 #![crate_type = "rlib"]
@@ -99,17 +98,6 @@
 pub extern "C" fn make_extern() {}
 
 
-// Extern C Extern Rust-Intrinsic ----------------------------------------------
-
-#[cfg(cfail1)]
-pub extern "C" fn make_intrinsic() {}
-
-#[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")]
-#[rustc_clean(cfg = "cfail3")]
-pub extern "rust-intrinsic" fn make_intrinsic() {}
-
-
 // Type Parameter --------------------------------------------------------------
 
 #[cfg(cfail1)]
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 81ff995..3006cdc 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -18,7 +18,6 @@
 #![feature(rustc_attrs)]
 #![crate_type="rlib"]
 #![feature(associated_type_defaults)]
-#![feature(intrinsics)]
 
 
 // Change trait visibility
@@ -318,7 +317,7 @@
 
 
 
-// Change extern "C" to extern "rust-intrinsic"
+// Change extern "C" to extern "stdcall"
 #[cfg(cfail1)]
 trait TraitChangeExternCToRustIntrinsic {
     extern "C" fn method();
@@ -330,7 +329,7 @@
 trait TraitChangeExternCToRustIntrinsic {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    extern "rust-intrinsic" fn method();
+    extern "stdcall" fn method();
 }
 
 
diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index ea24f58..bd9113c 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -24,7 +24,7 @@
 fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-    rustc_driver::report_ices_to_stderr_if_any(|| {
+    rustc_driver::catch_fatal_errors(|| {
         rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
     }).ok();
     assert_eq!(count, 2);
diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs
index 9f67f64..d79ef62 100644
--- a/src/test/ui-fulldeps/hash-stable-is-unstable.rs
+++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs
@@ -13,3 +13,5 @@
 #[derive(HashStable)]
 //~^ use of unstable library feature 'rustc_private'
 struct Test;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
index 02056d3..e2dc0c3 100644
--- a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
+++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
@@ -1,7 +1,3 @@
-error[E0601]: `main` function not found in crate `hash_stable_is_unstable`
-   |
-   = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs`
-
 error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
   --> $DIR/hash-stable-is-unstable.rs:3:1
    |
@@ -47,7 +43,6 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/27812
    = help: add `#![feature(rustc_private)]` to the crate attributes to enable
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0601, E0658.
-For more information about an error, try `rustc --explain E0601`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/allocator/hygiene.rs b/src/test/ui/allocator/hygiene.rs
new file mode 100644
index 0000000..9bd8406
--- /dev/null
+++ b/src/test/ui/allocator/hygiene.rs
@@ -0,0 +1,31 @@
+// run-pass
+// no-prefer-dynamic
+// aux-build:custom.rs
+// aux-build:helper.rs
+
+#![allow(nonstandard_style)]
+
+extern crate custom;
+extern crate helper;
+
+use custom::A;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+#[allow(dead_code)]
+struct u8;
+#[allow(dead_code)]
+struct usize;
+#[allow(dead_code)]
+static arg0: () = ();
+
+#[global_allocator]
+pub static GLOBAL: A = A(AtomicUsize::new(0));
+
+fn main() {
+    let n = GLOBAL.0.load(Ordering::SeqCst);
+    let s = Box::new(0);
+    helper::work_with(&s);
+    assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
+    drop(s);
+    assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
index 83a6082..59ce949 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.rs
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -31,3 +31,5 @@
 union U3 { f: dyn Iterator<Item: 'static> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 //~| ERROR could not find defining uses
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
index d0e0cec..9c4d03e 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.stderr
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -52,10 +52,6 @@
 LL | union U3 { f: dyn Iterator<Item: 'static> }
    |                            ^^^^^^^^^^^^^
 
-error[E0601]: `main` function not found in crate `inside_adt`
-   |
-   = note: consider adding a `main` function to `$DIR/inside-adt.rs`
-
 error: could not find defining uses
   --> $DIR/inside-adt.rs:5:29
    |
@@ -110,6 +106,5 @@
 LL | union U3 { f: dyn Iterator<Item: 'static> }
    |                            ^^^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/attributes/item-attributes.rs b/src/test/ui/attributes/item-attributes.rs
index c760a28..79cd0f5 100644
--- a/src/test/ui/attributes/item-attributes.rs
+++ b/src/test/ui/attributes/item-attributes.rs
@@ -11,8 +11,6 @@
 #![rustc_dummy]
 #![rustc_dummy(attr5)]
 
-#![crate_id="foobar#0.1"]
-
 // These are attributes of the following mod
 #[rustc_dummy = "val"]
 #[rustc_dummy = "val"]
diff --git a/src/test/ui/attributes/obsolete-attr.rs b/src/test/ui/attributes/obsolete-attr.rs
index cf6dd33..42f90ed 100644
--- a/src/test/ui/attributes/obsolete-attr.rs
+++ b/src/test/ui/attributes/obsolete-attr.rs
@@ -1,9 +1,9 @@
 // Obsolete attributes fall back to unstable custom attributes.
 
 #[ab_isize="stdcall"] extern {}
-//~^ ERROR cannot find attribute macro `ab_isize` in this scope
+//~^ ERROR cannot find attribute `ab_isize` in this scope
 
 #[fixed_stack_segment] fn f() {}
-//~^ ERROR cannot find attribute macro `fixed_stack_segment` in this scope
+//~^ ERROR cannot find attribute `fixed_stack_segment` in this scope
 
 fn main() {}
diff --git a/src/test/ui/attributes/obsolete-attr.stderr b/src/test/ui/attributes/obsolete-attr.stderr
index 9c6909f..2d7c257 100644
--- a/src/test/ui/attributes/obsolete-attr.stderr
+++ b/src/test/ui/attributes/obsolete-attr.stderr
@@ -1,10 +1,10 @@
-error: cannot find attribute macro `fixed_stack_segment` in this scope
+error: cannot find attribute `fixed_stack_segment` in this scope
   --> $DIR/obsolete-attr.rs:6:3
    |
 LL | #[fixed_stack_segment] fn f() {}
    |   ^^^^^^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `ab_isize` in this scope
+error: cannot find attribute `ab_isize` in this scope
   --> $DIR/obsolete-attr.rs:3:3
    |
 LL | #[ab_isize="stdcall"] extern {}
diff --git a/src/test/ui/attributes/unknown-attr.rs b/src/test/ui/attributes/unknown-attr.rs
index 544a6e2..70fef04 100644
--- a/src/test/ui/attributes/unknown-attr.rs
+++ b/src/test/ui/attributes/unknown-attr.rs
@@ -3,10 +3,10 @@
 #![feature(custom_inner_attributes)]
 
 #![mutable_doc]
-//~^ ERROR cannot find attribute macro `mutable_doc` in this scope
+//~^ ERROR cannot find attribute `mutable_doc` in this scope
 
 #[dance] mod a {}
-//~^ ERROR cannot find attribute macro `dance` in this scope
+//~^ ERROR cannot find attribute `dance` in this scope
 
 #[dance] fn main() {}
-//~^ ERROR cannot find attribute macro `dance` in this scope
+//~^ ERROR cannot find attribute `dance` in this scope
diff --git a/src/test/ui/attributes/unknown-attr.stderr b/src/test/ui/attributes/unknown-attr.stderr
index 4d46387..85c227d 100644
--- a/src/test/ui/attributes/unknown-attr.stderr
+++ b/src/test/ui/attributes/unknown-attr.stderr
@@ -1,16 +1,16 @@
-error: cannot find attribute macro `mutable_doc` in this scope
+error: cannot find attribute `mutable_doc` in this scope
   --> $DIR/unknown-attr.rs:5:4
    |
 LL | #![mutable_doc]
    |    ^^^^^^^^^^^
 
-error: cannot find attribute macro `dance` in this scope
+error: cannot find attribute `dance` in this scope
   --> $DIR/unknown-attr.rs:8:3
    |
 LL | #[dance] mod a {}
    |   ^^^^^
 
-error: cannot find attribute macro `dance` in this scope
+error: cannot find attribute `dance` in this scope
   --> $DIR/unknown-attr.rs:11:3
    |
 LL | #[dance] fn main() {}
diff --git a/src/test/ui/attributes/unnamed-field-attributes.rs b/src/test/ui/attributes/unnamed-field-attributes.rs
new file mode 100644
index 0000000..93f3640
--- /dev/null
+++ b/src/test/ui/attributes/unnamed-field-attributes.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+struct S(
+    #[rustfmt::skip] u8,
+    u16,
+    #[rustfmt::skip] u32,
+);
+
+fn main() {}
diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs
index 9f90185..dff2483 100644
--- a/src/test/ui/codemap_tests/bad-format-args.rs
+++ b/src/test/ui/codemap_tests/bad-format-args.rs
@@ -1,5 +1,5 @@
 fn main() {
     format!(); //~ ERROR requires at least a format string argument
     format!("" 1); //~ ERROR expected token: `,`
-    format!("", 1 1); //~ ERROR expected token: `,`
+    format!("", 1 1); //~ ERROR expected one of
 }
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
index 5b01314..3372ef6 100644
--- a/src/test/ui/codemap_tests/bad-format-args.stderr
+++ b/src/test/ui/codemap_tests/bad-format-args.stderr
@@ -12,11 +12,11 @@
 LL |     format!("" 1);
    |                ^ expected `,`
 
-error: expected token: `,`
+error: expected one of `,`, `.`, `?`, or an operator, found `1`
   --> $DIR/bad-format-args.rs:4:19
    |
 LL |     format!("", 1 1);
-   |                   ^ expected `,`
+   |                   ^ expected one of `,`, `.`, `?`, or an operator here
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
index db3c7ac..e9df780 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
@@ -1,6 +1,9 @@
 error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
+  --> $DIR/cfg-attr-cfg-2.rs:8:1
    |
-   = note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
+LL | / #[cfg_attr(foo, cfg(bar))]
+LL | | fn main() { }
+   | |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
index 22dbac7..45b757e 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
@@ -1,7 +1,7 @@
 macro_rules! foo {
     () => {
         #[cfg_attr(all(), unknown)]
-        //~^ ERROR cannot find attribute macro `unknown` in this scope
+        //~^ ERROR cannot find attribute `unknown` in this scope
         fn foo() {}
     }
 }
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
index c7c52a2..ef434ec 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27
    |
 LL |         #[cfg_attr(all(), unknown)]
diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.rs b/src/test/ui/conditional-compilation/cfg-generic-params.rs
index faf0195..53aa355 100644
--- a/src/test/ui/conditional-compilation/cfg-generic-params.rs
+++ b/src/test/ui/conditional-compilation/cfg-generic-params.rs
@@ -17,22 +17,22 @@
 
 fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK
 fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
-//~^ ERROR cannot find attribute macro `unknown` in this scope
+//~^ ERROR cannot find attribute `unknown` in this scope
 fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK
 fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
-//~^ ERROR cannot find attribute macro `unknown` in this scope
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK
 type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
-//~^ ERROR cannot find attribute macro `unknown` in this scope
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK
 type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
-//~^ ERROR cannot find attribute macro `unknown` in this scope
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK
 struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
-//~^ ERROR cannot find attribute macro `unknown` in this scope
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 fn main() {
     f_lt::<'static>();
diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr
index f6e5732..d9e29c8 100644
--- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr
+++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr
@@ -16,31 +16,31 @@
 LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
    |                                                      ^
 
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:34:43
    |
 LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
    |                                           ^^^^^^^
 
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:30:40
    |
 LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
    |                                        ^^^^^^^
 
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:26:34
    |
 LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
    |                                  ^^^^^^^
 
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:22:29
    |
 LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
    |                             ^^^^^^^
 
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:19:29
    |
 LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
diff --git a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
index c6d42c7..0b5c3e0 100644
--- a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
+++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `cfg_in_crate_1`
+  --> $DIR/cfg-in-crate-1.rs:3:1
    |
-   = note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
+LL | #![cfg(bar)]
+   | ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr
index aceabf3..b94c365 100644
--- a/src/test/ui/continue-after-missing-main.nll.stderr
+++ b/src/test/ui/continue-after-missing-main.nll.stderr
@@ -1,6 +1,14 @@
 error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | / #![allow(dead_code)]
+LL | |
+LL | | // error-pattern:`main` function not found in crate
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr
index cc5f876..d764e7d 100644
--- a/src/test/ui/continue-after-missing-main.stderr
+++ b/src/test/ui/continue-after-missing-main.stderr
@@ -1,6 +1,14 @@
 error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | / #![allow(dead_code)]
+LL | |
+LL | | // error-pattern:`main` function not found in crate
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
 
 error[E0623]: lifetime mismatch
   --> $DIR/continue-after-missing-main.rs:30:56
diff --git a/src/test/ui/custom_attribute.rs b/src/test/ui/custom_attribute.rs
index 13c873c..4957184 100644
--- a/src/test/ui/custom_attribute.rs
+++ b/src/test/ui/custom_attribute.rs
@@ -1,9 +1,9 @@
 #![feature(stmt_expr_attributes)]
 
-#[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+#[foo] //~ ERROR cannot find attribute `foo` in this scope
 fn main() {
-    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+    #[foo] //~ ERROR cannot find attribute `foo` in this scope
     let x = ();
-    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+    #[foo] //~ ERROR cannot find attribute `foo` in this scope
     x
 }
diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr
index b4f9f3f..4023892 100644
--- a/src/test/ui/custom_attribute.stderr
+++ b/src/test/ui/custom_attribute.stderr
@@ -1,16 +1,16 @@
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:3:3
    |
 LL | #[foo]
    |   ^^^
 
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:5:7
    |
 LL |     #[foo]
    |       ^^^
 
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:7:7
    |
 LL |     #[foo]
diff --git a/src/test/ui/elided-test.stderr b/src/test/ui/elided-test.stderr
index d22eee4..175bd03 100644
--- a/src/test/ui/elided-test.stderr
+++ b/src/test/ui/elided-test.stderr
@@ -1,6 +1,10 @@
 error[E0601]: `main` function not found in crate `elided_test`
+  --> $DIR/elided-test.rs:5:1
    |
-   = note: consider adding a `main` function to `$DIR/elided-test.rs`
+LL | / #[test]
+LL | | fn main() {
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/elided-test.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr
index 1630041..8e3e068 100644
--- a/src/test/ui/empty/empty-macro-use.stderr
+++ b/src/test/ui/empty/empty-macro-use.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/empty-macro-use.rs:7:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/error-codes/E0138.stderr b/src/test/ui/error-codes/E0138.stderr
index 745dccf..445053a 100644
--- a/src/test/ui/error-codes/E0138.stderr
+++ b/src/test/ui/error-codes/E0138.stderr
@@ -1,4 +1,4 @@
-error[E0138]: multiple 'start' functions
+error[E0138]: multiple `start` functions
   --> $DIR/E0138.rs:7:1
    |
 LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
diff --git a/src/test/ui/error-codes/E0601.rs b/src/test/ui/error-codes/E0601.rs
index 47feb7f..4380dde 100644
--- a/src/test/ui/error-codes/E0601.rs
+++ b/src/test/ui/error-codes/E0601.rs
@@ -1 +1 @@
-// Test for main function not found.
+//~ ERROR `main` function not found
diff --git a/src/test/ui/error-codes/E0601.stderr b/src/test/ui/error-codes/E0601.stderr
index cbc20db..a687f57 100644
--- a/src/test/ui/error-codes/E0601.stderr
+++ b/src/test/ui/error-codes/E0601.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `E0601`
+  --> $DIR/E0601.rs:1:37
    |
-   = note: consider adding a `main` function to `$DIR/E0601.rs`
+LL |
+   |                                     ^ consider adding a `main` function to `$DIR/E0601.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/ext-nonexistent.stderr b/src/test/ui/ext-nonexistent.stderr
index 3fbbb49..f3aa83f 100644
--- a/src/test/ui/ext-nonexistent.stderr
+++ b/src/test/ui/ext-nonexistent.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `iamnotanextensionthatexists!` in this scope
+error: cannot find macro `iamnotanextensionthatexists` in this scope
   --> $DIR/ext-nonexistent.rs:2:13
    |
 LL | fn main() { iamnotanextensionthatexists!(""); }
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index 6d51bb3..68ff95e 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -84,12 +84,12 @@
 #![crate_name = "0900"]
 #![crate_type = "bin"] // cannot pass "0800" here
 
-// For #![crate_id], see issue #43142. (I cannot bear to enshrine current behavior in a test)
+#![crate_id = "10"] //~ WARN use of deprecated attribute
 
 // FIXME(#44232) we should warn that this isn't used.
 #![feature(rust1)]
 
-// For #![no_start], see issue #43144. (I cannot bear to enshrine current behavior in a test)
+#![no_start] //~ WARN use of deprecated attribute
 
 // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400")
 #![no_builtins]
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index 864df35..b2a6018 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -186,6 +186,20 @@
    |
    = help: consider an outer attribute, `#[macro_use]` mod ...
 
+warning: use of deprecated attribute `crate_id`: no longer used.
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:87:1
+   |
+LL | #![crate_id = "10"]
+   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+warning: use of deprecated attribute `no_start`: no longer used.
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:92:1
+   |
+LL | #![no_start]
+   | ^^^^^^^^^^^^ help: remove this attribute
+
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:12
    |
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index 41c9f79..61da38e 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -10,7 +10,9 @@
 
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
+//~^ ERROR intrinsic must be in
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
+//~^ ERROR intrinsic must be in
 extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
 extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -22,7 +24,9 @@
 // Methods in trait definition
 trait Tr {
     extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
@@ -31,8 +35,6 @@
     extern "thiscall" fn m8(); //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn m9(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change
 
-    extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change
-    extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental
     extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -47,7 +49,9 @@
 // Methods in trait impl
 impl Tr for S {
     extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -60,7 +64,9 @@
 // Methods in inherent impl
 impl S {
     extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index 88e0b86..afda76d 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -7,7 +7,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:13:1
+  --> $DIR/feature-gate-abi.rs:14:1
    |
 LL | extern "platform-intrinsic" fn f2() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:14:1
+  --> $DIR/feature-gate-abi.rs:16:1
    |
 LL | extern "vectorcall" fn f3() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:15:1
+  --> $DIR/feature-gate-abi.rs:17:1
    |
 LL | extern "rust-call" fn f4() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:16:1
+  --> $DIR/feature-gate-abi.rs:18:1
    |
 LL | extern "msp430-interrupt" fn f5() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:17:1
+  --> $DIR/feature-gate-abi.rs:19:1
    |
 LL | extern "ptx-kernel" fn f6() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:18:1
+  --> $DIR/feature-gate-abi.rs:20:1
    |
 LL | extern "x86-interrupt" fn f7() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:19:1
+  --> $DIR/feature-gate-abi.rs:21:1
    |
 LL | extern "thiscall" fn f8() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:20:1
+  --> $DIR/feature-gate-abi.rs:22:1
    |
 LL | extern "amdgpu-kernel" fn f9() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:24:5
+  --> $DIR/feature-gate-abi.rs:26:5
    |
 LL |     extern "rust-intrinsic" fn m1();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:25:5
+  --> $DIR/feature-gate-abi.rs:28:5
    |
 LL |     extern "platform-intrinsic" fn m2();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +94,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:26:5
+  --> $DIR/feature-gate-abi.rs:30:5
    |
 LL |     extern "vectorcall" fn m3();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -102,7 +102,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:27:5
+  --> $DIR/feature-gate-abi.rs:31:5
    |
 LL |     extern "rust-call" fn m4();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:28:5
+  --> $DIR/feature-gate-abi.rs:32:5
    |
 LL |     extern "msp430-interrupt" fn m5();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:29:5
+  --> $DIR/feature-gate-abi.rs:33:5
    |
 LL |     extern "ptx-kernel" fn m6();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:30:5
+  --> $DIR/feature-gate-abi.rs:34:5
    |
 LL |     extern "x86-interrupt" fn m7();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:31:5
+  --> $DIR/feature-gate-abi.rs:35:5
    |
 LL |     extern "thiscall" fn m8();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -146,7 +146,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:32:5
+  --> $DIR/feature-gate-abi.rs:36:5
    |
 LL |     extern "amdgpu-kernel" fn m9();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,25 +154,8 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
-error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:34:5
-   |
-LL |     extern "rust-intrinsic" fn dm1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-
-error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:35:5
-   |
-LL |     extern "platform-intrinsic" fn dm2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/27731
-   = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
-
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:36:5
+  --> $DIR/feature-gate-abi.rs:38:5
    |
 LL |     extern "vectorcall" fn dm3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,7 +163,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:37:5
+  --> $DIR/feature-gate-abi.rs:39:5
    |
 LL |     extern "rust-call" fn dm4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -189,7 +172,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:38:5
+  --> $DIR/feature-gate-abi.rs:40:5
    |
 LL |     extern "msp430-interrupt" fn dm5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +181,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:39:5
+  --> $DIR/feature-gate-abi.rs:41:5
    |
 LL |     extern "ptx-kernel" fn dm6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -207,7 +190,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:40:5
+  --> $DIR/feature-gate-abi.rs:42:5
    |
 LL |     extern "x86-interrupt" fn dm7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,7 +199,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:41:5
+  --> $DIR/feature-gate-abi.rs:43:5
    |
 LL |     extern "thiscall" fn dm8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,7 +207,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:42:5
+  --> $DIR/feature-gate-abi.rs:44:5
    |
 LL |     extern "amdgpu-kernel" fn dm9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +216,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:49:5
+  --> $DIR/feature-gate-abi.rs:51:5
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +224,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:50:5
+  --> $DIR/feature-gate-abi.rs:53:5
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +233,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:51:5
+  --> $DIR/feature-gate-abi.rs:55:5
    |
 LL |     extern "vectorcall" fn m3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -258,7 +241,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:52:5
+  --> $DIR/feature-gate-abi.rs:56:5
    |
 LL |     extern "rust-call" fn m4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -267,7 +250,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:53:5
+  --> $DIR/feature-gate-abi.rs:57:5
    |
 LL |     extern "msp430-interrupt" fn m5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -276,7 +259,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:54:5
+  --> $DIR/feature-gate-abi.rs:58:5
    |
 LL |     extern "ptx-kernel" fn m6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -285,7 +268,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:55:5
+  --> $DIR/feature-gate-abi.rs:59:5
    |
 LL |     extern "x86-interrupt" fn m7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -294,7 +277,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:56:5
+  --> $DIR/feature-gate-abi.rs:60:5
    |
 LL |     extern "thiscall" fn m8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +285,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:57:5
+  --> $DIR/feature-gate-abi.rs:61:5
    |
 LL |     extern "amdgpu-kernel" fn m9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -311,7 +294,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:62:5
+  --> $DIR/feature-gate-abi.rs:66:5
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -319,7 +302,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:63:5
+  --> $DIR/feature-gate-abi.rs:68:5
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -328,7 +311,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:64:5
+  --> $DIR/feature-gate-abi.rs:70:5
    |
 LL |     extern "vectorcall" fn im3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,7 +319,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:65:5
+  --> $DIR/feature-gate-abi.rs:71:5
    |
 LL |     extern "rust-call" fn im4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -345,7 +328,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:66:5
+  --> $DIR/feature-gate-abi.rs:72:5
    |
 LL |     extern "msp430-interrupt" fn im5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -354,7 +337,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:67:5
+  --> $DIR/feature-gate-abi.rs:73:5
    |
 LL |     extern "ptx-kernel" fn im6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -363,7 +346,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:68:5
+  --> $DIR/feature-gate-abi.rs:74:5
    |
 LL |     extern "x86-interrupt" fn im7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +355,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:69:5
+  --> $DIR/feature-gate-abi.rs:75:5
    |
 LL |     extern "thiscall" fn im8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -380,7 +363,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:70:5
+  --> $DIR/feature-gate-abi.rs:76:5
    |
 LL |     extern "amdgpu-kernel" fn im9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -389,7 +372,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:74:11
+  --> $DIR/feature-gate-abi.rs:80:11
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -397,7 +380,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:75:11
+  --> $DIR/feature-gate-abi.rs:81:11
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -406,7 +389,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:76:11
+  --> $DIR/feature-gate-abi.rs:82:11
    |
 LL | type A3 = extern "vectorcall" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -414,7 +397,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:77:11
+  --> $DIR/feature-gate-abi.rs:83:11
    |
 LL | type A4 = extern "rust-call" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -423,7 +406,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:78:11
+  --> $DIR/feature-gate-abi.rs:84:11
    |
 LL | type A5 = extern "msp430-interrupt" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -432,7 +415,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:79:11
+  --> $DIR/feature-gate-abi.rs:85:11
    |
 LL | type A6 = extern "ptx-kernel" fn ();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -441,7 +424,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:80:11
+  --> $DIR/feature-gate-abi.rs:86:11
    |
 LL | type A7 = extern "x86-interrupt" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -450,7 +433,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:81:11
+  --> $DIR/feature-gate-abi.rs:87:11
    |
 LL | type A8 = extern "thiscall" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^
@@ -458,7 +441,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:82:11
+  --> $DIR/feature-gate-abi.rs:88:11
    |
 LL | type A9 = extern "amdgpu-kernel" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,7 +450,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:85:1
+  --> $DIR/feature-gate-abi.rs:91:1
    |
 LL | extern "rust-intrinsic" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,7 +458,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:86:1
+  --> $DIR/feature-gate-abi.rs:92:1
    |
 LL | extern "platform-intrinsic" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -484,7 +467,7 @@
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:87:1
+  --> $DIR/feature-gate-abi.rs:93:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -492,7 +475,7 @@
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:88:1
+  --> $DIR/feature-gate-abi.rs:94:1
    |
 LL | extern "rust-call" {}
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -501,7 +484,7 @@
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:89:1
+  --> $DIR/feature-gate-abi.rs:95:1
    |
 LL | extern "msp430-interrupt" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -510,7 +493,7 @@
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:90:1
+  --> $DIR/feature-gate-abi.rs:96:1
    |
 LL | extern "ptx-kernel" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -519,7 +502,7 @@
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:91:1
+  --> $DIR/feature-gate-abi.rs:97:1
    |
 LL | extern "x86-interrupt" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -528,7 +511,7 @@
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:92:1
+  --> $DIR/feature-gate-abi.rs:98:1
    |
 LL | extern "thiscall" {}
    | ^^^^^^^^^^^^^^^^^^^^
@@ -536,7 +519,7 @@
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:93:1
+  --> $DIR/feature-gate-abi.rs:99:1
    |
 LL | extern "amdgpu-kernel" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -544,6 +527,54 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
-error: aborting due to 63 previous errors
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:26:32
+   |
+LL |     extern "rust-intrinsic" fn m1();
+   |                                ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:28:36
+   |
+LL |     extern "platform-intrinsic" fn m2();
+   |                                    ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:12:33
+   |
+LL | extern "rust-intrinsic" fn f1() {}
+   |                                 ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:14:37
+   |
+LL | extern "platform-intrinsic" fn f2() {}
+   |                                     ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:51:37
+   |
+LL |     extern "rust-intrinsic" fn m1() {}
+   |                                     ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:53:41
+   |
+LL |     extern "platform-intrinsic" fn m2() {}
+   |                                         ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:66:38
+   |
+LL |     extern "rust-intrinsic" fn im1() {}
+   |                                      ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:68:42
+   |
+LL |     extern "platform-intrinsic" fn im2() {}
+   |                                          ^^
+
+error: aborting due to 69 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
index d34936b..936cab2 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
@@ -1,18 +1,18 @@
 // Check that literals in attributes parse just fine.
 
-#[fake_attr] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(100)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr("hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(name = "hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute macro `fake_attr` in th
-#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute macro `fake_attr` in this scop
-#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute macro `fake_attr` in
-#[fake_attr(true)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(b"hi")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_doc(r"doc")] //~ ERROR cannot find attribute macro `fake_doc` in this scope
+#[fake_attr] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(100)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr("hello")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(name = "hello")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute `fake_attr` in th
+#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute `fake_attr` in this scop
+#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute `fake_attr` in
+#[fake_attr(true)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(b"hi")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_doc(r"doc")] //~ ERROR cannot find attribute `fake_doc` in this scope
 struct Q {}
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
index efdc2d1..b7c45ec 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
@@ -1,76 +1,76 @@
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:3:3
    |
 LL | #[fake_attr]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:4:3
    |
 LL | #[fake_attr(100)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:5:3
    |
 LL | #[fake_attr(1, 2, 3)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:6:3
    |
 LL | #[fake_attr("hello")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:7:3
    |
 LL | #[fake_attr(name = "hello")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:8:3
    |
 LL | #[fake_attr(1, "hi", key = 12, true, false)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:9:3
    |
 LL | #[fake_attr(key = "hello", val = 10)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:10:3
    |
 LL | #[fake_attr(key("hello"), val(10))]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:11:3
    |
 LL | #[fake_attr(enabled = true, disabled = false)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:12:3
    |
 LL | #[fake_attr(true)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:13:3
    |
 LL | #[fake_attr(pi = 3.14159)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:14:3
    |
 LL | #[fake_attr(b"hi")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_doc` in this scope
+error: cannot find attribute `fake_doc` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:15:3
    |
 LL | #[fake_doc(r"doc")]
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
index 51b5bf5..e4c8014 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
@@ -4,54 +4,54 @@
 // gate-test-custom_attribute
 
 struct StLt<#[lt_struct] 'a>(&'a u32);
-//~^ ERROR cannot find attribute macro `lt_struct` in this scope
+//~^ ERROR cannot find attribute `lt_struct` in this scope
 struct StTy<#[ty_struct] I>(I);
-//~^ ERROR cannot find attribute macro `ty_struct` in this scope
+//~^ ERROR cannot find attribute `ty_struct` in this scope
 
 enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
-//~^ ERROR cannot find attribute macro `lt_enum` in this scope
+//~^ ERROR cannot find attribute `lt_enum` in this scope
 enum EnTy<#[ty_enum] J> { A(J), B }
-//~^ ERROR cannot find attribute macro `ty_enum` in this scope
+//~^ ERROR cannot find attribute `ty_enum` in this scope
 
 trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
-//~^ ERROR cannot find attribute macro `lt_trait` in this scope
+//~^ ERROR cannot find attribute `lt_trait` in this scope
 trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
-//~^ ERROR cannot find attribute macro `ty_trait` in this scope
+//~^ ERROR cannot find attribute `ty_trait` in this scope
 
 type TyLt<#[lt_type] 'd> = &'d u32;
-//~^ ERROR cannot find attribute macro `lt_type` in this scope
+//~^ ERROR cannot find attribute `lt_type` in this scope
 type TyTy<#[ty_type] L> = (L, );
-//~^ ERROR cannot find attribute macro `ty_type` in this scope
+//~^ ERROR cannot find attribute `ty_type` in this scope
 
 impl<#[lt_inherent] 'e> StLt<'e> { }
-//~^ ERROR cannot find attribute macro `lt_inherent` in this scope
+//~^ ERROR cannot find attribute `lt_inherent` in this scope
 impl<#[ty_inherent] M> StTy<M> { }
-//~^ ERROR cannot find attribute macro `ty_inherent` in this scope
+//~^ ERROR cannot find attribute `ty_inherent` in this scope
 
 impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
-    //~^ ERROR cannot find attribute macro `lt_impl_for` in this scope
+    //~^ ERROR cannot find attribute `lt_impl_for` in this scope
     fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
 }
 impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
-    //~^ ERROR cannot find attribute macro `ty_impl_for` in this scope
+    //~^ ERROR cannot find attribute `ty_impl_for` in this scope
     fn foo(&self, _: N) { }
 }
 
 fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
-//~^ ERROR cannot find attribute macro `lt_fn` in this scope
+//~^ ERROR cannot find attribute `lt_fn` in this scope
 fn f_ty<#[ty_fn] O>(_: O) { }
-//~^ ERROR cannot find attribute macro `ty_fn` in this scope
+//~^ ERROR cannot find attribute `ty_fn` in this scope
 
 impl<I> StTy<I> {
     fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
-    //~^ ERROR cannot find attribute macro `lt_meth` in this scope
+    //~^ ERROR cannot find attribute `lt_meth` in this scope
     fn m_ty<#[ty_meth] P>(_: P) { }
-    //~^ ERROR cannot find attribute macro `ty_meth` in this scope
+    //~^ ERROR cannot find attribute `ty_meth` in this scope
 }
 
 fn hof_lt<Q>(_: Q)
     where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
-    //~^ ERROR cannot find attribute macro `lt_hof` in this scope
+    //~^ ERROR cannot find attribute `lt_hof` in this scope
 {
 }
 
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
index 9250616..bc89cad 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
@@ -1,100 +1,100 @@
-error: cannot find attribute macro `lt_hof` in this scope
+error: cannot find attribute `lt_hof` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:53:21
    |
 LL |     where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
    |                     ^^^^^^
 
-error: cannot find attribute macro `ty_meth` in this scope
+error: cannot find attribute `ty_meth` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:48:15
    |
 LL |     fn m_ty<#[ty_meth] P>(_: P) { }
    |               ^^^^^^^
 
-error: cannot find attribute macro `lt_meth` in this scope
+error: cannot find attribute `lt_meth` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:46:15
    |
 LL |     fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
    |               ^^^^^^^
 
-error: cannot find attribute macro `ty_fn` in this scope
+error: cannot find attribute `ty_fn` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:42:11
    |
 LL | fn f_ty<#[ty_fn] O>(_: O) { }
    |           ^^^^^
 
-error: cannot find attribute macro `lt_fn` in this scope
+error: cannot find attribute `lt_fn` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:40:11
    |
 LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
    |           ^^^^^
 
-error: cannot find attribute macro `ty_impl_for` in this scope
+error: cannot find attribute `ty_impl_for` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:35:8
    |
 LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
    |        ^^^^^^^^^^^
 
-error: cannot find attribute macro `lt_impl_for` in this scope
+error: cannot find attribute `lt_impl_for` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:31:8
    |
 LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
    |        ^^^^^^^^^^^
 
-error: cannot find attribute macro `ty_inherent` in this scope
+error: cannot find attribute `ty_inherent` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:28:8
    |
 LL | impl<#[ty_inherent] M> StTy<M> { }
    |        ^^^^^^^^^^^
 
-error: cannot find attribute macro `lt_inherent` in this scope
+error: cannot find attribute `lt_inherent` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:26:8
    |
 LL | impl<#[lt_inherent] 'e> StLt<'e> { }
    |        ^^^^^^^^^^^
 
-error: cannot find attribute macro `ty_type` in this scope
+error: cannot find attribute `ty_type` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:23:13
    |
 LL | type TyTy<#[ty_type] L> = (L, );
    |             ^^^^^^^
 
-error: cannot find attribute macro `lt_type` in this scope
+error: cannot find attribute `lt_type` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:21:13
    |
 LL | type TyLt<#[lt_type] 'd> = &'d u32;
    |             ^^^^^^^
 
-error: cannot find attribute macro `ty_trait` in this scope
+error: cannot find attribute `ty_trait` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:18:14
    |
 LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
    |              ^^^^^^^^
 
-error: cannot find attribute macro `lt_trait` in this scope
+error: cannot find attribute `lt_trait` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:16:14
    |
 LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
    |              ^^^^^^^^
 
-error: cannot find attribute macro `ty_enum` in this scope
+error: cannot find attribute `ty_enum` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:13:13
    |
 LL | enum EnTy<#[ty_enum] J> { A(J), B }
    |             ^^^^^^^
 
-error: cannot find attribute macro `lt_enum` in this scope
+error: cannot find attribute `lt_enum` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:11:13
    |
 LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
    |             ^^^^^^^
 
-error: cannot find attribute macro `ty_struct` in this scope
+error: cannot find attribute `ty_struct` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:8:15
    |
 LL | struct StTy<#[ty_struct] I>(I);
    |               ^^^^^^^^^
 
-error: cannot find attribute macro `lt_struct` in this scope
+error: cannot find attribute `lt_struct` in this scope
   --> $DIR/feature-gate-custom_attribute2.rs:6:15
    |
 LL | struct StLt<#[lt_struct] 'a>(&'a u32);
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs
index adb6fc2..c957221 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_alias.rs
@@ -1,4 +1,4 @@
-#[doc(alias = "foo")] //~ ERROR: `#[doc(alias = "...")]` is experimental
+#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental
 pub struct Foo;
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
index dddaa45..540b1f5 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(alias = "...")]` is experimental
+error[E0658]: `#[doc(alias)]` is experimental
   --> $DIR/feature-gate-doc_alias.rs:1:1
    |
 LL | #[doc(alias = "foo")]
diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
index bb3846e..b12b8a1 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
@@ -1,2 +1,2 @@
-#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg(...))]` is experimental
+#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
index 7b0a231..eaa908d 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(cfg(...))]` is experimental
+error[E0658]: `#[doc(cfg)]` is experimental
   --> $DIR/feature-gate-doc_cfg.rs:1:1
    |
 LL | #[doc(cfg(unix))]
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
index 6cdcfa6..4bb9a40 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
@@ -1,4 +1,4 @@
-#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword = "...")]` is experimental
+#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is experimental
 /// wonderful
 mod foo{}
 
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
index abde0be..15a41d9 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(keyword = "...")]` is experimental
+error[E0658]: `#[doc(keyword)]` is experimental
   --> $DIR/feature-gate-doc_keyword.rs:1:1
    |
 LL | #[doc(keyword = "match")]
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.rs b/src/test/ui/feature-gates/feature-gate-external_doc.rs
index dec3fa1..9d68d3e 100644
--- a/src/test/ui/feature-gates/feature-gate-external_doc.rs
+++ b/src/test/ui/feature-gates/feature-gate-external_doc.rs
@@ -1,2 +1,2 @@
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include = "...")]` is experimental
+#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr
index a5a8743..683c0ad 100644
--- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr
+++ b/src/test/ui/feature-gates/feature-gate-external_doc.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(include = "...")]` is experimental
+error[E0658]: `#[doc(include)]` is experimental
   --> $DIR/feature-gate-external_doc.rs:1:1
    |
 LL | #[doc(include="asdf.md")]
diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.rs b/src/test/ui/feature-gates/feature-gate-intrinsics.rs
index d1da943..e0dc3cc 100644
--- a/src/test/ui/feature-gates/feature-gate-intrinsics.rs
+++ b/src/test/ui/feature-gates/feature-gate-intrinsics.rs
@@ -3,5 +3,6 @@
 }
 
 extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to change
+//~^ ERROR intrinsic must be in
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
index 09843f0..101a10e 100644
--- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -22,7 +22,13 @@
 LL |     fn bar();
    |     ^^^^^^^^^ unrecognized intrinsic
 
-error: aborting due to 3 previous errors
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-intrinsics.rs:5:34
+   |
+LL | extern "rust-intrinsic" fn baz() {}
+   |                                  ^^
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0093, E0658.
 For more information about an error, try `rustc --explain E0093`.
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
index 4044fd2..c985298 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -19,5 +19,5 @@
 //~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests
 #[rustc_unknown]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
-//~| ERROR cannot find attribute macro `rustc_unknown` in this scope
+//~| ERROR cannot find attribute `rustc_unknown` in this scope
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
index c106302..d6fdab2 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -37,7 +37,7 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error: cannot find attribute macro `rustc_unknown` in this scope
+error: cannot find attribute `rustc_unknown` in this scope
   --> $DIR/feature-gate-rustc-attrs.rs:20:3
    |
 LL | #[rustc_unknown]
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.rs b/src/test/ui/hygiene/no_implicit_prelude-2018.rs
index 3ad7435..83ca281 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.rs
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.rs
@@ -4,7 +4,7 @@
 mod bar {
     fn f() {
         ::std::print!(""); // OK
-        print!(); //~ ERROR cannot find macro `print!` in this scope
+        print!(); //~ ERROR cannot find macro `print` in this scope
     }
 }
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
index 0fdb18d..f31b752 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `print!` in this scope
+error: cannot find macro `print` in this scope
   --> $DIR/no_implicit_prelude-2018.rs:7:9
    |
 LL |         print!();
diff --git a/src/test/ui/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs
index 890c830..204e7b2 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.rs
+++ b/src/test/ui/hygiene/no_implicit_prelude.rs
@@ -13,7 +13,7 @@
     }
     fn f() {
         ::foo::m!();
-        assert_eq!(0, 0); //~ ERROR cannot find macro `panic!` in this scope
+        assert_eq!(0, 0); //~ ERROR cannot find macro `panic` in this scope
     }
 }
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 8fa55d0..bc0ce74 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `panic!` in this scope
+error: cannot find macro `panic` in this scope
   --> $DIR/no_implicit_prelude.rs:16:9
    |
 LL |         assert_eq!(0, 0);
diff --git a/src/test/ui/intrinsics-always-extern.rs b/src/test/ui/intrinsics-always-extern.rs
new file mode 100644
index 0000000..2295114
--- /dev/null
+++ b/src/test/ui/intrinsics-always-extern.rs
@@ -0,0 +1,16 @@
+#![feature(intrinsics)]
+
+trait Foo {
+    extern "rust-intrinsic" fn foo(&self); //~ ERROR intrinsic must
+}
+
+impl Foo for () {
+    extern "rust-intrinsic" fn foo(&self) { //~ ERROR intrinsic must
+    }
+}
+
+extern "rust-intrinsic" fn hello() {//~ ERROR intrinsic must
+}
+
+fn main() {
+}
diff --git a/src/test/ui/intrinsics-always-extern.stderr b/src/test/ui/intrinsics-always-extern.stderr
new file mode 100644
index 0000000..24b6da1
--- /dev/null
+++ b/src/test/ui/intrinsics-always-extern.stderr
@@ -0,0 +1,24 @@
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:4:32
+   |
+LL |     extern "rust-intrinsic" fn foo(&self);
+   |                                ^^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:8:43
+   |
+LL |       extern "rust-intrinsic" fn foo(&self) {
+   |  ___________________________________________^
+LL | |     }
+   | |_____^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:12:36
+   |
+LL |   extern "rust-intrinsic" fn hello() {
+   |  ____________________________________^
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/issues/issue-11692-1.rs b/src/test/ui/issues/issue-11692-1.rs
index 70b712c..b6f3bb8 100644
--- a/src/test/ui/issues/issue-11692-1.rs
+++ b/src/test/ui/issues/issue-11692-1.rs
@@ -1,3 +1,3 @@
 fn main() {
-    print!(testo!()); //~ ERROR cannot find macro `testo!` in this scope
+    print!(testo!()); //~ ERROR cannot find macro `testo` in this scope
 }
diff --git a/src/test/ui/issues/issue-11692-1.stderr b/src/test/ui/issues/issue-11692-1.stderr
index bfd1647..3864634 100644
--- a/src/test/ui/issues/issue-11692-1.stderr
+++ b/src/test/ui/issues/issue-11692-1.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `testo!` in this scope
+error: cannot find macro `testo` in this scope
   --> $DIR/issue-11692-1.rs:2:12
    |
 LL |     print!(testo!());
diff --git a/src/test/ui/issues/issue-11692-2.rs b/src/test/ui/issues/issue-11692-2.rs
index 61be284..5957ed3 100644
--- a/src/test/ui/issues/issue-11692-2.rs
+++ b/src/test/ui/issues/issue-11692-2.rs
@@ -1,3 +1,3 @@
 fn main() {
-    concat!(test!()); //~ ERROR cannot find macro `test!` in this scope
+    concat!(test!()); //~ ERROR cannot find macro `test` in this scope
 }
diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr
index 740c355..f021943 100644
--- a/src/test/ui/issues/issue-11692-2.stderr
+++ b/src/test/ui/issues/issue-11692-2.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `test!` in this scope
+error: cannot find macro `test` in this scope
   --> $DIR/issue-11692-2.rs:2:13
    |
 LL |     concat!(test!());
diff --git a/src/test/ui/issues/issue-1251.rs b/src/test/ui/issues/issue-1251.rs
index 63b5a4d..77278ec 100644
--- a/src/test/ui/issues/issue-1251.rs
+++ b/src/test/ui/issues/issue-1251.rs
@@ -6,8 +6,6 @@
 
 #![feature(rustc_private)]
 
-#![crate_id="rust_get_test_int"]
-
 mod rustrt {
     extern crate libc;
 
diff --git a/src/test/ui/issues/issue-19734.rs b/src/test/ui/issues/issue-19734.rs
index b730e19..fe4a327 100644
--- a/src/test/ui/issues/issue-19734.rs
+++ b/src/test/ui/issues/issue-19734.rs
@@ -4,5 +4,5 @@
 
 impl Type {
     undef!();
-    //~^ ERROR cannot find macro `undef!` in this scope
+    //~^ ERROR cannot find macro `undef` in this scope
 }
diff --git a/src/test/ui/issues/issue-19734.stderr b/src/test/ui/issues/issue-19734.stderr
index fc1a7d0..8175797 100644
--- a/src/test/ui/issues/issue-19734.stderr
+++ b/src/test/ui/issues/issue-19734.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `undef!` in this scope
+error: cannot find macro `undef` in this scope
   --> $DIR/issue-19734.rs:6:5
    |
 LL |     undef!();
diff --git a/src/test/ui/issues/issue-32655.rs b/src/test/ui/issues/issue-32655.rs
index fad7bf5..f52e092 100644
--- a/src/test/ui/issues/issue-32655.rs
+++ b/src/test/ui/issues/issue-32655.rs
@@ -1,6 +1,6 @@
 macro_rules! foo (
     () => (
-        #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
+        #[derive_Clone] //~ ERROR cannot find attribute `derive_Clone` in this scope
         struct T;
     );
 );
@@ -12,7 +12,7 @@
 foo!();
 
 bar!(
-    #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
+    #[derive_Clone] //~ ERROR cannot find attribute `derive_Clone` in this scope
     struct S;
 );
 
diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr
index e13bed0..ca085b2 100644
--- a/src/test/ui/issues/issue-32655.stderr
+++ b/src/test/ui/issues/issue-32655.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `derive_Clone` in this scope
+error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:3:11
    |
 LL |         #[derive_Clone]
@@ -7,7 +7,7 @@
 LL | foo!();
    | ------- in this macro invocation
 
-error: cannot find attribute macro `derive_Clone` in this scope
+error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:15:7
    |
 LL |     #[derive_Clone]
diff --git a/src/test/ui/issues/issue-40845.rs b/src/test/ui/issues/issue-40845.rs
index c9102f4..a4ede6a 100644
--- a/src/test/ui/issues/issue-40845.rs
+++ b/src/test/ui/issues/issue-40845.rs
@@ -1,6 +1,6 @@
-trait T { m!(); } //~ ERROR cannot find macro `m!` in this scope
+trait T { m!(); } //~ ERROR cannot find macro `m` in this scope
 
 struct S;
-impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope
+impl S { m!(); } //~ ERROR cannot find macro `m` in this scope
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr
index a8be38e..2744330 100644
--- a/src/test/ui/issues/issue-40845.stderr
+++ b/src/test/ui/issues/issue-40845.stderr
@@ -1,10 +1,10 @@
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/issue-40845.rs:4:10
    |
 LL | impl S { m!(); }
    |          ^
 
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/issue-40845.rs:1:11
    |
 LL | trait T { m!(); }
diff --git a/src/test/ui/issues/issue-46101.rs b/src/test/ui/issues/issue-46101.rs
index 2d9111e..8b1343b 100644
--- a/src/test/ui/issues/issue-46101.rs
+++ b/src/test/ui/issues/issue-46101.rs
@@ -2,3 +2,5 @@
 trait Foo {}
 #[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
 struct S;
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-46101.stderr b/src/test/ui/issues/issue-46101.stderr
index 772d4bf..9c88d3b 100644
--- a/src/test/ui/issues/issue-46101.stderr
+++ b/src/test/ui/issues/issue-46101.stderr
@@ -4,11 +4,6 @@
 LL | #[derive(Foo::Anything)]
    |          ^^^^^^^^^^^^^ partially resolved path in a derive macro
 
-error[E0601]: `main` function not found in crate `issue_46101`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-46101.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0433, E0601.
-For more information about an error, try `rustc --explain E0433`.
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/issues/issue-49040.rs b/src/test/ui/issues/issue-49040.rs
index a5f05d2..b7a541d 100644
--- a/src/test/ui/issues/issue-49040.rs
+++ b/src/test/ui/issues/issue-49040.rs
@@ -1,2 +1,3 @@
 #![allow(unused_variables)]; //~ ERROR expected item, found `;`
+//~^ ERROR `main` function
 fn foo() {}
diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr
index de78b8d..4134d6a 100644
--- a/src/test/ui/issues/issue-49040.stderr
+++ b/src/test/ui/issues/issue-49040.stderr
@@ -5,8 +5,12 @@
    |                            ^ help: remove this semicolon
 
 error[E0601]: `main` function not found in crate `issue_49040`
+  --> $DIR/issue-49040.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | / #![allow(unused_variables)];
+LL | |
+LL | | fn foo() {}
+   | |__^ consider adding a `main` function to `$DIR/issue-49040.rs`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-49074.rs b/src/test/ui/issues/issue-49074.rs
index 38074d5..752bb34 100644
--- a/src/test/ui/issues/issue-49074.rs
+++ b/src/test/ui/issues/issue-49074.rs
@@ -1,7 +1,7 @@
 // Check that unknown attribute error is shown even if there are unresolved macros.
 
 #[marco_use] // typo
-//~^ ERROR cannot find attribute macro `marco_use` in this scope
+//~^ ERROR cannot find attribute `marco_use` in this scope
 mod foo {
     macro_rules! bar {
         () => ();
@@ -9,5 +9,5 @@
 }
 
 fn main() {
-   bar!(); //~ ERROR cannot find macro `bar!` in this scope
+   bar!(); //~ ERROR cannot find macro `bar` in this scope
 }
diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr
index e0d3bb3..bbfeb4e 100644
--- a/src/test/ui/issues/issue-49074.stderr
+++ b/src/test/ui/issues/issue-49074.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `bar!` in this scope
+error: cannot find macro `bar` in this scope
   --> $DIR/issue-49074.rs:12:4
    |
 LL |    bar!();
@@ -6,7 +6,7 @@
    |
    = help: have you added the `#[macro_use]` on the module/import?
 
-error: cannot find attribute macro `marco_use` in this scope
+error: cannot find attribute `marco_use` in this scope
   --> $DIR/issue-49074.rs:3:3
    |
 LL | #[marco_use] // typo
diff --git a/src/test/ui/issues/issue-49934-errors.rs b/src/test/ui/issues/issue-49934-errors.rs
index 58f64d1..6fa5f01 100644
--- a/src/test/ui/issues/issue-49934-errors.rs
+++ b/src/test/ui/issues/issue-49934-errors.rs
@@ -1,10 +1,10 @@
 fn foo<#[derive(Debug)] T>() {
 //~^ ERROR `derive` may only be applied to structs, enums and unions
-//~| ERROR expected an inert attribute, found an attribute macro
+//~| ERROR expected an inert attribute, found a derive macro
     match 0 {
         #[derive(Debug)]
         //~^ ERROR `derive` may only be applied to structs, enums and unions
-        //~| ERROR expected an inert attribute, found an attribute macro
+        //~| ERROR expected an inert attribute, found a derive macro
         _ => (),
     }
 }
diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr
index fce1f65..8778d88 100644
--- a/src/test/ui/issues/issue-49934-errors.stderr
+++ b/src/test/ui/issues/issue-49934-errors.stderr
@@ -4,7 +4,7 @@
 LL | fn foo<#[derive(Debug)] T>() {
    |        ^^^^^^^^^^^^^^^^
 
-error: expected an inert attribute, found an attribute macro
+error: expected an inert attribute, found a derive macro
   --> $DIR/issue-49934-errors.rs:1:17
    |
 LL | fn foo<#[derive(Debug)] T>() {
@@ -16,7 +16,7 @@
 LL |         #[derive(Debug)]
    |         ^^^^^^^^^^^^^^^^
 
-error: expected an inert attribute, found an attribute macro
+error: expected an inert attribute, found a derive macro
   --> $DIR/issue-49934-errors.rs:5:18
    |
 LL |         #[derive(Debug)]
diff --git a/src/test/ui/issues/issue-60057.rs b/src/test/ui/issues/issue-60057.rs
index 3027d01..b52343a 100644
--- a/src/test/ui/issues/issue-60057.rs
+++ b/src/test/ui/issues/issue-60057.rs
@@ -15,3 +15,5 @@
         }
     }
 }
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-60057.stderr b/src/test/ui/issues/issue-60057.stderr
index 6b96720..4d915fc 100644
--- a/src/test/ui/issues/issue-60057.stderr
+++ b/src/test/ui/issues/issue-60057.stderr
@@ -10,11 +10,6 @@
 LL |             banana: banana
    |                     ^^^^^^ help: you might have meant to use the available field: `self.banana`
 
-error[E0601]: `main` function not found in crate `issue_60057`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-60057.rs`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0425, E0601.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/issues/issue-64430.rs b/src/test/ui/issues/issue-64430.rs
new file mode 100644
index 0000000..0bc66e0
--- /dev/null
+++ b/src/test/ui/issues/issue-64430.rs
@@ -0,0 +1,14 @@
+// compile-flags:-C panic=abort
+
+#![no_std]
+pub struct Foo;
+
+fn main() {
+    Foo.bar()
+    //~^ ERROR E0599
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop{}
+}
diff --git a/src/test/ui/issues/issue-64430.stderr b/src/test/ui/issues/issue-64430.stderr
new file mode 100644
index 0000000..f1b2de8
--- /dev/null
+++ b/src/test/ui/issues/issue-64430.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no method named `bar` found for type `Foo` in the current scope
+  --> $DIR/issue-64430.rs:7:9
+   |
+LL | pub struct Foo;
+   | --------------- method `bar` not found for this
+...
+LL |     Foo.bar()
+   |         ^^^ method not found in `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-6919.rs b/src/test/ui/issues/issue-6919.rs
index 11aed12..6f1e1f9 100644
--- a/src/test/ui/issues/issue-6919.rs
+++ b/src/test/ui/issues/issue-6919.rs
@@ -4,7 +4,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![crate_id="issue-6919"]
 extern crate issue6919_3;
 
 pub fn main() {
diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr
index dffbdb7..86cb2f0 100644
--- a/src/test/ui/json-short.stderr
+++ b/src/test/ui/json-short.stderr
@@ -11,7 +11,7 @@
 
 If you don't know the basics of Rust, you can go look to the Rust Book to get
 started: https://doc.rust-lang.org/book/
-"},"level":"error","spans":[],"children":[{"message":"consider adding a `main` function to `$DIR/json-short.rs`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error[E0601]: `main` function not found in crate `json_short`
+"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":76,"byte_end":76,"line_start":2,"line_end":2,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:2:63: error[E0601]: `main` function not found in crate `json_short`
 "}
 {"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
 "}
diff --git a/src/test/ui/lifetime-before-type-params.rs b/src/test/ui/lifetime-before-type-params.rs
index 9b905d4..5a71d6e 100644
--- a/src/test/ui/lifetime-before-type-params.rs
+++ b/src/test/ui/lifetime-before-type-params.rs
@@ -7,3 +7,5 @@
 //~^ ERROR lifetime parameters must be declared prior to type parameters
 fn fourth<'a, T, 'b, U, 'c, V>() {}
 //~^ ERROR lifetime parameters must be declared prior to type parameters
+
+fn main() {}
diff --git a/src/test/ui/lifetime-before-type-params.stderr b/src/test/ui/lifetime-before-type-params.stderr
index ffc6784..76d7d0f 100644
--- a/src/test/ui/lifetime-before-type-params.stderr
+++ b/src/test/ui/lifetime-before-type-params.stderr
@@ -22,10 +22,5 @@
 LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
    |          --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
-error[E0601]: `main` function not found in crate `lifetime_before_type_params`
-   |
-   = note: consider adding a `main` function to `$DIR/lifetime-before-type-params.rs`
+error: aborting due to 4 previous errors
 
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/macros/macro-expansion-tests.stderr b/src/test/ui/macros/macro-expansion-tests.stderr
index 4ad9ade..8b3f7ca 100644
--- a/src/test/ui/macros/macro-expansion-tests.stderr
+++ b/src/test/ui/macros/macro-expansion-tests.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/macro-expansion-tests.rs:7:21
    |
 LL |     fn g() -> i32 { m!() }
@@ -6,7 +6,7 @@
    |
    = help: have you added the `#[macro_use]` on the module/import?
 
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/macro-expansion-tests.rs:15:21
    |
 LL |     fn g() -> i32 { m!() }
diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr
index 967f4f3..ce2e198 100644
--- a/src/test/ui/macros/macro-name-typo.stderr
+++ b/src/test/ui/macros/macro-name-typo.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `printlx!` in this scope
+error: cannot find macro `printlx` in this scope
   --> $DIR/macro-name-typo.rs:2:5
    |
 LL |     printlx!("oh noes!");
diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.rs b/src/test/ui/macros/macro-path-prelude-fail-3.rs
index 597053d..68eb350 100644
--- a/src/test/ui/macros/macro-path-prelude-fail-3.rs
+++ b/src/test/ui/macros/macro-path-prelude-fail-3.rs
@@ -1,3 +1,3 @@
 fn main() {
-    inline!(); //~ ERROR cannot find macro `inline!` in this scope
+    inline!(); //~ ERROR cannot find macro `inline` in this scope
 }
diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.stderr b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
index 96b8a24..ec00760 100644
--- a/src/test/ui/macros/macro-path-prelude-fail-3.stderr
+++ b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `inline!` in this scope
+error: cannot find macro `inline` in this scope
   --> $DIR/macro-path-prelude-fail-3.rs:2:5
    |
 LL |     inline!();
diff --git a/src/test/ui/macros/macro-reexport-removed.rs b/src/test/ui/macros/macro-reexport-removed.rs
index b69a1fa..874c94d 100644
--- a/src/test/ui/macros/macro-reexport-removed.rs
+++ b/src/test/ui/macros/macro-reexport-removed.rs
@@ -2,7 +2,7 @@
 
 #![feature(macro_reexport)] //~ ERROR feature has been removed
 
-#[macro_reexport(macro_one)] //~ ERROR cannot find attribute macro `macro_reexport` in this scope
+#[macro_reexport(macro_one)] //~ ERROR cannot find attribute `macro_reexport` in this scope
 extern crate two_macros;
 
 fn main() {}
diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr
index 25778fb..4bec708 100644
--- a/src/test/ui/macros/macro-reexport-removed.stderr
+++ b/src/test/ui/macros/macro-reexport-removed.stderr
@@ -10,7 +10,7 @@
 LL | #![feature(macro_reexport)]
    |            ^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `macro_reexport` in this scope
+error: cannot find attribute `macro_reexport` in this scope
   --> $DIR/macro-reexport-removed.rs:5:3
    |
 LL | #[macro_reexport(macro_one)]
diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr
index 28f727d..8b4e90a 100644
--- a/src/test/ui/macros/macro-use-wrong-name.stderr
+++ b/src/test/ui/macros/macro-use-wrong-name.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/macro-use-wrong-name.rs:7:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr
index 9239b2a..01c8ebe 100644
--- a/src/test/ui/macros/macro_undefined.stderr
+++ b/src/test/ui/macros/macro_undefined.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `k!` in this scope
+error: cannot find macro `k` in this scope
   --> $DIR/macro_undefined.rs:11:5
    |
 LL |     k!();
diff --git a/src/test/ui/main-wrong-location.rs b/src/test/ui/main-wrong-location.rs
index d7ed512..f75d088 100644
--- a/src/test/ui/main-wrong-location.rs
+++ b/src/test/ui/main-wrong-location.rs
@@ -1,4 +1,5 @@
 mod m {
+//~^ ERROR `main` function not found
     // An inferred main entry point (that doesn't use #[main])
     // must appear at the top of the crate
     fn main() { }
diff --git a/src/test/ui/main-wrong-location.stderr b/src/test/ui/main-wrong-location.stderr
index b30931f..e301c2f 100644
--- a/src/test/ui/main-wrong-location.stderr
+++ b/src/test/ui/main-wrong-location.stderr
@@ -1,11 +1,21 @@
 error[E0601]: `main` function not found in crate `main_wrong_location`
+  --> $DIR/main-wrong-location.rs:1:1
    |
-   = note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
-note: here is a function named 'main'
-  --> $DIR/main-wrong-location.rs:4:5
+LL | / mod m {
+LL | |
+LL | |     // An inferred main entry point (that doesn't use #[main])
+LL | |     // must appear at the top of the crate
+LL | |     fn main() { }
+LL | | }
+   | |_^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
+   |
+note: here is a function named `main`
+  --> $DIR/main-wrong-location.rs:5:5
    |
 LL |     fn main() { }
    |     ^^^^^^^^^^^^^
+   = note: you have one or more functions named `main` not defined at the crate level
+   = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/missing/missing-macro-use.rs b/src/test/ui/missing/missing-macro-use.rs
index dff4c94..d494c44 100644
--- a/src/test/ui/missing/missing-macro-use.rs
+++ b/src/test/ui/missing/missing-macro-use.rs
@@ -4,5 +4,5 @@
 
 pub fn main() {
     macro_two!();
-    //~^ ERROR cannot find macro `macro_two!` in this scope
+    //~^ ERROR cannot find macro `macro_two` in this scope
 }
diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr
index 01a7beb..711e249 100644
--- a/src/test/ui/missing/missing-macro-use.stderr
+++ b/src/test/ui/missing/missing-macro-use.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/missing-macro-use.rs:6:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/missing/missing-main.stderr b/src/test/ui/missing/missing-main.stderr
index 34b03ad..6a35f51 100644
--- a/src/test/ui/missing/missing-main.stderr
+++ b/src/test/ui/missing/missing-main.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `missing_main`
+  --> $DIR/missing-main.rs:2:1
    |
-   = note: consider adding a `main` function to `$DIR/missing-main.rs`
+LL | fn mian() { }
+   | ^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/missing-main.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser-recovery-1.rs b/src/test/ui/parser-recovery-1.rs
index 21d3604..8126525 100644
--- a/src/test/ui/parser-recovery-1.rs
+++ b/src/test/ui/parser-recovery-1.rs
@@ -3,6 +3,7 @@
 // Test that we can recover from missing braces in the parser.
 
 trait Foo {
+//~^ ERROR `main` function not found
     fn bar() {
         let x = foo();
         //~^ ERROR cannot find function `foo` in this scope
diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr
index c29f427..ffe2b33 100644
--- a/src/test/ui/parser-recovery-1.stderr
+++ b/src/test/ui/parser-recovery-1.stderr
@@ -1,8 +1,9 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/parser-recovery-1.rs:15:55
+  --> $DIR/parser-recovery-1.rs:16:55
    |
 LL | trait Foo {
    |           - un-closed delimiter
+LL |
 LL |     fn bar() {
    |              - this delimiter might not be properly closed...
 ...
@@ -13,26 +14,34 @@
    |                                                       ^
 
 error: unexpected token: `;`
-  --> $DIR/parser-recovery-1.rs:12:15
+  --> $DIR/parser-recovery-1.rs:13:15
    |
 LL |     let x = y.;
    |               ^
 
 error[E0425]: cannot find function `foo` in this scope
-  --> $DIR/parser-recovery-1.rs:7:17
+  --> $DIR/parser-recovery-1.rs:8:17
    |
 LL |         let x = foo();
    |                 ^^^ not found in this scope
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/parser-recovery-1.rs:12:13
+  --> $DIR/parser-recovery-1.rs:13:13
    |
 LL |     let x = y.;
    |             ^ not found in this scope
 
 error[E0601]: `main` function not found in crate `parser_recovery_1`
+  --> $DIR/parser-recovery-1.rs:5:1
    |
-   = note: consider adding a `main` function to `$DIR/parser-recovery-1.rs`
+LL | / trait Foo {
+LL | |
+LL | |     fn bar() {
+LL | |         let x = foo();
+...  |
+LL | |
+LL | | }
+   | |______________________________________________________^ consider adding a `main` function to `$DIR/parser-recovery-1.rs`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/parser/issue-2354.rs b/src/test/ui/parser/issue-2354.rs
index 565f848..a14eb6e 100644
--- a/src/test/ui/parser/issue-2354.rs
+++ b/src/test/ui/parser/issue-2354.rs
@@ -1,4 +1,7 @@
 fn foo() { //~ NOTE un-closed delimiter
+//~^ ERROR `main` function not found
+//~^^ NOTE main function must be defined
+//~^^^ NOTE you have one or more functions
   match Some(10) {
   //~^ NOTE this delimiter might not be properly closed...
       Some(y) => { panic!(); }
@@ -11,5 +14,5 @@
     while (i < 1000) {}
 }
 
-fn main() {} //~ NOTE here is a function named 'main'
+fn main() {} //~ NOTE here is a function named `main`
              //~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/issue-2354.stderr b/src/test/ui/parser/issue-2354.stderr
index 7098da7..038e3dc 100644
--- a/src/test/ui/parser/issue-2354.stderr
+++ b/src/test/ui/parser/issue-2354.stderr
@@ -1,8 +1,9 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/issue-2354.rs:15:66
+  --> $DIR/issue-2354.rs:18:66
    |
 LL | fn foo() {
    |          - un-closed delimiter
+...
 LL |   match Some(10) {
    |                  - this delimiter might not be properly closed...
 ...
@@ -13,13 +14,24 @@
    |                                                                  ^
 
 error[E0601]: `main` function not found in crate `issue_2354`
+  --> $DIR/issue-2354.rs:1:1
    |
-   = note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
-note: here is a function named 'main'
-  --> $DIR/issue-2354.rs:14:1
+LL | / fn foo() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | | fn main() {}
+LL | |
+   | |_________________________________________________________________^ the main function must be defined at the crate level (in `$DIR/issue-2354.rs`)
+   |
+note: here is a function named `main`
+  --> $DIR/issue-2354.rs:17:1
    |
 LL | fn main() {}
    | ^^^^^^^^^^^^
+   = note: you have one or more functions named `main` not defined at the crate level
+   = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.rs b/src/test/ui/parser/lex-bad-char-literals-2.rs
index 1e180f8..d35dafd 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.rs
+++ b/src/test/ui/parser/lex-bad-char-literals-2.rs
@@ -2,3 +2,5 @@
 static c: char =
     'nope' //~ ERROR: character literal may only contain one codepoint
 ;
+
+fn main() {}
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/parser/lex-bad-char-literals-2.stderr
index b0a4ed0..5653d4e 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.stderr
+++ b/src/test/ui/parser/lex-bad-char-literals-2.stderr
@@ -8,10 +8,5 @@
 LL |     "nope"
    |     ^^^^^^
 
-error[E0601]: `main` function not found in crate `lex_bad_char_literals_2`
-   |
-   = note: consider adding a `main` function to `$DIR/lex-bad-char-literals-2.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
index 633c63b..818f61b 100644
--- a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
+++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
@@ -1,5 +1,5 @@
 error: incorrect close delimiter: `}`
-  --> $DIR/unclosed_delim_mod.rs:5:1
+  --> $DIR/unclosed_delim_mod.rs:7:1
    |
 LL | pub fn new() -> Result<Value, ()> {
    |                                   - close delimiter possibly meant for this
diff --git a/src/test/ui/parser/unclosed_delim_mod.rs b/src/test/ui/parser/unclosed_delim_mod.rs
index b1664f4..486e233 100644
--- a/src/test/ui/parser/unclosed_delim_mod.rs
+++ b/src/test/ui/parser/unclosed_delim_mod.rs
@@ -1,3 +1,5 @@
+fn main() {}
+
 pub struct Value {}
 pub fn new() -> Result<Value, ()> {
     Ok(Value {
diff --git a/src/test/ui/parser/unclosed_delim_mod.stderr b/src/test/ui/parser/unclosed_delim_mod.stderr
index cc04eb5..fe2d968 100644
--- a/src/test/ui/parser/unclosed_delim_mod.stderr
+++ b/src/test/ui/parser/unclosed_delim_mod.stderr
@@ -1,5 +1,5 @@
 error: incorrect close delimiter: `}`
-  --> $DIR/unclosed_delim_mod.rs:5:1
+  --> $DIR/unclosed_delim_mod.rs:7:1
    |
 LL | pub fn new() -> Result<Value, ()> {
    |                                   - close delimiter possibly meant for this
@@ -9,10 +9,5 @@
 LL | }
    | ^ incorrect close delimiter
 
-error[E0601]: `main` function not found in crate `unclosed_delim_mod`
-   |
-   = note: consider adding a `main` function to `$DIR/unclosed_delim_mod.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/proc-macro/derive-still-gated.rs b/src/test/ui/proc-macro/derive-still-gated.rs
index 4e6f9b0..3f8d6f0 100644
--- a/src/test/ui/proc-macro/derive-still-gated.rs
+++ b/src/test/ui/proc-macro/derive-still-gated.rs
@@ -3,7 +3,7 @@
 #[macro_use]
 extern crate test_macros;
 
-#[derive_Empty] //~ ERROR cannot find attribute macro `derive_Empty` in this scope
+#[derive_Empty] //~ ERROR cannot find attribute `derive_Empty` in this scope
 struct A;
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr
index 4df1715..99289fd 100644
--- a/src/test/ui/proc-macro/derive-still-gated.stderr
+++ b/src/test/ui/proc-macro/derive-still-gated.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `derive_Empty` in this scope
+error: cannot find attribute `derive_Empty` in this scope
   --> $DIR/derive-still-gated.rs:6:3
    |
 LL | #[derive_Empty]
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
index c9881ad..94a4b40 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
index 40333a3..107f5fb 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-1.rs:10:1
+  --> $DIR/invalid-punct-ident-1.rs:15:1
    |
 LL | invalid_punct!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
index 15e2286..778b7ee 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
index ec97e26..f1b9ecc 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-2.rs:10:1
+  --> $DIR/invalid-punct-ident-2.rs:15:1
    |
 LL | invalid_ident!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
index 629bbaa..f68ee3d 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
index a5e5ded..6044b98 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-3.rs:10:1
+  --> $DIR/invalid-punct-ident-3.rs:15:1
    |
 LL | invalid_raw_ident!();
    | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
index 8a26df9..b17c056 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
@@ -25,17 +25,17 @@
     my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
 }
 fn check_bang2() {
-    my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope
+    my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr` in this scope
     crate::my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines
                              //~| ERROR expected macro, found attribute macro `crate::my_macro_attr`
 }
 fn check_bang3() {
-    MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope
+    MyTrait!(); //~ ERROR cannot find macro `MyTrait` in this scope
     crate::MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
                        //~| ERROR expected macro, found derive macro `crate::MyTrait`
 }
 
-#[my_macro] //~ ERROR cannot find attribute macro `my_macro` in this scope
+#[my_macro] //~ ERROR cannot find attribute `my_macro` in this scope
 #[crate::my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
                    //~| ERROR expected attribute, found macro `crate::my_macro`
 fn check_attr1() {}
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
index 0c863e9..c011a70 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
@@ -88,19 +88,19 @@
 LL | #[derive(crate::my_macro)]
    |          ^^^^^^^^^^^^^^^ not a derive macro
 
-error: cannot find macro `my_macro_attr!` in this scope
+error: cannot find macro `my_macro_attr` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:28:5
    |
 LL |     my_macro_attr!();
    |     ^^^^^^^^^^^^^
 
-error: cannot find macro `MyTrait!` in this scope
+error: cannot find macro `MyTrait` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:33:5
    |
 LL |     MyTrait!();
    |     ^^^^^^^
 
-error: cannot find attribute macro `my_macro` in this scope
+error: cannot find attribute `my_macro` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:38:3
    |
 LL | #[my_macro]
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.rs b/src/test/ui/proc-macro/proc-macro-attributes.rs
index 0421522..6401522 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.rs
+++ b/src/test/ui/proc-macro/proc-macro-attributes.rs
@@ -4,7 +4,7 @@
 extern crate derive_b;
 
 #[B] //~ ERROR `B` is ambiguous
-#[C] //~ ERROR cannot find attribute macro `C` in this scope
+#[C] //~ ERROR cannot find attribute `C` in this scope
 #[B(D)] //~ ERROR `B` is ambiguous
 #[B(E = "foo")] //~ ERROR `B` is ambiguous
 #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr
index b068c6b..3ac93a7 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.stderr
+++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `C` in this scope
+error: cannot find attribute `C` in this scope
   --> $DIR/proc-macro-attributes.rs:7:3
    |
 LL | #[C]
diff --git a/src/test/ui/proc-macro/resolve-error.rs b/src/test/ui/proc-macro/resolve-error.rs
index 088f39c..d2282af 100644
--- a/src/test/ui/proc-macro/resolve-error.rs
+++ b/src/test/ui/proc-macro/resolve-error.rs
@@ -24,11 +24,11 @@
 struct Foo;
 
 // Interpreted as an unstable custom attribute
-#[attr_proc_macra] //~ ERROR cannot find attribute macro `attr_proc_macra` in this scope
+#[attr_proc_macra] //~ ERROR cannot find attribute `attr_proc_macra` in this scope
 struct Bar;
 
 // Interpreted as an unstable custom attribute
-#[FooWithLongNan] //~ ERROR cannot find attribute macro `FooWithLongNan` in this scope
+#[FooWithLongNan] //~ ERROR cannot find attribute `FooWithLongNan` in this scope
 struct Asdf;
 
 #[derive(Dlone)]
diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr
index 2a5f2b8..3dca5ce 100644
--- a/src/test/ui/proc-macro/resolve-error.stderr
+++ b/src/test/ui/proc-macro/resolve-error.stderr
@@ -1,22 +1,22 @@
-error: cannot find macro `bang_proc_macrp!` in this scope
+error: cannot find macro `bang_proc_macrp` in this scope
   --> $DIR/resolve-error.rs:56:5
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro`
 
-error: cannot find macro `Dlona!` in this scope
+error: cannot find macro `Dlona` in this scope
   --> $DIR/resolve-error.rs:53:5
    |
 LL |     Dlona!();
    |     ^^^^^
 
-error: cannot find macro `attr_proc_macra!` in this scope
+error: cannot find macro `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:50:5
    |
 LL |     attr_proc_macra!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac`
 
-error: cannot find macro `FooWithLongNama!` in this scope
+error: cannot find macro `FooWithLongNama` in this scope
   --> $DIR/resolve-error.rs:47:5
    |
 LL |     FooWithLongNama!();
@@ -40,13 +40,13 @@
 LL | #[derive(Dlone)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
 
-error: cannot find attribute macro `FooWithLongNan` in this scope
+error: cannot find attribute `FooWithLongNan` in this scope
   --> $DIR/resolve-error.rs:31:3
    |
 LL | #[FooWithLongNan]
    |   ^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `attr_proc_macra` in this scope
+error: cannot find attribute `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:27:3
    |
 LL | #[attr_proc_macra]
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.rs b/src/test/ui/reserved/reserved-attr-on-macro.rs
index fddb991..2630db0 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.rs
+++ b/src/test/ui/reserved/reserved-attr-on-macro.rs
@@ -1,5 +1,5 @@
 #[rustc_attribute_should_be_reserved]
-//~^ ERROR cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
+//~^ ERROR cannot find attribute `rustc_attribute_should_be_reserved` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 macro_rules! foo {
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr
index 856162b..6859605 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.stderr
+++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr
@@ -15,7 +15,7 @@
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
+error: cannot find attribute `rustc_attribute_should_be_reserved` in this scope
   --> $DIR/reserved-attr-on-macro.rs:1:3
    |
 LL | #[rustc_attribute_should_be_reserved]
diff --git a/src/test/ui/resolve/visibility-indeterminate.rs b/src/test/ui/resolve/visibility-indeterminate.rs
index 595eaf4..0e1142d 100644
--- a/src/test/ui/resolve/visibility-indeterminate.rs
+++ b/src/test/ui/resolve/visibility-indeterminate.rs
@@ -1,5 +1,7 @@
 // edition:2018
 
-foo!(); //~ ERROR cannot find macro `foo!` in this scope
+foo!(); //~ ERROR cannot find macro `foo` in this scope
 
 pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility
+
+fn main() {}
diff --git a/src/test/ui/resolve/visibility-indeterminate.stderr b/src/test/ui/resolve/visibility-indeterminate.stderr
index a259c80..b967829 100644
--- a/src/test/ui/resolve/visibility-indeterminate.stderr
+++ b/src/test/ui/resolve/visibility-indeterminate.stderr
@@ -4,16 +4,11 @@
 LL | pub(in ::bar) struct Baz {}
    |        ^^^^^
 
-error: cannot find macro `foo!` in this scope
+error: cannot find macro `foo` in this scope
   --> $DIR/visibility-indeterminate.rs:3:1
    |
 LL | foo!();
    | ^^^
 
-error[E0601]: `main` function not found in crate `visibility_indeterminate`
-   |
-   = note: consider adding a `main` function to `$DIR/visibility-indeterminate.rs`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs b/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs
new file mode 100644
index 0000000..5b378fb
--- /dev/null
+++ b/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs
@@ -0,0 +1,135 @@
+// run-pass
+
+// This file checks that fn ptrs are considered structurally matchable.
+// See also rust-lang/rust#63479.
+
+fn main() {
+    let mut count = 0;
+
+    // A type which is not structurally matchable:
+    struct NotSM;
+
+    // And one that is:
+    #[derive(PartialEq, Eq)]
+    struct SM;
+
+    fn trivial() {}
+
+    fn sm_to(_: SM) {}
+    fn not_sm_to(_: NotSM) {}
+    fn to_sm() -> SM { SM }
+    fn to_not_sm() -> NotSM { NotSM }
+
+    // To recreate the scenario of interest in #63479, we need to add
+    // a ref-level-of-indirection so that we descend into the type.
+
+    fn r_sm_to(_: &SM) {}
+    fn r_not_sm_to(_: &NotSM) {}
+    fn r_to_r_sm(_: &()) -> &SM { &SM }
+    fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM }
+
+    #[derive(PartialEq, Eq)]
+    struct Wrap<T>(T);
+
+    // In the code below, we put the match input into a local so that
+    // we can assign it an explicit type that is an fn ptr instead of
+    // a singleton type of the fn itself that the type inference would
+    // otherwise assign.
+
+    // Check that fn() is #[structural_match]
+    const CFN1: Wrap<fn()> = Wrap(trivial);
+    let input: Wrap<fn()> = Wrap(trivial);
+    match Wrap(input) {
+        Wrap(CFN1) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] when T is too.
+    const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
+    let input: Wrap<fn(SM)> = Wrap(sm_to);
+    match Wrap(input) {
+        Wrap(CFN2) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] when T is too.
+    const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
+    let input: Wrap<fn() -> SM> = Wrap(to_sm);
+    match Wrap(input) {
+        Wrap(CFN3) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] even if T is not.
+    const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
+    let input: Wrap<fn(NotSM)> = Wrap(not_sm_to);
+    match Wrap(input) {
+        Wrap(CFN4) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] even if T is not.
+    const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
+    let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
+    match Wrap(input) {
+        Wrap(CFN5) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(&T) is #[structural_match] when T is too.
+    const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
+    let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
+    match Wrap(input) {
+        Wrap(CFN6) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> &T is #[structural_match] when T is too.
+    const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
+    let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
+    match Wrap(input) {
+        Wrap(CFN7) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] even if T is not.
+    const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
+    let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
+    match Wrap(input) {
+        Wrap(CFN8) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] even if T is not.
+    const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
+    let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
+    match Wrap(input) {
+        Wrap(CFN9) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that a type which has fn ptrs is `#[structural_match]`.
+    #[derive(PartialEq, Eq)]
+    struct Foo {
+        alpha: fn(NotSM),
+        beta: fn() -> NotSM,
+        gamma: fn(SM),
+        delta: fn() -> SM,
+    }
+
+    const CFOO: Foo = Foo {
+        alpha: not_sm_to,
+        beta: to_not_sm,
+        gamma: sm_to,
+        delta: to_sm,
+    };
+
+    let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm };
+    match input {
+        CFOO => count += 1,
+        Foo { .. } => {}
+    };
+
+    // Final count must be 10 now if all
+    assert_eq!(count, 10);
+}
diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs
new file mode 100644
index 0000000..b3c91ce
--- /dev/null
+++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+// The actual regression test from #63479. (Including this because my
+// first draft at fn-ptr-is-structurally-matchable.rs failed to actually
+// cover the case this hit; I've since expanded it accordingly, but the
+// experience left me wary of leaving this regression test out.)
+
+#[derive(Eq)]
+struct A {
+  a: i64
+}
+
+impl PartialEq for A {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.a.eq(&other.a)
+    }
+}
+
+type Fn = fn(&[A]);
+
+fn my_fn(_args: &[A]) {
+  println!("hello world");
+}
+
+const TEST: Fn = my_fn;
+
+struct B(Fn);
+
+fn main() {
+  let s = B(my_fn);
+  match s {
+    B(TEST) => println!("matched"),
+    _ => panic!("didn't match")
+  };
+}
diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs
index 844f13c..dfb7d65 100644
--- a/src/test/ui/self/self_type_keyword.rs
+++ b/src/test/ui/self/self_type_keyword.rs
@@ -19,7 +19,7 @@
         ref mut Self => (),
         //~^ ERROR expected identifier, found keyword `Self`
         Self!() => (),
-        //~^ ERROR cannot find macro `Self!` in this scope
+        //~^ ERROR cannot find macro `Self` in this scope
         Foo { Self } => (),
         //~^ ERROR expected identifier, found keyword `Self`
     }
diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr
index bb63119..11b3b01 100644
--- a/src/test/ui/self/self_type_keyword.stderr
+++ b/src/test/ui/self/self_type_keyword.stderr
@@ -54,7 +54,7 @@
 LL | struct Bar<'Self>;
    |            ^^^^^
 
-error: cannot find macro `Self!` in this scope
+error: cannot find macro `Self` in this scope
   --> $DIR/self_type_keyword.rs:21:9
    |
 LL |         Self!() => (),
diff --git a/src/test/ui/suggestions/attribute-typos.rs b/src/test/ui/suggestions/attribute-typos.rs
index 74f63f2..7c8231b 100644
--- a/src/test/ui/suggestions/attribute-typos.rs
+++ b/src/test/ui/suggestions/attribute-typos.rs
@@ -1,11 +1,11 @@
-#[deprcated] //~ ERROR cannot find attribute macro `deprcated` in this scope
+#[deprcated] //~ ERROR cannot find attribute `deprcated` in this scope
 fn foo() {}
 
-#[tests] //~ ERROR cannot find attribute macro `tests` in this scope
+#[tests] //~ ERROR cannot find attribute `tests` in this scope
 fn bar() {}
 
 #[rustc_err]
-//~^ ERROR cannot find attribute macro `rustc_err` in this scope
+//~^ ERROR cannot find attribute `rustc_err` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 fn main() {}
diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr
index 6b2f591..e403293 100644
--- a/src/test/ui/suggestions/attribute-typos.stderr
+++ b/src/test/ui/suggestions/attribute-typos.stderr
@@ -7,19 +7,19 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error: cannot find attribute macro `rustc_err` in this scope
+error: cannot find attribute `rustc_err` in this scope
   --> $DIR/attribute-typos.rs:7:3
    |
 LL | #[rustc_err]
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_error`
 
-error: cannot find attribute macro `tests` in this scope
+error: cannot find attribute `tests` in this scope
   --> $DIR/attribute-typos.rs:4:3
    |
 LL | #[tests]
    |   ^^^^^ help: an attribute macro with a similar name exists: `test`
 
-error: cannot find attribute macro `deprcated` in this scope
+error: cannot find attribute `deprcated` in this scope
   --> $DIR/attribute-typos.rs:1:3
    |
 LL | #[deprcated]
diff --git a/src/test/ui/syntax-extension-minor.rs b/src/test/ui/syntax-extension-minor.rs
index 0206a76..2d6710a 100644
--- a/src/test/ui/syntax-extension-minor.rs
+++ b/src/test/ui/syntax-extension-minor.rs
@@ -1,3 +1,5 @@
+// run-pass
+
 #![feature(concat_idents)]
 
 pub fn main() {
@@ -5,10 +7,8 @@
     let _: concat_idents!(F, oo) = Foo; // Test that `concat_idents!` can be used in type positions
 
     let asdf_fdsa = "<.<".to_string();
-    // this now fails (correctly, I claim) because hygiene prevents
-    // the assembled identifier from being a reference to the binding.
+    // concat_idents should have call-site hygiene.
     assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-    //~^ ERROR cannot find value `asdf_fdsa` in this scope
 
     assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
 }
diff --git a/src/test/ui/syntax-extension-minor.stderr b/src/test/ui/syntax-extension-minor.stderr
deleted file mode 100644
index 2d8056d..0000000
--- a/src/test/ui/syntax-extension-minor.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `asdf_fdsa` in this scope
-  --> $DIR/syntax-extension-minor.rs:10:13
-   |
-LL |     assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/tool-attributes/diagnostic_item.rs b/src/test/ui/tool-attributes/diagnostic_item.rs
index 1d35422..26a52ce 100644
--- a/src/test/ui/tool-attributes/diagnostic_item.rs
+++ b/src/test/ui/tool-attributes/diagnostic_item.rs
@@ -1,2 +1,3 @@
 #[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting
 struct Foomp;
+fn main() {}
diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr
index deff4da..5432f8d 100644
--- a/src/test/ui/tool-attributes/diagnostic_item.stderr
+++ b/src/test/ui/tool-attributes/diagnostic_item.stderr
@@ -7,11 +7,6 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0601]: `main` function not found in crate `diagnostic_item`
-   |
-   = note: consider adding a `main` function to `$DIR/diagnostic_item.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0601, E0658.
-For more information about an error, try `rustc --explain E0601`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
index c07da43..d5698be 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
@@ -5,13 +5,13 @@
 struct S;
 
 // Interpreted as an unstable custom attribute
-#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+#[rustfmt] //~ ERROR cannot find attribute `rustfmt` in this scope
 fn check() {}
 
 #[rustfmt::skip] // OK
 fn main() {
     rustfmt; //~ ERROR expected value, found tool module `rustfmt`
-    rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+    rustfmt!(); //~ ERROR cannot find macro `rustfmt` in this scope
 
     rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip`
 }
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
index 33581a1..6bef793 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
@@ -4,13 +4,13 @@
 LL | #[derive(rustfmt)]
    |          ^^^^^^^
 
-error: cannot find attribute macro `rustfmt` in this scope
+error: cannot find attribute `rustfmt` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:8:3
    |
 LL | #[rustfmt]
    |   ^^^^^^^
 
-error: cannot find macro `rustfmt!` in this scope
+error: cannot find macro `rustfmt` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:14:5
    |
 LL |     rustfmt!();
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs
index 91c4576..9e96b1c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs
@@ -24,3 +24,5 @@
             .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
     }
 }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
index ebb13fc..b838c06 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
@@ -1,7 +1,3 @@
-error[E0601]: `main` function not found in crate `issue_60564`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-60564.rs`
-
 error: type parameter `E` is part of concrete type but not used in parameter list for the `impl Trait` type alias
   --> $DIR/issue-60564.rs:20:49
    |
@@ -20,6 +16,5 @@
 LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/type/ascription/issue-34255-1.rs b/src/test/ui/type/ascription/issue-34255-1.rs
index c11a248..c21d9f3 100644
--- a/src/test/ui/type/ascription/issue-34255-1.rs
+++ b/src/test/ui/type/ascription/issue-34255-1.rs
@@ -13,3 +13,4 @@
 }
 
 // This case isn't currently being handled gracefully, including for completeness.
+fn main() {}
diff --git a/src/test/ui/type/ascription/issue-34255-1.stderr b/src/test/ui/type/ascription/issue-34255-1.stderr
index 531455b..195b393 100644
--- a/src/test/ui/type/ascription/issue-34255-1.stderr
+++ b/src/test/ui/type/ascription/issue-34255-1.stderr
@@ -14,17 +14,13 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
 
-error[E0601]: `main` function not found in crate `issue_34255_1`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-34255-1.rs`
-
 error[E0107]: wrong number of type arguments: expected 1, found 0
   --> $DIR/issue-34255-1.rs:7:22
    |
 LL |         input_cells: Vec::new()
    |                      ^^^^^^^^^^ expected 1 type argument
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0425, E0601.
+Some errors have detailed explanations: E0107, E0425.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/type/ascription/issue-54516.rs b/src/test/ui/type/ascription/issue-54516.rs
index 6d65760..b53bfe5 100644
--- a/src/test/ui/type/ascription/issue-54516.rs
+++ b/src/test/ui/type/ascription/issue-54516.rs
@@ -2,5 +2,5 @@
 
 fn main() {
     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
-    //~^ ERROR expected token: `,`
+    //~^ ERROR expected one of
 }
diff --git a/src/test/ui/type/ascription/issue-54516.stderr b/src/test/ui/type/ascription/issue-54516.stderr
index a846f3b..9794290 100644
--- a/src/test/ui/type/ascription/issue-54516.stderr
+++ b/src/test/ui/type/ascription/issue-54516.stderr
@@ -1,8 +1,8 @@
-error: expected token: `,`
+error: expected one of `!`, `,`, or `::`, found `(`
   --> $DIR/issue-54516.rs:4:58
    |
 LL |     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
-   |                            -                             ^ expected `,`
+   |                            -                             ^ expected one of `!`, `,`, or `::` here
    |                            |
    |                            help: maybe write a path separator here: `::`
    |
diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs
index 832aa3b..592b3f1 100644
--- a/src/tools/error_index_generator/build.rs
+++ b/src/tools/error_index_generator/build.rs
@@ -35,7 +35,7 @@
         ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
             $(
                 {long_codes.extend([
-                    (stringify!($ecode), Some(stringify!($message))),
+                    (stringify!($ecode), Some($message)),
                 ].iter());}
             )*
             $(
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index 4ce4112..d068e1c 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -14,12 +14,6 @@
 # For documentation about what this is and why in the world these dependencies
 # are appearing, see `README.md`.
 
-[build-dependencies]
-# Currently Cargo/RLS depend on `failure` which depends on `synstructure` which
-# enables this feature. Clippy, however, does not depend on anything that
-# enables this feature. Enable it unconditionally.
-syn = { version = "0.15", features = ['extra-traits'] }
-
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
 features = [
@@ -65,14 +59,10 @@
 [dependencies]
 curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
 crossbeam-utils = { version = "0.6.5", features = ["nightly"] }
-parking_lot = { version = "0.7", features = ['nightly'] }
-rand = { version = "0.6.1", features = ["i128_support"] }
 serde = { version = "1.0.82", features = ['derive'] }
 serde_json = { version = "1.0.31", features = ["raw_value"] }
 smallvec = { version = "0.6", features = ['union', 'may_dangle'] }
-scopeguard = { version = "0.3.3", features = ["use_std", "default"] }
 byteorder = { version = "1.2.7", features = ["i128"] }
-syn = { version = "0.15.35", features = ["extra-traits", "full"] }
 
 
 [target.'cfg(not(windows))'.dependencies]