diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index ef151750af9bf..98a765e1cec95 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -12,6 +12,9 @@ ci_dir="`dirname $docker_dir`"
 src_dir="`dirname $ci_dir`"
 root_dir="`dirname $src_dir`"
 
+objdir=$root_dir/obj
+dist=$objdir/build/dist
+
 source "$ci_dir/shared.sh"
 
 travis_fold start build_docker
@@ -77,6 +80,11 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       else
         echo "Looks like docker image is the same as before, not uploading"
       fi
+      # Record the container image for reuse, e.g. by rustup.rs builds
+      info="$dist/image-$image.txt"
+      mkdir -p "$dist"
+      echo "$url" >"$info"
+      echo "$digest" >>"$info"
     fi
 elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
     if [ -n "$TRAVIS_OS_NAME" ]; then
@@ -99,8 +107,6 @@ fi
 travis_fold end build_docker
 travis_time_finish
 
-objdir=$root_dir/obj
-
 mkdir -p $HOME/.cargo
 mkdir -p $objdir/tmp
 mkdir -p $objdir/cores
diff --git a/src/doc/unstable-book/src/language-features/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md
index f787f629756f3..a770ab65c26f8 100644
--- a/src/doc/unstable-book/src/language-features/on-unimplemented.md
+++ b/src/doc/unstable-book/src/language-features/on-unimplemented.md
@@ -138,3 +138,16 @@ error[E0277]: `&str` is not an iterator
   = help: the trait `std::iter::Iterator` is not implemented for `&str`
   = note: required by `std::iter::IntoIterator::into_iter`
 ```
+
+If you need to filter on multiple attributes, you can use `all`, `any` or
+`not` in the following way:
+
+```rust,compile_fail
+#[rustc_on_unimplemented(
+    on(
+        all(_Self="&str", T="std::string::String"),
+        note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
+    )
+)]
+pub trait From<T>: Sized { /* ... */ }
+```
diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs
index 66d619b1298b4..581c66c7086a5 100644
--- a/src/liballoc/collections/btree/node.rs
+++ b/src/liballoc/collections/btree/node.rs
@@ -109,7 +109,7 @@ impl<K, V> LeafNode<K, V> {
             keys: uninitialized_array![_; CAPACITY],
             vals: uninitialized_array![_; CAPACITY],
             parent: ptr::null(),
-            parent_idx: MaybeUninit::uninitialized(),
+            parent_idx: MaybeUninit::uninit(),
             len: 0
         }
     }
@@ -129,7 +129,7 @@ unsafe impl Sync for NodeHeader<(), ()> {}
 // ever take a pointer past the first key.
 static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader {
     parent: ptr::null(),
-    parent_idx: MaybeUninit::uninitialized(),
+    parent_idx: MaybeUninit::uninit(),
     len: 0,
     keys_start: [],
 };
@@ -261,7 +261,7 @@ impl<K, V> Root<K, V> {
             -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
         debug_assert!(!self.is_shared_root());
         let mut new_node = Box::new(unsafe { InternalNode::new() });
-        new_node.edges[0].set(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) });
+        new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) });
 
         self.node = BoxedNode::from_internal(new_node);
         self.height += 1;
@@ -737,7 +737,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
         unsafe {
             ptr::write(self.keys_mut().get_unchecked_mut(idx), key);
             ptr::write(self.vals_mut().get_unchecked_mut(idx), val);
-            self.as_internal_mut().edges.get_unchecked_mut(idx + 1).set(edge.node);
+            self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node);
 
             (*self.as_leaf_mut()).len += 1;
 
@@ -1080,7 +1080,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
         let mut child = self.descend();
         unsafe {
             (*child.as_leaf_mut()).parent = ptr;
-            (*child.as_leaf_mut()).parent_idx.set(idx);
+            (*child.as_leaf_mut()).parent_idx.write(idx);
         }
     }
 
diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs
new file mode 100644
index 0000000000000..635537e312158
--- /dev/null
+++ b/src/libcore/benches/ascii.rs
@@ -0,0 +1,349 @@
+// Lower-case ASCII 'a' is the first byte that has its highest bit set
+// after wrap-adding 0x1F:
+//
+//     b'a' + 0x1F == 0x80 == 0b1000_0000
+//     b'z' + 0x1F == 0x98 == 0b10011000
+//
+// Lower-case ASCII 'z' is the last byte that has its highest bit unset
+// after wrap-adding 0x05:
+//
+//     b'a' + 0x05 == 0x66 == 0b0110_0110
+//     b'z' + 0x05 == 0x7F == 0b0111_1111
+//
+// … except for 0xFB to 0xFF, but those are in the range of bytes
+// that have the highest bit unset again after adding 0x1F.
+//
+// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set
+// iff `byte` is a lower-case ASCII letter.
+//
+// Lower-case ASCII letters all have the 0x20 bit set.
+// (Two positions right of 0x80, the highest bit.)
+// Unsetting that bit produces the same letter, in upper-case.
+//
+// Therefore:
+fn branchless_to_ascii_upper_case(byte: u8) -> u8 {
+    byte &
+    !(
+        (
+            byte.wrapping_add(0x1f) &
+            !byte.wrapping_add(0x05) &
+            0x80
+        ) >> 2
+    )
+}
+
+
+macro_rules! benches {
+    ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => {
+        benches! {@
+            $( fn $name($arg: &mut [u8]) $body )+
+            $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+
+        }
+    };
+
+    (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => {
+        benches!(mod short SHORT $($name $arg $body)+);
+        benches!(mod medium MEDIUM $($name $arg $body)+);
+        benches!(mod long LONG $($name $arg $body)+);
+    };
+
+    (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => {
+        mod $mod_name {
+            use super::*;
+
+            $(
+                #[bench]
+                fn $name(bencher: &mut Bencher) {
+                    bencher.bytes = $input.len() as u64;
+                    bencher.iter(|| {
+                        let mut vec = $input.as_bytes().to_vec();
+                        {
+                            let $arg = &mut vec[..];
+                            black_box($body);
+                        }
+                        vec
+                    })
+                }
+            )+
+        }
+    }
+}
+
+use test::black_box;
+use test::Bencher;
+
+benches! {
+    fn case00_alloc_only(_bytes: &mut [u8]) {}
+
+    fn case01_black_box_read_each_byte(bytes: &mut [u8]) {
+        for byte in bytes {
+            black_box(*byte);
+        }
+    }
+
+    fn case02_lookup_table(bytes: &mut [u8]) {
+        for byte in bytes {
+            *byte = ASCII_UPPERCASE_MAP[*byte as usize]
+        }
+    }
+
+    fn case03_branch_and_subtract(bytes: &mut [u8]) {
+        for byte in bytes {
+            *byte = if b'a' <= *byte && *byte <= b'z' {
+                *byte - b'a' + b'A'
+            } else {
+                *byte
+            }
+        }
+    }
+
+    fn case04_branch_and_mask(bytes: &mut [u8]) {
+        for byte in bytes {
+            *byte = if b'a' <= *byte && *byte <= b'z' {
+                *byte & !0x20
+            } else {
+                *byte
+            }
+        }
+    }
+
+    fn case05_branchless(bytes: &mut [u8]) {
+        for byte in bytes {
+            *byte = branchless_to_ascii_upper_case(*byte)
+        }
+    }
+
+    fn case06_libcore(bytes: &mut [u8]) {
+        bytes.make_ascii_uppercase()
+    }
+
+    fn case07_fake_simd_u32(bytes: &mut [u8]) {
+        let (before, aligned, after) = unsafe {
+            bytes.align_to_mut::<u32>()
+        };
+        for byte in before {
+            *byte = branchless_to_ascii_upper_case(*byte)
+        }
+        for word in aligned {
+            // FIXME: this is incorrect for some byte values:
+            // addition within a byte can carry/overflow into the next byte.
+            // Test case: b"\xFFz  "
+            *word &= !(
+                (
+                    word.wrapping_add(0x1f1f1f1f) &
+                    !word.wrapping_add(0x05050505) &
+                    0x80808080
+                ) >> 2
+            )
+        }
+        for byte in after {
+            *byte = branchless_to_ascii_upper_case(*byte)
+        }
+    }
+
+    fn case08_fake_simd_u64(bytes: &mut [u8]) {
+        let (before, aligned, after) = unsafe {
+            bytes.align_to_mut::<u64>()
+        };
+        for byte in before {
+            *byte = branchless_to_ascii_upper_case(*byte)
+        }
+        for word in aligned {
+            // FIXME: like above, this is incorrect for some byte values.
+            *word &= !(
+                (
+                    word.wrapping_add(0x1f1f1f1f_1f1f1f1f) &
+                    !word.wrapping_add(0x05050505_05050505) &
+                    0x80808080_80808080
+                ) >> 2
+            )
+        }
+        for byte in after {
+            *byte = branchless_to_ascii_upper_case(*byte)
+        }
+    }
+
+    fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            if b >= 0x80 { return false }
+            match ASCII_CHARACTER_CLASS[b as usize] {
+                L | Lx => true,
+                _ => false,
+            }
+        }
+        for byte in bytes {
+            *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+        }
+    }
+
+    fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            match ASCII_CHARACTER_CLASS[b as usize] {
+                L | Lx => true,
+                _ => false
+            }
+        }
+        for byte in bytes {
+            *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+        }
+    }
+
+    fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            match b {
+                b'a'...b'z' => true,
+                _ => false
+            }
+        }
+        for byte in bytes {
+            *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+        }
+    }
+
+    fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            match b {
+                b'a'...b'z' => true,
+                _ => false
+            }
+        }
+        for byte in bytes {
+            *byte &= !((is_ascii_lowercase(*byte) as u8) << 5)
+        }
+    }
+
+    fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            match b {
+                b'a'...b'z' => true,
+                _ => false
+            }
+        }
+        for byte in bytes {
+            *byte -= (is_ascii_lowercase(*byte) as u8) << 5
+        }
+    }
+
+    fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) {
+        fn is_ascii_lowercase(b: u8) -> bool {
+            match b {
+                b'a'...b'z' => true,
+                _ => false
+            }
+        }
+        for byte in bytes {
+            *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8
+        }
+    }
+
+    @iter
+
+    is_ascii,
+    is_ascii_alphabetic,
+    is_ascii_uppercase,
+    is_ascii_lowercase,
+    is_ascii_alphanumeric,
+    is_ascii_digit,
+    is_ascii_hexdigit,
+    is_ascii_punctuation,
+    is_ascii_graphic,
+    is_ascii_whitespace,
+    is_ascii_control,
+}
+
+macro_rules! repeat {
+    ($s: expr) => { concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) }
+}
+
+const SHORT: &'static str = "Alice's";
+const MEDIUM: &'static str = "Alice's Adventures in Wonderland";
+const LONG: &'static str = repeat!(r#"
+    La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850)
+    Alice's Adventures in Wonderland (1865)
+    Phantasmagoria and Other Poems (1869)
+    Through the Looking-Glass, and What Alice Found There
+        (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871)
+    The Hunting of the Snark (1876)
+    Rhyme? And Reason? (1883) – shares some contents with the 1869 collection,
+        including the long poem "Phantasmagoria"
+    A Tangled Tale (1885)
+    Sylvie and Bruno (1889)
+    Sylvie and Bruno Concluded (1893)
+    Pillow Problems (1893)
+    What the Tortoise Said to Achilles (1895)
+    Three Sunsets and Other Poems (1898)
+    The Manlet (1903)[106]
+"#);
+
+const ASCII_UPPERCASE_MAP: [u8; 256] = [
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
+    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
+    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
+    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
+    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
+    b'`',
+
+          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+    b'X', b'Y', b'Z',
+
+                      b'{', b'|', b'}', b'~', 0x7f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+enum AsciiCharacterClass {
+    C,  // control
+    Cw, // control whitespace
+    W,  // whitespace
+    D,  // digit
+    L,  // lowercase
+    Lx, // lowercase hex digit
+    U,  // uppercase
+    Ux, // uppercase hex digit
+    P,  // punctuation
+    N,  // Non-ASCII
+}
+use self::AsciiCharacterClass::*;
+
+static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [
+//  _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
+    C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
+    C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
+    W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
+    D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
+    P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
+    U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
+    P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
+    L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+    N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+];
diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs
index 48572af611a5b..707cdd5f450ea 100644
--- a/src/libcore/benches/lib.rs
+++ b/src/libcore/benches/lib.rs
@@ -5,6 +5,7 @@ extern crate core;
 extern crate test;
 
 mod any;
+mod ascii;
 mod char;
 mod hash;
 mod iter;
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index cee4fc6f49a71..a6c65e890a5ed 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -363,6 +363,12 @@ pub trait Into<T>: Sized {
 /// [`from`]: trait.From.html#tymethod.from
 /// [book]: ../../book/ch09-00-error-handling.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented(
+    on(
+        all(_Self="&str", T="std::string::String"),
+        note="to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
+    )
+)]
 pub trait From<T>: Sized {
     /// Performs the conversion.
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
index edeb65afd67b2..5f4c6f7b0a3f0 100644
--- a/src/libcore/fmt/float.rs
+++ b/src/libcore/fmt/float.rs
@@ -10,8 +10,8 @@ fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
     where T: flt2dec::DecodableFloat
 {
     unsafe {
-        let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
-        let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
+        let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
+        let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninit();
         // FIXME(#53491): Technically, this is calling `get_mut` on an uninitialized
         // `MaybeUninit` (here and elsewhere in this file).  Revisit this once
         // we decided whether that is valid or not.
@@ -32,8 +32,8 @@ fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, num: &T,
 {
     unsafe {
         // enough for f32 and f64
-        let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
-        let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
+        let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
+        let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninit();
         // FIXME(#53491)
         let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num,
                                                  sign, precision, false, buf.get_mut(),
@@ -71,8 +71,8 @@ fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
     where T: flt2dec::DecodableFloat
 {
     unsafe {
-        let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
-        let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
+        let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
+        let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninit();
         // FIXME(#53491)
         let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
                                                   *num, sign, precision,
@@ -91,8 +91,8 @@ fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
 {
     unsafe {
         // enough for f32 and f64
-        let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
-        let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
+        let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
+        let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninit();
         // FIXME(#53491)
         let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest,
                                                      *num, sign, (0, 0), upper,
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index b9fa364037108..e96dbcaa14416 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -60,7 +60,7 @@ trait GenericRadix {
             for byte in buf.iter_mut().rev() {
                 let n = x % base;               // Get the current place value.
                 x = x / base;                   // Deaccumulate the number.
-                byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer.
+                byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer.
                 curr -= 1;
                 if x == zero {
                     // No more digits left to accumulate.
@@ -72,7 +72,7 @@ trait GenericRadix {
             for byte in buf.iter_mut().rev() {
                 let n = zero - (x % base);      // Get the current place value.
                 x = x / base;                   // Deaccumulate the number.
-                byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer.
+                byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer.
                 curr -= 1;
                 if x == zero {
                     // No more digits left to accumulate.
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index d77936c7ddd91..ad8ce1af1f6a1 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -626,12 +626,12 @@ macro_rules! todo {
 #[macro_export]
 #[unstable(feature = "maybe_uninit_array", issue = "53491")]
 macro_rules! uninitialized_array {
-    // This `into_initialized` is safe because an array of `MaybeUninit` does not
+    // This `assume_init` is safe because an array of `MaybeUninit` does not
     // require initialization.
     // FIXME(#49147): Could be replaced by an array initializer, once those can
     // be any const expression.
     ($t:ty; $size:expr) => (unsafe {
-        MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized()
+        MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init()
     });
 }
 
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 3d2fcdc979377..66bcf1f7d0101 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -622,7 +622,7 @@ pub unsafe fn zeroed<T>() -> T {
 /// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
 /// [`Drop`]: ../ops/trait.Drop.html
 #[inline]
-#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")]
+#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn uninitialized<T>() -> T {
     intrinsics::panic_if_uninhabited::<T>();
@@ -1058,7 +1058,7 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 ///
 /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
 /// // The equivalent code with `MaybeUninit<&i32>`:
-/// let x: &i32 = unsafe { MaybeUninit::zeroed().into_initialized() }; // undefined behavior!
+/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior!
 /// ```
 ///
 /// This is exploited by the compiler for various optimizations, such as eliding
@@ -1073,7 +1073,7 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 ///
 /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
 /// // The equivalent code with `MaybeUninit<bool>`:
-/// let b: bool = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior!
+/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
 /// ```
 ///
 /// Moreover, uninitialized memory is special in that the compiler knows that
@@ -1087,7 +1087,7 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 ///
 /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
 /// // The equivalent code with `MaybeUninit<i32>`:
-/// let x: i32 = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior!
+/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
 /// ```
 /// (Notice that the rules around uninitialized integers are not finalized yet, but
 /// until they are, it is advisable to avoid them.)
@@ -1102,12 +1102,12 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 ///
 /// // Create an explicitly uninitialized reference. The compiler knows that data inside
 /// // a `MaybeUninit<T>` may be invalid, and hence this is not UB:
-/// let mut x = MaybeUninit::<&i32>::uninitialized();
+/// let mut x = MaybeUninit::<&i32>::uninit();
 /// // Set it to a valid value.
-/// x.set(&0);
+/// x.write(&0);
 /// // Extract the initialized data -- this is only allowed *after* properly
 /// // initializing `x`!
-/// let x = unsafe { x.into_initialized() };
+/// let x = unsafe { x.assume_init() };
 /// ```
 ///
 /// The compiler then knows to not make any incorrect assumptions or optimizations on this code.
@@ -1148,10 +1148,19 @@ impl<T> MaybeUninit<T> {
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
-    pub const fn uninitialized() -> MaybeUninit<T> {
+    pub const fn uninit() -> MaybeUninit<T> {
         MaybeUninit { uninit: () }
     }
 
+    /// Deprecated before stabilization.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    // FIXME: still used by stdsimd
+    // #[rustc_deprecated(since = "1.35.0", reason = "use `uninit` instead")]
+    pub const fn uninitialized() -> MaybeUninit<T> {
+        Self::uninit()
+    }
+
     /// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being
     /// filled with `0` bytes. It depends on `T` whether that already makes for
     /// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized,
@@ -1171,7 +1180,7 @@ impl<T> MaybeUninit<T> {
     /// use std::mem::MaybeUninit;
     ///
     /// let x = MaybeUninit::<(u8, bool)>::zeroed();
-    /// let x = unsafe { x.into_initialized() };
+    /// let x = unsafe { x.assume_init() };
     /// assert_eq!(x, (0, false));
     /// ```
     ///
@@ -1185,14 +1194,14 @@ impl<T> MaybeUninit<T> {
     /// enum NotZero { One = 1, Two = 2 };
     ///
     /// let x = MaybeUninit::<(u8, NotZero)>::zeroed();
-    /// let x = unsafe { x.into_initialized() };
+    /// let x = unsafe { x.assume_init() };
     /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
     /// // This is undefined behavior.
     /// ```
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline]
     pub fn zeroed() -> MaybeUninit<T> {
-        let mut u = MaybeUninit::<T>::uninitialized();
+        let mut u = MaybeUninit::<T>::uninit();
         unsafe {
             u.as_mut_ptr().write_bytes(0u8, 1);
         }
@@ -1205,13 +1214,21 @@ impl<T> MaybeUninit<T> {
     /// reference to the (now safely initialized) contents of `self`.
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
-    pub fn set(&mut self, val: T) -> &mut T {
+    pub fn write(&mut self, val: T) -> &mut T {
         unsafe {
             self.value = ManuallyDrop::new(val);
             self.get_mut()
         }
     }
 
+    /// Deprecated before stabilization.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    #[rustc_deprecated(since = "1.35.0", reason = "use `write` instead")]
+    pub fn set(&mut self, val: T) -> &mut T {
+        self.write(val)
+    }
+
     /// Gets a pointer to the contained value. Reading from this pointer or turning it
     /// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
     ///
@@ -1223,7 +1240,7 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<Vec<u32>>::uninitialized();
+    /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
     /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); }
     /// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it.
     /// let x_vec = unsafe { &*x.as_ptr() };
@@ -1236,7 +1253,7 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let x = MaybeUninit::<Vec<u32>>::uninitialized();
+    /// let x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_vec = unsafe { &*x.as_ptr() };
     /// // We have created a reference to an uninitialized vector! This is undefined behavior.
     /// ```
@@ -1260,7 +1277,7 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<Vec<u32>>::uninitialized();
+    /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
     /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); }
     /// // Create a reference into the `MaybeUninit<Vec<u32>>`.
     /// // This is okay because we initialized it.
@@ -1275,7 +1292,7 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<Vec<u32>>::uninitialized();
+    /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_vec = unsafe { &mut *x.as_mut_ptr() };
     /// // We have created a reference to an uninitialized vector! This is undefined behavior.
     /// ```
@@ -1306,9 +1323,9 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<bool>::uninitialized();
+    /// let mut x = MaybeUninit::<bool>::uninit();
     /// unsafe { x.as_mut_ptr().write(true); }
-    /// let x_init = unsafe { x.into_initialized() };
+    /// let x_init = unsafe { x.assume_init() };
     /// assert_eq!(x_init, true);
     /// ```
     ///
@@ -1318,21 +1335,30 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let x = MaybeUninit::<Vec<u32>>::uninitialized();
-    /// let x_init = unsafe { x.into_initialized() };
+    /// let x = MaybeUninit::<Vec<u32>>::uninit();
+    /// let x_init = unsafe { x.assume_init() };
     /// // `x` had not been initialized yet, so this last line caused undefined behavior.
     /// ```
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
-    pub unsafe fn into_initialized(self) -> T {
+    pub unsafe fn assume_init(self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
         ManuallyDrop::into_inner(self.value)
     }
 
+    /// Deprecated before stabilization.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    // FIXME: still used by stdsimd
+    // #[rustc_deprecated(since = "1.35.0", reason = "use `assume_init` instead")]
+    pub unsafe fn into_initialized(self) -> T {
+        self.assume_init()
+    }
+
     /// Reads the value from the `MaybeUninit<T>` container. The resulting `T` is subject
     /// to the usual drop handling.
     ///
-    /// Whenever possible, it is preferrable to use [`into_initialized`] instead, which
+    /// Whenever possible, it is preferrable to use [`assume_init`] instead, which
     /// prevents duplicating the content of the `MaybeUninit<T>`.
     ///
     /// # Safety
@@ -1342,11 +1368,11 @@ impl<T> MaybeUninit<T> {
     /// behavior.
     ///
     /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
-    /// multiple copies of the data (by calling `read_initialized` multiple times, or first
-    /// calling `read_initialized` and then [`into_initialized`]), it is your responsibility
+    /// multiple copies of the data (by calling `read` multiple times, or first
+    /// calling `read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
-    /// [`into_initialized`]: #method.into_initialized
+    /// [`assume_init`]: #method.assume_init
     ///
     /// # Examples
     ///
@@ -1356,18 +1382,18 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<u32>::uninitialized();
-    /// x.set(13);
-    /// let x1 = unsafe { x.read_initialized() };
+    /// let mut x = MaybeUninit::<u32>::uninit();
+    /// x.write(13);
+    /// let x1 = unsafe { x.read() };
     /// // `u32` is `Copy`, so we may read multiple times.
-    /// let x2 = unsafe { x.read_initialized() };
+    /// let x2 = unsafe { x.read() };
     /// assert_eq!(x1, x2);
     ///
-    /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninitialized();
-    /// x.set(None);
-    /// let x1 = unsafe { x.read_initialized() };
+    /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
+    /// x.write(None);
+    /// let x1 = unsafe { x.read() };
     /// // Duplicating a `None` value is okay, so we may read multiple times.
-    /// let x2 = unsafe { x.read_initialized() };
+    /// let x2 = unsafe { x.read() };
     /// assert_eq!(x1, x2);
     /// ```
     ///
@@ -1377,20 +1403,28 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
-    /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninitialized();
-    /// x.set(Some(vec![0,1,2]));
-    /// let x1 = unsafe { x.read_initialized() };
-    /// let x2 = unsafe { x.read_initialized() };
+    /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
+    /// x.write(Some(vec![0,1,2]));
+    /// let x1 = unsafe { x.read() };
+    /// let x2 = unsafe { x.read() };
     /// // We now created two copies of the same vector, leading to a double-free when
     /// // they both get dropped!
     /// ```
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
-    pub unsafe fn read_initialized(&self) -> T {
+    pub unsafe fn read(&self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
         self.as_ptr().read()
     }
 
+    /// Deprecated before stabilization.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    #[rustc_deprecated(since = "1.35.0", reason = "use `read` instead")]
+    pub unsafe fn read_initialized(&self) -> T {
+        self.read()
+    }
+
     /// Gets a reference to the contained value.
     ///
     /// # Safety
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index d93cfbc2a28ac..3fcae6b94b06d 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -3794,7 +3794,8 @@ impl u8 {
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> u8 {
-        ASCII_UPPERCASE_MAP[*self as usize]
+        // Unset the fith bit if this is a lowercase letter
+        *self & !((self.is_ascii_lowercase() as u8) << 5)
     }
 
     /// Makes a copy of the value in its ASCII lower case equivalent.
@@ -3816,7 +3817,8 @@ impl u8 {
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> u8 {
-        ASCII_LOWERCASE_MAP[*self as usize]
+        // Set the fith bit if this is an uppercase letter
+        *self | ((self.is_ascii_uppercase() as u8) << 5)
     }
 
     /// Checks that two values are an ASCII case-insensitive match.
@@ -3918,9 +3920,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_alphabetic(&self) -> bool {
-        if *self >= 0x80 { return false; }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            L | Lx | U | Ux => true,
+        match *self {
+            b'A'...b'Z' | b'a'...b'z' => true,
             _ => false
         }
     }
@@ -3954,9 +3955,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_uppercase(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            U | Ux => true,
+        match *self {
+            b'A'...b'Z' => true,
             _ => false
         }
     }
@@ -3990,9 +3990,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_lowercase(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            L | Lx => true,
+        match *self {
+            b'a'...b'z' => true,
             _ => false
         }
     }
@@ -4029,9 +4028,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_alphanumeric(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            D | L | Lx | U | Ux => true,
+        match *self {
+            b'0'...b'9' | b'A'...b'Z' | b'a'...b'z' => true,
             _ => false
         }
     }
@@ -4065,9 +4063,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_digit(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            D => true,
+        match *self {
+            b'0'...b'9' => true,
             _ => false
         }
     }
@@ -4104,9 +4101,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_hexdigit(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            D | Lx | Ux => true,
+        match *self {
+            b'0'...b'9' | b'A'...b'F' | b'a'...b'f' => true,
             _ => false
         }
     }
@@ -4144,9 +4140,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_punctuation(&self) -> bool {
-        if *self >= 0x80 { return false }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            P => true,
+        match *self {
+            b'!'...b'/' | b':'...b'@' | b'['...b'`' | b'{'...b'~' => true,
             _ => false
         }
     }
@@ -4180,9 +4175,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_graphic(&self) -> bool {
-        if *self >= 0x80 { return false; }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            Ux | U | Lx | L | D | P => true,
+        match *self {
+            b'!'...b'~' => true,
             _ => false
         }
     }
@@ -4233,9 +4227,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_whitespace(&self) -> bool {
-        if *self >= 0x80 { return false; }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            Cw | W => true,
+        match *self {
+            b'\t' | b'\n' | b'\x0C' | b'\r' | b' ' => true,
             _ => false
         }
     }
@@ -4271,9 +4264,8 @@ impl u8 {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_control(&self) -> bool {
-        if *self >= 0x80 { return false; }
-        match ASCII_CHARACTER_CLASS[*self as usize] {
-            C | Cw => true,
+        match *self {
+            b'\0'...b'\x1F' | b'\x7F' => true,
             _ => false
         }
     }
@@ -4939,106 +4931,3 @@ impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
 
 // Float -> Float
 impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-
-static ASCII_LOWERCASE_MAP: [u8; 256] = [
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
-    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
-    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
-    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
-    b'@',
-
-          b'a', b'b', b'c', b'd', b'e', b'f', b'g',
-    b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
-    b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
-    b'x', b'y', b'z',
-
-                      b'[', b'\\', b']', b'^', b'_',
-    b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
-    b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
-    b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
-    b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
-    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
-    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
-    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
-    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
-    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
-    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
-    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
-    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
-    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
-
-static ASCII_UPPERCASE_MAP: [u8; 256] = [
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
-    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
-    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
-    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
-    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
-    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
-    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
-    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
-    b'`',
-
-          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
-    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
-    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
-    b'X', b'Y', b'Z',
-
-                      b'{', b'|', b'}', b'~', 0x7f,
-    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
-    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
-    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
-    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
-    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
-    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
-    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
-    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
-    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
-
-enum AsciiCharacterClass {
-    C,  // control
-    Cw, // control whitespace
-    W,  // whitespace
-    D,  // digit
-    L,  // lowercase
-    Lx, // lowercase hex digit
-    U,  // uppercase
-    Ux, // uppercase hex digit
-    P,  // punctuation
-}
-use self::AsciiCharacterClass::*;
-
-static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [
-//  _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
-    C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
-    C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
-    W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
-    D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
-    P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
-    U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
-    P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
-    L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
-];
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 1897caa5aa53f..dabf914fdb2cd 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -296,7 +296,7 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
 pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
     // Give ourselves some scratch space to work with.
     // We do not have to worry about drops: `MaybeUninit` does nothing when dropped.
-    let mut tmp = MaybeUninit::<T>::uninitialized();
+    let mut tmp = MaybeUninit::<T>::uninit();
 
     // Perform the swap
     copy_nonoverlapping(x, tmp.as_mut_ptr(), 1);
@@ -388,7 +388,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
     while i + block_size <= len {
         // Create some uninitialized memory as scratch space
         // Declaring `t` here avoids aligning the stack when this loop is unused
-        let mut t = mem::MaybeUninit::<Block>::uninitialized();
+        let mut t = mem::MaybeUninit::<Block>::uninit();
         let t = t.as_mut_ptr() as *mut u8;
         let x = x.add(i);
         let y = y.add(i);
@@ -403,7 +403,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
 
     if i < len {
         // Swap any remaining bytes
-        let mut t = mem::MaybeUninit::<UnalignedBlock>::uninitialized();
+        let mut t = mem::MaybeUninit::<UnalignedBlock>::uninit();
         let rem = len - i;
 
         let t = t.as_mut_ptr() as *mut u8;
@@ -571,9 +571,9 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn read<T>(src: *const T) -> T {
-    let mut tmp = MaybeUninit::<T>::uninitialized();
+    let mut tmp = MaybeUninit::<T>::uninit();
     copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-    tmp.into_initialized()
+    tmp.assume_init()
 }
 
 /// Reads the value from `src` without moving it. This leaves the
@@ -638,11 +638,11 @@ pub unsafe fn read<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn read_unaligned<T>(src: *const T) -> T {
-    let mut tmp = MaybeUninit::<T>::uninitialized();
+    let mut tmp = MaybeUninit::<T>::uninit();
     copy_nonoverlapping(src as *const u8,
                         tmp.as_mut_ptr() as *mut u8,
                         mem::size_of::<T>());
-    tmp.into_initialized()
+    tmp.assume_init()
 }
 
 /// Overwrites a memory location with the given value without reading or
@@ -2495,11 +2495,57 @@ impl<T: ?Sized> Eq for *mut T {}
 /// let other_five_ref = &other_five;
 ///
 /// assert!(five_ref == same_five_ref);
-/// assert!(five_ref == other_five_ref);
-///
 /// assert!(ptr::eq(five_ref, same_five_ref));
+///
+/// assert!(five_ref == other_five_ref);
 /// assert!(!ptr::eq(five_ref, other_five_ref));
 /// ```
+///
+/// Slices are also compared by their length (fat pointers):
+///
+/// ```
+/// let a = [1, 2, 3];
+/// assert!(std::ptr::eq(&a[..3], &a[..3]));
+/// assert!(!std::ptr::eq(&a[..2], &a[..3]));
+/// assert!(!std::ptr::eq(&a[0..2], &a[1..3]));
+/// ```
+///
+/// Traits are also compared by their implementation:
+///
+/// ```
+/// #[repr(transparent)]
+/// struct Wrapper { member: i32 }
+///
+/// trait Trait {}
+/// impl Trait for Wrapper {}
+/// impl Trait for i32 {}
+///
+/// fn main() {
+///     let wrapper = Wrapper { member: 10 };
+///
+///     // Pointers have equal addresses.
+///     assert!(std::ptr::eq(
+///         &wrapper as *const Wrapper as *const u8,
+///         &wrapper.member as *const i32 as *const u8
+///     ));
+///
+///     // Objects have equal addresses, but `Trait` has different implementations.
+///     assert!(!std::ptr::eq(
+///         &wrapper as &dyn Trait,
+///         &wrapper.member as &dyn Trait,
+///     ));
+///     assert!(!std::ptr::eq(
+///         &wrapper as &dyn Trait as *const dyn Trait,
+///         &wrapper.member as &dyn Trait as *const dyn Trait,
+///     ));
+///
+///     // Converting the reference to a `*const u8` compares by address.
+///     assert!(std::ptr::eq(
+///         &wrapper as &dyn Trait as *const dyn Trait as *const u8,
+///         &wrapper.member as &dyn Trait as *const dyn Trait as *const u8,
+///     ));
+/// }
+/// ```
 #[stable(feature = "ptr_eq", since = "1.17.0")]
 #[inline]
 pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs
index 9b35b51349a02..8f10c3576a787 100644
--- a/src/libcore/slice/rotate.rs
+++ b/src/libcore/slice/rotate.rs
@@ -72,7 +72,7 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
         }
     }
 
-    let mut rawarray = MaybeUninit::<RawArray<T>>::uninitialized();
+    let mut rawarray = MaybeUninit::<RawArray<T>>::uninit();
     let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T;
 
     let dim = mid.sub(left).add(right);
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 528281d317be3..f54d7badc3ae0 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -3601,7 +3601,11 @@ impl str {
     /// assert!(Some('ע') == s.trim_left().chars().next());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")]
+    #[rustc_deprecated(
+        since = "1.33.0",
+        reason = "superseded by `trim_start`",
+        suggestion = "trim_start",
+    )]
     pub fn trim_left(&self) -> &str {
         self.trim_start()
     }
@@ -3638,7 +3642,11 @@ impl str {
     /// assert!(Some('ת') == s.trim_right().chars().rev().next());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")]
+    #[rustc_deprecated(
+        since = "1.33.0",
+        reason = "superseded by `trim_end`",
+        suggestion = "trim_end",
+    )]
     pub fn trim_right(&self) -> &str {
         self.trim_end()
     }
@@ -3802,7 +3810,11 @@ impl str {
     /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")]
+    #[rustc_deprecated(
+        since = "1.33.0",
+        reason = "superseded by `trim_start_matches`",
+        suggestion = "trim_start_matches",
+    )]
     pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
         self.trim_start_matches(pat)
     }
@@ -3840,7 +3852,11 @@ impl str {
     /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")]
+    #[rustc_deprecated(
+        since = "1.33.0",
+        reason = "superseded by `trim_end_matches`",
+        suggestion = "trim_end_matches",
+    )]
     pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: ReverseSearcher<'a>
     {
diff --git a/src/libcore/tests/tuple.rs b/src/libcore/tests/tuple.rs
index a4c171eb4243b..c7ed1612dd5ea 100644
--- a/src/libcore/tests/tuple.rs
+++ b/src/libcore/tests/tuple.rs
@@ -1,4 +1,5 @@
 use std::cmp::Ordering::{Equal, Less, Greater};
+use std::f64::NAN;
 
 #[test]
 fn test_clone() {
@@ -8,18 +9,18 @@ fn test_clone() {
 }
 
 #[test]
-fn test_tuple_cmp() {
+fn test_partial_eq() {
     let (small, big) = ((1, 2, 3), (3, 2, 1));
-
-    let nan = 0.0f64/0.0;
-
-    // PartialEq
     assert_eq!(small, small);
     assert_eq!(big, big);
-    assert!(small != big);
-    assert!(big != small);
+    assert_ne!(small, big);
+    assert_ne!(big, small);
+}
+
+#[test]
+fn test_partial_ord() {
+    let (small, big) = ((1, 2, 3), (3, 2, 1));
 
-    // PartialOrd
     assert!(small < big);
     assert!(!(small < small));
     assert!(!(big < small));
@@ -33,18 +34,21 @@ fn test_tuple_cmp() {
     assert!(big >= small);
     assert!(big >= big);
 
-    assert!(!((1.0f64, 2.0f64) < (nan, 3.0)));
-    assert!(!((1.0f64, 2.0f64) <= (nan, 3.0)));
-    assert!(!((1.0f64, 2.0f64) > (nan, 3.0)));
-    assert!(!((1.0f64, 2.0f64) >= (nan, 3.0)));
-    assert!(((1.0f64, 2.0f64) < (2.0, nan)));
-    assert!(!((2.0f64, 2.0f64) < (2.0, nan)));
-
-    // Ord
-    assert!(small.cmp(&small) == Equal);
-    assert!(big.cmp(&big) == Equal);
-    assert!(small.cmp(&big) == Less);
-    assert!(big.cmp(&small) == Greater);
+    assert!(!((1.0f64, 2.0f64) < (NAN, 3.0)));
+    assert!(!((1.0f64, 2.0f64) <= (NAN, 3.0)));
+    assert!(!((1.0f64, 2.0f64) > (NAN, 3.0)));
+    assert!(!((1.0f64, 2.0f64) >= (NAN, 3.0)));
+    assert!(((1.0f64, 2.0f64) < (2.0, NAN)));
+    assert!(!((2.0f64, 2.0f64) < (2.0, NAN)));
+}
+
+#[test]
+fn test_ord() {
+    let (small, big) = ((1, 2, 3), (3, 2, 1));
+    assert_eq!(small.cmp(&small), Equal);
+    assert_eq!(big.cmp(&big), Equal);
+    assert_eq!(small.cmp(&big), Less);
+    assert_eq!(big.cmp(&small), Greater);
 }
 
 #[test]
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 4babadb67bce6..9c6d03af9f51b 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -469,6 +469,7 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
     [] UnsafetyCheckResult(DefId),
     [] UnsafeDeriveOnReprPacked(DefId),
 
+    [] LintMod(DefId),
     [] CheckModAttrs(DefId),
     [] CheckModLoops(DefId),
     [] CheckModUnstableApiUsage(DefId),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d810a9310c55f..2ffb4959951b8 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -580,17 +580,17 @@ impl<'hir> Map<'hir> {
         &self.forest.krate.attrs
     }
 
-    pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, NodeId)
-    {
+    pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, HirId) {
         let node_id = self.as_local_node_id(module).unwrap();
+        let hir_id = self.node_to_hir_id(node_id);
         self.read(node_id);
         match self.find_entry(node_id).unwrap().node {
             Node::Item(&Item {
                 span,
                 node: ItemKind::Mod(ref m),
                 ..
-            }) => (m, span, node_id),
-            Node::Crate => (&self.forest.krate.module, self.forest.krate.span, node_id),
+            }) => (m, span, hir_id),
+            Node::Crate => (&self.forest.krate.module, self.forest.krate.span, hir_id),
             _ => panic!("not a module")
         }
     }
@@ -1013,7 +1013,7 @@ impl<'hir> Map<'hir> {
     /// corresponding to the Node ID
     pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] {
         self.read(id); // reveals attributes on the node
-        let attrs = match self.find(id) {
+        let attrs = match self.find_entry(id).map(|entry| entry.node) {
             Some(Node::Local(l)) => Some(&l.attrs[..]),
             Some(Node::Item(i)) => Some(&i.attrs[..]),
             Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
@@ -1027,6 +1027,7 @@ impl<'hir> Map<'hir> {
             // Unit/tuple structs/variants take the attributes straight from
             // the struct/variant definition.
             Some(Node::Ctor(..)) => return self.attrs(self.get_parent(id)),
+            Some(Node::Crate) => Some(&self.forest.krate.attrs[..]),
             _ => None
         };
         attrs.unwrap_or(&[])
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 94f1d9c271007..953d0116aa2ba 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -27,6 +27,7 @@ use crate::rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use crate::session::{config, early_error, Session};
 use crate::ty::{self, TyCtxt, Ty};
 use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
+use crate::ty::query::Providers;
 use crate::util::nodemap::FxHashMap;
 use crate::util::common::time;
 
@@ -36,8 +37,9 @@ use syntax::edition;
 use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}};
 use errors::DiagnosticBuilder;
 use crate::hir;
-use crate::hir::def_id::LOCAL_CRATE;
+use crate::hir::def_id::{DefId, LOCAL_CRATE};
 use crate::hir::intravisit as hir_visit;
+use crate::hir::intravisit::Visitor;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::visit as ast_visit;
 
@@ -55,6 +57,7 @@ pub struct LintStore {
     pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
     early_passes: Option<Vec<EarlyLintPassObject>>,
     late_passes: Option<Vec<LateLintPassObject>>,
+    late_module_passes: Option<Vec<LateLintPassObject>>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
@@ -150,6 +153,7 @@ impl LintStore {
             pre_expansion_passes: Some(vec![]),
             early_passes: Some(vec![]),
             late_passes: Some(vec![]),
+            late_module_passes: Some(vec![]),
             by_name: Default::default(),
             future_incompatible: Default::default(),
             lint_groups: Default::default(),
@@ -199,9 +203,14 @@ impl LintStore {
     pub fn register_late_pass(&mut self,
                               sess: Option<&Session>,
                               from_plugin: bool,
+                              per_module: bool,
                               pass: LateLintPassObject) {
         self.push_pass(sess, from_plugin, &pass);
-        self.late_passes.as_mut().unwrap().push(pass);
+        if per_module {
+            self.late_module_passes.as_mut().unwrap().push(pass);
+        } else {
+            self.late_passes.as_mut().unwrap().push(pass);
+        }
     }
 
     // Helper method for register_early/late_pass
@@ -508,6 +517,7 @@ pub struct LateContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     /// Side-tables for the body we are in.
+    // FIXME: Make this lazy to avoid running the TypeckTables query?
     pub tables: &'a ty::TypeckTables<'tcx>,
 
     /// Parameter environment for the item we are in.
@@ -523,6 +533,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
 
     /// Generic type parameters in scope for the item we are in.
     pub generics: Option<&'tcx hir::Generics>,
+
+    /// We are only looking at one module
+    only_module: bool,
 }
 
 /// Context for lint checking of the AST, after expansion, before lowering to
@@ -803,6 +816,12 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
     pub fn current_lint_root(&self) -> hir::HirId {
         self.last_node_with_lint_attrs
     }
+
+    fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
+        run_lints!(self, check_mod, m, s, n);
+        hir_visit::walk_mod(self, m, n);
+        run_lints!(self, check_mod_post, m, s, n);
+    }
 }
 
 impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
@@ -934,9 +953,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     }
 
     fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
-        run_lints!(self, check_mod, m, s, n);
-        hir_visit::walk_mod(self, m, n);
-        run_lints!(self, check_mod_post, m, s, n);
+        if !self.only_module {
+            self.process_mod(m, s, n);
+        }
     }
 
     fn visit_local(&mut self, l: &'tcx hir::Local) {
@@ -1203,11 +1222,48 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 }
 
+pub fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
+    let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
-/// Performs lint checking on a crate.
-///
-/// Consumes the `lint_store` field of the `Session`.
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let store = &tcx.sess.lint_store;
+    let passes = store.borrow_mut().late_module_passes.take();
+
+    let mut cx = LateContext {
+        tcx,
+        tables: &ty::TypeckTables::empty(None),
+        param_env: ty::ParamEnv::empty(),
+        access_levels,
+        lint_sess: LintSession {
+            lints: store.borrow(),
+            passes,
+        },
+        last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
+        generics: None,
+        only_module: true,
+    };
+
+    let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
+    cx.process_mod(module, span, hir_id);
+
+    // Visit the crate attributes
+    if hir_id == hir::CRATE_HIR_ID {
+        walk_list!(cx, visit_attribute, cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID));
+    }
+
+    // Put the lint store levels and passes back in the session.
+    let passes = cx.lint_sess.passes;
+    drop(cx.lint_sess.lints);
+    store.borrow_mut().late_module_passes = passes;
+}
+
+pub(crate) fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        lint_mod,
+        ..*providers
+    };
+}
+
+fn lint_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
     let krate = tcx.hir().krate();
@@ -1225,6 +1281,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
             },
             last_node_with_lint_attrs: hir::CRATE_HIR_ID,
             generics: None,
+            only_module: false,
         };
 
         // Visit the whole crate.
@@ -1244,6 +1301,17 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.sess.lint_store.borrow_mut().late_passes = passes;
 }
 
+/// Performs lint checking on a crate.
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    // Run per-module lints
+    for &module in tcx.hir().krate().modules.keys() {
+        tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
+    }
+
+    // Run whole crate non-incremental lints
+    lint_crate(tcx);
+}
+
 struct EarlyLintPassObjects<'a> {
     lints: &'a mut [EarlyLintPassObject],
 }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index ae44210bcfffc..cf1c5d50000fa 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -824,6 +824,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
 
 pub fn provide(providers: &mut Providers<'_>) {
     providers.lint_levels = lint_levels;
+    context::provide(providers);
 }
 
 /// Returns whether `span` originates in a foreign crate's external macro.
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 9fb023156022a..0dd8316852780 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -344,7 +344,7 @@ impl<'tcx> AllocMap<'tcx> {
         }
     }
 
-    /// Returns `None` in case the `AllocId` is dangling. An `EvalContext` can still have a
+    /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
     /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
     /// illegal and will likely ICE.
     /// This function exists to allow const eval to detect the difference between evaluation-
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 85c2afd1159a1..9c705104d1888 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -217,6 +217,8 @@ rustc_query_append! { [define_queries!][ <'tcx>
     },
 
     Other {
+        [] fn lint_mod: LintMod(DefId) -> (),
+
         /// Checks the attributes in the module
         [] fn check_mod_attrs: CheckModAttrs(DefId) -> (),
 
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index adac19d3410b2..b2b141fd0f514 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1262,6 +1262,7 @@ pub fn force_from_dep_node<'tcx>(
         DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); }
         DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); }
         DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); }
+        DepKind::LintMod => { force!(lint_mod, def_id!()); }
         DepKind::CheckModAttrs => { force!(check_mod_attrs, def_id!()); }
         DepKind::CheckModLoops => { force!(check_mod_loops, def_id!()); }
         DepKind::CheckModUnstableApiUsage => { force!(check_mod_unstable_api_usage, def_id!()); }
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index a77e497af7b87..5432f80a1712c 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -2,6 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "rustc_driver"
 version = "0.0.0"
+edition = "2018"
 
 [lib]
 name = "rustc_driver"
@@ -13,14 +14,14 @@ arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
 env_logger = { version = "0.5", default-features = false }
-rustc-rayon = "0.1.2"
+rayon = { version = "0.1.2", package = "rustc-rayon" }
 scoped-tls = "1.0"
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_target = { path = "../librustc_target" }
 rustc_borrowck = { path = "../librustc_borrowck" }
 rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_errors = { path = "../librustc_errors" }
+errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_metadata = { path = "../librustc_metadata" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 25984616b878b..4b7cffaad5509 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -16,40 +16,13 @@
 
 #![recursion_limit="256"]
 
-extern crate arena;
+#![deny(rust_2018_idioms)]
+
 pub extern crate getopts;
-extern crate graphviz;
-extern crate env_logger;
 #[cfg(unix)]
 extern crate libc;
-extern crate rustc_rayon as rayon;
-extern crate rustc;
-extern crate rustc_allocator;
-extern crate rustc_target;
-extern crate rustc_borrowck;
-extern crate rustc_data_structures;
-extern crate rustc_errors as errors;
-extern crate rustc_passes;
-extern crate rustc_lint;
-extern crate rustc_plugin;
-extern crate rustc_privacy;
-extern crate rustc_incremental;
-extern crate rustc_metadata;
-extern crate rustc_mir;
-extern crate rustc_resolve;
-extern crate rustc_save_analysis;
-extern crate rustc_traits;
-extern crate rustc_codegen_utils;
-extern crate rustc_typeck;
-extern crate rustc_interface;
-extern crate scoped_tls;
-extern crate serialize;
-extern crate smallvec;
 #[macro_use]
 extern crate log;
-extern crate syntax;
-extern crate syntax_ext;
-extern crate syntax_pos;
 
 use pretty::{PpMode, UserIdentifiedItem};
 
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index ace5198deaf2e..5cefc35607db0 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -35,9 +35,9 @@ pub use self::UserIdentifiedItem::*;
 pub use self::PpSourceMode::*;
 pub use self::PpMode::*;
 use self::NodesMatchingUII::*;
-use abort_on_err;
+use crate::abort_on_err;
 
-use source_name;
+use crate::source_name;
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum PpSourceMode {
@@ -191,7 +191,7 @@ impl PpSourceMode {
         tcx: TyCtxt<'tcx, 'tcx, 'tcx>,
         f: F
     ) -> A
-        where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A
+        where F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A
     {
         match *self {
             PpmNormal => {
@@ -296,7 +296,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
 
 impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
 impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
-    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested)
               -> io::Result<()> {
         if let Some(tcx) = self.tcx {
             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
@@ -322,13 +322,13 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
 }
 
 impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
-    fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
+    fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
-    fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
+    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust::AnnNode::Ident(_) |
             pprust::AnnNode::Name(_) => Ok(()),
@@ -373,7 +373,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
 }
 
 impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
-    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested)
               -> io::Result<()> {
         if let Some(ref tcx) = self.tcx {
             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
@@ -381,13 +381,13 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
             Ok(())
         }
     }
-    fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
+    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust_hir::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
-    fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
+    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust_hir::AnnNode::Name(_) => Ok(()),
             pprust_hir::AnnNode::Item(item) => {
@@ -434,7 +434,7 @@ impl<'a> PrinterSupport for HygieneAnnotation<'a> {
 }
 
 impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
-    fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
+    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust::AnnNode::Ident(&ast::Ident { name, span }) => {
                 s.s.space()?;
@@ -476,7 +476,7 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
 }
 
 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
-    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested)
               -> io::Result<()> {
         let old_tables = self.tables.get();
         if let pprust_hir::Nested::Body(id) = nested {
@@ -486,13 +486,13 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
         self.tables.set(old_tables);
         Ok(())
     }
-    fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
+    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust_hir::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
-    fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
+    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> {
         match node {
             pprust_hir::AnnNode::Expr(expr) => {
                 s.s.space()?;
@@ -580,7 +580,11 @@ impl UserIdentifiedItem {
         }
     }
 
-    fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId {
+    fn to_one_node_id(self,
+                      user_option: &str,
+                      sess: &Session,
+                      map: &hir_map::Map<'_>)
+                      -> ast::NodeId {
         let fail_because = |is_wrong_because| -> ast::NodeId {
             let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
                                    {}, which {}",
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 7dcd5c94bf298..7f697b5448464 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -886,7 +886,10 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
 fn safe_remove_file(p: &Path) -> io::Result<()> {
     if p.exists() {
         let canonicalized = p.canonicalize()?;
-        std_fs::remove_file(canonicalized)
+        match std_fs::remove_file(canonicalized) {
+            Err(ref err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
+            result => result,
+        }
     } else {
         Ok(())
     }
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 294e23dc6177c..ec934ee48212c 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -2,6 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "rustc_interface"
 version = "0.0.0"
+edition = "2018"
 
 [lib]
 name = "rustc_interface"
@@ -10,7 +11,7 @@ crate-type = ["dylib"]
 
 [dependencies]
 log = "0.4"
-rustc-rayon = "0.1.1"
+rayon = { version = "0.1.1", package = "rustc-rayon" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 scoped-tls = "1.0"
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index ec6b26afb8c50..bec868be505b5 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -1,4 +1,8 @@
-use queries::Queries;
+use crate::queries::Queries;
+use crate::util;
+use crate::profile;
+pub use crate::passes::BoxedResolver;
+
 use rustc::lint;
 use rustc::session::config::{self, Input};
 use rustc::session::{DiagnosticOutput, Session};
@@ -15,10 +19,6 @@ use std::result;
 use std::sync::{Arc, Mutex};
 use syntax;
 use syntax::source_map::{FileLoader, SourceMap};
-use util;
-use profile;
-
-pub use passes::BoxedResolver;
 
 pub type Result<T> = result::Result<T, ErrorReported>;
 
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index 6a931c249b5bf..3314681b6981a 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -6,37 +6,14 @@
 #![feature(generators)]
 #![cfg_attr(unix, feature(libc))]
 
+#![deny(rust_2018_idioms)]
+
 #![allow(unused_imports)]
 
 #![recursion_limit="256"]
 
 #[cfg(unix)]
 extern crate libc;
-#[macro_use]
-extern crate log;
-extern crate rustc;
-extern crate rustc_codegen_utils;
-extern crate rustc_allocator;
-extern crate rustc_borrowck;
-extern crate rustc_incremental;
-extern crate rustc_traits;
-#[macro_use]
-extern crate rustc_data_structures;
-extern crate rustc_errors;
-extern crate rustc_lint;
-extern crate rustc_metadata;
-extern crate rustc_mir;
-extern crate rustc_passes;
-extern crate rustc_plugin;
-extern crate rustc_privacy;
-extern crate rustc_rayon as rayon;
-extern crate rustc_resolve;
-extern crate rustc_typeck;
-extern crate smallvec;
-extern crate serialize;
-extern crate syntax;
-extern crate syntax_pos;
-extern crate syntax_ext;
 
 pub mod interface;
 mod passes;
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index c199829b298c0..44ca11df694a9 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -1,7 +1,8 @@
-use interface::{Compiler, Result};
-use util;
-use proc_macro_decls;
+use crate::interface::{Compiler, Result};
+use crate::util;
+use crate::proc_macro_decls;
 
+use log::{debug, info, warn, log_enabled};
 use rustc::dep_graph::DepGraph;
 use rustc::hir;
 use rustc::hir::lowering::lower_crate;
@@ -20,6 +21,7 @@ use rustc::session::search_paths::PathKind;
 use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
@@ -328,7 +330,7 @@ pub fn register_plugins<'a>(
         ls.register_early_pass(Some(sess), true, false, pass);
     }
     for pass in late_lint_passes {
-        ls.register_late_pass(Some(sess), true, pass);
+        ls.register_late_pass(Some(sess), true, false, pass);
     }
 
     for (name, (to, deprecated_name)) in lint_groups {
@@ -758,7 +760,7 @@ pub fn prepare_outputs(
     Ok(outputs)
 }
 
-pub fn default_provide(providers: &mut ty::query::Providers) {
+pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
     plugin::build::provide(providers);
@@ -783,7 +785,7 @@ pub fn default_provide(providers: &mut ty::query::Providers) {
     lint::provide(providers);
 }
 
-pub fn default_provide_extern(providers: &mut ty::query::Providers) {
+pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
     cstore::provide_extern(providers);
 }
 
diff --git a/src/librustc_interface/profile/mod.rs b/src/librustc_interface/profile/mod.rs
index eb13a5668f927..d0c8dff207083 100644
--- a/src/librustc_interface/profile/mod.rs
+++ b/src/librustc_interface/profile/mod.rs
@@ -1,8 +1,9 @@
+use log::debug;
+use rustc::dep_graph::DepNode;
 use rustc::session::Session;
 use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan};
 use std::sync::mpsc::{Receiver};
 use std::io::{Write};
-use rustc::dep_graph::{DepNode};
 use std::time::{Duration, Instant};
 
 pub mod trace;
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 57ced0464d9fa..570509ffb2b8c 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -1,5 +1,6 @@
-use interface::{Compiler, Result};
-use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
+use crate::interface::{Compiler, Result};
+use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
+
 use rustc_incremental::DepGraphFuture;
 use rustc_data_structures::sync::Lrc;
 use rustc::session::config::{Input, OutputFilenames, OutputType};
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index b1ef4e315d98d..6e4f2bf24e32f 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -1,3 +1,4 @@
+use log::info;
 use rustc::session::config::{Input, OutputFilenames, ErrorOutputType};
 use rustc::session::{self, config, early_error, filesearch, Session, DiagnosticOutput};
 use rustc::session::CrateDisambiguator;
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 304e6eb712e3c..492ac1bf14dcc 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1360,6 +1360,7 @@ fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
         promoted: None
     };
     // trigger the query once for all constants since that will already report the errors
+    // FIXME: Use ensure here
     let _ = cx.tcx.const_eval(param_env.and(cid));
 }
 
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 73a32f6d2003a..4c624a267af9b 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -125,37 +125,72 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new());
     }
 
-    late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [
+    late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedModuleLateLintPass, [
         HardwiredLints: HardwiredLints,
         WhileTrue: WhileTrue,
         ImproperCTypes: ImproperCTypes,
         VariantSizeDifferences: VariantSizeDifferences,
         BoxPointers: BoxPointers,
-        UnusedAttributes: UnusedAttributes,
         PathStatements: PathStatements,
+
+        // Depends on referenced function signatures in expressions
         UnusedResults: UnusedResults,
-        NonSnakeCase: NonSnakeCase,
+
         NonUpperCaseGlobals: NonUpperCaseGlobals,
         NonShorthandFieldPatterns: NonShorthandFieldPatterns,
         UnusedAllocation: UnusedAllocation,
+
+        // Depends on types used in type definitions
         MissingCopyImplementations: MissingCopyImplementations,
-        UnstableFeatures: UnstableFeatures,
-        InvalidNoMangleItems: InvalidNoMangleItems,
+
         PluginAsLibrary: PluginAsLibrary,
+
+        // Depends on referenced function signatures in expressions
         MutableTransmutes: MutableTransmutes,
+
+        // Depends on types of fields, checks if they implement Drop
         UnionsWithDropFields: UnionsWithDropFields,
-        UnreachablePub: UnreachablePub,
-        UnnameableTestItems: UnnameableTestItems::new(),
+
         TypeAliasBounds: TypeAliasBounds,
-        UnusedBrokenConst: UnusedBrokenConst,
+
         TrivialConstraints: TrivialConstraints,
         TypeLimits: TypeLimits::new(),
+
+        NonSnakeCase: NonSnakeCase,
+        InvalidNoMangleItems: InvalidNoMangleItems,
+
+        // Depends on access levels
+        UnreachablePub: UnreachablePub,
+
+        ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
+    ]], ['tcx]);
+
+    store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new());
+
+    late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [
+        // FIXME: Look into regression when this is used as a module lint
+        // May Depend on constants elsewhere
+        UnusedBrokenConst: UnusedBrokenConst,
+
+        // Uses attr::is_used which is untracked, can't be an incremental module pass.
+        UnusedAttributes: UnusedAttributes,
+
+        // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
+        UnstableFeatures: UnstableFeatures,
+
+        // Tracks state across modules
+        UnnameableTestItems: UnnameableTestItems::new(),
+
+        // Tracks attributes of parents
         MissingDoc: MissingDoc::new(),
+
+        // Depends on access levels
+        // FIXME: Turn the computation of types which implement Debug into a query
+        // and change this to a module lint pass
         MissingDebugImplementations: MissingDebugImplementations::new(),
-        ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
     ]], ['tcx]);
 
-    store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new());
+    store.register_late_pass(sess, false, false, box BuiltinCombinedLateLintPass::new());
 
     add_lint_group!(sess,
                     "nonstandard_style",
diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs
index fa18dd1eb8ddb..7a164dbcdf12d 100644
--- a/src/librustc_lint/nonstandard_style.rs
+++ b/src/librustc_lint/nonstandard_style.rs
@@ -267,11 +267,15 @@ impl LintPass for NonSnakeCase {
 }
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
-    fn check_crate(&mut self, cx: &LateContext<'_, '_>, cr: &hir::Crate) {
+    fn check_mod(&mut self, cx: &LateContext<'_, '_>, _: &'tcx hir::Mod, _: Span, id: hir::HirId) {
+        if id != hir::CRATE_HIR_ID {
+            return;
+        }
+
         let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
             Some(Ident::from_str(name))
         } else {
-            attr::find_by_name(&cr.attrs, "crate_name")
+            attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), "crate_name")
                 .and_then(|attr| attr.meta())
                 .and_then(|meta| {
                     meta.name_value_literal().and_then(|lit| {
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 8c774e0d54cce..6ab89f80ef528 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -22,7 +22,7 @@ use syntax::source_map::{Span, DUMMY_SP};
 use crate::interpret::{self,
     PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
     RawConst, ConstValue,
-    EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
+    EvalResult, EvalError, EvalErrorKind, GlobalId, InterpretCx, StackPopCleanup,
     Allocation, AllocId, MemoryKind,
     snapshot, RefTracking,
 };
@@ -34,7 +34,7 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
 /// Should be a power of two for performance reasons.
 const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
 
-/// The `EvalContext` is only meant to be used to do field and index projections into constants for
+/// The `InterpretCx` is only meant to be used to do field and index projections into constants for
 /// `simd_shuffle` and const patterns in match arms.
 ///
 /// The function containing the `match` that is currently being analyzed may have generic bounds
@@ -47,7 +47,7 @@ pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
 ) -> CompileTimeEvalContext<'a, 'mir, 'tcx> {
     debug!("mk_eval_cx: {:?}", param_env);
-    EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new())
+    InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new())
 }
 
 pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
@@ -116,7 +116,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     // and try improving it down the road when more information is available
     let span = tcx.def_span(cid.instance.def_id());
     let span = mir.map(|mir| mir.span).unwrap_or(span);
-    let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
+    let mut ecx = InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
     let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
     (r, ecx)
 }
@@ -292,7 +292,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
 }
 
 type CompileTimeEvalContext<'a, 'mir, 'tcx> =
-    EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
+    InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
 
 impl interpret::MayLeak for ! {
     #[inline(always)]
@@ -317,12 +317,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     const STATIC_KIND: Option<!> = None; // no copying of statics allowed
 
     #[inline(always)]
-    fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
+    fn enforce_validity(_ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool {
         false // for now, we don't enforce validity
     }
 
     fn find_fn(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         dest: Option<PlaceTy<'tcx>>,
@@ -362,7 +362,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     }
 
     fn call_intrinsic(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         dest: PlaceTy<'tcx>,
@@ -378,7 +378,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     }
 
     fn ptr_op(
-        _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>,
         _bin_op: mir::BinOp,
         _left: ImmTy<'tcx>,
         _right: ImmTy<'tcx>,
@@ -406,7 +406,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     }
 
     fn box_alloc(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         _dest: PlaceTy<'tcx>,
     ) -> EvalResult<'tcx> {
         Err(
@@ -414,7 +414,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
         )
     }
 
-    fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
+    fn before_terminator(ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
         {
             let steps = &mut ecx.machine.steps_since_detector_enabled;
 
@@ -440,7 +440,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
 
     #[inline(always)]
     fn tag_new_allocation(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         ptr: Pointer,
         _kind: MemoryKind<Self::MemoryKinds>,
     ) -> Pointer {
@@ -449,7 +449,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
 
     #[inline(always)]
     fn stack_push(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
     ) -> EvalResult<'tcx> {
         Ok(())
     }
@@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     /// Called immediately before a stack frame gets popped.
     #[inline(always)]
     fn stack_pop(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         _extra: (),
     ) -> EvalResult<'tcx> {
         Ok(())
@@ -504,7 +504,7 @@ pub fn const_variant_index<'a, 'tcx>(
 }
 
 pub fn error_to_const_error<'a, 'mir, 'tcx>(
-    ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
+    ecx: &InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
     mut error: EvalError<'tcx>
 ) -> ConstEvalErr<'tcx> {
     error.print_backtrace();
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 7543dd678d032..003c2182d0b45 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -9,9 +9,9 @@ use rustc::mir::interpret::{
 use rustc::mir::CastKind;
 use rustc_apfloat::Float;
 
-use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate};
+use super::{InterpretCx, Machine, PlaceTy, OpTy, ImmTy, Immediate};
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
             ty::RawPtr(ty::TypeAndMut { ty, .. }) |
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index e81d0a56b2b05..8b7e28c3de077 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -26,7 +26,7 @@ use super::{
     Memory, Machine
 };
 
-pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
+pub struct InterpretCx<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
     /// Stores the `Machine` instance.
     pub machine: M,
 
@@ -141,7 +141,7 @@ impl<'tcx, Tag> LocalState<'tcx, Tag> {
 }
 
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout
-    for EvalContext<'a, 'mir, 'tcx, M>
+    for InterpretCx<'a, 'mir, 'tcx, M>
 {
     #[inline]
     fn data_layout(&self) -> &layout::TargetDataLayout {
@@ -149,7 +149,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout
     }
 }
 
-impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx, M>
+impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpretCx<'a, 'mir, 'tcx, M>
     where M: Machine<'a, 'mir, 'tcx>
 {
     #[inline]
@@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx,
 }
 
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
-    for EvalContext<'a, 'mir, 'tcx, M>
+    for InterpretCx<'a, 'mir, 'tcx, M>
 {
     type Ty = Ty<'tcx>;
     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
@@ -171,13 +171,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
     }
 }
 
-impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     pub fn new(
         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         machine: M,
     ) -> Self {
-        EvalContext {
+        InterpretCx {
             machine,
             tcx,
             param_env,
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index e002c3fd511d6..99dd654df21e3 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -11,7 +11,7 @@ use rustc::mir::interpret::{
 };
 
 use super::{
-    Machine, PlaceTy, OpTy, EvalContext,
+    Machine, PlaceTy, OpTy, InterpretCx,
 };
 
 
@@ -36,7 +36,7 @@ fn numeric_intrinsic<'tcx, Tag>(
     Ok(Scalar::from_uint(bits_out, size))
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// Returns `true` if emulation happened.
     pub fn emulate_intrinsic(
         &mut self,
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 7fb4c47d92acb..09d403ab243d6 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -11,7 +11,7 @@ use rustc::ty::{self, query::TyCtxtAt};
 
 use super::{
     Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
-    EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
+    InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
 };
 
 /// Whether this kind of memory is allowed to leak
@@ -95,11 +95,11 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     const STATIC_KIND: Option<Self::MemoryKinds>;
 
     /// Whether to enforce the validity invariant
-    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool;
+    fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool;
 
     /// Called before a basic block terminator is executed.
     /// You can use this to detect endlessly running programs.
-    fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;
+    fn before_terminator(ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;
 
     /// Entry point to all function calls.
     ///
@@ -112,7 +112,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
     /// was used.
     fn find_fn(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
@@ -122,7 +122,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// Directly process an intrinsic without pushing a stack frame.
     /// If this returns successfully, the engine will take care of jumping to the next block.
     fn call_intrinsic(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         dest: PlaceTy<'tcx, Self::PointerTag>,
@@ -156,7 +156,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     ///
     /// Returns a (value, overflowed) pair if the operation succeeded
     fn ptr_op(
-        ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
         left: ImmTy<'tcx, Self::PointerTag>,
         right: ImmTy<'tcx, Self::PointerTag>,
@@ -164,13 +164,13 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
 
     /// Heap allocations via the `box` keyword.
     fn box_alloc(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         dest: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx>;
 
     /// Adds the tag for a newly allocated pointer.
     fn tag_new_allocation(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         ptr: Pointer,
         kind: MemoryKind<Self::MemoryKinds>,
     ) -> Pointer<Self::PointerTag>;
@@ -180,7 +180,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// `mutability` can be `None` in case a raw ptr is being dereferenced.
     #[inline]
     fn tag_dereference(
-        _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>,
         place: MPlaceTy<'tcx, Self::PointerTag>,
         _mutability: Option<hir::Mutability>,
     ) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
@@ -190,7 +190,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// Executes a retagging operation
     #[inline]
     fn retag(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         _kind: mir::RetagKind,
         _place: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx> {
@@ -199,12 +199,12 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
 
     /// Called immediately before a new stack frame got pushed
     fn stack_push(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
     ) -> EvalResult<'tcx, Self::FrameExtra>;
 
     /// Called immediately after a stack frame gets popped
     fn stack_pop(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
         extra: Self::FrameExtra,
     ) -> EvalResult<'tcx>;
 }
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index d2ab3fcb7a30a..ea358389ddb76 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -18,7 +18,7 @@ mod visitor;
 pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
 pub use self::eval_context::{
-    EvalContext, Frame, StackPopCleanup, LocalState, LocalValue,
+    InterpretCx, Frame, StackPopCleanup, LocalState, LocalValue,
 };
 
 pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 70511075e87c9..15b6d5c914d20 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -13,7 +13,7 @@ use rustc::mir::interpret::{
     sign_extend, truncate,
 };
 use super::{
-    EvalContext, Machine,
+    InterpretCx, Machine,
     MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
 };
 pub use rustc::mir::interpret::ScalarMaybeUndef;
@@ -267,7 +267,7 @@ pub(super) fn from_known_layout<'tcx>(
     }
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// Try reading an immediate in memory; this is interesting particularly for ScalarPair.
     /// Returns `None` if the layout does not permit loading this as a value.
     fn try_read_immediate_from_mplace(
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 944e393d296fc..ca93007788e03 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -5,10 +5,10 @@ use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
 use rustc::mir::interpret::{EvalResult, Scalar};
 
-use super::{EvalContext, PlaceTy, Immediate, Machine, ImmTy};
+use super::{InterpretCx, PlaceTy, Immediate, Machine, ImmTy};
 
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// Applies the binary operation `op` to the two operands and writes a tuple of the result
     /// and a boolean signifying the potential overflow to the destination.
     pub fn binop_with_overflow(
@@ -37,7 +37,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     }
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     fn binary_char_op(
         &self,
         bin_op: mir::BinOp,
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index d2c279e48fe28..82b92acdb764c 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -14,7 +14,7 @@ use rustc::ty::TypeFoldable;
 
 use super::{
     GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
-    EvalContext, Machine, AllocMap, AllocationExtra,
+    InterpretCx, Machine, AllocMap, AllocationExtra,
     RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
 };
 
@@ -305,7 +305,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
 }
 
 // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
-impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
+impl<'a, 'mir, 'tcx, Tag, M> InterpretCx<'a, 'mir, 'tcx, M>
 where
     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
     Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
@@ -607,7 +607,7 @@ where
                 // global table but not in its local memory: It calls back into tcx through
                 // a query, triggering the CTFE machinery to actually turn this lazy reference
                 // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
-                // this EvalContext uses another Machine (e.g., in miri).  This is what we
+                // this InterpretCx uses another Machine (e.g., in miri).  This is what we
                 // want!  This way, computing statics works concistently between codegen
                 // and miri: They use the same query to eventually obtain a `ty::Const`
                 // and use that for further computation.
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 656c13c16d9ed..29a8547035e4a 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -1,4 +1,4 @@
-//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
+//! This module contains the `InterpretCx` methods for executing a single step of the interpreter.
 //!
 //! The main entry point is the `step` method.
 
@@ -6,7 +6,7 @@ use rustc::mir;
 use rustc::ty::layout::LayoutOf;
 use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic};
 
-use super::{EvalContext, Machine};
+use super::{InterpretCx, Machine};
 
 /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
 /// same type as the result.
@@ -35,7 +35,7 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     }
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     pub fn run(&mut self) -> EvalResult<'tcx> {
         while self.step()? {}
         Ok(())
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 83469d749870f..01965f53c157d 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -7,10 +7,10 @@ use rustc_target::spec::abi::Abi;
 
 use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
 use super::{
-    EvalContext, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
+    InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
 };
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     #[inline]
     pub fn goto_block(&mut self, target: Option<mir::BasicBlock>) -> EvalResult<'tcx> {
         if let Some(target) = target {
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 1b0a9b17d3686..cce6c95a31240 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -3,9 +3,9 @@ use rustc::ty::{self, Ty};
 use rustc::ty::layout::{Size, Align, LayoutOf};
 use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
 
-use super::{EvalContext, Machine, MemoryKind};
+use super::{InterpretCx, Machine, MemoryKind};
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
     /// objects.
     ///
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 252e8bac2a3f8..3323ec387bfd5 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -11,7 +11,7 @@ use rustc::mir::interpret::{
 };
 
 use super::{
-    OpTy, Machine, EvalContext, ValueVisitor, MPlaceTy,
+    OpTy, Machine, InterpretCx, ValueVisitor, MPlaceTy,
 };
 
 macro_rules! validation_failure {
@@ -153,7 +153,7 @@ struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a
     path: Vec<PathElem>,
     ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>>>,
     const_mode: bool,
-    ecx: &'rt EvalContext<'a, 'mir, 'tcx, M>,
+    ecx: &'rt InterpretCx<'a, 'mir, 'tcx, M>,
 }
 
 impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> {
@@ -224,7 +224,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
     type V = OpTy<'tcx, M::PointerTag>;
 
     #[inline(always)]
-    fn ecx(&self) -> &EvalContext<'a, 'mir, 'tcx, M> {
+    fn ecx(&self) -> &InterpretCx<'a, 'mir, 'tcx, M> {
         &self.ecx
     }
 
@@ -587,7 +587,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
     }
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
     /// This function checks the data at `op`. `op` is assumed to cover valid memory if it
     /// is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs
index e2abf2ffc849c..90d4fff421837 100644
--- a/src/librustc_mir/interpret/visitor.rs
+++ b/src/librustc_mir/interpret/visitor.rs
@@ -8,7 +8,7 @@ use rustc::mir::interpret::{
 };
 
 use super::{
-    Machine, EvalContext, MPlaceTy, OpTy,
+    Machine, InterpretCx, MPlaceTy, OpTy,
 };
 
 // A thing that we can project into, and that has a layout.
@@ -22,7 +22,7 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
     /// Makes this into an `OpTy`.
     fn to_op(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;
 
     /// Creates this from an `MPlaceTy`.
@@ -31,14 +31,14 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
     /// Projects to the given enum variant.
     fn project_downcast(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> EvalResult<'tcx, Self>;
 
     /// Projects to the n-th field.
     fn project_field(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         field: u64,
     ) -> EvalResult<'tcx, Self>;
 }
@@ -56,7 +56,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn to_op(
         self,
-        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        _ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         Ok(self)
     }
@@ -69,7 +69,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn project_downcast(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> EvalResult<'tcx, Self> {
         ecx.operand_downcast(self, variant)
@@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn project_field(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         field: u64,
     ) -> EvalResult<'tcx, Self> {
         ecx.operand_field(self, field)
@@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn to_op(
         self,
-        _ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        _ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         Ok(self.into())
     }
@@ -108,7 +108,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn project_downcast(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> EvalResult<'tcx, Self> {
         ecx.mplace_downcast(self, variant)
@@ -117,7 +117,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     #[inline(always)]
     fn project_field(
         self,
-        ecx: &EvalContext<'a, 'mir, 'tcx, M>,
+        ecx: &InterpretCx<'a, 'mir, 'tcx, M>,
         field: u64,
     ) -> EvalResult<'tcx, Self> {
         ecx.mplace_field(self, field)
@@ -130,9 +130,9 @@ macro_rules! make_value_visitor {
         pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
             type V: Value<'a, 'mir, 'tcx, M>;
 
-            /// The visitor must have an `EvalContext` in it.
+            /// The visitor must have an `InterpretCx` in it.
             fn ecx(&$($mutability)? self)
-                -> &$($mutability)? EvalContext<'a, 'mir, 'tcx, M>;
+                -> &$($mutability)? InterpretCx<'a, 'mir, 'tcx, M>;
 
             // Recursive actions, ready to be overloaded.
             /// Visits the given value, dispatching as appropriate to more specialized visitors.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 102d03d7baac4..b3ef7407a7c3d 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -18,7 +18,7 @@ use rustc::ty::layout::{
     HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
 
-use crate::interpret::{EvalContext, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
+use crate::interpret::{InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
 use crate::const_eval::{
     CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
 };
@@ -70,7 +70,7 @@ type Const<'tcx> = (OpTy<'tcx>, Span);
 
 /// Finds optimization opportunities on the MIR.
 struct ConstPropagator<'a, 'mir, 'tcx:'a+'mir> {
-    ecx: EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
+    ecx: InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
     mir: &'mir Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     source: MirSource<'tcx>,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index bbd03e82a3730..b532e5c94d531 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1790,8 +1790,7 @@ fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
         current_item: hir::DUMMY_HIR_ID,
         empty_tables: &empty_tables,
     };
-    let (module, span, node_id) = tcx.hir().get_module(module_def_id);
-    let hir_id = tcx.hir().node_to_hir_id(node_id);
+    let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
     intravisit::walk_mod(&mut visitor, module, hir_id);
 
     // Check privacy of explicitly written types and traits as well as
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 6f3cd56c7bf5b..ac8b639edbfa3 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1233,7 +1233,12 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
                     augment_error(&mut db);
                 }
 
-                db.emit();
+                if expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some() {
+                    // Error reported in `check_assign` so avoid emitting error again.
+                    db.delay_as_bug();
+                } else {
+                    db.emit();
+                }
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index b1a249d821bec..60fa266f0bbe1 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -119,44 +119,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
 
-        // If the expected type is an enum (Issue #55250) with any variants whose
-        // sole field is of the found type, suggest such variants. (Issue #42764)
-        if let ty::Adt(expected_adt, substs) = expected.sty {
-            if expected_adt.is_enum() {
-                let mut compatible_variants = expected_adt.variants
-                    .iter()
-                    .filter(|variant| variant.fields.len() == 1)
-                    .filter_map(|variant| {
-                        let sole_field = &variant.fields[0];
-                        let sole_field_ty = sole_field.ty(self.tcx, substs);
-                        if self.can_coerce(expr_ty, sole_field_ty) {
-                            let variant_path = self.tcx.def_path_str(variant.def_id);
-                            // FIXME #56861: DRYer prelude filtering
-                            Some(variant_path.trim_start_matches("std::prelude::v1::").to_string())
-                        } else {
-                            None
-                        }
-                    }).peekable();
-
-                if compatible_variants.peek().is_some() {
-                    let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
-                    let suggestions = compatible_variants
-                        .map(|v| format!("{}({})", v, expr_text));
-                    err.span_suggestions(
-                        expr.span,
-                        "try using a variant of the expected type",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
+        if self.is_assign_to_bool(expr, expected) {
+            // Error reported in `check_assign` so avoid emitting error again.
+            err.delay_as_bug();
+            return (expected, None)
         }
 
+        self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
         self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
 
         (expected, Some(err))
     }
 
+    /// Returns whether the expected type is `bool` and the expression is `x = y`.
+    pub fn is_assign_to_bool(&self, expr: &hir::Expr, expected: Ty<'tcx>) -> bool {
+        if let hir::ExprKind::Assign(..) = expr.node {
+            return expected == self.tcx.types.bool;
+        }
+        false
+    }
+
+    /// If the expected type is an enum (Issue #55250) with any variants whose
+    /// sole field is of the found type, suggest such variants. (Issue #42764)
+    fn suggest_compatible_variants(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr,
+        expected: Ty<'tcx>,
+        expr_ty: Ty<'tcx>,
+    ) {
+        if let ty::Adt(expected_adt, substs) = expected.sty {
+            if !expected_adt.is_enum() {
+                return;
+            }
+
+            let mut compatible_variants = expected_adt.variants
+                .iter()
+                .filter(|variant| variant.fields.len() == 1)
+                .filter_map(|variant| {
+                    let sole_field = &variant.fields[0];
+                    let sole_field_ty = sole_field.ty(self.tcx, substs);
+                    if self.can_coerce(expr_ty, sole_field_ty) {
+                        let variant_path = self.tcx.def_path_str(variant.def_id);
+                        // FIXME #56861: DRYer prelude filtering
+                        Some(variant_path.trim_start_matches("std::prelude::v1::").to_string())
+                    } else {
+                        None
+                    }
+                }).peekable();
+
+            if compatible_variants.peek().is_some() {
+                let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
+                let suggestions = compatible_variants
+                    .map(|v| format!("{}({})", v, expr_text));
+                let msg = "try using a variant of the expected type";
+                err.span_suggestions(expr.span, msg, suggestions, Applicability::MaybeIncorrect);
+            }
+        }
+    }
+
     pub fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>)
                               -> Vec<AssociatedItem> {
         let mut methods = self.probe_for_return_type(span,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ec4fc2a3bfb88..3d904d518ca8e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -246,9 +246,6 @@ pub enum Expectation<'tcx> {
     /// We know nothing about what type this expression should have.
     NoExpectation,
 
-    /// This expression is an `if` condition, it must resolve to `bool`.
-    ExpectIfCondition,
-
     /// This expression should have the type given (or some subtype).
     ExpectHasType(Ty<'tcx>),
 
@@ -328,7 +325,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
     fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> {
         match self {
             NoExpectation => NoExpectation,
-            ExpectIfCondition => ExpectIfCondition,
             ExpectCastableToType(t) => {
                 ExpectCastableToType(fcx.resolve_type_vars_if_possible(&t))
             }
@@ -344,7 +340,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
     fn to_option(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
         match self.resolve(fcx) {
             NoExpectation => None,
-            ExpectIfCondition => Some(fcx.tcx.types.bool),
             ExpectCastableToType(ty) |
             ExpectHasType(ty) |
             ExpectRvalueLikeUnsized(ty) => Some(ty),
@@ -358,7 +353,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
     fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
         match self.resolve(fcx) {
             ExpectHasType(ty) => Some(ty),
-            ExpectIfCondition => Some(fcx.tcx.types.bool),
             NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
         }
     }
@@ -3148,25 +3142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
-            // Add help to type error if this is an `if` condition with an assignment.
-            if let (ExpectIfCondition, &ExprKind::Assign(ref lhs, ref rhs))
-                 = (expected, &expr.node)
-            {
-                let msg = "try comparing for equality";
-                if let (Ok(left), Ok(right)) = (
-                    self.tcx.sess.source_map().span_to_snippet(lhs.span),
-                    self.tcx.sess.source_map().span_to_snippet(rhs.span))
-                {
-                    err.span_suggestion(
-                        expr.span,
-                        msg,
-                        format!("{} == {}", left, right),
-                        Applicability::MaybeIncorrect);
-                } else {
-                    err.help(msg);
-                }
+            if self.is_assign_to_bool(expr, expected_ty) {
+                // Error reported in `check_assign` so avoid emitting error again.
+                // FIXME(centril): Consider removing if/when `if` desugars to `match`.
+                err.delay_as_bug();
+            } else {
+                err.emit();
             }
-            err.emit();
         }
         ty
     }
@@ -3337,7 +3319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        opt_else_expr: Option<&'gcx hir::Expr>,
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let cond_ty = self.check_expr_meets_expectation_or_error(cond_expr, ExpectIfCondition);
+        let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool);
         let cond_diverges = self.diverges.get();
         self.diverges.set(Diverges::Maybe);
 
@@ -4422,34 +4404,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 tcx.types.never
             }
             ExprKind::Assign(ref lhs, ref rhs) => {
-                let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
-
-                let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
-
-                match expected {
-                    ExpectIfCondition => {
-                        self.tcx.sess.delay_span_bug(lhs.span, "invalid lhs expression in if;\
-                                                                expected error elsehwere");
-                    }
-                    _ => {
-                        // Only check this if not in an `if` condition, as the
-                        // mistyped comparison help is more appropriate.
-                        if !lhs.is_place_expr() {
-                            struct_span_err!(self.tcx.sess, expr.span, E0070,
-                                                "invalid left-hand side expression")
-                                .span_label(expr.span, "left-hand of expression not valid")
-                                .emit();
-                        }
-                    }
-                }
-
-                self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
-
-                if lhs_ty.references_error() || rhs_ty.references_error() {
-                    tcx.types.err
-                } else {
-                    tcx.mk_unit()
-                }
+                self.check_assign(expr, expected, lhs, rhs)
             }
             ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => {
                 self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e),
@@ -4750,6 +4705,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Type check assignment expression `expr` of form `lhs = rhs`.
+    /// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
+    fn check_assign(
+        &self,
+        expr: &'gcx hir::Expr,
+        expected: Expectation<'tcx>,
+        lhs: &'gcx hir::Expr,
+        rhs: &'gcx hir::Expr,
+    ) -> Ty<'tcx> {
+        let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
+        let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
+
+        let expected_ty = expected.coercion_target_type(self, expr.span);
+        if expected_ty == self.tcx.types.bool {
+            // The expected type is `bool` but this will result in `()` so we can reasonably
+            // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
+            // The likely cause of this is `if foo = bar { .. }`.
+            let actual_ty = self.tcx.mk_unit();
+            let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap();
+            let msg = "try comparing for equality";
+            let left = self.tcx.sess.source_map().span_to_snippet(lhs.span);
+            let right = self.tcx.sess.source_map().span_to_snippet(rhs.span);
+            if let (Ok(left), Ok(right)) = (left, right) {
+                let help = format!("{} == {}", left, right);
+                err.span_suggestion(expr.span, msg, help, Applicability::MaybeIncorrect);
+            } else {
+                err.help(msg);
+            }
+            err.emit();
+        } else if !lhs.is_place_expr() {
+            struct_span_err!(self.tcx.sess, expr.span, E0070,
+                                "invalid left-hand side expression")
+                .span_label(expr.span, "left-hand of expression not valid")
+                .emit();
+        }
+
+        self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
+
+        if lhs_ty.references_error() || rhs_ty.references_error() {
+            self.tcx.types.err
+        } else {
+            self.tcx.mk_unit()
+        }
+    }
+
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
     // The newly resolved definition is written into `type_dependent_defs`.
     fn finish_resolving_struct_path(&self,
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index a13da2901df94..4241f47b661d7 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -130,7 +130,7 @@ pub use alloc_crate::alloc::*;
 /// program opts in to using jemalloc as the global allocator, `System` will
 /// still allocate memory using `malloc` and `HeapAlloc`.
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Default, Copy, Clone)]
 pub struct System;
 
 // The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`.
diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs
index 53fb371947a99..5056e388112ce 100644
--- a/src/libstd/sys/sgx/ext/arch.rs
+++ b/src/libstd/sys/sgx/ext/arch.rs
@@ -28,7 +28,7 @@ const ENCLU_EGETKEY: u32 = 1;
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
     unsafe {
-        let mut out = MaybeUninit::uninitialized();
+        let mut out = MaybeUninit::uninit();
         let error;
 
         asm!(
@@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
         );
 
         match error {
-            0 => Ok(out.into_initialized()),
+            0 => Ok(out.assume_init()),
             err => Err(err),
         }
     }
@@ -58,7 +58,7 @@ pub fn ereport(
     reportdata: &Align128<[u8; 64]>,
 ) -> Align512<[u8; 432]> {
     unsafe {
-        let mut report = MaybeUninit::uninitialized();
+        let mut report = MaybeUninit::uninit();
 
         asm!(
             "enclu"
@@ -69,6 +69,6 @@ pub fn ereport(
               "{rdx}"(report.as_mut_ptr())
         );
 
-        report.into_initialized()
+        report.assume_init()
     }
 }
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 7b113267865b6..7e2d13b9e2476 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -280,7 +280,7 @@ mod tests {
             let mut init = MaybeUninit::<RWLock>::zeroed();
             rwlock_new(&mut init);
             assert_eq!(
-                mem::transmute::<_, [u8; 128]>(init.into_initialized()).as_slice(),
+                mem::transmute::<_, [u8; 128]>(init.assume_init()).as_slice(),
                 RWLOCK_INIT
             )
         };
diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs
index 1aa910f05c9c3..37cbdcefcedcc 100644
--- a/src/libstd/sys/windows/mutex.rs
+++ b/src/libstd/sys/windows/mutex.rs
@@ -154,7 +154,7 @@ unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
     pub fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninitialized()) }
+        ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) }
     }
 
     pub unsafe fn init(&mut self) {
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 6d305aed748d0..058fee4484d68 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -1257,7 +1257,10 @@ impl Thread {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for Thread {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.name(), f)
+        f.debug_struct("Thread")
+            .field("id", &self.id())
+            .field("name", &self.name())
+            .finish()
     }
 }
 
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 1a419e7fadaa0..ab5823eaca52a 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -929,7 +929,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
             p.fatal(&format!("expected ident, found {}", &token_str)).emit();
             FatalError.raise()
         }
-        "path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))),
+        "path" => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
         "meta" => token::NtMeta(panictry!(p.parse_meta_item())),
         "vis" => token::NtVis(panictry!(p.parse_visibility(true))),
         "lifetime" => if p.check_lifetime() {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a0c3fe356083f..d3eadfeceb289 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1119,9 +1119,8 @@ impl<'a> Parser<'a> {
                 if text.is_empty() {
                     self.span_bug(sp, "found empty literal suffix in Some")
                 }
-                let msg = format!("{} with a suffix is invalid", kind);
-                self.struct_span_err(sp, &msg)
-                    .span_label(sp, msg)
+                self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
+                    .span_label(sp, format!("invalid suffix `{}`", text))
                     .emit();
             }
         }
@@ -1903,7 +1902,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::ModSep)?;
 
         let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
-        self.parse_path_segments(&mut path.segments, T::PATH_STYLE, true)?;
+        self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
         path.span = ty_span.to(self.prev_span);
 
         let ty_str = self.sess.source_map().span_to_snippet(ty_span)
@@ -2150,7 +2149,7 @@ impl<'a> Parser<'a> {
 
                 if suffix_illegal {
                     let sp = self.span;
-                    self.expect_no_suffix(sp, lit.literal_name(), suf)
+                    self.expect_no_suffix(sp, &format!("a {}", lit.literal_name()), suf)
                 }
 
                 result.unwrap()
@@ -2294,7 +2293,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::ModSep)?;
 
         let qself = QSelf { ty, path_span, position: path.segments.len() };
-        self.parse_path_segments(&mut path.segments, style, true)?;
+        self.parse_path_segments(&mut path.segments, style)?;
 
         Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) }))
     }
@@ -2310,11 +2309,6 @@ impl<'a> Parser<'a> {
     /// `Fn(Args)` (without disambiguator)
     /// `Fn::(Args)` (with disambiguator)
     pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> {
-        self.parse_path_common(style, true)
-    }
-
-    crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool)
-                             -> PResult<'a, ast::Path> {
         maybe_whole!(self, NtPath, |path| {
             if style == PathStyle::Mod &&
                path.segments.iter().any(|segment| segment.args.is_some()) {
@@ -2329,7 +2323,7 @@ impl<'a> Parser<'a> {
         if self.eat(&token::ModSep) {
             segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
         }
-        self.parse_path_segments(&mut segments, style, enable_warning)?;
+        self.parse_path_segments(&mut segments, style)?;
 
         Ok(ast::Path { segments, span: lo.to(self.prev_span) })
     }
@@ -2357,11 +2351,10 @@ impl<'a> Parser<'a> {
 
     fn parse_path_segments(&mut self,
                            segments: &mut Vec<PathSegment>,
-                           style: PathStyle,
-                           enable_warning: bool)
+                           style: PathStyle)
                            -> PResult<'a, ()> {
         loop {
-            let segment = self.parse_path_segment(style, enable_warning)?;
+            let segment = self.parse_path_segment(style)?;
             if style == PathStyle::Expr {
                 // In order to check for trailing angle brackets, we must have finished
                 // recursing (`parse_path_segment` can indirectly call this function),
@@ -2389,8 +2382,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool)
-                          -> PResult<'a, PathSegment> {
+    fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
         let ident = self.parse_path_segment_ident()?;
 
         let is_args_start = |token: &token::Token| match *token {
@@ -2407,13 +2399,6 @@ impl<'a> Parser<'a> {
         Ok(if style == PathStyle::Type && check_args_start(self) ||
               style != PathStyle::Mod && self.check(&token::ModSep)
                                       && self.look_ahead(1, |t| is_args_start(t)) {
-            // Generic arguments are found - `<`, `(`, `::<` or `::(`.
-            if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning {
-                self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator")
-                                 .span_label(self.prev_span, "try removing `::`").emit();
-            }
-            let lo = self.span;
-
             // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
             // it isn't, then we reset the unmatched angle bracket count as we're about to start
             // parsing a new path.
@@ -2422,6 +2407,9 @@ impl<'a> Parser<'a> {
                 self.max_angle_bracket_count = 0;
             }
 
+            // Generic arguments are found - `<`, `(`, `::<` or `::(`.
+            self.eat(&token::ModSep);
+            let lo = self.span;
             let args = if self.eat_lt() {
                 // `<'a, T, A = U>`
                 let (args, bindings) =
@@ -2492,7 +2480,8 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_field_name(&mut self) -> PResult<'a, Ident> {
-        if let token::Literal(token::Integer(name), None) = self.token {
+        if let token::Literal(token::Integer(name), suffix) = self.token {
+            self.expect_no_suffix(self.span, "a tuple index", suffix);
             self.bump();
             Ok(Ident::new(name, self.prev_span))
         } else {
@@ -3043,7 +3032,7 @@ impl<'a> Parser<'a> {
 
     // Assuming we have just parsed `.`, continue parsing into an expression.
     fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
-        let segment = self.parse_path_segment(PathStyle::Expr, true)?;
+        let segment = self.parse_path_segment(PathStyle::Expr)?;
         self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
 
         Ok(match self.token {
@@ -3196,51 +3185,53 @@ impl<'a> Parser<'a> {
             // expr.f
             if self.eat(&token::Dot) {
                 match self.token {
-                  token::Ident(..) => {
-                    e = self.parse_dot_suffix(e, lo)?;
-                  }
-                  token::Literal(token::Integer(name), _) => {
-                    let span = self.span;
-                    self.bump();
-                    let field = ExprKind::Field(e, Ident::new(name, span));
-                    e = self.mk_expr(lo.to(span), field, ThinVec::new());
-                  }
-                  token::Literal(token::Float(n), _suf) => {
-                    self.bump();
-                    let fstr = n.as_str();
-                    let mut err = self.diagnostic()
-                        .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n));
-                    err.span_label(self.prev_span, "unexpected token");
-                    if fstr.chars().all(|x| "0123456789.".contains(x)) {
-                        let float = match fstr.parse::<f64>().ok() {
-                            Some(f) => f,
-                            None => continue,
-                        };
-                        let sugg = pprust::to_string(|s| {
-                            use crate::print::pprust::PrintState;
-                            s.popen()?;
-                            s.print_expr(&e)?;
-                            s.s.word( ".")?;
-                            s.print_usize(float.trunc() as usize)?;
-                            s.pclose()?;
-                            s.s.word(".")?;
-                            s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
-                        });
-                        err.span_suggestion(
-                            lo.to(self.prev_span),
-                            "try parenthesizing the first index",
-                            sugg,
-                            Applicability::MachineApplicable
-                        );
+                    token::Ident(..) => {
+                        e = self.parse_dot_suffix(e, lo)?;
                     }
-                    return Err(err);
+                    token::Literal(token::Integer(name), suffix) => {
+                        let span = self.span;
+                        self.bump();
+                        let field = ExprKind::Field(e, Ident::new(name, span));
+                        e = self.mk_expr(lo.to(span), field, ThinVec::new());
+
+                        self.expect_no_suffix(span, "a tuple index", suffix);
+                    }
+                    token::Literal(token::Float(n), _suf) => {
+                      self.bump();
+                      let fstr = n.as_str();
+                      let mut err = self.diagnostic()
+                          .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n));
+                      err.span_label(self.prev_span, "unexpected token");
+                      if fstr.chars().all(|x| "0123456789.".contains(x)) {
+                          let float = match fstr.parse::<f64>().ok() {
+                              Some(f) => f,
+                              None => continue,
+                          };
+                          let sugg = pprust::to_string(|s| {
+                              use crate::print::pprust::PrintState;
+                              s.popen()?;
+                              s.print_expr(&e)?;
+                              s.s.word( ".")?;
+                              s.print_usize(float.trunc() as usize)?;
+                              s.pclose()?;
+                              s.s.word(".")?;
+                              s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
+                          });
+                          err.span_suggestion(
+                              lo.to(self.prev_span),
+                              "try parenthesizing the first index",
+                              sugg,
+                              Applicability::MachineApplicable
+                          );
+                      }
+                      return Err(err);
 
-                  }
-                  _ => {
-                    // FIXME Could factor this out into non_fatal_unexpected or something.
-                    let actual = self.this_token_to_string();
-                    self.span_err(self.span, &format!("unexpected token: `{}`", actual));
-                  }
+                    }
+                    _ => {
+                        // FIXME Could factor this out into non_fatal_unexpected or something.
+                        let actual = self.this_token_to_string();
+                        self.span_err(self.span, &format!("unexpected token: `{}`", actual));
+                    }
                 }
                 continue;
             }
@@ -7838,7 +7829,7 @@ impl<'a> Parser<'a> {
         match self.token {
             token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => {
                 let sp = self.span;
-                self.expect_no_suffix(sp, "ABI spec", suf);
+                self.expect_no_suffix(sp, "an ABI spec", suf);
                 self.bump();
                 match abi::lookup(&s.as_str()) {
                     Some(abi) => Ok(Some(abi)),
@@ -8659,7 +8650,7 @@ impl<'a> Parser<'a> {
         match self.parse_optional_str() {
             Some((s, style, suf)) => {
                 let sp = self.prev_span;
-                self.expect_no_suffix(sp, "string literal", suf);
+                self.expect_no_suffix(sp, "a string literal", suf);
                 Ok((s, style))
             }
             _ => {
diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs
index ad1d259a0da21..0dd67bb95ccaa 100644
--- a/src/test/codegen/box-maybe-uninit.rs
+++ b/src/test/codegen/box-maybe-uninit.rs
@@ -12,5 +12,8 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
     // CHECK-NOT: alloca
     // CHECK-NOT: memcpy
     // CHECK-NOT: memset
-    Box::new(MaybeUninit::uninitialized())
+    Box::new(MaybeUninit::uninit())
 }
+
+// FIXME: add a test for a bigger box. Currently broken, see
+// https://github.com/rust-lang/rust/issues/58201.
diff --git a/src/test/run-pass/packed/packed-struct-generic-size.rs b/src/test/run-pass/packed/packed-struct-generic-size.rs
index 08d4674d2a88a..7c93e46c30c23 100644
--- a/src/test/run-pass/packed/packed-struct-generic-size.rs
+++ b/src/test/run-pass/packed/packed-struct-generic-size.rs
@@ -33,12 +33,12 @@ macro_rules! check {
 }
 
 pub fn main() {
-    check!(P1::<u8, u8>, 1, 3);
-    check!(P1::<u64, u16>, 1, 11);
+    check!(P1<u8, u8>, 1, 3);
+    check!(P1<u64, u16>, 1, 11);
 
-    check!(P2::<u8, u8>, 1, 3);
-    check!(P2::<u64, u16>, 2, 12);
+    check!(P2<u8, u8>, 1, 3);
+    check!(P2<u64, u16>, 2, 12);
 
-    check!(P4C::<u8, u8>, 1, 3);
-    check!(P4C::<u16, u64>, 4, 12);
+    check!(P4C<u8, u8>, 1, 3);
+    check!(P4C<u16, u64>, 4, 12);
 }
diff --git a/src/test/run-pass/packed/packed-struct-generic-size.stderr b/src/test/run-pass/packed/packed-struct-generic-size.stderr
deleted file mode 100644
index 1af476c156866..0000000000000
--- a/src/test/run-pass/packed/packed-struct-generic-size.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:36:14
-   |
-LL |     check!(P1::<u8, u8>, 1, 3);
-   |              ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:37:14
-   |
-LL |     check!(P1::<u64, u16>, 1, 11);
-   |              ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:39:14
-   |
-LL |     check!(P2::<u8, u8>, 1, 3);
-   |              ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:40:14
-   |
-LL |     check!(P2::<u64, u16>, 2, 12);
-   |              ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:42:15
-   |
-LL |     check!(P4C::<u8, u8>, 1, 3);
-   |               ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/packed-struct-generic-size.rs:43:15
-   |
-LL |     check!(P4C::<u16, u64>, 4, 12);
-   |               ^^ try removing `::`
-
diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs
index 31c0d2994d415..3f6e489bb8327 100644
--- a/src/test/run-pass/panic-uninitialized-zeroed.rs
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -36,7 +36,7 @@ fn main() {
 
         assert_eq!(
             panic::catch_unwind(|| {
-                mem::MaybeUninit::<!>::uninitialized().into_initialized()
+                mem::MaybeUninit::<!>::uninit().assume_init()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
                 s == "Attempted to instantiate uninhabited type !"
             })),
@@ -63,7 +63,7 @@ fn main() {
 
         assert_eq!(
             panic::catch_unwind(|| {
-                mem::MaybeUninit::<Foo>::uninitialized().into_initialized()
+                mem::MaybeUninit::<Foo>::uninit().assume_init()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
                 s == "Attempted to instantiate uninhabited type Foo"
             })),
@@ -90,7 +90,7 @@ fn main() {
 
         assert_eq!(
             panic::catch_unwind(|| {
-                mem::MaybeUninit::<Bar>::uninitialized().into_initialized()
+                mem::MaybeUninit::<Bar>::uninit().assume_init()
             }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
                 s == "Attempted to instantiate uninhabited type Bar"
             })),
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.rs b/src/test/ui/existential_types/existential-types-with-cycle-error.rs
new file mode 100644
index 0000000000000..3f0190892ebb3
--- /dev/null
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error.rs
@@ -0,0 +1,12 @@
+#![feature(existential_type)]
+
+existential type Foo: Fn() -> Foo;
+//~^ ERROR: cycle detected when processing `Foo`
+
+fn crash(x: Foo) -> Foo {
+    x
+}
+
+fn main() {
+
+}
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr
new file mode 100644
index 0000000000000..56057a9caa4a5
--- /dev/null
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr
@@ -0,0 +1,30 @@
+error[E0391]: cycle detected when processing `Foo`
+  --> $DIR/existential-types-with-cycle-error.rs:3:1
+   |
+LL | existential type Foo: Fn() -> Foo;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires processing `crash`...
+  --> $DIR/existential-types-with-cycle-error.rs:6:25
+   |
+LL |   fn crash(x: Foo) -> Foo {
+   |  _________________________^
+LL | |     x
+LL | | }
+   | |_^
+   = note: ...which again requires processing `Foo`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/existential-types-with-cycle-error.rs:1:1
+   |
+LL | / #![feature(existential_type)]
+LL | |
+LL | | existential type Foo: Fn() -> Foo;
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.rs b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs
new file mode 100644
index 0000000000000..29410309ef26e
--- /dev/null
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs
@@ -0,0 +1,16 @@
+#![feature(existential_type)]
+
+pub trait Bar<T> {
+    type Item;
+}
+
+existential type Foo: Bar<Foo, Item = Foo>;
+//~^ ERROR: cycle detected when processing `Foo`
+
+fn crash(x: Foo) -> Foo {
+    x
+}
+
+fn main() {
+
+}
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr
new file mode 100644
index 0000000000000..8c7bf52470ab2
--- /dev/null
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr
@@ -0,0 +1,30 @@
+error[E0391]: cycle detected when processing `Foo`
+  --> $DIR/existential-types-with-cycle-error2.rs:7:1
+   |
+LL | existential type Foo: Bar<Foo, Item = Foo>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires processing `crash`...
+  --> $DIR/existential-types-with-cycle-error2.rs:10:25
+   |
+LL |   fn crash(x: Foo) -> Foo {
+   |  _________________________^
+LL | |     x
+LL | | }
+   | |_^
+   = note: ...which again requires processing `Foo`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/existential-types-with-cycle-error2.rs:1:1
+   |
+LL | / #![feature(existential_type)]
+LL | |
+LL | | pub trait Bar<T> {
+LL | |     type Item;
+...  |
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/issues/issue-36116.rs b/src/test/ui/issues/issue-36116.rs
index f4fe96cf75b55..b4bfba4d6e5d7 100644
--- a/src/test/ui/issues/issue-36116.rs
+++ b/src/test/ui/issues/issue-36116.rs
@@ -17,10 +17,10 @@ struct Foo<T> {
 struct S<T>(T);
 
 fn f() {
-    let f = Some(Foo { _a: 42 }).map(|a| a as Foo::<i32>); //~ WARN unnecessary path disambiguator
-    let g: Foo::<i32> = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator
+    let f = Some(Foo { _a: 42 }).map(|a| a as Foo::<i32>);
+    let g: Foo::<i32> = Foo { _a: 42 };
 
-    m!(S::<u8>); // OK, no warning
+    m!(S::<u8>);
 }
 
 
diff --git a/src/test/ui/issues/issue-36116.stderr b/src/test/ui/issues/issue-36116.stderr
deleted file mode 100644
index 5236db29ae4af..0000000000000
--- a/src/test/ui/issues/issue-36116.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-warning: unnecessary path disambiguator
-  --> $DIR/issue-36116.rs:20:50
-   |
-LL |     let f = Some(Foo { _a: 42 }).map(|a| a as Foo::<i32>);
-   |                                                  ^^ try removing `::`
-
-warning: unnecessary path disambiguator
-  --> $DIR/issue-36116.rs:21:15
-   |
-LL |     let g: Foo::<i32> = Foo { _a: 42 };
-   |               ^^ try removing `::`
-
diff --git a/src/test/ui/lint/lint-impl-fn.stderr b/src/test/ui/lint/lint-impl-fn.stderr
index 2c9a264287c96..56f85111d428f 100644
--- a/src/test/ui/lint/lint-impl-fn.stderr
+++ b/src/test/ui/lint/lint-impl-fn.stderr
@@ -11,25 +11,25 @@ LL |     #[deny(while_true)]
    |            ^^^^^^^^^^
 
 error: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-impl-fn.rs:18:25
+  --> $DIR/lint-impl-fn.rs:27:5
    |
-LL |         fn foo(&self) { while true {} }
-   |                         ^^^^^^^^^^ help: use `loop`
+LL |     while true {}
+   |     ^^^^^^^^^^ help: use `loop`
    |
 note: lint level defined here
-  --> $DIR/lint-impl-fn.rs:13:8
+  --> $DIR/lint-impl-fn.rs:25:8
    |
 LL | #[deny(while_true)]
    |        ^^^^^^^^^^
 
 error: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-impl-fn.rs:27:5
+  --> $DIR/lint-impl-fn.rs:18:25
    |
-LL |     while true {}
-   |     ^^^^^^^^^^ help: use `loop`
+LL |         fn foo(&self) { while true {} }
+   |                         ^^^^^^^^^^ help: use `loop`
    |
 note: lint level defined here
-  --> $DIR/lint-impl-fn.rs:25:8
+  --> $DIR/lint-impl-fn.rs:13:8
    |
 LL | #[deny(while_true)]
    |        ^^^^^^^^^^
diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr
index c28814aeee8f9..5aaa9947f998a 100644
--- a/src/test/ui/lint/suggestions.stderr
+++ b/src/test/ui/lint/suggestions.stderr
@@ -65,6 +65,24 @@ LL | pub fn defiant<T>(_t: T) {}
    |
    = note: #[warn(no_mangle_generic_items)] on by default
 
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/suggestions.rs:46:5
+   |
+LL |     while true {
+   |     ^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
+warning: the `warp_factor:` in this pattern is redundant
+  --> $DIR/suggestions.rs:61:23
+   |
+LL |             Equinox { warp_factor: warp_factor } => {}
+   |                       ------------^^^^^^^^^^^^
+   |                       |
+   |                       help: remove this
+   |
+   = note: #[warn(non_shorthand_field_patterns)] on by default
+
 error: const items should never be #[no_mangle]
   --> $DIR/suggestions.rs:22:18
    |
@@ -97,23 +115,5 @@ LL |     #[no_mangle] pub(crate) fn crossfield<T>() {}
    |     |
    |     help: remove this attribute
 
-warning: denote infinite loops with `loop { ... }`
-  --> $DIR/suggestions.rs:46:5
-   |
-LL |     while true {
-   |     ^^^^^^^^^^ help: use `loop`
-   |
-   = note: #[warn(while_true)] on by default
-
-warning: the `warp_factor:` in this pattern is redundant
-  --> $DIR/suggestions.rs:61:23
-   |
-LL |             Equinox { warp_factor: warp_factor } => {}
-   |                       ------------^^^^^^^^^^^^
-   |                       |
-   |                       help: remove this
-   |
-   = note: #[warn(non_shorthand_field_patterns)] on by default
-
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs
index 391e7f0acf979..75bed3088587c 100644
--- a/src/test/ui/parser/bad-lit-suffixes.rs
+++ b/src/test/ui/parser/bad-lit-suffixes.rs
@@ -2,20 +2,20 @@
 
 
 extern
-    "C"suffix //~ ERROR ABI spec with a suffix is invalid
+    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
     fn foo() {}
 
 extern
-    "C"suffix //~ ERROR ABI spec with a suffix is invalid
+    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
 {}
 
 fn main() {
-    ""suffix; //~ ERROR string literal with a suffix is invalid
-    b""suffix; //~ ERROR byte string literal with a suffix is invalid
-    r#""#suffix; //~ ERROR string literal with a suffix is invalid
-    br#""#suffix; //~ ERROR byte string literal with a suffix is invalid
-    'a'suffix; //~ ERROR char literal with a suffix is invalid
-    b'a'suffix; //~ ERROR byte literal with a suffix is invalid
+    ""suffix; //~ ERROR suffixes on a string literal are invalid
+    b""suffix; //~ ERROR suffixes on a byte string literal are invalid
+    r#""#suffix; //~ ERROR suffixes on a string literal are invalid
+    br#""#suffix; //~ ERROR suffixes on a byte string literal are invalid
+    'a'suffix; //~ ERROR suffixes on a char literal are invalid
+    b'a'suffix; //~ ERROR suffixes on a byte literal are invalid
 
     1234u1024; //~ ERROR invalid width `1024` for integer literal
     1234i1024; //~ ERROR invalid width `1024` for integer literal
diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr
index 3d4d7b4a78b43..de194f4820de0 100644
--- a/src/test/ui/parser/bad-lit-suffixes.stderr
+++ b/src/test/ui/parser/bad-lit-suffixes.stderr
@@ -1,50 +1,50 @@
-error: ABI spec with a suffix is invalid
+error: suffixes on an ABI spec are invalid
   --> $DIR/bad-lit-suffixes.rs:5:5
    |
 LL |     "C"suffix
-   |     ^^^^^^^^^ ABI spec with a suffix is invalid
+   |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: ABI spec with a suffix is invalid
+error: suffixes on an ABI spec are invalid
   --> $DIR/bad-lit-suffixes.rs:9:5
    |
 LL |     "C"suffix
-   |     ^^^^^^^^^ ABI spec with a suffix is invalid
+   |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: string literal with a suffix is invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:13:5
    |
 LL |     ""suffix;
-   |     ^^^^^^^^ string literal with a suffix is invalid
+   |     ^^^^^^^^ invalid suffix `suffix`
 
-error: byte string literal with a suffix is invalid
+error: suffixes on a byte string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:14:5
    |
 LL |     b""suffix;
-   |     ^^^^^^^^^ byte string literal with a suffix is invalid
+   |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: string literal with a suffix is invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:15:5
    |
 LL |     r#""#suffix;
-   |     ^^^^^^^^^^^ string literal with a suffix is invalid
+   |     ^^^^^^^^^^^ invalid suffix `suffix`
 
-error: byte string literal with a suffix is invalid
+error: suffixes on a byte string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:16:5
    |
 LL |     br#""#suffix;
-   |     ^^^^^^^^^^^^ byte string literal with a suffix is invalid
+   |     ^^^^^^^^^^^^ invalid suffix `suffix`
 
-error: char literal with a suffix is invalid
+error: suffixes on a char literal are invalid
   --> $DIR/bad-lit-suffixes.rs:17:5
    |
 LL |     'a'suffix;
-   |     ^^^^^^^^^ char literal with a suffix is invalid
+   |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: byte literal with a suffix is invalid
+error: suffixes on a byte literal are invalid
   --> $DIR/bad-lit-suffixes.rs:18:5
    |
 LL |     b'a'suffix;
-   |     ^^^^^^^^^^ byte literal with a suffix is invalid
+   |     ^^^^^^^^^^ invalid suffix `suffix`
 
 error: invalid width `1024` for integer literal
   --> $DIR/bad-lit-suffixes.rs:20:5
diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs
new file mode 100644
index 0000000000000..0fa191d4a7ef4
--- /dev/null
+++ b/src/test/ui/parser/issue-59418.rs
@@ -0,0 +1,18 @@
+struct X(i32,i32,i32);
+
+fn main() {
+    let a = X(1, 2, 3);
+    let b = a.1suffix;
+    //~^ ERROR suffixes on a tuple index are invalid
+    println!("{}", b);
+    let c = (1, 2, 3);
+    let d = c.1suffix;
+    //~^ ERROR suffixes on a tuple index are invalid
+    println!("{}", d);
+    let s = X { 0suffix: 0, 1: 1, 2: 2 };
+    //~^ ERROR suffixes on a tuple index are invalid
+    match s {
+        X { 0suffix: _, .. } => {}
+        //~^ ERROR suffixes on a tuple index are invalid
+    }
+}
diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr
new file mode 100644
index 0000000000000..347051e9f921c
--- /dev/null
+++ b/src/test/ui/parser/issue-59418.stderr
@@ -0,0 +1,26 @@
+error: suffixes on a tuple index are invalid
+  --> $DIR/issue-59418.rs:5:15
+   |
+LL |     let b = a.1suffix;
+   |               ^^^^^^^ invalid suffix `suffix`
+
+error: suffixes on a tuple index are invalid
+  --> $DIR/issue-59418.rs:9:15
+   |
+LL |     let d = c.1suffix;
+   |               ^^^^^^^ invalid suffix `suffix`
+
+error: suffixes on a tuple index are invalid
+  --> $DIR/issue-59418.rs:12:17
+   |
+LL |     let s = X { 0suffix: 0, 1: 1, 2: 2 };
+   |                 ^^^^^^^ invalid suffix `suffix`
+
+error: suffixes on a tuple index are invalid
+  --> $DIR/issue-59418.rs:15:13
+   |
+LL |         X { 0suffix: _, .. } => {}
+   |             ^^^^^^^ invalid suffix `suffix`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/into-str.rs b/src/test/ui/suggestions/into-str.rs
new file mode 100644
index 0000000000000..9793ee801d185
--- /dev/null
+++ b/src/test/ui/suggestions/into-str.rs
@@ -0,0 +1,6 @@
+fn foo<'a, T>(_t: T) where T: Into<&'a str> {}
+
+fn main() {
+    foo(String::new());
+    //~^ ERROR the trait bound `&str: std::convert::From<std::string::String>` is not satisfied
+}
diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr
new file mode 100644
index 0000000000000..3e28700ce9552
--- /dev/null
+++ b/src/test/ui/suggestions/into-str.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `&str: std::convert::From<std::string::String>` is not satisfied
+  --> $DIR/into-str.rs:4:5
+   |
+LL |     foo(String::new());
+   |     ^^^ the trait `std::convert::From<std::string::String>` is not implemented for `&str`
+   |
+   = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix
+   = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String`
+note: required by `foo`
+  --> $DIR/into-str.rs:1:1
+   |
+LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type/type-check/assignment-expected-bool.rs b/src/test/ui/type/type-check/assignment-expected-bool.rs
new file mode 100644
index 0000000000000..03830fea062cf
--- /dev/null
+++ b/src/test/ui/type/type-check/assignment-expected-bool.rs
@@ -0,0 +1,34 @@
+// The purpose of this text is to ensure that we get good
+// diagnostics when a `bool` is expected but that due to
+// an assignment expression `x = y` the type is `()`.
+
+fn main() {
+    let _: bool = 0 = 0; //~ ERROR mismatched types [E0308]
+
+    let _: bool = match 0 {
+        0 => 0 = 0, //~ ERROR mismatched types [E0308]
+        _ => 0 = 0, //~ ERROR mismatched types [E0308]
+    };
+
+    let _: bool = match true {
+        true => 0 = 0, //~ ERROR mismatched types [E0308]
+        _ => (),
+    };
+
+    if 0 = 0 {} //~ ERROR mismatched types [E0308]
+
+    let _: bool = if { 0 = 0 } { //~ ERROR mismatched types [E0308]
+        0 = 0 //~ ERROR mismatched types [E0308]
+    } else {
+        0 = 0 //~ ERROR mismatched types [E0308]
+    };
+
+    let _ = (0 = 0) //~ ERROR mismatched types [E0308]
+        && { 0 = 0 } //~ ERROR mismatched types [E0308]
+        || (0 = 0); //~ ERROR mismatched types [E0308]
+
+    // A test to check that not expecting `bool` behaves well:
+    let _: usize = 0 = 0;
+    //~^ ERROR mismatched types [E0308]
+    //~| ERROR invalid left-hand side expression [E0070]
+}
diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr
new file mode 100644
index 0000000000000..fed8b91346582
--- /dev/null
+++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr
@@ -0,0 +1,151 @@
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:6:19
+   |
+LL |     let _: bool = 0 = 0;
+   |                   ^^^^^
+   |                   |
+   |                   expected bool, found ()
+   |                   help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:9:14
+   |
+LL |         0 => 0 = 0,
+   |              ^^^^^
+   |              |
+   |              expected bool, found ()
+   |              help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:10:14
+   |
+LL |         _ => 0 = 0,
+   |              ^^^^^
+   |              |
+   |              expected bool, found ()
+   |              help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:14:17
+   |
+LL |         true => 0 = 0,
+   |                 ^^^^^
+   |                 |
+   |                 expected bool, found ()
+   |                 help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:18:8
+   |
+LL |     if 0 = 0 {}
+   |        ^^^^^
+   |        |
+   |        expected bool, found ()
+   |        help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:20:24
+   |
+LL |     let _: bool = if { 0 = 0 } {
+   |                        ^^^^^
+   |                        |
+   |                        expected bool, found ()
+   |                        help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:21:9
+   |
+LL |         0 = 0
+   |         ^^^^^
+   |         |
+   |         expected bool, found ()
+   |         help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:23:9
+   |
+LL |         0 = 0
+   |         ^^^^^
+   |         |
+   |         expected bool, found ()
+   |         help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:26:13
+   |
+LL |     let _ = (0 = 0)
+   |             ^^^^^^^
+   |             |
+   |             expected bool, found ()
+   |             help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:27:14
+   |
+LL |         && { 0 = 0 }
+   |              ^^^^^
+   |              |
+   |              expected bool, found ()
+   |              help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:28:12
+   |
+LL |         || (0 = 0);
+   |            ^^^^^^^
+   |            |
+   |            expected bool, found ()
+   |            help: try comparing for equality: `0 == 0`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error[E0070]: invalid left-hand side expression
+  --> $DIR/assignment-expected-bool.rs:31:20
+   |
+LL |     let _: usize = 0 = 0;
+   |                    ^^^^^ left-hand of expression not valid
+
+error[E0308]: mismatched types
+  --> $DIR/assignment-expected-bool.rs:31:20
+   |
+LL |     let _: usize = 0 = 0;
+   |                    ^^^^^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error: aborting due to 13 previous errors
+
+Some errors occurred: E0070, E0308.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/type/type-check/assignment-in-if.rs b/src/test/ui/type/type-check/assignment-in-if.rs
index 232b0a00b307d..77b122b0a794a 100644
--- a/src/test/ui/type/type-check/assignment-in-if.rs
+++ b/src/test/ui/type/type-check/assignment-in-if.rs
@@ -31,8 +31,13 @@ fn main() {
         //~^ ERROR mismatched types
         println!("{}", x);
     }
-    if (if true { x = 4 } else { x = 5 }) {
-        //~^ ERROR mismatched types
+    if (
+        if true {
+            x = 4 //~ ERROR mismatched types
+        } else {
+            x = 5 //~ ERROR mismatched types
+        }
+    ) {
         println!("{}", x);
     }
 }
diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr
index 403f7b4f7ae89..87b8d17c21bcc 100644
--- a/src/test/ui/type/type-check/assignment-in-if.stderr
+++ b/src/test/ui/type/type-check/assignment-in-if.stderr
@@ -47,14 +47,29 @@ LL |     if 3 = x {
               found type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/assignment-in-if.rs:34:8
+  --> $DIR/assignment-in-if.rs:36:13
    |
-LL |     if (if true { x = 4 } else { x = 5 }) {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found ()
+LL |             x = 4
+   |             ^^^^^
+   |             |
+   |             expected bool, found ()
+   |             help: try comparing for equality: `x == 4`
    |
    = note: expected type `bool`
               found type `()`
 
-error: aborting due to 5 previous errors
+error[E0308]: mismatched types
+  --> $DIR/assignment-in-if.rs:38:13
+   |
+LL |             x = 5
+   |             ^^^^^
+   |             |
+   |             expected bool, found ()
+   |             help: try comparing for equality: `x == 5`
+   |
+   = note: expected type `bool`
+              found type `()`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.