Auto merge of #68069 - JohnTitor:fix-closure-ice, r=matthewjasper

Attempt to fix ICE #68025

Fixes #68025
diff --git a/Cargo.lock b/Cargo.lock
index f33d7ff..0a76aab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -307,7 +307,7 @@
  "glob",
  "hex 0.4.0",
  "home",
- "humantime",
+ "humantime 2.0.0",
  "ignore",
  "im-rc",
  "jobserver",
@@ -1013,7 +1013,7 @@
 checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
 dependencies = [
  "atty",
- "humantime",
+ "humantime 1.3.0",
  "log",
  "regex",
  "termcolor",
@@ -1026,7 +1026,7 @@
 checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
 dependencies = [
  "atty",
- "humantime",
+ "humantime 1.3.0",
  "log",
  "regex",
  "termcolor",
@@ -1455,6 +1455,12 @@
 ]
 
 [[package]]
+name = "humantime"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da"
+
+[[package]]
 name = "hyper"
 version = "0.12.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2647,7 +2653,7 @@
  "clap",
  "derive_more",
  "env_logger 0.6.2",
- "humantime",
+ "humantime 1.3.0",
  "lazy_static 1.3.0",
  "log",
  "rls-span",
@@ -3092,7 +3098,6 @@
  "rustc-rayon-core",
  "rustc_apfloat",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_hir",
@@ -3358,7 +3363,6 @@
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
@@ -3375,7 +3379,6 @@
 dependencies = [
  "log",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_parse",
@@ -3391,7 +3394,6 @@
  "fmt_macros",
  "log",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_expand",
  "rustc_feature",
@@ -3445,7 +3447,6 @@
  "rustc_apfloat",
  "rustc_codegen_utils",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_fs_util",
  "rustc_hir",
@@ -3675,7 +3676,6 @@
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_hir",
@@ -3716,7 +3716,6 @@
  "memmap",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_expand",
  "rustc_hir",
@@ -3744,7 +3743,6 @@
  "rustc",
  "rustc_apfloat",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
@@ -3767,11 +3765,11 @@
  "rustc",
  "rustc_apfloat",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
  "rustc_macros",
+ "rustc_session",
  "rustc_span",
  "rustc_target",
  "serialize",
@@ -3786,7 +3784,6 @@
  "bitflags",
  "log",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
@@ -3804,7 +3801,6 @@
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_hir",
@@ -3820,7 +3816,6 @@
 version = "0.0.0"
 dependencies = [
  "rustc",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_lint",
@@ -3836,7 +3831,6 @@
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_span",
@@ -3854,7 +3848,6 @@
  "rustc",
  "rustc_ast_lowering",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_expand",
  "rustc_feature",
@@ -3890,7 +3883,6 @@
  "log",
  "num_cpus",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_fs_util",
@@ -3973,7 +3965,6 @@
  "log",
  "rustc",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
@@ -4493,7 +4484,6 @@
 dependencies = [
  "log",
  "rustc_data_structures",
- "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_index",
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
index 16fe87b..1b5ec8b 100644
--- a/LICENSE-APACHE
+++ b/LICENSE-APACHE
@@ -174,28 +174,3 @@
    of your accepting any such warranty or additional liability.
 
 END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
-   To apply the Apache License to your work, attach the following
-   boilerplate notice, with the fields enclosed by brackets "[]"
-   replaced with your own identifying information. (Don't include
-   the brackets!)  The text should be enclosed in the appropriate
-   comment syntax for the file format. We also recommend that a
-   file or class name and description of purpose be included on the
-   same "printed page" as the copyright notice for easier
-   identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-	http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/src/doc/book b/src/doc/book
index 5c5cfd2..87dd684 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 5c5cfd2e94cd42632798d9bd3d1116133e128ac9
+Subproject commit 87dd6843678575f8dda962f239d14ef4be14b352
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index 9493b7d..4d78994 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit 9493b7d4dc97eda439bd8780f05ad7b234cd1cd7
+Subproject commit 4d78994915af1bde9a95c04a8c27d8dca066232a
diff --git a/src/doc/reference b/src/doc/reference
index e115753..11e893f 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit e1157538e86d83df0cf95d5e33bd943f80d0248f
+Subproject commit 11e893fc1357bc688418ddf1087c2b7aa25d154d
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 1d59403..1c2bd02 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 1d59403cb5269c190cc52a95584ecc280345495a
+Subproject commit 1c2bd024d13f8011307e13386cf1fea2180352b5
diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs
index eb5f51d..ea69769 100644
--- a/src/liballoc/benches/btree/map.rs
+++ b/src/liballoc/benches/btree/map.rs
@@ -146,6 +146,36 @@
     bench_iter(b, 100000);
 }
 
+fn bench_iter_mut(b: &mut Bencher, size: i32) {
+    let mut map = BTreeMap::<i32, i32>::new();
+    let mut rng = thread_rng();
+
+    for _ in 0..size {
+        map.insert(rng.gen(), rng.gen());
+    }
+
+    b.iter(|| {
+        for kv in map.iter_mut() {
+            black_box(kv);
+        }
+    });
+}
+
+#[bench]
+pub fn iter_mut_20(b: &mut Bencher) {
+    bench_iter_mut(b, 20);
+}
+
+#[bench]
+pub fn iter_mut_1000(b: &mut Bencher) {
+    bench_iter_mut(b, 1000);
+}
+
+#[bench]
+pub fn iter_mut_100000(b: &mut Bencher) {
+    bench_iter_mut(b, 100000);
+}
+
 fn bench_first_and_last(b: &mut Bencher, size: i32) {
     let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
     b.iter(|| {
diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs
index 18502de..d7c1d95 100644
--- a/src/liballoc/benches/btree/set.rs
+++ b/src/liballoc/benches/btree/set.rs
@@ -14,19 +14,13 @@
 }
 
 fn neg(n: usize) -> BTreeSet<i32> {
-    let mut set = BTreeSet::new();
-    for i in -(n as i32)..=-1 {
-        set.insert(i);
-    }
+    let set: BTreeSet<i32> = (-(n as i32)..=-1).collect();
     assert_eq!(set.len(), n);
     set
 }
 
 fn pos(n: usize) -> BTreeSet<i32> {
-    let mut set = BTreeSet::new();
-    for i in 1..=(n as i32) {
-        set.insert(i);
-    }
+    let set: BTreeSet<i32> = (1..=(n as i32)).collect();
     assert_eq!(set.len(), n);
     set
 }
@@ -56,6 +50,43 @@
     };
 }
 
+const BUILD_SET_SIZE: usize = 100;
+
+#[bench]
+pub fn build_and_clear(b: &mut Bencher) {
+    b.iter(|| pos(BUILD_SET_SIZE).clear())
+}
+
+#[bench]
+pub fn build_and_drop(b: &mut Bencher) {
+    b.iter(|| pos(BUILD_SET_SIZE))
+}
+
+#[bench]
+pub fn build_and_into_iter(b: &mut Bencher) {
+    b.iter(|| pos(BUILD_SET_SIZE).into_iter().count())
+}
+
+#[bench]
+pub fn build_and_pop_all(b: &mut Bencher) {
+    b.iter(|| {
+        let mut s = pos(BUILD_SET_SIZE);
+        while s.pop_first().is_some() {}
+        s
+    });
+}
+
+#[bench]
+pub fn build_and_remove_all(b: &mut Bencher) {
+    b.iter(|| {
+        let mut s = pos(BUILD_SET_SIZE);
+        while let Some(elt) = s.iter().copied().next() {
+            s.remove(&elt);
+        }
+        s
+    });
+}
+
 set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]}
 set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]}
 set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]}
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 302c2bc..e70f881 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -1968,7 +1968,7 @@
                 (i, false) => i,
             },
             (_, Unbounded) => 0,
-            (true, Included(_)) => min_node.keys().len(),
+            (true, Included(_)) => min_node.len(),
             (true, Excluded(_)) => 0,
         };
 
@@ -1987,9 +1987,9 @@
                 }
                 (i, false) => i,
             },
-            (_, Unbounded) => max_node.keys().len(),
+            (_, Unbounded) => max_node.len(),
             (true, Included(_)) => 0,
-            (true, Excluded(_)) => max_node.keys().len(),
+            (true, Excluded(_)) => max_node.len(),
         };
 
         if !diverged {
diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs
index f40e0b0..d9cdebb 100644
--- a/src/liballoc/collections/btree/node.rs
+++ b/src/liballoc/collections/btree/node.rs
@@ -54,10 +54,8 @@
 /// `NodeHeader` because we do not want unnecessary padding between `len` and the keys.
 /// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited
 /// by `as_header`.)
-/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around
-/// because the size of `NodeHeader` depends on its alignment!
 #[repr(C)]
-struct NodeHeader<K, V, K2 = ()> {
+struct NodeHeader<K, V> {
     /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
     /// This either points to an actual node or is null.
     parent: *const InternalNode<K, V>,
@@ -72,9 +70,6 @@
     /// This next to `parent_idx` to encourage the compiler to join `len` and
     /// `parent_idx` into the same 32-bit word, reducing space overhead.
     len: u16,
-
-    /// See `into_key_slice`.
-    keys_start: [K2; 0],
 }
 #[repr(C)]
 struct LeafNode<K, V> {
@@ -128,7 +123,7 @@
 // We use just a header in order to save space, since no operation on an empty tree will
 // ever take a pointer past the first key.
 static EMPTY_ROOT_NODE: NodeHeader<(), ()> =
-    NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0, keys_start: [] };
+    NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0 };
 
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
 /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
@@ -390,14 +385,13 @@
     }
 
     /// Borrows a view into the keys stored in the node.
-    /// Works on all possible nodes, including the shared root.
-    pub fn keys(&self) -> &[K] {
+    /// The caller must ensure that the node is not the shared root.
+    pub unsafe fn keys(&self) -> &[K] {
         self.reborrow().into_key_slice()
     }
 
     /// Borrows a view into the values stored in the node.
     /// The caller must ensure that the node is not the shared root.
-    /// This function is not public, so doesn't have to support shared roots like `keys` does.
     fn vals(&self) -> &[V] {
         self.reborrow().into_val_slice()
     }
@@ -515,7 +509,6 @@
     }
 
     /// The caller must ensure that the node is not the shared root.
-    /// This function is not public, so doesn't have to support shared roots like `keys` does.
     fn keys_mut(&mut self) -> &mut [K] {
         unsafe { self.reborrow_mut().into_key_slice_mut() }
     }
@@ -527,48 +520,11 @@
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    fn into_key_slice(self) -> &'a [K] {
-        // We have to be careful here because we might be pointing to the shared root.
-        // In that case, we must not create an `&LeafNode`.  We could just return
-        // an empty slice whenever the length is 0 (this includes the shared root),
-        // but we want to avoid that run-time check.
-        // Instead, we create a slice pointing into the node whenever possible.
-        // We can sometimes do this even for the shared root, as the slice will be
-        // empty and `NodeHeader` contains an empty `keys_start` array.
-        // We cannot *always* do this because:
-        // - `keys_start` is not correctly typed because we want `NodeHeader`'s size to
-        //   not depend on the alignment of `K` (needed because `as_header` should be safe).
-        //   For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
-        //   and hence just adds a size-0-align-1 field, not affecting layout).
-        //   If the correctly typed header is more highly aligned than the allocated header,
-        //   we cannot transmute safely.
-        // - Even if we can transmute, the offset of a correctly typed `keys_start` might
-        //   be different and outside the bounds of the allocated header!
-        // So we do an alignment check and a size check first, that will be evaluated
-        // at compile-time, and only do any run-time check in the rare case that
-        // the compile-time checks signal danger.
-        if (mem::align_of::<NodeHeader<K, V, K>>() > mem::align_of::<NodeHeader<K, V>>()
-            || mem::size_of::<NodeHeader<K, V, K>>() != mem::size_of::<NodeHeader<K, V>>())
-            && self.is_shared_root()
-        {
-            &[]
-        } else {
-            // If we are a `LeafNode<K, V>`, we can always transmute to
-            // `NodeHeader<K, V, K>` and `keys_start` always has the same offset
-            // as the actual `keys`.
-            // Thanks to the checks above, we know that we can transmute to
-            // `NodeHeader<K, V, K>` and that `keys_start` will be
-            // in-bounds of some allocation even if this is the shared root!
-            // (We might be one-past-the-end, but that is allowed by LLVM.)
-            // Thus we can use `NodeHeader<K, V, K>`
-            // to compute the pointer where the keys start.
-            // This entire hack will become unnecessary once
-            // <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw
-            // pointer to the `keys` field of `*const InternalNode<K, V>`.
-            let header = self.as_header() as *const _ as *const NodeHeader<K, V, K>;
-            let keys = unsafe { &(*header).keys_start as *const _ as *const K };
-            unsafe { slice::from_raw_parts(keys, self.len()) }
-        }
+    /// The caller must ensure that the node is not the shared root.
+    unsafe fn into_key_slice(self) -> &'a [K] {
+        debug_assert!(!self.is_shared_root());
+        // We cannot be the shared root, so `as_leaf` is okay.
+        slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len())
     }
 
     /// The caller must ensure that the node is not the shared root.
@@ -578,9 +534,10 @@
         unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().vals), self.len()) }
     }
 
+    /// The caller must ensure that the node is not the shared root.
     fn into_slices(self) -> (&'a [K], &'a [V]) {
         let k = unsafe { ptr::read(&self) };
-        (k.into_key_slice(), self.into_val_slice())
+        (unsafe { k.into_key_slice() }, self.into_val_slice())
     }
 }
 
diff --git a/src/liballoc/collections/btree/search.rs b/src/liballoc/collections/btree/search.rs
index 48cbf67..579624c 100644
--- a/src/liballoc/collections/btree/search.rs
+++ b/src/liballoc/collections/btree/search.rs
@@ -61,16 +61,18 @@
 {
     // This function is defined over all borrow types (immutable, mutable, owned),
     // and may be called on the shared root in each case.
-    // Crucially, we use `keys()` here, i.e., we work with immutable data.
-    // `keys_mut()` does not support the shared root, so we cannot use it.
     // Using `keys()` is fine here even if BorrowType is mutable, as all we return
     // is an index -- not a reference.
-    for (i, k) in node.keys().iter().enumerate() {
-        match key.cmp(k.borrow()) {
-            Ordering::Greater => {}
-            Ordering::Equal => return (i, true),
-            Ordering::Less => return (i, false),
+    let len = node.len();
+    if len > 0 {
+        let keys = unsafe { node.keys() }; // safe because a non-empty node cannot be the shared root
+        for (i, k) in keys.iter().enumerate() {
+            match key.cmp(k.borrow()) {
+                Ordering::Greater => {}
+                Ordering::Equal => return (i, true),
+                Ordering::Less => return (i, false),
+            }
         }
     }
-    (node.keys().len(), false)
+    (len, false)
 }
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 4354e1c..09f743f 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -525,7 +525,8 @@
     /// The memory may or may not have been deallocated,
     /// and should be considered unusable (unless of course it was
     /// transferred back to the caller again via the return value of
-    /// this method).
+    /// this method). The new memory block is allocated with `layout`, but
+    /// with the `size` updated to `new_size`.
     ///
     /// If this method returns null, then ownership of the memory
     /// block has not been transferred to this allocator, and the
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index e68f3c5..900ef63 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -10,7 +10,6 @@
 use crate::num::flt2dec;
 use crate::ops::Deref;
 use crate::result;
-use crate::slice;
 use crate::str;
 
 mod builders;
@@ -234,8 +233,6 @@
     precision: Option<usize>,
 
     buf: &'a mut (dyn Write + 'a),
-    curarg: slice::Iter<'a, ArgumentV1<'a>>,
-    args: &'a [ArgumentV1<'a>],
 }
 
 // NB. Argument is essentially an optimized partially applied formatting function,
@@ -1043,8 +1040,6 @@
         buf: output,
         align: rt::v1::Alignment::Unknown,
         fill: ' ',
-        args: args.args,
-        curarg: args.args.iter(),
     };
 
     let mut idx = 0;
@@ -1063,7 +1058,7 @@
             // a string piece.
             for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
                 formatter.buf.write_str(*piece)?;
-                formatter.run(arg)?;
+                run(&mut formatter, arg, &args.args)?;
                 idx += 1;
             }
         }
@@ -1077,6 +1072,39 @@
     Ok(())
 }
 
+fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
+    fmt.fill = arg.format.fill;
+    fmt.align = arg.format.align;
+    fmt.flags = arg.format.flags;
+    fmt.width = getcount(args, &arg.format.width);
+    fmt.precision = getcount(args, &arg.format.precision);
+
+    // Extract the correct argument
+    let value = {
+        #[cfg(bootstrap)]
+        {
+            match arg.position {
+                rt::v1::Position::At(i) => args[i],
+            }
+        }
+        #[cfg(not(bootstrap))]
+        {
+            args[arg.position]
+        }
+    };
+
+    // Then actually do some printing
+    (value.formatter)(value.value, fmt)
+}
+
+fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
+    match *cnt {
+        rt::v1::Count::Is(n) => Some(n),
+        rt::v1::Count::Implied => None,
+        rt::v1::Count::Param(i) => args[i].as_usize(),
+    }
+}
+
 /// Padding after the end of something. Returned by `Formatter::padding`.
 #[must_use = "don't forget to write the post padding"]
 struct PostPadding {
@@ -1114,41 +1142,6 @@
             align: self.align,
             width: self.width,
             precision: self.precision,
-
-            // These only exist in the struct for the `run` method,
-            // which won’t be used together with this method.
-            curarg: self.curarg.clone(),
-            args: self.args,
-        }
-    }
-
-    // First up is the collection of functions used to execute a format string
-    // at runtime. This consumes all of the compile-time statics generated by
-    // the format! syntax extension.
-    fn run(&mut self, arg: &rt::v1::Argument) -> Result {
-        // Fill in the format parameters into the formatter
-        self.fill = arg.format.fill;
-        self.align = arg.format.align;
-        self.flags = arg.format.flags;
-        self.width = self.getcount(&arg.format.width);
-        self.precision = self.getcount(&arg.format.precision);
-
-        // Extract the correct argument
-        let value = match arg.position {
-            rt::v1::Position::Next => *self.curarg.next().unwrap(),
-            rt::v1::Position::At(i) => self.args[i],
-        };
-
-        // Then actually do some printing
-        (value.formatter)(value.value, self)
-    }
-
-    fn getcount(&mut self, cnt: &rt::v1::Count) -> Option<usize> {
-        match *cnt {
-            rt::v1::Count::Is(n) => Some(n),
-            rt::v1::Count::Implied => None,
-            rt::v1::Count::Param(i) => self.args[i].as_usize(),
-            rt::v1::Count::NextParam => self.curarg.next()?.as_usize(),
         }
     }
 
diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs
index 826ae36..fd81f932 100644
--- a/src/libcore/fmt/rt/v1.rs
+++ b/src/libcore/fmt/rt/v1.rs
@@ -7,7 +7,10 @@
 
 #[derive(Copy, Clone)]
 pub struct Argument {
+    #[cfg(bootstrap)]
     pub position: Position,
+    #[cfg(not(bootstrap))]
+    pub position: usize,
     pub format: FormatSpec,
 }
 
@@ -37,12 +40,11 @@
 pub enum Count {
     Is(usize),
     Param(usize),
-    NextParam,
     Implied,
 }
 
+#[cfg(bootstrap)]
 #[derive(Copy, Clone)]
 pub enum Position {
-    Next,
     At(usize),
 }
diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs
index 3606448..4c3b81e 100644
--- a/src/libcore/mem/manually_drop.rs
+++ b/src/libcore/mem/manually_drop.rs
@@ -87,27 +87,28 @@
         slot.value
     }
 
-    /// Takes the contained value out.
+    /// Takes the value from the `ManuallyDrop<T>` container out.
     ///
     /// This method is primarily intended for moving out values in drop.
     /// Instead of using [`ManuallyDrop::drop`] to manually drop the value,
     /// you can use this method to take the value and use it however desired.
-    /// `Drop` will be invoked on the returned value following normal end-of-scope rules.
     ///
-    /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead.
+    /// Whenever possible, it is preferrable to use [`into_inner`][`ManuallyDrop::into_inner`]
+    /// instead, which prevents duplicating the content of the `ManuallyDrop<T>`.
     ///
     /// # Safety
     ///
-    /// This function semantically moves out the contained value without preventing further usage.
-    /// It is up to the user of this method to ensure that this container is not used again.
+    /// This function semantically moves out the contained value without preventing further usage,
+    /// leaving the state of this container unchanged.
+    /// It is your responsibility to ensure that this `ManuallyDrop` is not used again.
     ///
     /// [`ManuallyDrop::drop`]: #method.drop
     /// [`ManuallyDrop::into_inner`]: #method.into_inner
     #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
-    #[unstable(feature = "manually_drop_take", issue = "55422")]
+    #[stable(feature = "manually_drop_take", since = "1.42.0")]
     #[inline]
     pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
-        ManuallyDrop::into_inner(ptr::read(slot))
+        ptr::read(&slot.value)
     }
 }
 
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index d7b351f..c197686 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -169,22 +169,12 @@
 /// i.e., you do not usually have to worry about such issues unless you call `drop_in_place`
 /// manually.
 #[stable(feature = "drop_in_place", since = "1.8.0")]
-#[inline(always)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    real_drop_in_place(&mut *to_drop)
-}
-
-// The real `drop_in_place` -- the one that gets called implicitly when variables go
-// out of scope -- should have a safe reference and not a raw pointer as argument
-// type.  When we drop a local variable, we access it with a pointer that behaves
-// like a safe reference; transmuting that to a raw pointer does not mean we can
-// actually access it with raw pointers.
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
-unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) {
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     // Code here does not matter - this is replaced by the
     // real drop glue by the compiler.
-    real_drop_in_place(to_drop)
+    drop_in_place(to_drop)
 }
 
 /// Creates a null raw pointer.
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 323ce3b6..b65635b 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -37,5 +37,4 @@
 chalk-engine = { version = "0.9.0", default-features=false }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "0.7.1"
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 5a4d7ce..86eab3d 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -8,7 +8,6 @@
 use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
 
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index a200946..77182b9 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -65,7 +65,6 @@
     Region, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_error_codes::*;
 use rustc_errors::{pluralize, struct_span_err};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_hir as hir;
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 70f7987..9947dea 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -13,8 +13,6 @@
 use rustc_span::Span;
 use std::borrow::Cow;
 
-use rustc_error_codes::*;
-
 struct FindLocalByTypeVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
     target_ty: Ty<'tcx>,
diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
index d6e5020..8f4c643 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -5,7 +5,6 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::util::common::ErrorReported;
 
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 2344d40..df37f53 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -5,8 +5,6 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir::{FunctionRetTy, TyKind};
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
     /// an anonymous region, emit an descriptive diagnostic error.
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index 6303104..11dda71 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -5,8 +5,6 @@
 use crate::ty::{self, Region};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub(super) fn note_region_origin(
         &self,
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index ee214be..fe3a5d1 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -15,8 +15,6 @@
 use rustc_hir::Node;
 use rustc_span::Span;
 
-use rustc_error_codes::*;
-
 pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
 
 /// Information about the opaque types whose values we
diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs
index e4af54f..a349b34 100644
--- a/src/librustc/middle/exported_symbols.rs
+++ b/src/librustc/middle/exported_symbols.rs
@@ -32,7 +32,9 @@
 }
 
 impl<'tcx> ExportedSymbol<'tcx> {
-    pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
+    /// This is the symbol name of an instance if it is instantiated in the
+    /// local crate.
+    pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
         match *self {
             ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)),
             ExportedSymbol::Generic(def_id, substs) => {
@@ -50,9 +52,22 @@
                 }
                 ExportedSymbol::Generic(..) | ExportedSymbol::NoDefId(_) => cmp::Ordering::Less,
             },
-            ExportedSymbol::Generic(..) => match *other {
+            ExportedSymbol::Generic(self_def_id, self_substs) => match *other {
                 ExportedSymbol::NonGeneric(_) => cmp::Ordering::Greater,
-                ExportedSymbol::Generic(..) => self.symbol_name(tcx).cmp(&other.symbol_name(tcx)),
+                ExportedSymbol::Generic(other_def_id, other_substs) => {
+                    // We compare the symbol names because they are cached as query
+                    // results which makes them relatively cheap to access repeatedly.
+                    //
+                    // It might be even faster to build a local cache of stable IDs
+                    // for sorting. Exported symbols are really only sorted once
+                    // in order to make the `exported_symbols` query result stable.
+                    let self_symbol_name =
+                        tcx.symbol_name(ty::Instance::new(self_def_id, self_substs));
+                    let other_symbol_name =
+                        tcx.symbol_name(ty::Instance::new(other_def_id, other_substs));
+
+                    self_symbol_name.cmp(&other_symbol_name)
+                }
                 ExportedSymbol::NoDefId(_) => cmp::Ordering::Less,
             },
             ExportedSymbol::NoDefId(self_symbol_name) => match *other {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 643359f..27b7697 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -24,8 +24,6 @@
 use rustc_span::Span;
 use syntax::ast;
 
-use rustc_error_codes::*;
-
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index fdffd12..5571f8f 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -15,8 +15,6 @@
 use rustc_target::spec::PanicStrategy;
 use syntax::ast;
 
-use rustc_error_codes::*;
-
 macro_rules! weak_lang_items {
     ($($name:ident, $item:ident, $sym:ident;)*) => (
 
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 42d896af8..349dbd7 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -16,8 +16,6 @@
 use rustc_target::spec::abi::Abi;
 use std::{any::Any, env, fmt};
 
-use rustc_error_codes::*;
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
 pub enum ErrorHandled {
     /// Already reported a lint or an error for this evaluation.
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ccd2a96..3a7c650 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -215,6 +215,31 @@
         }
     }
 
+    /// Returns a partially initialized MIR body containing only a list of basic blocks.
+    ///
+    /// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It
+    /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
+    /// crate.
+    pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
+        Body {
+            phase: MirPhase::Build,
+            basic_blocks,
+            source_scopes: IndexVec::new(),
+            yield_ty: None,
+            generator_drop: None,
+            generator_layout: None,
+            local_decls: IndexVec::new(),
+            user_type_annotations: IndexVec::new(),
+            arg_count: 0,
+            spread_arg: None,
+            span: DUMMY_SP,
+            control_flow_destroyed: Vec::new(),
+            generator_kind: None,
+            var_debug_info: Vec::new(),
+            ignore_interior_mut_in_const_validation: false,
+        }
+    }
+
     #[inline]
     pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
         &self.basic_blocks
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index e7a4c5b..51ce575 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -1,7 +1,6 @@
 use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId};
 use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext};
 use crate::session::config::OptLevel;
-use crate::traits::TraitQueryMode;
 use crate::ty::print::obsolete::DefPathBasedNames;
 use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
 use rustc_data_structures::base_n;
@@ -168,9 +167,7 @@
             MonoItem::GlobalAsm(..) => return true,
         };
 
-        // We shouldn't encounter any overflow here, so we use TraitQueryMode::Standard\
-        // to report an error if overflow somehow occurs.
-        tcx.substitute_normalize_and_test_predicates((def_id, &substs, TraitQueryMode::Standard))
+        tcx.substitute_normalize_and_test_predicates((def_id, &substs))
     }
 
     pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index a20e011..deb2d6a 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -557,6 +557,9 @@
             desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
         }
 
+        /// The `symbol_name` query provides the symbol name for calling a
+        /// given instance from the local crate. In particular, it will also
+        /// look up the correct symbol name of instances from upstream crates.
         query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName {
             no_force
             desc { "computing the symbol for `{}`", key }
@@ -971,6 +974,11 @@
     }
 
     Linking {
+        /// The list of symbols exported from the given crate.
+        ///
+        /// - All names contained in `exported_symbols(cnum)` are guaranteed to
+        ///   correspond to a publicly visible symbol in `cnum` machine code.
+        /// - The `exported_symbols` sets of different crates do not intersect.
         query exported_symbols(_: CrateNum)
             -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>> {
             desc { "exported_symbols" }
@@ -1148,11 +1156,11 @@
             desc { "normalizing `{:?}`", goal }
         }
 
-        query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>, traits::TraitQueryMode)) -> bool {
+        query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
             no_force
             desc { |tcx|
-                "testing substituted normalized predicates in mode {:?}:`{}`",
-                key.2, tcx.def_path_str(key.0)
+                "testing substituted normalized predicates:`{}`",
+                tcx.def_path_str(key.0)
             }
         }
 
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 89b28ae..c97c5c2 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -337,7 +337,10 @@
                 &Err(SelectionError::Unimplemented) => {
                     if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) {
                         already_visited.remove(&pred);
-                        self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred));
+                        self.add_user_pred(
+                            &mut user_computed_preds,
+                            ty::Predicate::Trait(pred, ast::Constness::NotConst),
+                        );
                         predicates.push_back(pred);
                     } else {
                         debug!(
@@ -405,7 +408,7 @@
         let mut should_add_new = true;
         user_computed_preds.retain(|&old_pred| {
             match (&new_pred, old_pred) {
-                (&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => {
+                (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => {
                     if new_trait.def_id() == old_trait.def_id() {
                         let new_substs = new_trait.skip_binder().trait_ref.substs;
                         let old_substs = old_trait.skip_binder().trait_ref.substs;
@@ -627,7 +630,7 @@
             // We check this by calling is_of_param on the relevant types
             // from the various possible predicates
             match &predicate {
-                &ty::Predicate::Trait(p) => {
+                &ty::Predicate::Trait(p, _) => {
                     if self.is_param_no_infer(p.skip_binder().trait_ref.substs)
                         && !only_projections
                         && is_new_pred
diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs
index 5b80448..84bfc86 100644
--- a/src/librustc/traits/engine.rs
+++ b/src/librustc/traits/engine.rs
@@ -1,6 +1,6 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
-use crate::ty::{self, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_hir::def_id::DefId;
 
 use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
@@ -33,7 +33,7 @@
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: trait_ref.to_predicate(),
+                predicate: trait_ref.without_const().to_predicate(),
             },
         );
     }
diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs
index db31739..d1c369d 100644
--- a/src/librustc/traits/error_reporting/mod.rs
+++ b/src/librustc/traits/error_reporting/mod.rs
@@ -19,7 +19,9 @@
 use crate::ty::fast_reject;
 use crate::ty::fold::TypeFolder;
 use crate::ty::SubtypePredicate;
-use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{
+    self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -30,8 +32,6 @@
 use std::fmt;
 use syntax::ast;
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_fulfillment_errors(
         &self,
@@ -130,7 +130,7 @@
         }
 
         let (cond, error) = match (cond, error) {
-            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error),
+            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error),
             _ => {
                 // FIXME: make this work in other cases too.
                 return false;
@@ -138,7 +138,7 @@
         };
 
         for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
-            if let ty::Predicate::Trait(implication) = implication {
+            if let ty::Predicate::Trait(implication, _) = implication {
                 let error = error.to_poly_trait_ref();
                 let implication = implication.to_poly_trait_ref();
                 // FIXME: I'm just not taking associated types at all here.
@@ -530,7 +530,7 @@
                     return;
                 }
                 match obligation.predicate {
-                    ty::Predicate::Trait(ref trait_predicate) => {
+                    ty::Predicate::Trait(ref trait_predicate, _) => {
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
@@ -583,7 +583,7 @@
                             "{}",
                             message.unwrap_or_else(|| format!(
                                 "the trait bound `{}` is not satisfied{}",
-                                trait_ref.to_predicate(),
+                                trait_ref.without_const().to_predicate(),
                                 post_message,
                             ))
                         );
@@ -695,7 +695,10 @@
                                 trait_pred
                             });
                             let unit_obligation = Obligation {
-                                predicate: ty::Predicate::Trait(predicate),
+                                predicate: ty::Predicate::Trait(
+                                    predicate,
+                                    ast::Constness::NotConst,
+                                ),
                                 ..obligation.clone()
                             };
                             if self.predicate_may_hold(&unit_obligation) {
@@ -988,7 +991,7 @@
     ) -> PredicateObligation<'tcx> {
         let new_trait_ref =
             ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) };
-        Obligation::new(cause, param_env, new_trait_ref.to_predicate())
+        Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate())
     }
 }
 
@@ -1076,7 +1079,7 @@
         }
 
         let mut err = match predicate {
-            ty::Predicate::Trait(ref data) => {
+            ty::Predicate::Trait(ref data, _) => {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
                 debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
@@ -1269,8 +1272,11 @@
             )
             .value;
 
-            let obligation =
-                Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate());
+            let obligation = Obligation::new(
+                ObligationCause::dummy(),
+                param_env,
+                cleaned_pred.without_const().to_predicate(),
+            );
 
             self.predicate_may_hold(&obligation)
         })
diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index c09fd30..4559007 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -6,7 +6,7 @@
 use crate::infer::InferCtxt;
 use crate::traits::object_safety::object_safety_violations;
 use crate::ty::TypeckTables;
-use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 
 use rustc_errors::{
     error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
@@ -20,8 +20,6 @@
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     crate fn suggest_restricting_param_bound(
         &self,
@@ -50,7 +48,7 @@
                             } else {
                                 " where"
                             },
-                            trait_ref.to_predicate(),
+                            trait_ref.without_const().to_predicate(),
                         ),
                         Applicability::MachineApplicable,
                     );
@@ -340,8 +338,11 @@
             let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
             let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
             let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
-            let new_obligation =
-                Obligation::new(ObligationCause::dummy(), param_env, new_trait_ref.to_predicate());
+            let new_obligation = Obligation::new(
+                ObligationCause::dummy(),
+                param_env,
+                new_trait_ref.without_const().to_predicate(),
+            );
             if self.predicate_must_hold_modulo_regions(&new_obligation) {
                 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                     // We have a very specific type of error, where just borrowing this argument
@@ -1122,7 +1123,7 @@
         // the type. The last generator has information about where the bound was introduced. At
         // least one generator should be present for this diagnostic to be modified.
         let (mut trait_ref, mut target_ty) = match obligation.predicate {
-            ty::Predicate::Trait(p) => {
+            ty::Predicate::Trait(p, _) => {
                 (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty()))
             }
             _ => (None, None),
@@ -1545,7 +1546,7 @@
                 err.note(&format!("required because it appears within the type `{}`", ty));
                 obligated_types.push(ty);
 
-                let parent_predicate = parent_trait_ref.to_predicate();
+                let parent_predicate = parent_trait_ref.without_const().to_predicate();
                 if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
                     self.note_obligation_cause_code(
                         err,
@@ -1562,7 +1563,7 @@
                     parent_trait_ref.print_only_trait_path(),
                     parent_trait_ref.skip_binder().self_ty()
                 ));
-                let parent_predicate = parent_trait_ref.to_predicate();
+                let parent_predicate = parent_trait_ref.without_const().to_predicate();
                 self.note_obligation_cause_code(
                     err,
                     &parent_predicate,
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 9e5abc8..0aac6fb 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -16,7 +16,6 @@
 use super::{ConstEvalFailure, Unimplemented};
 use super::{FulfillmentError, FulfillmentErrorCode};
 use super::{ObligationCause, PredicateObligation};
-use crate::traits::TraitQueryMode;
 
 impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
     type Predicate = ty::Predicate<'tcx>;
@@ -63,9 +62,6 @@
     // a snapshot (they don't *straddle* a snapshot, so there
     // is no trouble there).
     usable_in_snapshot: bool,
-
-    // The `TraitQueryMode` used when constructing a `SelectionContext`
-    query_mode: TraitQueryMode,
 }
 
 #[derive(Clone, Debug)]
@@ -79,26 +75,12 @@
 static_assert_size!(PendingPredicateObligation<'_>, 136);
 
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
-    /// Creates a new fulfillment context with `TraitQueryMode::Standard`
-    /// You almost always want to use this instead of `with_query_mode`
+    /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             register_region_obligations: true,
             usable_in_snapshot: false,
-            query_mode: TraitQueryMode::Standard,
-        }
-    }
-
-    /// Creates a new fulfillment context with the specified query mode.
-    /// This should only be used when you want to ignore overflow,
-    /// rather than reporting it as an error.
-    pub fn with_query_mode(query_mode: TraitQueryMode) -> FulfillmentContext<'tcx> {
-        FulfillmentContext {
-            predicates: ObligationForest::new(),
-            register_region_obligations: true,
-            usable_in_snapshot: false,
-            query_mode,
         }
     }
 
@@ -107,7 +89,6 @@
             predicates: ObligationForest::new(),
             register_region_obligations: true,
             usable_in_snapshot: true,
-            query_mode: TraitQueryMode::Standard,
         }
     }
 
@@ -116,7 +97,6 @@
             predicates: ObligationForest::new(),
             register_region_obligations: false,
             usable_in_snapshot: false,
-            query_mode: TraitQueryMode::Standard,
         }
     }
 
@@ -237,7 +217,7 @@
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
-        let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode);
+        let mut selcx = SelectionContext::new(infcx);
         self.select(&mut selcx)
     }
 
@@ -331,7 +311,7 @@
         }
 
         match obligation.predicate {
-            ty::Predicate::Trait(ref data) => {
+            ty::Predicate::Trait(ref data, _) => {
                 let trait_obligation = obligation.with(data.clone());
 
                 if data.is_global() {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 2e5da2b..daaba95 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -29,7 +29,7 @@
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::subst::{InternalSubsts, SubstsRef};
-use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness};
 use crate::util::common::ErrorReported;
 use chalk_engine;
 use rustc_hir as hir;
@@ -95,7 +95,7 @@
 }
 
 /// The mode that trait queries run in.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum TraitQueryMode {
     // Standard/un-canonicalized queries get accurate
     // spans etc. passed in and hence can do reasonable
@@ -732,7 +732,7 @@
         param_env,
         cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID),
         recursion_depth: 0,
-        predicate: trait_ref.to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(),
     };
 
     let result = infcx.predicate_must_hold_modulo_regions(&obligation);
@@ -1014,17 +1014,16 @@
 /// environment. If this returns false, then either normalize
 /// encountered an error or one of the predicates did not hold. Used
 /// when creating vtables to check for unsatisfiable methods.
-fn normalize_and_test_predicates<'tcx>(
+pub fn normalize_and_test_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: Vec<ty::Predicate<'tcx>>,
-    mode: TraitQueryMode,
 ) -> bool {
-    debug!("normalize_and_test_predicates(predicates={:?}, mode={:?})", predicates, mode);
+    debug!("normalize_and_test_predicates(predicates={:?})", predicates);
 
     let result = tcx.infer_ctxt().enter(|infcx| {
         let param_env = ty::ParamEnv::reveal_all();
-        let mut selcx = SelectionContext::with_query_mode(&infcx, mode);
-        let mut fulfill_cx = FulfillmentContext::with_query_mode(mode);
+        let mut selcx = SelectionContext::new(&infcx);
+        let mut fulfill_cx = FulfillmentContext::new();
         let cause = ObligationCause::dummy();
         let Normalized { value: predicates, obligations } =
             normalize(&mut selcx, param_env, cause.clone(), &predicates);
@@ -1044,12 +1043,12 @@
 
 fn substitute_normalize_and_test_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: (DefId, SubstsRef<'tcx>, TraitQueryMode),
+    key: (DefId, SubstsRef<'tcx>),
 ) -> bool {
     debug!("substitute_normalize_and_test_predicates(key={:?})", key);
 
     let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
-    let result = normalize_and_test_predicates(tcx, predicates, key.2);
+    let result = normalize_and_test_predicates(tcx, predicates);
 
     debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
     result
@@ -1102,10 +1101,7 @@
             // Note that this method could then never be called, so we
             // do not want to try and codegen it, in that case (see #23435).
             let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-            // We don't expect overflow here, so report an error if it somehow ends
-            // up happening.
-            if !normalize_and_test_predicates(tcx, predicates.predicates, TraitQueryMode::Standard)
-            {
+            if !normalize_and_test_predicates(tcx, predicates.predicates) {
                 debug!("vtable_methods: predicates do not hold");
                 return None;
             }
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index ce57fb8..15f81bb 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -12,7 +12,7 @@
 
 use crate::traits::{self, Obligation, ObligationCause};
 use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
@@ -234,7 +234,7 @@
         .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
         .any(|predicate| {
             match predicate {
-                ty::Predicate::Trait(ref data) => {
+                ty::Predicate::Trait(ref data, _) => {
                     // In the case of a trait predicate, we can skip the "self" type.
                     data.skip_binder().input_types().skip(1).any(has_self_ty)
                 }
@@ -285,7 +285,7 @@
     let predicates = tcx.predicates_of(def_id);
     let predicates = predicates.instantiate_identity(tcx).predicates;
     elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
-        ty::Predicate::Trait(ref trait_pred) => {
+        ty::Predicate::Trait(ref trait_pred, _) => {
             trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
         }
         ty::Predicate::Projection(..)
@@ -585,6 +585,7 @@
             def_id: unsize_did,
             substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
         }
+        .without_const()
         .to_predicate();
 
         // U: Trait<Arg1, ..., ArgN>
@@ -598,7 +599,7 @@
                     }
                 });
 
-            ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
+            ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate()
         };
 
         let caller_bounds: Vec<Predicate<'tcx>> = param_env
@@ -620,6 +621,7 @@
             def_id: dispatch_from_dyn_did,
             substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
         }
+        .without_const()
         .to_predicate();
 
         Obligation::new(ObligationCause::dummy(), param_env, predicate)
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs
index 1afe153..669ec5c 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc/traits/on_unimplemented.rs
@@ -11,8 +11,6 @@
 use syntax::ast::{MetaItem, NestedMetaItem};
 use syntax::attr;
 
-use rustc_error_codes::*;
-
 #[derive(Clone, Debug)]
 pub struct OnUnimplementedFormatString(Symbol);
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 5bc211a..62672a7 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -16,7 +16,7 @@
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use crate::ty::fold::{TypeFoldable, TypeFolder};
 use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -738,7 +738,12 @@
     depth: usize,
 ) -> PredicateObligation<'tcx> {
     let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
-    Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() }
+    Obligation {
+        cause,
+        recursion_depth: depth,
+        param_env,
+        predicate: trait_ref.without_const().to_predicate(),
+    }
 }
 
 /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
@@ -772,7 +777,7 @@
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.to_predicate(),
+        predicate: trait_ref.without_const().to_predicate(),
     };
     let tcx = selcx.infcx().tcx;
     let def_id = projection_ty.item_def_id;
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index 34866b6..2e5ef5a 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -6,8 +6,6 @@
 use rustc_span::source_map::Span;
 use std::iter::FromIterator;
 
-use rustc_error_codes::*;
-
 impl<'cx, 'tcx> At<'cx, 'tcx> {
     /// Given a type `ty` of some value being dropped, computes a set
     /// of "kinds" (types, regions) that must be outlive the execution
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index c0a0cbe..15870ec 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -24,7 +24,7 @@
         // `&T`, accounts for about 60% percentage of the predicates
         // we have to prove. No need to canonicalize and all that for
         // such cases.
-        if let Predicate::Trait(trait_ref) = key.value.predicate {
+        if let Predicate::Trait(trait_ref, _) = key.value.predicate {
             if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
                 if trait_ref.def_id() == sized_def_id {
                     if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) {
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index fb1c468..ac1ca4d 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -37,7 +37,7 @@
 use crate::ty::fast_reject;
 use crate::ty::relate::TypeRelation;
 use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_hir::def_id::DefId;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -51,7 +51,7 @@
 use std::fmt::{self, Display};
 use std::iter;
 use std::rc::Rc;
-use syntax::attr;
+use syntax::{ast, attr};
 
 pub struct SelectionContext<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
@@ -718,7 +718,7 @@
         }
 
         match obligation.predicate {
-            ty::Predicate::Trait(ref t) => {
+            ty::Predicate::Trait(ref t, _) => {
                 debug_assert!(!t.has_escaping_bound_vars());
                 let obligation = obligation.with(t.clone());
                 self.evaluate_trait_predicate_recursively(previous_stack, obligation)
@@ -945,7 +945,9 @@
             // trait refs. This is important because it's only a cycle
             // if the regions match exactly.
             let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
-            let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate));
+            let cycle = cycle.map(|stack| {
+                ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst)
+            });
             if self.coinductive_match(cycle) {
                 debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
                 Some(EvaluatedToOk)
@@ -1060,7 +1062,7 @@
 
     fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
         let result = match predicate {
-            ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
+            ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
             _ => false,
         };
         debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
@@ -1417,6 +1419,8 @@
 
         debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
 
+        let needs_infer = stack.obligation.predicate.needs_infer();
+
         // If there are STILL multiple candidates, we can further
         // reduce the list by dropping duplicates -- including
         // resolving specializations.
@@ -1424,7 +1428,11 @@
             let mut i = 0;
             while i < candidates.len() {
                 let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
-                    self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
+                    self.candidate_should_be_dropped_in_favor_of(
+                        &candidates[i],
+                        &candidates[j],
+                        needs_infer,
+                    )
                 });
                 if is_dup {
                     debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
@@ -2258,6 +2266,7 @@
         &mut self,
         victim: &EvaluatedCandidate<'tcx>,
         other: &EvaluatedCandidate<'tcx>,
+        needs_infer: bool,
     ) -> bool {
         if victim.candidate == other.candidate {
             return true;
@@ -2339,10 +2348,55 @@
                     match victim.candidate {
                         ImplCandidate(victim_def) => {
                             let tcx = self.tcx();
-                            return tcx.specializes((other_def, victim_def))
-                                || tcx
-                                    .impls_are_allowed_to_overlap(other_def, victim_def)
-                                    .is_some();
+                            if tcx.specializes((other_def, victim_def)) {
+                                return true;
+                            }
+                            return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+                                Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+                                    // Subtle: If the predicate we are evaluating has inference
+                                    // variables, do *not* allow discarding candidates due to
+                                    // marker trait impls.
+                                    //
+                                    // Without this restriction, we could end up accidentally
+                                    // constrainting inference variables based on an arbitrarily
+                                    // chosen trait impl.
+                                    //
+                                    // Imagine we have the following code:
+                                    //
+                                    // ```rust
+                                    // #[marker] trait MyTrait {}
+                                    // impl MyTrait for u8 {}
+                                    // impl MyTrait for bool {}
+                                    // ```
+                                    //
+                                    // And we are evaluating the predicate `<_#0t as MyTrait>`.
+                                    //
+                                    // During selection, we will end up with one candidate for each
+                                    // impl of `MyTrait`. If we were to discard one impl in favor
+                                    // of the other, we would be left with one candidate, causing
+                                    // us to "successfully" select the predicate, unifying
+                                    // _#0t with (for example) `u8`.
+                                    //
+                                    // However, we have no reason to believe that this unification
+                                    // is correct - we've essentially just picked an arbitrary
+                                    // *possibility* for _#0t, and required that this be the *only*
+                                    // possibility.
+                                    //
+                                    // Eventually, we will either:
+                                    // 1) Unify all inference variables in the predicate through
+                                    // some other means (e.g. type-checking of a function). We will
+                                    // then be in a position to drop marker trait candidates
+                                    // without constraining inference variables (since there are
+                                    // none left to constrin)
+                                    // 2) Be left with some unconstrained inference variables. We
+                                    // will then correctly report an inference error, since the
+                                    // existence of multiple marker trait impls tells us nothing
+                                    // about which one should actually apply.
+                                    !needs_infer
+                                }
+                                Some(_) => true,
+                                None => false,
+                            };
                         }
                         ParamCandidate(ref cand) => {
                             // Prefer the impl to a global where clause candidate.
@@ -3314,7 +3368,7 @@
                     tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                     tcx.mk_substs_trait(source, &[]),
                 );
-                nested.push(predicate_to_obligation(tr.to_predicate()));
+                nested.push(predicate_to_obligation(tr.without_const().to_predicate()));
 
                 // If the type is `Foo + 'a`, ensure that the type
                 // being cast to `Foo + 'a` outlives `'a`:
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index f5199db..e559ea3 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -25,8 +25,6 @@
 use super::util::impl_trait_ref_and_oblig;
 use super::{FulfillmentContext, SelectionContext};
 
-use rustc_error_codes::*;
-
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
 pub struct OverlapError {
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index c176f13..9509b62 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -163,7 +163,7 @@
                         tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
                     {
                         match overlap_kind {
-                            ty::ImplOverlapKind::Permitted => {}
+                            ty::ImplOverlapKind::Permitted { marker: _ } => {}
                             ty::ImplOverlapKind::Issue33140 => {
                                 last_lint = Some(FutureCompatOverlapError {
                                     error: overlap_error(overlap),
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index f058a4d..f3bd98b 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -4,7 +4,7 @@
 
 use crate::ty::outlives::Component;
 use crate::ty::subst::{GenericArg, Subst, SubstsRef};
-use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -13,8 +13,8 @@
 
 fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
     match *pred {
-        ty::Predicate::Trait(ref data) => {
-            ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data))
+        ty::Predicate::Trait(ref data, constness) => {
+            ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
         }
 
         ty::Predicate::RegionOutlives(ref data) => {
@@ -99,14 +99,14 @@
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> Elaborator<'tcx> {
-    elaborate_predicates(tcx, vec![trait_ref.to_predicate()])
+    elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()])
 }
 
 pub fn elaborate_trait_refs<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
 ) -> Elaborator<'tcx> {
-    let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect();
+    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect();
     elaborate_predicates(tcx, predicates)
 }
 
@@ -127,7 +127,7 @@
     fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
         let tcx = self.visited.tcx;
         match *predicate {
-            ty::Predicate::Trait(ref data) => {
+            ty::Predicate::Trait(ref data, _) => {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
@@ -358,7 +358,7 @@
     fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.tcx;
         let trait_ref = item.trait_ref();
-        let pred = trait_ref.to_predicate();
+        let pred = trait_ref.without_const().to_predicate();
 
         debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
 
@@ -370,13 +370,9 @@
 
         // Don't recurse if this trait alias is already on the stack for the DFS search.
         let anon_pred = anonymize_predicate(tcx, &pred);
-        if item
-            .path
-            .iter()
-            .rev()
-            .skip(1)
-            .any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred)
-        {
+        if item.path.iter().rev().skip(1).any(|(tr, _)| {
+            anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred
+        }) {
             return false;
         }
 
@@ -471,7 +467,7 @@
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(pred) = self.base_iterator.next() {
-            if let ty::Predicate::Trait(data) = pred {
+            if let ty::Predicate::Trait(data, _) = pred {
                 return Some(data.to_poly_trait_ref());
             }
         }
@@ -545,7 +541,12 @@
     trait_ref: ty::TraitRef<'tcx>,
     recursion_depth: usize,
 ) -> PredicateObligation<'tcx> {
-    Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
+    Obligation {
+        cause,
+        param_env,
+        recursion_depth,
+        predicate: trait_ref.without_const().to_predicate(),
+    }
 }
 
 pub fn predicate_for_trait_def(
diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs
index 869ba53..a0cb844 100644
--- a/src/librustc/traits/wf.rs
+++ b/src/librustc/traits/wf.rs
@@ -3,7 +3,7 @@
 use crate::middle::lang_items;
 use crate::traits::{self, AssocTypeBoundData};
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{kw, Ident};
@@ -62,7 +62,7 @@
 
     // (*) ok to skip binders, because wf code is prepared for it
     match *predicate {
-        ty::Predicate::Trait(ref t) => {
+        ty::Predicate::Trait(ref t, _) => {
             wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
         }
         ty::Predicate::RegionOutlives(..) => {}
@@ -245,7 +245,7 @@
                             }
                         }
                     }
-                    ty::Predicate::Trait(proj) => {
+                    ty::Predicate::Trait(proj, _) => {
                         // An associated item obligation born out of the `trait` failed to be met.
                         // Point at the `impl` that failed the obligation, the associated item that
                         // needed to meet the obligation, and the definition of that associated item,
@@ -350,7 +350,7 @@
         self.compute_trait_ref(&trait_ref, Elaborate::None);
 
         if !data.has_escaping_bound_vars() {
-            let predicate = trait_ref.to_predicate();
+            let predicate = trait_ref.without_const().to_predicate();
             let cause = self.cause(traits::ProjectionWf(data));
             self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
@@ -378,7 +378,11 @@
                 def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                 substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
             };
-            self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
+            self.out.push(traits::Obligation::new(
+                cause,
+                self.param_env,
+                trait_ref.without_const().to_predicate(),
+            ));
         }
     }
 
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index b16db6a..0dddca9 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -150,6 +150,15 @@
     }
 }
 
+impl TypeFoldable<'tcx> for syntax::ast::Constness {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
 /// The `TypeFolder` trait defines the actual *folding*. There is a
 /// method defined for every foldable type. Each of these has a
 /// default implementation that does an "identity" fold. Within each
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 9be50d1..1ea695e 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -141,7 +141,12 @@
     }
 
     pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
-        tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+        match *self {
+            InstanceDef::Item(def_id) => {
+                tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+            }
+            _ => false,
+        }
     }
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 282136f..0470ab2 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -52,7 +52,7 @@
 use std::ops::Range;
 use std::slice;
 use std::{mem, ptr};
-use syntax::ast::{self, Ident, Name, NodeId};
+use syntax::ast::{self, Constness, Ident, Name, NodeId};
 use syntax::attr;
 
 pub use self::sty::BoundRegion::*;
@@ -1068,7 +1068,11 @@
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
-    Trait(PolyTraitPredicate<'tcx>),
+    ///
+    /// A trait predicate will have `Constness::Const` if it originates
+    /// from a bound on a `const fn` without the `?const` opt-out (e.g.,
+    /// `const fn foobar<Foo: Bar>() {}`).
+    Trait(PolyTraitPredicate<'tcx>, Constness),
 
     /// `where 'a: 'b`
     RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
@@ -1191,8 +1195,8 @@
 
         let substs = &trait_ref.skip_binder().substs;
         match *self {
-            Predicate::Trait(ref binder) => {
-                Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)))
+            Predicate::Trait(ref binder, constness) => {
+                Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness)
             }
             Predicate::Subtype(ref binder) => {
                 Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs)))
@@ -1336,15 +1340,33 @@
     fn to_predicate(&self) -> Predicate<'tcx>;
 }
 
-impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
     fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() }))
+        ty::Predicate::Trait(
+            ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }),
+            self.constness,
+        )
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> {
     fn to_predicate(&self) -> Predicate<'tcx> {
-        ty::Predicate::Trait(self.to_poly_trait_predicate())
+        ty::Predicate::Trait(
+            ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }),
+            self.constness,
+        )
+    }
+}
+
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
+    fn to_predicate(&self) -> Predicate<'tcx> {
+        ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
+    }
+}
+
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> {
+    fn to_predicate(&self) -> Predicate<'tcx> {
+        ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
     }
 }
 
@@ -1413,7 +1435,7 @@
     /// with depth 0 are bound by the predicate.
     pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a {
         match *self {
-            ty::Predicate::Trait(ref data) => {
+            ty::Predicate::Trait(ref data, _) => {
                 WalkTysIter::InputTypes(data.skip_binder().input_types())
             }
             ty::Predicate::Subtype(binder) => {
@@ -1439,7 +1461,7 @@
 
     pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
         match *self {
-            Predicate::Trait(ref t) => Some(t.to_poly_trait_ref()),
+            Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
             Predicate::Projection(..)
             | Predicate::Subtype(..)
             | Predicate::RegionOutlives(..)
@@ -1700,6 +1722,33 @@
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ConstnessAnd<T> {
+    pub constness: Constness,
+    pub value: T,
+}
+
+// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that
+// the constness of trait bounds is being propagated correctly.
+pub trait WithConstness: Sized {
+    #[inline]
+    fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> {
+        ConstnessAnd { constness, value: self }
+    }
+
+    #[inline]
+    fn with_const(self) -> ConstnessAnd<Self> {
+        self.with_constness(Constness::Const)
+    }
+
+    #[inline]
+    fn without_const(self) -> ConstnessAnd<Self> {
+        self.with_constness(Constness::NotConst)
+    }
+}
+
+impl<T> WithConstness for T {}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
 pub struct ParamEnvAnd<'tcx, T> {
     pub param_env: ParamEnv<'tcx>,
@@ -2591,7 +2640,12 @@
 #[derive(Debug, PartialEq, Eq)]
 pub enum ImplOverlapKind {
     /// These impls are always allowed to overlap.
-    Permitted,
+    Permitted {
+        /// Whether or not the impl is permitted due to the trait being
+        /// a marker trait (a trait with #[marker], or a trait with
+        /// no associated items and #![feature(overlapping_marker_traits)] enabled)
+        marker: bool,
+    },
     /// These impls are allowed to overlap, but that raises
     /// an issue #33140 future-compatibility warning.
     ///
@@ -2711,7 +2765,7 @@
         if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
             || self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
         {
-            return Some(ImplOverlapKind::Permitted);
+            return Some(ImplOverlapKind::Permitted { marker: false });
         }
 
         match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) {
@@ -2721,7 +2775,7 @@
                     "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)",
                     def_id1, def_id2
                 );
-                return Some(ImplOverlapKind::Permitted);
+                return Some(ImplOverlapKind::Permitted { marker: false });
             }
             (ImplPolarity::Positive, ImplPolarity::Negative)
             | (ImplPolarity::Negative, ImplPolarity::Positive) => {
@@ -2757,7 +2811,7 @@
                 "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)",
                 def_id1, def_id2
             );
-            Some(ImplOverlapKind::Permitted)
+            Some(ImplOverlapKind::Permitted { marker: true })
         } else {
             if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {
                 if let Some(self_ty2) = self.issue33140_self_ty(def_id2) {
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8b1b2bb..9091de5 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1791,7 +1791,12 @@
 
     ty::Predicate<'tcx> {
         match *self {
-            ty::Predicate::Trait(ref data) => p!(print(data)),
+            ty::Predicate::Trait(ref data, constness) => {
+                if let ast::Constness::Const = constness {
+                    p!(write("const "));
+                }
+                p!(print(data))
+            }
             ty::Predicate::Subtype(ref predicate) => p!(print(predicate)),
             ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)),
             ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)),
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index 3fb3720..cbf335a 100644
--- a/src/librustc/ty/query/keys.rs
+++ b/src/librustc/ty/query/keys.rs
@@ -125,15 +125,6 @@
     }
 }
 
-impl<'tcx> Key for (DefId, SubstsRef<'tcx>, traits::TraitQueryMode) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
-    }
-    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
-        self.0.default_span(tcx)
-    }
-}
-
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
     fn query_crate(&self) -> CrateNum {
         self.1.def_id().krate
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 84efbe2..117a38c 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -25,8 +25,6 @@
 use std::mem;
 use std::ptr;
 
-use rustc_error_codes::*;
-
 pub struct QueryCache<'tcx, D: QueryConfig<'tcx> + ?Sized> {
     pub(super) results: FxHashMap<D::Key, QueryValue<D::Value>>,
     pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>,
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 62e895a..25f9dc5 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -15,6 +15,7 @@
 use std::fmt;
 use std::rc::Rc;
 use std::sync::Arc;
+use syntax::ast;
 
 impl fmt::Debug for ty::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -234,7 +235,12 @@
 impl fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ty::Predicate::Trait(ref a) => a.fmt(f),
+            ty::Predicate::Trait(ref a, constness) => {
+                if let ast::Constness::Const = constness {
+                    write!(f, "const ")?;
+                }
+                a.fmt(f)
+            }
             ty::Predicate::Subtype(ref pair) => pair.fmt(f),
             ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f),
             ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f),
@@ -474,7 +480,9 @@
     type Lifted = ty::Predicate<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match *self {
-            ty::Predicate::Trait(ref binder) => tcx.lift(binder).map(ty::Predicate::Trait),
+            ty::Predicate::Trait(ref binder, constness) => {
+                tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness))
+            }
             ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype),
             ty::Predicate::RegionOutlives(ref binder) => {
                 tcx.lift(binder).map(ty::Predicate::RegionOutlives)
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 8423612..13f623a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -12,7 +12,9 @@
 use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
+use crate::ty::{
+    self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
+};
 use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
@@ -665,14 +667,16 @@
     pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
         use crate::ty::ToPredicate;
         match *self.skip_binder() {
-            ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(),
+            ExistentialPredicate::Trait(tr) => {
+                Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate()
+            }
             ExistentialPredicate::Projection(p) => {
                 ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty)))
             }
             ExistentialPredicate::AutoTrait(did) => {
                 let trait_ref =
                     Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) });
-                trait_ref.to_predicate()
+                trait_ref.without_const().to_predicate()
             }
         }
     }
diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml
index 408e9a7..4b786d6 100644
--- a/src/librustc_ast_lowering/Cargo.toml
+++ b/src/librustc_ast_lowering/Cargo.toml
@@ -17,7 +17,6 @@
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
 rustc_span = { path = "../librustc_span" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_session = { path = "../librustc_session" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index 2866a16..5dc855e 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -2,7 +2,6 @@
 
 use rustc::bug;
 use rustc_data_structures::thin_vec::ThinVec;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -849,10 +848,7 @@
         }
     }
 
-    fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
         let len = self.catch_scopes.len();
         self.catch_scopes.push(catch_id);
 
@@ -868,10 +864,7 @@
         result
     }
 
-    fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
         // We're no longer in the base loop's condition; we're in another loop.
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
@@ -893,10 +886,7 @@
         result
     }
 
-    fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = true;
 
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 6da2d45..2025d0c 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -3,7 +3,6 @@
 
 use rustc::arena::Arena;
 use rustc::bug;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -67,9 +66,8 @@
         if let Some(hir_id) = item_hir_id {
             self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
                 let this = &mut ItemLowerer { lctx: this };
-                if let ItemKind::Impl { ref of_trait, .. } = item.kind {
-                    if of_trait.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) {
-                        this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+                if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind {
+                    if constness == Constness::Const {
                         this.lctx
                             .diagnostic()
                             .span_err(item.span, "const trait impls are not yet implemented");
@@ -366,6 +364,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 generics: ref ast_generics,
                 of_trait: ref trait_ref,
                 self_ty: ref ty,
@@ -422,6 +421,7 @@
                     unsafety,
                     polarity,
                     defaultness: self.lower_defaultness(defaultness, true /* [1] */),
+                    constness,
                     generics,
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 76a0889..284ede3 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -41,7 +41,6 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
@@ -1250,10 +1249,16 @@
                     let bounds =
                         this.arena.alloc_from_iter(bounds.iter().filter_map(
                             |bound| match *bound {
-                                GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
+                                GenericBound::Trait(ref ty, TraitBoundModifier::None)
+                                | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => {
                                     Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
                                 }
-                                GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+                                // `?const ?Bound` will cause an error during AST validation
+                                // anyways, so treat it like `?Bound` as compilation proceeds.
+                                GenericBound::Trait(_, TraitBoundModifier::Maybe)
+                                | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
+                                    None
+                                }
                                 GenericBound::Outlives(ref lifetime) => {
                                     if lifetime_bound.is_none() {
                                         lifetime_bound = Some(this.lower_lifetime(lifetime));
@@ -2158,10 +2163,6 @@
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
-        if p.trait_ref.constness.is_some() {
-            self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
-        }
-
         let bound_generic_params = self.lower_generic_params(
             &p.bound_generic_params,
             &NodeMap::default(),
@@ -2300,7 +2301,13 @@
     fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
         match f {
             TraitBoundModifier::None => hir::TraitBoundModifier::None,
-            TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
+            TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
+
+            // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
+            // placeholder for compilation to proceed.
+            TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
+                hir::TraitBoundModifier::Maybe
+            }
         }
     }
 
diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs
index 65347d3..e5f7df6 100644
--- a/src/librustc_ast_lowering/path.rs
+++ b/src/librustc_ast_lowering/path.rs
@@ -3,7 +3,6 @@
 
 use rustc::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
 use rustc::span_bug;
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, PartialRes, Res};
diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml
index 2d45e28..25b1ace 100644
--- a/src/librustc_ast_passes/Cargo.toml
+++ b/src/librustc_ast_passes/Cargo.toml
@@ -12,7 +12,6 @@
 log = "0.4"
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 2370145..152086b 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -23,8 +23,6 @@
 use syntax::visit::{self, Visitor};
 use syntax::walk_list;
 
-use rustc_error_codes::*;
-
 /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
 #[derive(Clone, Copy)]
 enum BoundContext {
@@ -616,6 +614,7 @@
                 unsafety,
                 polarity,
                 defaultness: _,
+                constness: _,
                 generics: _,
                 of_trait: Some(_),
                 ref self_ty,
@@ -649,6 +648,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 generics: _,
                 of_trait: None,
                 self_ty: _,
@@ -676,6 +676,12 @@
                         .note("only trait implementations may be annotated with default")
                         .emit();
                 }
+                if constness == Constness::Const {
+                    self.err_handler()
+                        .struct_span_err(item.span, "inherent impls cannot be `const`")
+                        .note("only trait implementations may be annotated with `const`")
+                        .emit();
+                }
             }
             ItemKind::Fn(ref sig, ref generics, _) => {
                 self.visit_fn_header(&sig.header);
@@ -909,23 +915,20 @@
     }
 
     fn visit_param_bound(&mut self, bound: &'a GenericBound) {
-        if let GenericBound::Trait(poly, maybe_bound) = bound {
-            match poly.trait_ref.constness {
-                Some(Constness::NotConst) => {
-                    if *maybe_bound == TraitBoundModifier::Maybe {
-                        self.err_handler()
-                            .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
-                    }
-
-                    if let Some(ctx) = self.bound_context {
-                        let msg = format!("`?const` is not permitted in {}", ctx.description());
-                        self.err_handler().span_err(bound.span(), &msg);
-                    }
+        match bound {
+            GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
+                if let Some(ctx) = self.bound_context {
+                    let msg = format!("`?const` is not permitted in {}", ctx.description());
+                    self.err_handler().span_err(bound.span(), &msg);
                 }
-
-                Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"),
-                None => {}
             }
+
+            GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
+                self.err_handler()
+                    .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
+            }
+
+            _ => {}
         }
 
         visit::walk_param_bound(self, bound)
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index 4610728..9531274 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -1,4 +1,3 @@
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Handler};
 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue, UnstableFeatures};
diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml
index f291eaf..3ce7f5d 100644
--- a/src/librustc_builtin_macros/Cargo.toml
+++ b/src/librustc_builtin_macros/Cargo.toml
@@ -22,4 +22,3 @@
 syntax = { path = "../libsyntax" }
 rustc_expand = { path = "../librustc_expand" }
 rustc_span = { path = "../librustc_span" }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs
index a6b45e0..4723544 100644
--- a/src/librustc_builtin_macros/asm.rs
+++ b/src/librustc_builtin_macros/asm.rs
@@ -12,8 +12,6 @@
 use syntax::token::{self, Token};
 use syntax::tokenstream::{self, TokenStream};
 
-use rustc_error_codes::*;
-
 enum State {
     Asm,
     Outputs,
diff --git a/src/librustc_builtin_macros/deriving/default.rs b/src/librustc_builtin_macros/deriving/default.rs
index 72c41ad..b4f059e 100644
--- a/src/librustc_builtin_macros/deriving/default.rs
+++ b/src/librustc_builtin_macros/deriving/default.rs
@@ -9,8 +9,6 @@
 use syntax::ast::{Expr, MetaItem};
 use syntax::ptr::P;
 
-use rustc_error_codes::*;
-
 pub fn expand_deriving_default(
     cx: &mut ExtCtxt<'_>,
     span: Span,
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index d346dbc8..f891801 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -709,6 +709,7 @@
                 unsafety,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
+                constness: ast::Constness::NotConst,
                 generics: trait_generics,
                 of_trait: opt_trait_ref,
                 self_ty: self_type,
diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs
index 9aa7623..914dcdf 100644
--- a/src/librustc_builtin_macros/deriving/mod.rs
+++ b/src/librustc_builtin_macros/deriving/mod.rs
@@ -160,6 +160,7 @@
             unsafety: ast::Unsafety::Normal,
             polarity: ast::ImplPolarity::Positive,
             defaultness: ast::Defaultness::Final,
+            constness: ast::Constness::NotConst,
             generics,
             of_trait: Some(trait_ref),
             self_ty: self_type,
diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs
index 6fca74e..3f4e24c 100644
--- a/src/librustc_builtin_macros/format.rs
+++ b/src/librustc_builtin_macros/format.rs
@@ -590,17 +590,6 @@
             parse::NextArgument(ref arg) => {
                 // Build the position
                 let pos = {
-                    let pos = |c, arg| {
-                        let mut path = Context::rtpath(self.ecx, "Position");
-                        path.push(self.ecx.ident_of(c, sp));
-                        match arg {
-                            Some(i) => {
-                                let arg = self.ecx.expr_usize(sp, i);
-                                self.ecx.expr_call_global(sp, path, vec![arg])
-                            }
-                            None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
-                        }
-                    };
                     match arg.position {
                         parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => {
                             // Map to index in final generated argument array
@@ -615,7 +604,7 @@
                                     arg_idx
                                 }
                             };
-                            pos("At", Some(arg_idx))
+                            self.ecx.expr_usize(sp, arg_idx)
                         }
 
                         // should never be the case, because names are already
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 52613fe..4823fe1 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -58,9 +58,10 @@
 
     let cg_opts = sess.opts.cg.llvm_args.iter();
     let tg_opts = sess.target.target.options.llvm_args.iter();
+    let sess_args = cg_opts.chain(tg_opts);
 
     let user_specified_args: FxHashSet<_> =
-        cg_opts.chain(tg_opts).map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect();
+        sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect();
 
     {
         // This adds the given argument to LLVM. Unless `force` is true
@@ -107,7 +108,7 @@
         // during inlining. Unfortunately these may block other optimizations.
         add("-preserve-alignment-assumptions-during-inlining=false", false);
 
-        for arg in &sess.opts.cg.llvm_args {
+        for arg in sess_args {
             add(&(*arg), true);
         }
     }
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index eb192b2..9f8b4e7 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -32,5 +32,4 @@
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_index = { path = "../librustc_index" }
 rustc_target = { path = "../librustc_target" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 11f5d30..4679f650 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -1103,7 +1103,11 @@
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
         if level.is_below_threshold(export_threshold) {
-            symbols.push(symbol.symbol_name(tcx).to_string());
+            symbols.push(symbol_export::symbol_name_for_instance_in_crate(
+                tcx,
+                symbol,
+                LOCAL_CRATE,
+            ));
         }
     }
 
@@ -1124,12 +1128,7 @@
                     continue;
                 }
 
-                // FIXME rust-lang/rust#64319, rust-lang/rust#64872:
-                // We want to block export of generics from dylibs,
-                // but we must fix rust-lang/rust#65890 before we can
-                // do that robustly.
-
-                symbols.push(symbol.symbol_name(tcx).to_string());
+                symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
             }
         }
     }
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index a406b5f..bd44b4a 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -8,6 +8,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::Instance;
 use rustc::ty::{SymbolName, TyCtxt};
+use rustc_codegen_utils::symbol_names;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
@@ -358,3 +359,32 @@
         SymbolExportLevel::Rust
     }
 }
+
+/// This is the symbol name of the given instance instantiated in a specific crate.
+pub fn symbol_name_for_instance_in_crate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    symbol: ExportedSymbol<'tcx>,
+    instantiating_crate: CrateNum,
+) -> String {
+    // If this is something instantiated in the local crate then we might
+    // already have cached the name as a query result.
+    if instantiating_crate == LOCAL_CRATE {
+        return symbol.symbol_name_for_local_instance(tcx).to_string();
+    }
+
+    // This is something instantiated in an upstream crate, so we have to use
+    // the slower (because uncached) version of computing the symbol name.
+    match symbol {
+        ExportedSymbol::NonGeneric(def_id) => symbol_names::symbol_name_for_instance_in_crate(
+            tcx,
+            Instance::mono(tcx, def_id),
+            instantiating_crate,
+        ),
+        ExportedSymbol::Generic(def_id, substs) => symbol_names::symbol_name_for_instance_in_crate(
+            tcx,
+            Instance::new(def_id, substs),
+            instantiating_crate,
+        ),
+        ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(),
+    }
+}
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 801bfde..049faff 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -2,7 +2,7 @@
 use super::link::{self, get_linker, remove};
 use super::linker::LinkerInfo;
 use super::lto::{self, SerializedModule};
-use super::symbol_export::ExportedSymbols;
+use super::symbol_export::{symbol_name_for_instance_in_crate, ExportedSymbols};
 use crate::{
     CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
     RLIB_BYTECODE_EXTENSION,
@@ -956,7 +956,7 @@
             let symbols = tcx
                 .exported_symbols(cnum)
                 .iter()
-                .map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl))
+                .map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl))
                 .collect();
             Arc::new(symbols)
         };
diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs
index e4531a7..28b61e0 100644
--- a/src/librustc_codegen_ssa/common.rs
+++ b/src/librustc_codegen_ssa/common.rs
@@ -13,8 +13,6 @@
 use crate::traits::BuilderMethods;
 use rustc_hir as hir;
 
-use rustc_error_codes::*;
-
 pub enum IntPredicate {
     IntEQ,
     IntNE,
diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs
index 574c06d..8422c62 100644
--- a/src/librustc_codegen_ssa/mir/statement.rs
+++ b/src/librustc_codegen_ssa/mir/statement.rs
@@ -7,8 +7,6 @@
 use crate::traits::BuilderMethods;
 use crate::traits::*;
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
         debug!("codegen_statement(statement={:?})", statement);
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 450dcd3..96a74f9 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -91,8 +91,9 @@
 use rustc::mir::mono::{InstantiationMode, MonoItem};
 use rustc::session::config::SymbolManglingVersion;
 use rustc::ty::query::Providers;
+use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Instance, TyCtxt};
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::Node;
 
 use rustc_span::symbol::Symbol;
@@ -102,15 +103,70 @@
 mod legacy;
 mod v0;
 
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        symbol_name: |tcx, instance| ty::SymbolName { name: symbol_name(tcx, instance) },
-
-        ..*providers
-    };
+/// This function computes the symbol name for the given `instance` and the
+/// given instantiating crate. That is, if you know that instance X is
+/// instantiated in crate Y, this is the symbol name this instance would have.
+pub fn symbol_name_for_instance_in_crate(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    instantiating_crate: CrateNum,
+) -> String {
+    compute_symbol_name(tcx, instance, || instantiating_crate)
 }
 
-fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers { symbol_name: symbol_name_provider, ..*providers };
+}
+
+// The `symbol_name` query provides the symbol name for calling a given
+// instance from the local crate. In particular, it will also look up the
+// correct symbol name of instances from upstream crates.
+fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
+    let symbol_name = compute_symbol_name(tcx, instance, || {
+        // This closure determines the instantiating crate for instances that
+        // need an instantiating-crate-suffix for their symbol name, in order
+        // to differentiate between local copies.
+        //
+        // For generics we might find re-usable upstream instances. For anything
+        // else we rely on their being a local copy available.
+
+        if is_generic(instance.substs) {
+            let def_id = instance.def_id();
+
+            if !def_id.is_local() && tcx.sess.opts.share_generics() {
+                // If we are re-using a monomorphization from another crate,
+                // we have to compute the symbol hash accordingly.
+                let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
+
+                upstream_monomorphizations
+                    .and_then(|monos| monos.get(&instance.substs).cloned())
+                    // If there is no instance available upstream, there'll be
+                    // one in the current crate.
+                    .unwrap_or(LOCAL_CRATE)
+            } else {
+                // For generic functions defined in the current crate, there
+                // can be no upstream instances. Also, if we don't share
+                // generics, we'll instantiate a local copy too.
+                LOCAL_CRATE
+            }
+        } else {
+            // For non-generic things that need to avoid naming conflicts, we
+            // always instantiate a copy in the local crate.
+            LOCAL_CRATE
+        }
+    });
+
+    ty::SymbolName { name: Symbol::intern(&symbol_name) }
+}
+
+/// Computes the symbol name for the given instance. This function will call
+/// `compute_instantiating_crate` if it needs to factor the instantiating crate
+/// into the symbol name.
+fn compute_symbol_name(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    compute_instantiating_crate: impl FnOnce() -> CrateNum,
+) -> String {
     let def_id = instance.def_id();
     let substs = instance.substs;
 
@@ -121,11 +177,11 @@
     if def_id.is_local() {
         if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
             let disambiguator = tcx.sess.local_crate_disambiguator();
-            return Symbol::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator));
+            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
         }
         if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
             let disambiguator = tcx.sess.local_crate_disambiguator();
-            return Symbol::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator));
+            return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
         }
     }
 
@@ -162,29 +218,28 @@
             || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
         {
             if let Some(name) = attrs.link_name {
-                return name;
+                return name.to_string();
             }
-            return tcx.item_name(def_id);
+            return tcx.item_name(def_id).to_string();
         }
     }
 
     if let Some(name) = attrs.export_name {
         // Use provided name
-        return name;
+        return name.to_string();
     }
 
     if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
         // Don't mangle
-        return tcx.item_name(def_id);
+        return tcx.item_name(def_id).to_string();
     }
 
-    let is_generic = substs.non_erasable_generics().next().is_some();
     let avoid_cross_crate_conflicts =
         // If this is an instance of a generic function, we also hash in
         // the ID of the instantiating crate. This avoids symbol conflicts
         // in case the same instances is emitted in two crates of the same
         // project.
-        is_generic ||
+        is_generic(substs) ||
 
         // If we're dealing with an instance of a function that's inlined from
         // another crate but we're marking it as globally shared to our
@@ -197,25 +252,8 @@
             _ => false,
         };
 
-    let instantiating_crate = if avoid_cross_crate_conflicts {
-        Some(if is_generic {
-            if !def_id.is_local() && tcx.sess.opts.share_generics() {
-                // If we are re-using a monomorphization from another crate,
-                // we have to compute the symbol hash accordingly.
-                let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
-
-                upstream_monomorphizations
-                    .and_then(|monos| monos.get(&substs).cloned())
-                    .unwrap_or(LOCAL_CRATE)
-            } else {
-                LOCAL_CRATE
-            }
-        } else {
-            LOCAL_CRATE
-        })
-    } else {
-        None
-    };
+    let instantiating_crate =
+        if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
 
     // Pick the crate responsible for the symbol mangling version, which has to:
     // 1. be stable for each instance, whether it's being defined or imported
@@ -232,10 +270,12 @@
         tcx.symbol_mangling_version(mangling_version_crate)
     };
 
-    let mangled = match mangling_version {
+    match mangling_version {
         SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
         SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
-    };
+    }
+}
 
-    Symbol::intern(&mangled)
+fn is_generic(substs: SubstsRef<'_>) -> bool {
+    substs.non_erasable_generics().next().is_some()
 }
diff --git a/src/librustc_error_codes/error_codes/E0201.md b/src/librustc_error_codes/error_codes/E0201.md
index bdbf02f..0e1a7b7 100644
--- a/src/librustc_error_codes/error_codes/E0201.md
+++ b/src/librustc_error_codes/error_codes/E0201.md
@@ -1,7 +1,7 @@
-It is an error to define two associated items (like methods, associated types,
-associated functions, etc.) with the same identifier.
+Two associated items (like methods, associated types, associated functions,
+etc.) were defined with the same identifier.
 
-For example:
+Erroneous code example:
 
 ```compile_fail,E0201
 struct Foo(u8);
diff --git a/src/librustc_error_codes/error_codes/E0204.md b/src/librustc_error_codes/error_codes/E0204.md
index 3156901..96e4475 100644
--- a/src/librustc_error_codes/error_codes/E0204.md
+++ b/src/librustc_error_codes/error_codes/E0204.md
@@ -1,21 +1,24 @@
-An attempt to implement the `Copy` trait for a struct failed because one of the
-fields does not implement `Copy`. To fix this, you must implement `Copy` for the
-mentioned field. Note that this may not be possible, as in the example of
+The `Copy` trait was implemented on a type which contains a field that doesn't
+implement the `Copy` trait.
+
+Erroneous code example:
 
 ```compile_fail,E0204
 struct Foo {
-    foo : Vec<u32>,
+    foo: Vec<u32>,
 }
 
-impl Copy for Foo { }
+impl Copy for Foo { } // error!
 ```
 
-This fails because `Vec<T>` does not implement `Copy` for any `T`.
+The `Copy` trait is implemented by default only on primitive types. If your
+type only contains primitive types, you'll be able to implement `Copy` on it.
+Otherwise, it won't be possible.
 
 Here's another example that will fail:
 
 ```compile_fail,E0204
-#[derive(Copy)]
+#[derive(Copy)] // error!
 struct Foo<'a> {
     ty: &'a mut bool,
 }
diff --git a/src/librustc_error_codes/lib.rs b/src/librustc_error_codes/lib.rs
index 14210fd..f051fdd 100644
--- a/src/librustc_error_codes/lib.rs
+++ b/src/librustc_error_codes/lib.rs
@@ -6,16 +6,8 @@
         pub static DIAGNOSTICS: &[(&str, &str)] = &[
             $( (stringify!($ecode), $message), )*
         ];
-
-        $(
-            pub const $ecode: () = ();
-        )*
-        $(
-            pub const $code: () = ();
-        )*
     )
 }
 
 mod error_codes;
-
-pub use error_codes::*;
+pub use error_codes::DIAGNOSTICS;
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 73f66d5..3c217c1 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -399,8 +399,5 @@
 
 #[macro_export]
 macro_rules! error_code {
-    ($code:ident) => {{
-        let _ = $code;
-        $crate::DiagnosticId::Error(stringify!($code).to_owned())
-    }};
+    ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
 }
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index bd3d6b5..11f94ab 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -110,7 +110,7 @@
     }
 
     pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
-        ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID }
+        ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
     }
 
     pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 1fef871b..b62a7e4 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -364,6 +364,7 @@
 pub enum TraitBoundModifier {
     None,
     Maybe,
+    MaybeConst,
 }
 
 /// The AST represents all type param bounds as types.
@@ -2440,6 +2441,7 @@
         unsafety: Unsafety,
         polarity: ImplPolarity,
         defaultness: Defaultness,
+        constness: Constness,
         generics: Generics<'hir>,
 
         /// The trait being implemented, if any.
diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs
index 1a73e41..539a0ee 100644
--- a/src/librustc_hir/intravisit.rs
+++ b/src/librustc_hir/intravisit.rs
@@ -570,6 +570,7 @@
             unsafety: _,
             defaultness: _,
             polarity: _,
+            constness: _,
             ref generics,
             ref of_trait,
             ref self_ty,
diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs
index 6c7d419..b9598c9 100644
--- a/src/librustc_hir/print.rs
+++ b/src/librustc_hir/print.rs
@@ -631,6 +631,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 ref generics,
                 ref of_trait,
                 ref self_ty,
@@ -647,6 +648,10 @@
                     self.s.space();
                 }
 
+                if constness == ast::Constness::Const {
+                    self.word_nbsp("const");
+                }
+
                 if let hir::ImplPolarity::Negative = polarity {
                     self.s.word("!");
                 }
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index abf9f96..7e23e70 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -13,7 +13,6 @@
 unicode-security = "0.0.2"
 rustc = { path = "../librustc" }
 rustc_errors = { path = "../librustc_errors" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs
index 42ec878..3b8cce5 100644
--- a/src/librustc_lint/context.rs
+++ b/src/librustc_lint/context.rs
@@ -26,7 +26,6 @@
 use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId};
diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs
index bbc3e57..d5bbdc5 100644
--- a/src/librustc_lint/levels.rs
+++ b/src/librustc_lint/levels.rs
@@ -6,7 +6,6 @@
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 26cbda3..15158c0 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -144,7 +144,7 @@
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
                     for (predicate, _) in cx.tcx.predicates_of(def).predicates {
-                        if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
+                        if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate {
                             let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
                             let def_id = trait_ref.def_id;
                             let descr_pre =
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index 0a0bcb1..6da5847 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -26,7 +26,6 @@
 rustc_expand = { path = "../librustc_expand" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_span = { path = "../librustc_span" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 181f872..351e72d 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -12,7 +12,6 @@
 use rustc::ty::TyCtxt;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index 4745ad0..5782164 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -241,8 +241,6 @@
 
 use log::{debug, info, warn};
 
-use rustc_error_codes::*;
-
 #[derive(Clone)]
 struct CrateMismatch {
     path: PathBuf,
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index 9426d5e..bbf6973 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -3,7 +3,6 @@
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index f9b61b9..00881e3 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -29,4 +29,3 @@
 rustc_span = { path = "../librustc_span" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 947bbef..c9a1c46 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -27,12 +27,12 @@
     TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_span::{Span, DUMMY_SP};
+use syntax::ast;
 
 use crate::dataflow::move_paths::MoveData;
 use crate::dataflow::FlowAtLocation;
@@ -1931,12 +1931,15 @@
                                         traits::ObligationCauseCode::RepeatVec(should_suggest),
                                     ),
                                     self.param_env,
-                                    ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
-                                        trait_ref: ty::TraitRef::new(
-                                            self.tcx().lang_items().copy_trait().unwrap(),
-                                            tcx.mk_substs_trait(ty, &[]),
-                                        ),
-                                    })),
+                                    ty::Predicate::Trait(
+                                        ty::Binder::bind(ty::TraitPredicate {
+                                            trait_ref: ty::TraitRef::new(
+                                                self.tcx().lang_items().copy_trait().unwrap(),
+                                                tcx.mk_substs_trait(ty, &[]),
+                                            ),
+                                        }),
+                                        ast::Constness::NotConst,
+                                    ),
                                 ),
                                 &traits::SelectionError::Unimplemented,
                                 false,
@@ -2574,7 +2577,10 @@
         category: ConstraintCategory,
     ) {
         self.prove_predicates(
-            Some(ty::Predicate::Trait(trait_ref.to_poly_trait_ref().to_poly_trait_predicate())),
+            Some(ty::Predicate::Trait(
+                trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
+                ast::Constness::NotConst,
+            )),
             locations,
             category,
         );
diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs
deleted file mode 100644
index d2ca4f1..0000000
--- a/src/librustc_mir/dataflow/generic.rs
+++ /dev/null
@@ -1,595 +0,0 @@
-//! Dataflow analysis with arbitrary transfer functions.
-//!
-//! This module is a work in progress. You should instead use `BitDenotation` in
-//! `librustc_mir/dataflow/mod.rs` and encode your transfer function as a [gen/kill set][gk]. In
-//! doing so, your analysis will run faster and you will be able to generate graphviz diagrams for
-//! debugging with no extra effort. The interface in this module is intended only for dataflow
-//! problems that cannot be expressed using gen/kill sets.
-//!
-//! FIXME(ecstaticmorse): In the long term, the plan is to preserve the existing `BitDenotation`
-//! interface, but make `Engine` and `ResultsCursor` the canonical way to perform and inspect a
-//! dataflow analysis. This requires porting the graphviz debugging logic to this module, deciding
-//! on a way to handle the `before` methods in `BitDenotation` and creating an adapter so that
-//! gen-kill problems can still be evaluated efficiently. See the discussion in [#64566] for more
-//! information.
-//!
-//! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
-//! [#64566]: https://github.com/rust-lang/rust/pull/64566
-
-use std::borrow::Borrow;
-use std::cmp::Ordering;
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
-use std::{fs, io, ops};
-
-use rustc::mir::{self, traversal, BasicBlock, Location};
-use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::work_queue::WorkQueue;
-use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_span::symbol::sym;
-
-use crate::dataflow::BottomValue;
-
-mod graphviz;
-
-/// A specific kind of dataflow analysis.
-///
-/// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via
-/// `initialize_start_block` and define a transfer function for each statement or terminator via
-/// the various `effect` methods. The entry set for all other basic blocks is initialized to
-/// `Self::BOTTOM_VALUE`. The dataflow `Engine` then iteratively updates the various entry sets for
-/// each block with the cumulative effects of the transfer functions of all preceding blocks.
-///
-/// You should use an `Engine` to actually run an analysis, and a `ResultsCursor` to inspect the
-/// results of that analysis like so:
-///
-/// ```ignore(cross-crate-imports)
-/// fn do_my_analysis(body: &mir::Body<'tcx>, dead_unwinds: &BitSet<BasicBlock>) {
-///     // `MyAnalysis` implements `Analysis`.
-///     let analysis = MyAnalysis::new();
-///
-///     let results = Engine::new(body, dead_unwinds, analysis).iterate_to_fixpoint();
-///     let mut cursor = ResultsCursor::new(body, results);
-///
-///     for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() {
-///         cursor.seek_after(Location { block: START_BLOCK, statement_index });
-///         let state = cursor.get();
-///         println!("{:?}", state);
-///     }
-/// }
-/// ```
-pub trait Analysis<'tcx>: BottomValue {
-    /// The index type used to access the dataflow state.
-    type Idx: Idx;
-
-    /// A name, used for debugging, that describes this dataflow analysis.
-    ///
-    /// The name should be suitable as part of a filename, so avoid whitespace, slashes or periods
-    /// and try to keep it short.
-    const NAME: &'static str;
-
-    /// How each element of your dataflow state will be displayed during debugging.
-    ///
-    /// By default, this is the `fmt::Debug` representation of `Self::Idx`.
-    fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
-        write!(w, "{:?}", idx)
-    }
-
-    /// The size of each bitvector allocated for each block.
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;
-
-    /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow
-    /// analysis.
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>);
-
-    /// Updates the current dataflow state with the effect of evaluating a statement.
-    fn apply_statement_effect(
-        &self,
-        state: &mut BitSet<Self::Idx>,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    );
-
-    /// Updates the current dataflow state with the effect of evaluating a terminator.
-    ///
-    /// Note that the effect of a successful return from a `Call` terminator should **not** be
-    /// acounted for in this function. That should go in `apply_call_return_effect`. For example,
-    /// in the `InitializedPlaces` analyses, the return place is not marked as initialized here.
-    fn apply_terminator_effect(
-        &self,
-        state: &mut BitSet<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    );
-
-    /// Updates the current dataflow state with the effect of a successful return from a `Call`
-    /// terminator.
-    ///
-    /// This is separated from `apply_terminator_effect` to properly track state across
-    /// unwind edges for `Call`s.
-    fn apply_call_return_effect(
-        &self,
-        state: &mut BitSet<Self::Idx>,
-        block: BasicBlock,
-        func: &mir::Operand<'tcx>,
-        args: &[mir::Operand<'tcx>],
-        return_place: &mir::Place<'tcx>,
-    );
-
-    /// Applies the cumulative effect of an entire basic block to the dataflow state (except for
-    /// `call_return_effect`, which is handled in the `Engine`).
-    ///
-    /// The default implementation calls `statement_effect` for every statement in the block before
-    /// finally calling `terminator_effect`. However, some dataflow analyses are able to coalesce
-    /// transfer functions for an entire block and apply them at once. Such analyses should
-    /// override `block_effect`.
-    fn apply_whole_block_effect(
-        &self,
-        state: &mut BitSet<Self::Idx>,
-        block: BasicBlock,
-        block_data: &mir::BasicBlockData<'tcx>,
-    ) {
-        for (statement_index, stmt) in block_data.statements.iter().enumerate() {
-            let location = Location { block, statement_index };
-            self.apply_statement_effect(state, stmt, location);
-        }
-
-        let location = Location { block, statement_index: block_data.statements.len() };
-        self.apply_terminator_effect(state, block_data.terminator(), location);
-    }
-
-    /// Applies the cumulative effect of a sequence of statements (and possibly a terminator)
-    /// within a single basic block.
-    ///
-    /// When called with `0..block_data.statements.len() + 1` as the statement range, this function
-    /// is equivalent to `apply_whole_block_effect`.
-    fn apply_partial_block_effect(
-        &self,
-        state: &mut BitSet<Self::Idx>,
-        block: BasicBlock,
-        block_data: &mir::BasicBlockData<'tcx>,
-        mut range: ops::Range<usize>,
-    ) {
-        if range.is_empty() {
-            return;
-        }
-
-        // The final location might be a terminator, so iterate through all statements until the
-        // final one, then check to see whether the final one is a statement or terminator.
-        //
-        // This can't cause the range to wrap-around since we check that the range contains at
-        // least one element above.
-        range.end -= 1;
-        let final_location = Location { block, statement_index: range.end };
-
-        for statement_index in range {
-            let location = Location { block, statement_index };
-            let stmt = &block_data.statements[statement_index];
-            self.apply_statement_effect(state, stmt, location);
-        }
-
-        if final_location.statement_index == block_data.statements.len() {
-            let terminator = block_data.terminator();
-            self.apply_terminator_effect(state, terminator, final_location);
-        } else {
-            let stmt = &block_data.statements[final_location.statement_index];
-            self.apply_statement_effect(state, stmt, final_location);
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug)]
-enum CursorPosition {
-    AtBlockStart(BasicBlock),
-    After(Location),
-}
-
-impl CursorPosition {
-    fn block(&self) -> BasicBlock {
-        match *self {
-            Self::AtBlockStart(block) => block,
-            Self::After(Location { block, .. }) => block,
-        }
-    }
-}
-
-type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
-
-/// Inspect the results of dataflow analysis.
-///
-/// This cursor has linear performance when visiting statements in a block in order. Visiting
-/// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements
-/// in that block.
-pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
-where
-    A: Analysis<'tcx>,
-{
-    body: &'mir mir::Body<'tcx>,
-    results: R,
-    state: BitSet<A::Idx>,
-
-    pos: CursorPosition,
-
-    /// Whether the effects of `apply_call_return_effect` are currently stored in `state`.
-    ///
-    /// This flag ensures that multiple calls to `seek_after_assume_call_returns` with the same
-    /// target only result in one invocation of `apply_call_return_effect`.
-    is_call_return_effect_applied: bool,
-}
-
-impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
-where
-    A: Analysis<'tcx>,
-    R: Borrow<Results<'tcx, A>>,
-{
-    /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`.
-    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
-        ResultsCursor {
-            body,
-            pos: CursorPosition::AtBlockStart(mir::START_BLOCK),
-            is_call_return_effect_applied: false,
-            state: results.borrow().entry_sets[mir::START_BLOCK].clone(),
-            results,
-        }
-    }
-
-    pub fn analysis(&self) -> &A {
-        &self.results.borrow().analysis
-    }
-
-    /// Resets the cursor to the start of the given `block`.
-    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
-        self.state.overwrite(&self.results.borrow().entry_sets[block]);
-        self.pos = CursorPosition::AtBlockStart(block);
-        self.is_call_return_effect_applied = false;
-    }
-
-    /// Updates the cursor to hold the dataflow state immediately before `target`.
-    pub fn seek_before(&mut self, target: Location) {
-        assert!(target <= self.body.terminator_loc(target.block));
-
-        if target.statement_index == 0 {
-            self.seek_to_block_start(target.block);
-        } else {
-            self._seek_after(Location {
-                block: target.block,
-                statement_index: target.statement_index - 1,
-            });
-        }
-    }
-
-    /// Updates the cursor to hold the dataflow state at `target`.
-    ///
-    /// If `target` is a `Call` terminator, `apply_call_return_effect` will not be called. See
-    /// `seek_after_assume_call_returns` if you wish to observe the dataflow state upon a
-    /// successful return.
-    pub fn seek_after(&mut self, target: Location) {
-        assert!(target <= self.body.terminator_loc(target.block));
-
-        // This check ensures the correctness of a call to `seek_after_assume_call_returns`
-        // followed by one to `seek_after` with the same target.
-        if self.is_call_return_effect_applied {
-            self.seek_to_block_start(target.block);
-        }
-
-        self._seek_after(target);
-    }
-
-    /// Equivalent to `seek_after`, but also calls `apply_call_return_effect` if `target` is a
-    /// `Call` terminator whose callee is convergent.
-    pub fn seek_after_assume_call_returns(&mut self, target: Location) {
-        assert!(target <= self.body.terminator_loc(target.block));
-
-        self._seek_after(target);
-
-        if target != self.body.terminator_loc(target.block) {
-            return;
-        }
-
-        let term = self.body.basic_blocks()[target.block].terminator();
-        if let mir::TerminatorKind::Call {
-            destination: Some((return_place, _)), func, args, ..
-        } = &term.kind
-        {
-            if !self.is_call_return_effect_applied {
-                self.is_call_return_effect_applied = true;
-                self.results.borrow().analysis.apply_call_return_effect(
-                    &mut self.state,
-                    target.block,
-                    func,
-                    args,
-                    return_place,
-                );
-            }
-        }
-    }
-
-    fn _seek_after(&mut self, target: Location) {
-        let Location { block: target_block, statement_index: target_index } = target;
-
-        if self.pos.block() != target_block {
-            self.seek_to_block_start(target_block);
-        }
-
-        // If we're in the same block but after the target statement, we need to reset to the start
-        // of the block.
-        if let CursorPosition::After(Location { statement_index: curr_index, .. }) = self.pos {
-            match curr_index.cmp(&target_index) {
-                Ordering::Equal => return,
-                Ordering::Less => {}
-                Ordering::Greater => self.seek_to_block_start(target_block),
-            }
-        }
-
-        // The cursor is now in the same block as the target location pointing at an earlier
-        // statement.
-        debug_assert_eq!(self.pos.block(), target_block);
-        if let CursorPosition::After(Location { statement_index, .. }) = self.pos {
-            debug_assert!(statement_index < target_index);
-        }
-
-        let first_unapplied_statement = match self.pos {
-            CursorPosition::AtBlockStart(_) => 0,
-            CursorPosition::After(Location { statement_index, .. }) => statement_index + 1,
-        };
-
-        let block_data = &self.body.basic_blocks()[target_block];
-        self.results.borrow().analysis.apply_partial_block_effect(
-            &mut self.state,
-            target_block,
-            block_data,
-            first_unapplied_statement..target_index + 1,
-        );
-
-        self.pos = CursorPosition::After(target);
-        self.is_call_return_effect_applied = false;
-    }
-
-    /// Gets the dataflow state at the current location.
-    pub fn get(&self) -> &BitSet<A::Idx> {
-        &self.state
-    }
-}
-
-/// A completed dataflow analysis.
-pub struct Results<'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    analysis: A,
-    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
-}
-
-/// All information required to iterate a dataflow analysis to fixpoint.
-pub struct Engine<'a, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    analysis: A,
-    bits_per_block: usize,
-    tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
-    def_id: DefId,
-    dead_unwinds: &'a BitSet<BasicBlock>,
-    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
-}
-
-impl<A> Engine<'a, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
-        def_id: DefId,
-        dead_unwinds: &'a BitSet<BasicBlock>,
-        analysis: A,
-    ) -> Self {
-        let bits_per_block = analysis.bits_per_block(body);
-
-        let bottom_value_set = if A::BOTTOM_VALUE == true {
-            BitSet::new_filled(bits_per_block)
-        } else {
-            BitSet::new_empty(bits_per_block)
-        };
-
-        let mut entry_sets = IndexVec::from_elem(bottom_value_set, body.basic_blocks());
-        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
-
-        Engine { analysis, bits_per_block, tcx, body, def_id, dead_unwinds, entry_sets }
-    }
-
-    pub fn iterate_to_fixpoint(mut self) -> Results<'tcx, A> {
-        let mut temp_state = BitSet::new_empty(self.bits_per_block);
-
-        let mut dirty_queue: WorkQueue<BasicBlock> =
-            WorkQueue::with_none(self.body.basic_blocks().len());
-
-        for (bb, _) in traversal::reverse_postorder(self.body) {
-            dirty_queue.insert(bb);
-        }
-
-        // Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will
-        // be processed after the ones added above.
-        for bb in self.body.basic_blocks().indices() {
-            dirty_queue.insert(bb);
-        }
-
-        while let Some(bb) = dirty_queue.pop() {
-            let bb_data = &self.body[bb];
-            let on_entry = &self.entry_sets[bb];
-
-            temp_state.overwrite(on_entry);
-            self.analysis.apply_whole_block_effect(&mut temp_state, bb, bb_data);
-
-            self.propagate_bits_into_graph_successors_of(
-                &mut temp_state,
-                (bb, bb_data),
-                &mut dirty_queue,
-            );
-        }
-
-        let Engine { tcx, body, def_id, analysis, entry_sets, .. } = self;
-
-        let results = Results { analysis, entry_sets };
-
-        let attrs = tcx.get_attrs(def_id);
-        if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) {
-            let result = write_dataflow_graphviz_results(body, def_id, &path, &results);
-            if let Err(e) = result {
-                warn!("Failed to write dataflow results to {}: {}", path.display(), e);
-            }
-        }
-
-        results
-    }
-
-    fn propagate_bits_into_graph_successors_of(
-        &mut self,
-        in_out: &mut BitSet<A::Idx>,
-        (bb, bb_data): (BasicBlock, &'a mir::BasicBlockData<'tcx>),
-        dirty_list: &mut WorkQueue<BasicBlock>,
-    ) {
-        match bb_data.terminator().kind {
-            mir::TerminatorKind::Return
-            | mir::TerminatorKind::Resume
-            | mir::TerminatorKind::Abort
-            | mir::TerminatorKind::GeneratorDrop
-            | mir::TerminatorKind::Unreachable => {}
-
-            mir::TerminatorKind::Goto { target }
-            | mir::TerminatorKind::Assert { target, cleanup: None, .. }
-            | mir::TerminatorKind::Yield { resume: target, drop: None, .. }
-            | mir::TerminatorKind::Drop { target, location: _, unwind: None }
-            | mir::TerminatorKind::DropAndReplace { target, value: _, location: _, unwind: None } =>
-            {
-                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
-            }
-
-            mir::TerminatorKind::Yield { resume: target, drop: Some(drop), .. } => {
-                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
-                self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list);
-            }
-
-            mir::TerminatorKind::Assert { target, cleanup: Some(unwind), .. }
-            | mir::TerminatorKind::Drop { target, location: _, unwind: Some(unwind) }
-            | mir::TerminatorKind::DropAndReplace {
-                target,
-                value: _,
-                location: _,
-                unwind: Some(unwind),
-            } => {
-                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
-                if !self.dead_unwinds.contains(bb) {
-                    self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
-                }
-            }
-
-            mir::TerminatorKind::SwitchInt { ref targets, .. } => {
-                for target in targets {
-                    self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
-                }
-            }
-
-            mir::TerminatorKind::Call { cleanup, ref destination, ref func, ref args, .. } => {
-                if let Some(unwind) = cleanup {
-                    if !self.dead_unwinds.contains(bb) {
-                        self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
-                    }
-                }
-
-                if let Some((ref dest_place, dest_bb)) = *destination {
-                    // N.B.: This must be done *last*, after all other
-                    // propagation, as documented in comment above.
-                    self.analysis.apply_call_return_effect(in_out, bb, func, args, dest_place);
-                    self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list);
-                }
-            }
-
-            mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => {
-                self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
-                self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list);
-            }
-
-            mir::TerminatorKind::FalseUnwind { real_target, unwind } => {
-                self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
-                if let Some(unwind) = unwind {
-                    if !self.dead_unwinds.contains(bb) {
-                        self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
-                    }
-                }
-            }
-        }
-    }
-
-    fn propagate_bits_into_entry_set_for(
-        &mut self,
-        in_out: &BitSet<A::Idx>,
-        bb: BasicBlock,
-        dirty_queue: &mut WorkQueue<BasicBlock>,
-    ) {
-        let entry_set = &mut self.entry_sets[bb];
-        let set_changed = self.analysis.join(entry_set, &in_out);
-        if set_changed {
-            dirty_queue.insert(bb);
-        }
-    }
-}
-
-/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and
-/// extracts the path with the given analysis name prepended to the suffix.
-///
-/// Returns `None` if no such attribute exists.
-fn get_dataflow_graphviz_output_path(
-    tcx: TyCtxt<'tcx>,
-    attrs: ty::Attributes<'tcx>,
-    analysis: &str,
-) -> Option<PathBuf> {
-    let mut rustc_mir_attrs = attrs
-        .into_iter()
-        .filter(|attr| attr.check_name(sym::rustc_mir))
-        .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
-
-    let borrowck_graphviz_postflow =
-        rustc_mir_attrs.find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?;
-
-    let path_and_suffix = match borrowck_graphviz_postflow.value_str() {
-        Some(p) => p,
-        None => {
-            tcx.sess.span_err(
-                borrowck_graphviz_postflow.span(),
-                "borrowck_graphviz_postflow requires a path",
-            );
-
-            return None;
-        }
-    };
-
-    // Change "path/suffix.dot" to "path/analysis_name_suffix.dot"
-    let mut ret = PathBuf::from(path_and_suffix.to_string());
-    let suffix = ret.file_name().unwrap();
-
-    let mut file_name: OsString = analysis.into();
-    file_name.push("_");
-    file_name.push(suffix);
-    ret.set_file_name(file_name);
-
-    Some(ret)
-}
-
-fn write_dataflow_graphviz_results<A: Analysis<'tcx>>(
-    body: &mir::Body<'tcx>,
-    def_id: DefId,
-    path: &Path,
-    results: &Results<'tcx, A>,
-) -> io::Result<()> {
-    debug!("printing dataflow results for {:?} to {}", def_id, path.display());
-
-    let mut buf = Vec::new();
-    let graphviz = graphviz::Formatter::new(body, def_id, results);
-
-    dot::render(&graphviz, &mut buf)?;
-    fs::write(path, buf)
-}
diff --git a/src/librustc_mir/dataflow/generic/cursor.rs b/src/librustc_mir/dataflow/generic/cursor.rs
new file mode 100644
index 0000000..d2eff49
--- /dev/null
+++ b/src/librustc_mir/dataflow/generic/cursor.rs
@@ -0,0 +1,265 @@
+//! Random access inspection of the results of a dataflow analysis.
+
+use std::borrow::Borrow;
+
+use rustc::mir::{self, BasicBlock, Location};
+use rustc_index::bit_set::BitSet;
+
+use super::{Analysis, Results};
+
+/// A `ResultsCursor` that borrows the underlying `Results`.
+pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
+
+/// Allows random access inspection of the results of a dataflow analysis.
+///
+/// This cursor only has linear performance within a basic block when its statements are visited in
+/// order. In the worst case—when statements are visited in *reverse* order—performance will be
+/// quadratic in the number of statements in the block. The order in which basic blocks are
+/// inspected has no impact on performance.
+///
+/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
+/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
+pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
+where
+    A: Analysis<'tcx>,
+{
+    body: &'mir mir::Body<'tcx>,
+    results: R,
+    state: BitSet<A::Idx>,
+
+    pos: CursorPosition,
+
+    /// When this flag is set, the cursor is pointing at a `Call` terminator whose call return
+    /// effect has been applied to `state`.
+    ///
+    /// This flag helps to ensure that multiple calls to `seek_after_assume_call_returns` with the
+    /// same target will result in exactly one invocation of `apply_call_return_effect`. It is
+    /// sufficient to clear this only in `seek_to_block_start`, since seeking away from a
+    /// terminator will always require a cursor reset.
+    call_return_effect_applied: bool,
+}
+
+impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
+where
+    A: Analysis<'tcx>,
+    R: Borrow<Results<'tcx, A>>,
+{
+    /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`.
+    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
+        ResultsCursor {
+            body,
+            pos: CursorPosition::BlockStart(mir::START_BLOCK),
+            state: results.borrow().entry_sets[mir::START_BLOCK].clone(),
+            call_return_effect_applied: false,
+            results,
+        }
+    }
+
+    /// Returns the `Analysis` used to generate the underlying results.
+    pub fn analysis(&self) -> &A {
+        &self.results.borrow().analysis
+    }
+
+    /// Returns the dataflow state at the current location.
+    pub fn get(&self) -> &BitSet<A::Idx> {
+        &self.state
+    }
+
+    /// Resets the cursor to the start of the given basic block.
+    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
+        self.state.overwrite(&self.results.borrow().entry_sets[block]);
+        self.pos = CursorPosition::BlockStart(block);
+        self.call_return_effect_applied = false;
+    }
+
+    /// Advances the cursor to hold all effects up to and including to the "before" effect of the
+    /// statement (or terminator) at the given location.
+    ///
+    /// If you wish to observe the full effect of a statement or terminator, not just the "before"
+    /// effect, use `seek_after` or `seek_after_assume_call_returns`.
+    pub fn seek_before(&mut self, target: Location) {
+        assert!(target <= self.body.terminator_loc(target.block));
+        self.seek_(target, false);
+    }
+
+    /// Advances the cursor to hold the full effect of all statements (and possibly closing
+    /// terminators) up to and including the `target`.
+    ///
+    /// If the `target` is a `Call` terminator, any call return effect for that terminator will
+    /// **not** be observed. Use `seek_after_assume_call_returns` if you wish to observe the call
+    /// return effect.
+    pub fn seek_after(&mut self, target: Location) {
+        assert!(target <= self.body.terminator_loc(target.block));
+
+        // If we have already applied the call return effect, we are currently pointing at a `Call`
+        // terminator. Unconditionally reset the dataflow cursor, since there is no way to "undo"
+        // the call return effect.
+        if self.call_return_effect_applied {
+            self.seek_to_block_start(target.block);
+        }
+
+        self.seek_(target, true);
+    }
+
+    /// Advances the cursor to hold all effects up to and including of the statement (or
+    /// terminator) at the given location.
+    ///
+    /// If the `target` is a `Call` terminator, any call return effect for that terminator will
+    /// be observed. Use `seek_after` if you do **not** wish to observe the call return effect.
+    pub fn seek_after_assume_call_returns(&mut self, target: Location) {
+        let terminator_loc = self.body.terminator_loc(target.block);
+        assert!(target.statement_index <= terminator_loc.statement_index);
+
+        self.seek_(target, true);
+
+        if target != terminator_loc {
+            return;
+        }
+
+        let terminator = self.body.basic_blocks()[target.block].terminator();
+        if let mir::TerminatorKind::Call {
+            destination: Some((return_place, _)), func, args, ..
+        } = &terminator.kind
+        {
+            if !self.call_return_effect_applied {
+                self.call_return_effect_applied = true;
+                self.results.borrow().analysis.apply_call_return_effect(
+                    &mut self.state,
+                    target.block,
+                    func,
+                    args,
+                    return_place,
+                );
+            }
+        }
+    }
+
+    fn seek_(&mut self, target: Location, apply_after_effect_at_target: bool) {
+        use CursorPosition::*;
+
+        match self.pos {
+            // Return early if we are already at the target location.
+            Before(curr) if curr == target && !apply_after_effect_at_target => return,
+            After(curr) if curr == target && apply_after_effect_at_target => return,
+
+            // Otherwise, we must reset to the start of the target block if...
+
+            // we are in a different block entirely.
+            BlockStart(block) | Before(Location { block, .. }) | After(Location { block, .. })
+                if block != target.block =>
+            {
+                self.seek_to_block_start(target.block)
+            }
+
+            // we are in the same block but have advanced past the target statement.
+            Before(curr) | After(curr) if curr.statement_index > target.statement_index => {
+                self.seek_to_block_start(target.block)
+            }
+
+            // we have already applied the entire effect of a statement but only wish to observe
+            // its "before" effect.
+            After(curr)
+                if curr.statement_index == target.statement_index
+                    && !apply_after_effect_at_target =>
+            {
+                self.seek_to_block_start(target.block)
+            }
+
+            // N.B., `call_return_effect_applied` is checked in `seek_after`, not here.
+            _ => (),
+        }
+
+        let analysis = &self.results.borrow().analysis;
+        let block_data = &self.body.basic_blocks()[target.block];
+
+        // At this point, the cursor is in the same block as the target location at an earlier
+        // statement.
+        debug_assert_eq!(target.block, self.pos.block());
+
+        // Find the first statement whose transfer function has not yet been applied.
+        let first_unapplied_statement = match self.pos {
+            BlockStart(_) => 0,
+            After(Location { statement_index, .. }) => statement_index + 1,
+
+            // If we have only applied the "before" effect for the current statement, apply the
+            // remainder before continuing.
+            Before(curr) => {
+                if curr.statement_index == block_data.statements.len() {
+                    let terminator = block_data.terminator();
+                    analysis.apply_terminator_effect(&mut self.state, terminator, curr);
+                } else {
+                    let statement = &block_data.statements[curr.statement_index];
+                    analysis.apply_statement_effect(&mut self.state, statement, curr);
+                }
+
+                // If all we needed to do was go from `Before` to `After` in the same statement,
+                // we are now done.
+                if curr.statement_index == target.statement_index {
+                    debug_assert!(apply_after_effect_at_target);
+                    self.pos = After(target);
+                    return;
+                }
+
+                curr.statement_index + 1
+            }
+        };
+
+        // We have now applied all effects prior to `first_unapplied_statement`.
+
+        // Apply the effects of all statements before `target`.
+        let mut location = Location { block: target.block, statement_index: 0 };
+        for statement_index in first_unapplied_statement..target.statement_index {
+            location.statement_index = statement_index;
+            let statement = &block_data.statements[statement_index];
+            analysis.apply_before_statement_effect(&mut self.state, statement, location);
+            analysis.apply_statement_effect(&mut self.state, statement, location);
+        }
+
+        // Apply the effect of the statement (or terminator) at `target`.
+        location.statement_index = target.statement_index;
+        if target.statement_index == block_data.statements.len() {
+            let terminator = &block_data.terminator();
+            analysis.apply_before_terminator_effect(&mut self.state, terminator, location);
+
+            if apply_after_effect_at_target {
+                analysis.apply_terminator_effect(&mut self.state, terminator, location);
+                self.pos = After(target);
+            } else {
+                self.pos = Before(target);
+            }
+        } else {
+            let statement = &block_data.statements[target.statement_index];
+            analysis.apply_before_statement_effect(&mut self.state, statement, location);
+
+            if apply_after_effect_at_target {
+                analysis.apply_statement_effect(&mut self.state, statement, location);
+                self.pos = After(target)
+            } else {
+                self.pos = Before(target);
+            }
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+enum CursorPosition {
+    /// No effects within this block have been applied.
+    BlockStart(BasicBlock),
+
+    /// Only the "before" effect of the statement (or terminator) at this location has been
+    /// applied (along with the effects of all previous statements).
+    Before(Location),
+
+    /// The effects of all statements up to and including the one at this location have been
+    /// applied.
+    After(Location),
+}
+
+impl CursorPosition {
+    fn block(&self) -> BasicBlock {
+        match *self {
+            Self::BlockStart(block) => block,
+            Self::Before(loc) | Self::After(loc) => loc.block,
+        }
+    }
+}
diff --git a/src/librustc_mir/dataflow/generic/engine.rs b/src/librustc_mir/dataflow/generic/engine.rs
new file mode 100644
index 0000000..c0152b0
--- /dev/null
+++ b/src/librustc_mir/dataflow/generic/engine.rs
@@ -0,0 +1,427 @@
+//! A solver for dataflow problems.
+
+use std::ffi::OsString;
+use std::fs;
+use std::path::PathBuf;
+
+use rustc::mir::{self, traversal, BasicBlock, Location};
+use rustc::ty::TyCtxt;
+use rustc_data_structures::work_queue::WorkQueue;
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_span::symbol::{sym, Symbol};
+use syntax::ast;
+
+use super::graphviz;
+use super::{Analysis, GenKillAnalysis, GenKillSet, Results};
+
+/// A solver for dataflow problems.
+pub struct Engine<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    bits_per_block: usize,
+    tcx: TyCtxt<'tcx>,
+    body: &'a mir::Body<'tcx>,
+    def_id: DefId,
+    dead_unwinds: Option<&'a BitSet<BasicBlock>>,
+    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
+    analysis: A,
+
+    /// Cached, cumulative transfer functions for each block.
+    trans_for_block: Option<IndexVec<BasicBlock, GenKillSet<A::Idx>>>,
+}
+
+impl<A> Engine<'a, 'tcx, A>
+where
+    A: GenKillAnalysis<'tcx>,
+{
+    /// Creates a new `Engine` to solve a gen-kill dataflow problem.
+    pub fn new_gen_kill(
+        tcx: TyCtxt<'tcx>,
+        body: &'a mir::Body<'tcx>,
+        def_id: DefId,
+        analysis: A,
+    ) -> Self {
+        let bits_per_block = analysis.bits_per_block(body);
+        let mut trans_for_block =
+            IndexVec::from_elem(GenKillSet::identity(bits_per_block), body.basic_blocks());
+
+        // Compute cumulative block transfer functions.
+        //
+        // FIXME: we may want to skip this if the MIR is acyclic, since we will never access a
+        // block transfer function more than once.
+
+        for (block, block_data) in body.basic_blocks().iter_enumerated() {
+            let trans = &mut trans_for_block[block];
+
+            for (i, statement) in block_data.statements.iter().enumerate() {
+                let loc = Location { block, statement_index: i };
+                analysis.before_statement_effect(trans, statement, loc);
+                analysis.statement_effect(trans, statement, loc);
+            }
+
+            if let Some(terminator) = &block_data.terminator {
+                let loc = Location { block, statement_index: block_data.statements.len() };
+                analysis.before_terminator_effect(trans, terminator, loc);
+                analysis.terminator_effect(trans, terminator, loc);
+            }
+        }
+
+        Self::new(tcx, body, def_id, analysis, Some(trans_for_block))
+    }
+}
+
+impl<A> Engine<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
+    /// function.
+    ///
+    /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
+    /// better performance.
+    pub fn new_generic(
+        tcx: TyCtxt<'tcx>,
+        body: &'a mir::Body<'tcx>,
+        def_id: DefId,
+        analysis: A,
+    ) -> Self {
+        Self::new(tcx, body, def_id, analysis, None)
+    }
+
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        body: &'a mir::Body<'tcx>,
+        def_id: DefId,
+        analysis: A,
+        trans_for_block: Option<IndexVec<BasicBlock, GenKillSet<A::Idx>>>,
+    ) -> Self {
+        let bits_per_block = analysis.bits_per_block(body);
+
+        let bottom_value_set = if A::BOTTOM_VALUE == true {
+            BitSet::new_filled(bits_per_block)
+        } else {
+            BitSet::new_empty(bits_per_block)
+        };
+
+        let mut entry_sets = IndexVec::from_elem(bottom_value_set, body.basic_blocks());
+        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
+
+        Engine {
+            analysis,
+            bits_per_block,
+            tcx,
+            body,
+            def_id,
+            dead_unwinds: None,
+            entry_sets,
+            trans_for_block,
+        }
+    }
+
+    /// Signals that we do not want dataflow state to propagate across unwind edges for these
+    /// `BasicBlock`s.
+    ///
+    /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually
+    /// unwind during execution. Otherwise, your dataflow results will not be correct.
+    pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet<BasicBlock>) -> Self {
+        self.dead_unwinds = Some(dead_unwinds);
+        self
+    }
+
+    /// Computes the fixpoint for this dataflow problem and returns it.
+    pub fn iterate_to_fixpoint(mut self) -> Results<'tcx, A> {
+        let mut temp_state = BitSet::new_empty(self.bits_per_block);
+
+        let mut dirty_queue: WorkQueue<BasicBlock> =
+            WorkQueue::with_none(self.body.basic_blocks().len());
+
+        for (bb, _) in traversal::reverse_postorder(self.body) {
+            dirty_queue.insert(bb);
+        }
+
+        // Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will
+        // be processed after the ones added above.
+        for bb in self.body.basic_blocks().indices() {
+            dirty_queue.insert(bb);
+        }
+
+        while let Some(bb) = dirty_queue.pop() {
+            let bb_data = &self.body[bb];
+            let on_entry = &self.entry_sets[bb];
+
+            temp_state.overwrite(on_entry);
+            self.apply_whole_block_effect(&mut temp_state, bb, bb_data);
+
+            self.propagate_bits_into_graph_successors_of(
+                &mut temp_state,
+                (bb, bb_data),
+                &mut dirty_queue,
+            );
+        }
+
+        let Engine { tcx, body, def_id, trans_for_block, entry_sets, analysis, .. } = self;
+        let results = Results { analysis, entry_sets };
+
+        let res = write_graphviz_results(tcx, def_id, body, &results, trans_for_block);
+        if let Err(e) = res {
+            warn!("Failed to write graphviz dataflow results: {}", e);
+        }
+
+        results
+    }
+
+    /// Applies the cumulative effect of an entire block, excluding the call return effect if one
+    /// exists.
+    fn apply_whole_block_effect(
+        &self,
+        state: &mut BitSet<A::Idx>,
+        block: BasicBlock,
+        block_data: &mir::BasicBlockData<'tcx>,
+    ) {
+        // Use the cached block transfer function if available.
+        if let Some(trans_for_block) = &self.trans_for_block {
+            trans_for_block[block].apply(state);
+            return;
+        }
+
+        // Otherwise apply effects one-by-one.
+
+        for (statement_index, statement) in block_data.statements.iter().enumerate() {
+            let location = Location { block, statement_index };
+            self.analysis.apply_before_statement_effect(state, statement, location);
+            self.analysis.apply_statement_effect(state, statement, location);
+        }
+
+        let terminator = block_data.terminator();
+        let location = Location { block, statement_index: block_data.statements.len() };
+        self.analysis.apply_before_terminator_effect(state, terminator, location);
+        self.analysis.apply_terminator_effect(state, terminator, location);
+    }
+
+    fn propagate_bits_into_graph_successors_of(
+        &mut self,
+        in_out: &mut BitSet<A::Idx>,
+        (bb, bb_data): (BasicBlock, &'a mir::BasicBlockData<'tcx>),
+        dirty_list: &mut WorkQueue<BasicBlock>,
+    ) {
+        use mir::TerminatorKind::*;
+
+        match bb_data.terminator().kind {
+            Return | Resume | Abort | GeneratorDrop | Unreachable => {}
+
+            Goto { target }
+            | Assert { target, cleanup: None, .. }
+            | Yield { resume: target, drop: None, .. }
+            | Drop { target, location: _, unwind: None }
+            | DropAndReplace { target, value: _, location: _, unwind: None } => {
+                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list)
+            }
+
+            Yield { resume: target, drop: Some(drop), .. } => {
+                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
+                self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list);
+            }
+
+            Assert { target, cleanup: Some(unwind), .. }
+            | Drop { target, location: _, unwind: Some(unwind) }
+            | DropAndReplace { target, value: _, location: _, unwind: Some(unwind) } => {
+                self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
+                if self.dead_unwinds.map_or(true, |bbs| !bbs.contains(bb)) {
+                    self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
+                }
+            }
+
+            SwitchInt { ref targets, .. } => {
+                for target in targets {
+                    self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
+                }
+            }
+
+            Call { cleanup, ref destination, ref func, ref args, .. } => {
+                if let Some(unwind) = cleanup {
+                    if self.dead_unwinds.map_or(true, |bbs| !bbs.contains(bb)) {
+                        self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
+                    }
+                }
+
+                if let Some((ref dest_place, dest_bb)) = *destination {
+                    // N.B.: This must be done *last*, otherwise the unwind path will see the call
+                    // return effect.
+                    self.analysis.apply_call_return_effect(in_out, bb, func, args, dest_place);
+                    self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list);
+                }
+            }
+
+            FalseEdges { real_target, imaginary_target } => {
+                self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
+                self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list);
+            }
+
+            FalseUnwind { real_target, unwind } => {
+                self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
+                if let Some(unwind) = unwind {
+                    if self.dead_unwinds.map_or(true, |bbs| !bbs.contains(bb)) {
+                        self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
+                    }
+                }
+            }
+        }
+    }
+
+    fn propagate_bits_into_entry_set_for(
+        &mut self,
+        in_out: &BitSet<A::Idx>,
+        bb: BasicBlock,
+        dirty_queue: &mut WorkQueue<BasicBlock>,
+    ) {
+        let entry_set = &mut self.entry_sets[bb];
+        let set_changed = self.analysis.join(entry_set, &in_out);
+        if set_changed {
+            dirty_queue.insert(bb);
+        }
+    }
+}
+
+// Graphviz
+
+/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
+/// `rustc_mir` attributes.
+fn write_graphviz_results<A>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    body: &mir::Body<'tcx>,
+    results: &Results<'tcx, A>,
+    block_transfer_functions: Option<IndexVec<BasicBlock, GenKillSet<A::Idx>>>,
+) -> std::io::Result<()>
+where
+    A: Analysis<'tcx>,
+{
+    let attrs = match RustcMirAttrs::parse(tcx, def_id) {
+        Ok(attrs) => attrs,
+
+        // Invalid `rustc_mir` attrs will be reported using `span_err`.
+        Err(()) => return Ok(()),
+    };
+
+    let path = match attrs.output_path(A::NAME) {
+        Some(path) => path,
+        None => return Ok(()),
+    };
+
+    let bits_per_block = results.analysis.bits_per_block(body);
+
+    let mut formatter: Box<dyn graphviz::StateFormatter<'tcx, _>> = match attrs.formatter {
+        Some(sym::two_phase) => Box::new(graphviz::TwoPhaseDiff::new(bits_per_block)),
+        Some(sym::gen_kill) => {
+            if let Some(trans_for_block) = block_transfer_functions {
+                Box::new(graphviz::BlockTransferFunc::new(body, trans_for_block))
+            } else {
+                Box::new(graphviz::SimpleDiff::new(bits_per_block))
+            }
+        }
+
+        // Default to the `SimpleDiff` output style.
+        _ => Box::new(graphviz::SimpleDiff::new(bits_per_block)),
+    };
+
+    debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+    let mut buf = Vec::new();
+
+    let graphviz = graphviz::Formatter::new(body, def_id, results, &mut *formatter);
+    dot::render(&graphviz, &mut buf)?;
+    fs::write(&path, buf)?;
+    Ok(())
+}
+
+#[derive(Default)]
+struct RustcMirAttrs {
+    basename_and_suffix: Option<PathBuf>,
+    formatter: Option<Symbol>,
+}
+
+impl RustcMirAttrs {
+    fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<Self, ()> {
+        let attrs = tcx.get_attrs(def_id);
+
+        let mut result = Ok(());
+        let mut ret = RustcMirAttrs::default();
+
+        let rustc_mir_attrs = attrs
+            .into_iter()
+            .filter(|attr| attr.check_name(sym::rustc_mir))
+            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
+
+        for attr in rustc_mir_attrs {
+            let attr_result = if attr.check_name(sym::borrowck_graphviz_postflow) {
+                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
+                    let path = PathBuf::from(s.to_string());
+                    match path.file_name() {
+                        Some(_) => Ok(path),
+                        None => {
+                            tcx.sess.span_err(attr.span(), "path must end in a filename");
+                            Err(())
+                        }
+                    }
+                })
+            } else if attr.check_name(sym::borrowck_graphviz_format) {
+                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
+                    sym::gen_kill | sym::two_phase => Ok(s),
+                    _ => {
+                        tcx.sess.span_err(attr.span(), "unknown formatter");
+                        Err(())
+                    }
+                })
+            } else {
+                Ok(())
+            };
+
+            result = result.and(attr_result);
+        }
+
+        result.map(|()| ret)
+    }
+
+    fn set_field<T>(
+        field: &mut Option<T>,
+        tcx: TyCtxt<'tcx>,
+        attr: &ast::NestedMetaItem,
+        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
+    ) -> Result<(), ()> {
+        if field.is_some() {
+            tcx.sess
+                .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty()));
+
+            return Err(());
+        }
+
+        if let Some(s) = attr.value_str() {
+            *field = Some(mapper(s)?);
+            Ok(())
+        } else {
+            tcx.sess
+                .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty()));
+            Err(())
+        }
+    }
+
+    /// Returns the path where dataflow results should be written, or `None`
+    /// `borrowck_graphviz_postflow` was not specified.
+    ///
+    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
+    ///
+    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
+    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
+        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
+        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs
+
+        let mut file_name: OsString = analysis_name.into();
+        file_name.push("_");
+        file_name.push(suffix);
+        ret.set_file_name(file_name);
+
+        Some(ret)
+    }
+}
diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs
index e843956..fdf86e7 100644
--- a/src/librustc_mir/dataflow/generic/graphviz.rs
+++ b/src/librustc_mir/dataflow/generic/graphviz.rs
@@ -1,13 +1,14 @@
+//! A helpful diagram for debugging dataflow problems.
+
 use std::cell::RefCell;
-use std::io::{self, Write};
-use std::{ops, str};
+use std::{io, ops, str};
 
 use rustc::mir::{self, BasicBlock, Body, Location};
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::{BitSet, HybridBitSet};
-use rustc_index::vec::Idx;
+use rustc_index::vec::{Idx, IndexVec};
 
-use super::{Analysis, Results, ResultsRefCursor};
+use super::{Analysis, GenKillSet, Results, ResultsRefCursor};
 use crate::util::graphviz_safe_def_name;
 
 pub struct Formatter<'a, 'tcx, A>
@@ -25,11 +26,16 @@
 where
     A: Analysis<'tcx>,
 {
-    pub fn new(body: &'a Body<'tcx>, def_id: DefId, results: &'a Results<'tcx, A>) -> Self {
+    pub fn new(
+        body: &'a Body<'tcx>,
+        def_id: DefId,
+        results: &'a Results<'tcx, A>,
+        state_formatter: &'a mut dyn StateFormatter<'tcx, A>,
+    ) -> Self {
         let block_formatter = BlockFormatter {
             bg: Background::Light,
-            prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)),
             results: ResultsRefCursor::new(body, results),
+            state_formatter,
         };
 
         Formatter { body, def_id, block_formatter: RefCell::new(block_formatter) }
@@ -117,15 +123,21 @@
 where
     A: Analysis<'tcx>,
 {
-    prev_state: BitSet<A::Idx>,
     results: ResultsRefCursor<'a, 'a, 'tcx, A>,
     bg: Background,
+    state_formatter: &'a mut dyn StateFormatter<'tcx, A>,
 }
 
 impl<A> BlockFormatter<'a, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
+    const HEADER_COLOR: &'static str = "#a0a0a0";
+
+    fn num_state_columns(&self) -> usize {
+        std::cmp::max(1, self.state_formatter.column_names().len())
+    }
+
     fn toggle_background(&mut self) -> Background {
         let bg = self.bg;
         self.bg = !bg;
@@ -164,196 +176,470 @@
             r#"<table border="1" cellborder="1" cellspacing="0" cellpadding="3" sides="rb">"#,
         )?;
 
-        // A: Block info
-        write!(
-            w,
-            r#"<tr>
-                 <td colspan="{num_headers}" sides="tl">bb{block_id}</td>
-               </tr>"#,
-            num_headers = 3,
-            block_id = block.index(),
-        )?;
-
-        // B: Column headings
-        write!(
-            w,
-            r#"<tr>
-                 <td colspan="2" {fmt}>MIR</td>
-                 <td {fmt}>STATE</td>
-               </tr>"#,
-            fmt = r##"bgcolor="#a0a0a0" sides="tl""##,
-        )?;
+        // A + B: Block header
+        if self.state_formatter.column_names().is_empty() {
+            self.write_block_header_simple(w, block)?;
+        } else {
+            self.write_block_header_with_state_columns(w, block)?;
+        }
 
         // C: Entry state
         self.bg = Background::Light;
         self.results.seek_to_block_start(block);
-        self.write_row_with_curr_state(w, "", "(on entry)")?;
-        self.prev_state.overwrite(self.results.get());
+        self.write_row_with_full_state(w, "", "(on_entry)")?;
 
         // D: Statement transfer functions
         for (i, statement) in body[block].statements.iter().enumerate() {
             let location = Location { block, statement_index: i };
-
-            let mir_col = format!("{:?}", statement);
-            let i_col = i.to_string();
-
-            self.results.seek_after(location);
-            self.write_row_with_curr_diff(w, &i_col, &mir_col)?;
-            self.prev_state.overwrite(self.results.get());
+            let statement_str = format!("{:?}", statement);
+            self.write_row_for_location(w, &i.to_string(), &statement_str, location)?;
         }
 
         // E: Terminator transfer function
         let terminator = body[block].terminator();
-        let location = body.terminator_loc(block);
+        let terminator_loc = body.terminator_loc(block);
+        let mut terminator_str = String::new();
+        terminator.kind.fmt_head(&mut terminator_str).unwrap();
 
-        let mut mir_col = String::new();
-        terminator.kind.fmt_head(&mut mir_col).unwrap();
-
-        self.results.seek_after(location);
-        self.write_row_with_curr_diff(w, "T", &mir_col)?;
-        self.prev_state.overwrite(self.results.get());
+        self.write_row_for_location(w, "T", &terminator_str, terminator_loc)?;
 
         // F: Exit state
+        self.results.seek_after(terminator_loc);
         if let mir::TerminatorKind::Call { destination: Some(_), .. } = &terminator.kind {
-            self.write_row_with_curr_state(w, "", "(on unwind)")?;
+            self.write_row_with_full_state(w, "", "(on unwind)")?;
 
-            self.results.seek_after_assume_call_returns(location);
-            self.write_row_with_curr_diff(w, "", "(on successful return)")?;
+            let num_state_columns = self.num_state_columns();
+            self.write_row(w, "", "(on successful return)", |this, w, fmt| {
+                write!(
+                    w,
+                    r#"<td colspan="{colspan}" {fmt} align="left">"#,
+                    colspan = num_state_columns,
+                    fmt = fmt,
+                )?;
+
+                let state_on_unwind = this.results.get().clone();
+                this.results.seek_after_assume_call_returns(terminator_loc);
+                write_diff(w, this.results.analysis(), &state_on_unwind, this.results.get())?;
+
+                write!(w, "</td>")
+            })?;
         } else {
-            self.write_row_with_curr_state(w, "", "(on exit)")?;
+            self.write_row_with_full_state(w, "", "(on exit)")?;
         }
 
         write!(w, "</table>")
     }
 
-    fn write_row_with_curr_state(
+    fn write_block_header_simple(
         &mut self,
         w: &mut impl io::Write,
-        i: &str,
-        mir: &str,
+        block: BasicBlock,
     ) -> io::Result<()> {
-        let bg = self.toggle_background();
+        //   +-------------------------------------------------+
+        // A |                      bb4                        |
+        //   +-----------------------------------+-------------+
+        // B |                MIR                |    STATE    |
+        //   +-+---------------------------------+-------------+
+        //   | |              ...                |             |
 
-        let mut out = Vec::new();
-        write!(&mut out, "{{")?;
-        pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?;
-        write!(&mut out, "}}")?;
-
+        // A
         write!(
             w,
-            r#"<tr>
-                 <td {fmt} align="right">{i}</td>
-                 <td {fmt} align="left">{mir}</td>
-                 <td {fmt} align="left">{state}</td>
-               </tr>"#,
-            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
-            i = i,
-            mir = dot::escape_html(mir),
-            state = dot::escape_html(str::from_utf8(&out).unwrap()),
+            concat!("<tr>", r#"<td colspan="3" sides="tl">bb{block_id}</td>"#, "</tr>",),
+            block_id = block.index(),
+        )?;
+
+        // B
+        write!(
+            w,
+            concat!(
+                "<tr>",
+                r#"<td colspan="2" {fmt}>MIR</td>"#,
+                r#"<td {fmt}>STATE</td>"#,
+                "</tr>",
+            ),
+            fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR),
         )
     }
 
-    fn write_row_with_curr_diff(
+    fn write_block_header_with_state_columns(
+        &mut self,
+        w: &mut impl io::Write,
+        block: BasicBlock,
+    ) -> io::Result<()> {
+        //   +------------------------------------+-------------+
+        // A |                bb4                 |    STATE    |
+        //   +------------------------------------+------+------+
+        // B |                MIR                 |  GEN | KILL |
+        //   +-+----------------------------------+------+------+
+        //   | |              ...                 |      |      |
+
+        let state_column_names = self.state_formatter.column_names();
+
+        // A
+        write!(
+            w,
+            concat!(
+                "<tr>",
+                r#"<td {fmt} colspan="2">bb{block_id}</td>"#,
+                r#"<td {fmt} colspan="{num_state_cols}">STATE</td>"#,
+                "</tr>",
+            ),
+            fmt = "sides=\"tl\"",
+            num_state_cols = state_column_names.len(),
+            block_id = block.index(),
+        )?;
+
+        // B
+        let fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR);
+        write!(w, concat!("<tr>", r#"<td colspan="2" {fmt}>MIR</td>"#,), fmt = fmt,)?;
+
+        for name in state_column_names {
+            write!(w, "<td {fmt}>{name}</td>", fmt = fmt, name = name)?;
+        }
+
+        write!(w, "</tr>")
+    }
+
+    /// Write a row with the given index and MIR, using the function argument to fill in the
+    /// "STATE" column(s).
+    fn write_row<W: io::Write>(
+        &mut self,
+        w: &mut W,
+        i: &str,
+        mir: &str,
+        f: impl FnOnce(&mut Self, &mut W, &str) -> io::Result<()>,
+    ) -> io::Result<()> {
+        let bg = self.toggle_background();
+        let fmt = format!("sides=\"tl\" {}", bg.attr());
+
+        write!(
+            w,
+            concat!(
+                "<tr>",
+                r#"<td {fmt} align="right">{i}</td>"#,
+                r#"<td {fmt} align="left">{mir}</td>"#,
+            ),
+            i = i,
+            fmt = fmt,
+            mir = dot::escape_html(mir),
+        )?;
+
+        f(self, w, &fmt)?;
+        write!(w, "</tr>")
+    }
+
+    fn write_row_with_full_state(
         &mut self,
         w: &mut impl io::Write,
         i: &str,
         mir: &str,
     ) -> io::Result<()> {
-        let bg = self.toggle_background();
-        let analysis = self.results.analysis();
+        self.write_row(w, i, mir, |this, w, fmt| {
+            let state = this.results.get();
+            let analysis = this.results.analysis();
 
-        let diff = BitSetDiff::compute(&self.prev_state, self.results.get());
-
-        let mut set = Vec::new();
-        pretty_print_state_elems(&mut set, analysis, diff.set.iter())?;
-
-        let mut clear = Vec::new();
-        pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?;
-
-        write!(
-            w,
-            r#"<tr>
-                 <td {fmt} align="right">{i}</td>
-                 <td {fmt} align="left">{mir}</td>
-                 <td {fmt} align="left">"#,
-            i = i,
-            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
-            mir = dot::escape_html(mir),
-        )?;
-
-        if !set.is_empty() {
             write!(
                 w,
-                r#"<font color="darkgreen">+{}</font>"#,
-                dot::escape_html(str::from_utf8(&set).unwrap()),
+                r#"<td colspan="{colspan}" {fmt} align="left">{{"#,
+                colspan = this.num_state_columns(),
+                fmt = fmt,
             )?;
-        }
+            pretty_print_state_elems(w, analysis, state.iter(), ",", LIMIT_40_ALIGN_1)?;
+            write!(w, "}}</td>")
+        })
+    }
 
-        if !set.is_empty() && !clear.is_empty() {
-            write!(w, "  ")?;
-        }
-
-        if !clear.is_empty() {
-            write!(
-                w,
-                r#"<font color="red">-{}</font>"#,
-                dot::escape_html(str::from_utf8(&clear).unwrap()),
-            )?;
-        }
-
-        write!(w, "</td></tr>")
+    fn write_row_for_location(
+        &mut self,
+        w: &mut impl io::Write,
+        i: &str,
+        mir: &str,
+        location: Location,
+    ) -> io::Result<()> {
+        self.write_row(w, i, mir, |this, w, fmt| {
+            this.state_formatter.write_state_for_location(w, fmt, &mut this.results, location)
+        })
     }
 }
 
-/// The operations required to transform one `BitSet` into another.
-struct BitSetDiff<T: Idx> {
-    set: HybridBitSet<T>,
-    clear: HybridBitSet<T>,
+/// Controls what gets printed under the `STATE` header.
+pub trait StateFormatter<'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    /// The columns that will get printed under `STATE`.
+    fn column_names(&self) -> &[&str];
+
+    fn write_state_for_location(
+        &mut self,
+        w: &mut dyn io::Write,
+        fmt: &str,
+        results: &mut ResultsRefCursor<'_, '_, 'tcx, A>,
+        location: Location,
+    ) -> io::Result<()>;
 }
 
-impl<T: Idx> BitSetDiff<T> {
-    fn compute(from: &BitSet<T>, to: &BitSet<T>) -> Self {
-        assert_eq!(from.domain_size(), to.domain_size());
-        let len = from.domain_size();
+/// Prints a single column containing the state vector immediately *after* each statement.
+pub struct SimpleDiff<T: Idx> {
+    prev_state: BitSet<T>,
+    prev_loc: Location,
+}
 
-        let mut set = HybridBitSet::new_empty(len);
-        let mut clear = HybridBitSet::new_empty(len);
-
-        // FIXME: This could be made faster if `BitSet::xor` were implemented.
-        for i in (0..len).map(|i| T::new(i)) {
-            match (from.contains(i), to.contains(i)) {
-                (false, true) => set.insert(i),
-                (true, false) => clear.insert(i),
-                _ => continue,
-            };
-        }
-
-        BitSetDiff { set, clear }
+impl<T: Idx> SimpleDiff<T> {
+    #![allow(unused)]
+    pub fn new(bits_per_block: usize) -> Self {
+        SimpleDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START }
     }
 }
 
-/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated
-/// list.
+impl<A> StateFormatter<'tcx, A> for SimpleDiff<A::Idx>
+where
+    A: Analysis<'tcx>,
+{
+    fn column_names(&self) -> &[&str] {
+        &[]
+    }
+
+    fn write_state_for_location(
+        &mut self,
+        mut w: &mut dyn io::Write,
+        fmt: &str,
+        results: &mut ResultsRefCursor<'_, '_, 'tcx, A>,
+        location: Location,
+    ) -> io::Result<()> {
+        if location.statement_index == 0 {
+            results.seek_to_block_start(location.block);
+            self.prev_state.overwrite(results.get());
+        } else {
+            // Ensure that we are visiting statements in order, so `prev_state` is correct.
+            assert_eq!(self.prev_loc.successor_within_block(), location);
+        }
+
+        self.prev_loc = location;
+        write!(w, r#"<td {fmt} align="left">"#, fmt = fmt)?;
+        results.seek_before(location);
+        let curr_state = results.get();
+        write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?;
+        self.prev_state.overwrite(curr_state);
+        write!(w, "</td>")
+    }
+}
+
+/// Prints two state columns, one containing only the "before" effect of each statement and one
+/// containing the full effect.
+pub struct TwoPhaseDiff<T: Idx> {
+    prev_state: BitSet<T>,
+    prev_loc: Location,
+}
+
+impl<T: Idx> TwoPhaseDiff<T> {
+    #![allow(unused)]
+    pub fn new(bits_per_block: usize) -> Self {
+        TwoPhaseDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START }
+    }
+}
+
+impl<A> StateFormatter<'tcx, A> for TwoPhaseDiff<A::Idx>
+where
+    A: Analysis<'tcx>,
+{
+    fn column_names(&self) -> &[&str] {
+        &["ENTRY", " EXIT"]
+    }
+
+    fn write_state_for_location(
+        &mut self,
+        mut w: &mut dyn io::Write,
+        fmt: &str,
+        results: &mut ResultsRefCursor<'_, '_, 'tcx, A>,
+        location: Location,
+    ) -> io::Result<()> {
+        if location.statement_index == 0 {
+            results.seek_to_block_start(location.block);
+            self.prev_state.overwrite(results.get());
+        } else {
+            // Ensure that we are visiting statements in order, so `prev_state` is correct.
+            assert_eq!(self.prev_loc.successor_within_block(), location);
+        }
+
+        self.prev_loc = location;
+
+        // Entry
+
+        write!(w, r#"<td {fmt} align="left">"#, fmt = fmt)?;
+        results.seek_before(location);
+        let curr_state = results.get();
+        write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?;
+        self.prev_state.overwrite(curr_state);
+        write!(w, "</td>")?;
+
+        // Exit
+
+        write!(w, r#"<td {fmt} align="left">"#, fmt = fmt)?;
+        results.seek_after(location);
+        let curr_state = results.get();
+        write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?;
+        self.prev_state.overwrite(curr_state);
+        write!(w, "</td>")
+    }
+}
+
+/// Prints the gen/kill set for the entire block.
+pub struct BlockTransferFunc<'a, 'tcx, T: Idx> {
+    body: &'a mir::Body<'tcx>,
+    trans_for_block: IndexVec<BasicBlock, GenKillSet<T>>,
+}
+
+impl<T: Idx> BlockTransferFunc<'mir, 'tcx, T> {
+    #![allow(unused)]
+    pub fn new(
+        body: &'mir mir::Body<'tcx>,
+        trans_for_block: IndexVec<BasicBlock, GenKillSet<T>>,
+    ) -> Self {
+        BlockTransferFunc { body, trans_for_block }
+    }
+}
+
+impl<A> StateFormatter<'tcx, A> for BlockTransferFunc<'mir, 'tcx, A::Idx>
+where
+    A: Analysis<'tcx>,
+{
+    fn column_names(&self) -> &[&str] {
+        &["GEN", "KILL"]
+    }
+
+    fn write_state_for_location(
+        &mut self,
+        mut w: &mut dyn io::Write,
+        fmt: &str,
+        results: &mut ResultsRefCursor<'_, '_, 'tcx, A>,
+        location: Location,
+    ) -> io::Result<()> {
+        // Only print a single row.
+        if location.statement_index != 0 {
+            return Ok(());
+        }
+
+        let block_trans = &self.trans_for_block[location.block];
+        let rowspan = self.body.basic_blocks()[location.block].statements.len();
+
+        for set in &[&block_trans.gen, &block_trans.kill] {
+            write!(
+                w,
+                r#"<td {fmt} rowspan="{rowspan}" align="center">"#,
+                fmt = fmt,
+                rowspan = rowspan
+            )?;
+
+            pretty_print_state_elems(&mut w, results.analysis(), set.iter(), "\n", None)?;
+            write!(w, "</td>")?;
+        }
+
+        Ok(())
+    }
+}
+
+/// Writes two lines, one containing the added bits and one the removed bits.
+fn write_diff<A: Analysis<'tcx>>(
+    w: &mut impl io::Write,
+    analysis: &A,
+    from: &BitSet<A::Idx>,
+    to: &BitSet<A::Idx>,
+) -> io::Result<()> {
+    assert_eq!(from.domain_size(), to.domain_size());
+    let len = from.domain_size();
+
+    let mut set = HybridBitSet::new_empty(len);
+    let mut clear = HybridBitSet::new_empty(len);
+
+    // FIXME: Implement a lazy iterator over the symmetric difference of two bitsets.
+    for i in (0..len).map(|i| A::Idx::new(i)) {
+        match (from.contains(i), to.contains(i)) {
+            (false, true) => set.insert(i),
+            (true, false) => clear.insert(i),
+            _ => continue,
+        };
+    }
+
+    if !set.is_empty() {
+        write!(w, r#"<font color="darkgreen">+"#)?;
+        pretty_print_state_elems(w, analysis, set.iter(), ",", LIMIT_40_ALIGN_1)?;
+        write!(w, r#"</font>"#)?;
+    }
+
+    if !set.is_empty() && !clear.is_empty() {
+        write!(w, "<br/>")?;
+    }
+
+    if !clear.is_empty() {
+        write!(w, r#"<font color="red">-"#)?;
+        pretty_print_state_elems(w, analysis, clear.iter(), ",", LIMIT_40_ALIGN_1)?;
+        write!(w, r#"</font>"#)?;
+    }
+
+    Ok(())
+}
+
+/// Line break policy that breaks at 40 characters and starts the next line with a single space.
+const LIMIT_40_ALIGN_1: Option<LineBreak> = Some(LineBreak { sequence: "<br/> ", limit: 40 });
+
+struct LineBreak {
+    sequence: &'static str,
+    limit: usize,
+}
+
+/// Formats each `elem` using the pretty printer provided by `analysis` into a list with the given
+/// separator (`sep`).
+///
+/// Optionally, it will break lines using the given character sequence (usually `<br/>`) and
+/// character limit.
 fn pretty_print_state_elems<A>(
     w: &mut impl io::Write,
     analysis: &A,
     elems: impl Iterator<Item = A::Idx>,
-) -> io::Result<()>
+    sep: &str,
+    line_break: Option<LineBreak>,
+) -> io::Result<bool>
 where
     A: Analysis<'tcx>,
 {
+    let sep_width = sep.chars().count();
+
+    let mut buf = Vec::new();
+
     let mut first = true;
+    let mut curr_line_width = 0;
+    let mut line_break_inserted = false;
+
     for idx in elems {
         if first {
             first = false;
         } else {
-            write!(w, ",")?;
+            write!(w, "{}", sep)?;
+            curr_line_width += sep_width;
         }
 
-        analysis.pretty_print_idx(w, idx)?;
+        buf.clear();
+        analysis.pretty_print_idx(&mut buf, idx)?;
+        let idx_str =
+            str::from_utf8(&buf).expect("Output of `pretty_print_idx` must be valid UTF-8");
+        let escaped = dot::escape_html(idx_str);
+        let escaped_width = escaped.chars().count();
+
+        if let Some(line_break) = &line_break {
+            if curr_line_width + sep_width + escaped_width > line_break.limit {
+                write!(w, "{}", line_break.sequence)?;
+                line_break_inserted = true;
+                curr_line_width = 0;
+            }
+        }
+
+        write!(w, "{}", escaped)?;
+        curr_line_width += escaped_width;
     }
 
-    Ok(())
+    Ok(line_break_inserted)
 }
 
 /// The background color used for zebra-striping the table.
diff --git a/src/librustc_mir/dataflow/generic/mod.rs b/src/librustc_mir/dataflow/generic/mod.rs
new file mode 100644
index 0000000..c9b4f87
--- /dev/null
+++ b/src/librustc_mir/dataflow/generic/mod.rs
@@ -0,0 +1,358 @@
+//! A framework that can express both [gen-kill] and generic dataflow problems.
+//!
+//! There is another interface for dataflow in the compiler in `librustc_mir/dataflow/mod.rs`. The
+//! interface in this module will eventually [replace that one][design-meeting].
+//!
+//! To actually use this framework, you must implement either the `Analysis` or the `GenKillAnalysis`
+//! trait. If your transfer function can be expressed with only gen/kill operations, prefer
+//! `GenKillAnalysis` since it will run faster while iterating to fixpoint. Create an `Engine` using
+//! the appropriate constructor and call `iterate_to_fixpoint`. You can use a `ResultsCursor` to
+//! inspect the fixpoint solution to your dataflow problem.
+//!
+//! ```ignore(cross-crate-imports)
+//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) {
+//!     let analysis = MyAnalysis::new();
+//!
+//!     // If `MyAnalysis` implements `GenKillAnalysis`.
+//!     let results = Engine::new_gen_kill(tcx, body, did, analysis).iterate_to_fixpoint();
+//!
+//!     // If `MyAnalysis` implements `Analysis`.
+//!     // let results = Engine::new_generic(tcx, body, did, analysis).iterate_to_fixpoint();
+//!
+//!     let mut cursor = ResultsCursor::new(body, results);
+//!
+//!     for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() {
+//!         cursor.seek_after(Location { block: START_BLOCK, statement_index });
+//!         let state = cursor.get();
+//!         println!("{:?}", state);
+//!     }
+//! }
+//! ```
+//!
+//! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
+//! [design-meeting]https://github.com/rust-lang/compiler-team/issues/202
+
+use std::io;
+
+use rustc::mir::{self, BasicBlock, Location};
+use rustc_index::bit_set::{BitSet, HybridBitSet};
+use rustc_index::vec::{Idx, IndexVec};
+
+use crate::dataflow::BottomValue;
+
+mod cursor;
+mod engine;
+mod graphviz;
+
+pub use self::cursor::{ResultsCursor, ResultsRefCursor};
+pub use self::engine::Engine;
+
+/// A dataflow analysis that has converged to fixpoint.
+pub struct Results<'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    pub analysis: A,
+    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
+}
+
+impl<A> Results<'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    /// Creates a `ResultsCursor` that can inspect these `Results`.
+    pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
+        ResultsCursor::new(body, self)
+    }
+
+    /// Gets the entry set for the given block.
+    pub fn entry_set_for_block(&self, block: BasicBlock) -> &BitSet<A::Idx> {
+        &self.entry_sets[block]
+    }
+}
+
+/// Define the domain of a dataflow problem.
+///
+/// This trait specifies the lattice on which this analysis operates. For now, this must be a
+/// powerset of values of type `Idx`. The elements of this lattice are represented with a `BitSet`
+/// and referred to as the state vector.
+///
+/// This trait also defines the initial value for the dataflow state upon entry to the
+/// `START_BLOCK`, as well as some names used to refer to this analysis when debugging.
+pub trait AnalysisDomain<'tcx>: BottomValue {
+    /// The type of the elements in the state vector.
+    type Idx: Idx;
+
+    /// A descriptive name for this analysis. Used only for debugging.
+    ///
+    /// This name should be brief and contain no spaces, periods or other characters that are not
+    /// suitable as part of a filename.
+    const NAME: &'static str;
+
+    /// The size of the state vector.
+    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;
+
+    /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow
+    /// analysis.
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>);
+
+    /// Prints an element in the state vector for debugging.
+    fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
+        write!(w, "{:?}", idx)
+    }
+}
+
+/// A dataflow problem with an arbitrarily complex transfer function.
+pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
+    /// Updates the current dataflow state with the effect of evaluating a statement.
+    fn apply_statement_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        statement: &mir::Statement<'tcx>,
+        location: Location,
+    );
+
+    /// Updates the current dataflow state with an effect that occurs immediately *before* the
+    /// given statement.
+    ///
+    /// This method is useful if the consumer of the results of this analysis needs only to observe
+    /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
+    /// analyses should not implement this without implementing `apply_statement_effect`.
+    fn apply_before_statement_effect(
+        &self,
+        _state: &mut BitSet<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        _location: Location,
+    ) {
+    }
+
+    /// Updates the current dataflow state with the effect of evaluating a terminator.
+    ///
+    /// The effect of a successful return from a `Call` terminator should **not** be accounted for
+    /// in this function. That should go in `apply_call_return_effect`. For example, in the
+    /// `InitializedPlaces` analyses, the return place for a function call is not marked as
+    /// initialized here.
+    fn apply_terminator_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    );
+
+    /// Updates the current dataflow state with an effect that occurs immediately *before* the
+    /// given terminator.
+    ///
+    /// This method is useful if the consumer of the results of this analysis needs only to observe
+    /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
+    /// analyses should not implement this without implementing `apply_terminator_effect`.
+    fn apply_before_terminator_effect(
+        &self,
+        _state: &mut BitSet<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        _location: Location,
+    ) {
+    }
+
+    /// Updates the current dataflow state with the effect of a successful return from a `Call`
+    /// terminator.
+    ///
+    /// This is separate from `apply_terminator_effect` to properly track state across unwind
+    /// edges.
+    fn apply_call_return_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        block: BasicBlock,
+        func: &mir::Operand<'tcx>,
+        args: &[mir::Operand<'tcx>],
+        return_place: &mir::Place<'tcx>,
+    );
+}
+
+/// A gen/kill dataflow problem.
+///
+/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
+/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer
+/// functions for each statement in this way, the transfer function for an entire basic block can
+/// be computed efficiently.
+///
+/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`.
+pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
+    /// See `Analysis::apply_statement_effect`.
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        statement: &mir::Statement<'tcx>,
+        location: Location,
+    );
+
+    /// See `Analysis::apply_before_statement_effect`.
+    fn before_statement_effect(
+        &self,
+        _trans: &mut impl GenKill<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        _location: Location,
+    ) {
+    }
+
+    /// See `Analysis::apply_terminator_effect`.
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    );
+
+    /// See `Analysis::apply_before_terminator_effect`.
+    fn before_terminator_effect(
+        &self,
+        _trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        _location: Location,
+    ) {
+    }
+
+    /// See `Analysis::apply_call_return_effect`.
+    fn call_return_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        block: BasicBlock,
+        func: &mir::Operand<'tcx>,
+        args: &[mir::Operand<'tcx>],
+        return_place: &mir::Place<'tcx>,
+    );
+}
+
+impl<A> Analysis<'tcx> for A
+where
+    A: GenKillAnalysis<'tcx>,
+{
+    fn apply_statement_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        self.statement_effect(state, statement, location);
+    }
+
+    fn apply_before_statement_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        self.before_statement_effect(state, statement, location);
+    }
+
+    fn apply_terminator_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        self.terminator_effect(state, terminator, location);
+    }
+
+    fn apply_before_terminator_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        self.before_terminator_effect(state, terminator, location);
+    }
+
+    fn apply_call_return_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        block: BasicBlock,
+        func: &mir::Operand<'tcx>,
+        args: &[mir::Operand<'tcx>],
+        return_place: &mir::Place<'tcx>,
+    ) {
+        self.call_return_effect(state, block, func, args, return_place);
+    }
+}
+
+/// The legal operations for a transfer function in a gen/kill problem.
+///
+/// This abstraction exists because there are two different contexts in which we call the methods in
+/// `GenKillAnalysis`. Sometimes we need to store a single transfer function that can be efficiently
+/// applied multiple times, such as when computing the cumulative transfer function for each block.
+/// These cases require a `GenKillSet`, which in turn requires two `BitSet`s of storage. Oftentimes,
+/// however, we only need to apply an effect once. In *these* cases, it is more efficient to pass the
+/// `BitSet` representing the state vector directly into the `*_effect` methods as opposed to
+/// building up a `GenKillSet` and then throwing it away.
+pub trait GenKill<T> {
+    /// Inserts `elem` into the state vector.
+    fn gen(&mut self, elem: T);
+
+    /// Removes `elem` from the state vector.
+    fn kill(&mut self, elem: T);
+
+    /// Calls `gen` for each element in `elems`.
+    fn gen_all(&mut self, elems: impl IntoIterator<Item = T>) {
+        for elem in elems {
+            self.gen(elem);
+        }
+    }
+
+    /// Calls `kill` for each element in `elems`.
+    fn kill_all(&mut self, elems: impl IntoIterator<Item = T>) {
+        for elem in elems {
+            self.kill(elem);
+        }
+    }
+}
+
+/// Stores a transfer function for a gen/kill problem.
+///
+/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be
+/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for
+/// the same element, the most recent one takes precedence.
+#[derive(Clone)]
+pub struct GenKillSet<T: Idx> {
+    gen: HybridBitSet<T>,
+    kill: HybridBitSet<T>,
+}
+
+impl<T: Idx> GenKillSet<T> {
+    /// Creates a new transfer function that will leave the dataflow state unchanged.
+    pub fn identity(universe: usize) -> Self {
+        GenKillSet {
+            gen: HybridBitSet::new_empty(universe),
+            kill: HybridBitSet::new_empty(universe),
+        }
+    }
+
+    /// Applies this transfer function to the given state vector.
+    pub fn apply(&self, state: &mut BitSet<T>) {
+        state.union(&self.gen);
+        state.subtract(&self.kill);
+    }
+}
+
+impl<T: Idx> GenKill<T> for GenKillSet<T> {
+    fn gen(&mut self, elem: T) {
+        self.gen.insert(elem);
+        self.kill.remove(elem);
+    }
+
+    fn kill(&mut self, elem: T) {
+        self.kill.insert(elem);
+        self.gen.remove(elem);
+    }
+}
+
+impl<T: Idx> GenKill<T> for BitSet<T> {
+    fn gen(&mut self, elem: T) {
+        self.insert(elem);
+    }
+
+    fn kill(&mut self, elem: T) {
+        self.remove(elem);
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustc_mir/dataflow/generic/tests.rs b/src/librustc_mir/dataflow/generic/tests.rs
new file mode 100644
index 0000000..50d4bdb
--- /dev/null
+++ b/src/librustc_mir/dataflow/generic/tests.rs
@@ -0,0 +1,332 @@
+//! A test for the logic that updates the state in a `ResultsCursor` during seek.
+
+use rustc::mir::{self, BasicBlock, Location};
+use rustc::ty;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_span::DUMMY_SP;
+
+use super::*;
+use crate::dataflow::BottomValue;
+
+/// Returns `true` if the given location points to a `Call` terminator that can return
+/// successfully.
+fn is_call_terminator_non_diverging(body: &mir::Body<'_>, loc: Location) -> bool {
+    loc == body.terminator_loc(loc.block)
+        && matches!(
+            body[loc.block].terminator().kind,
+            mir::TerminatorKind::Call { destination: Some(_), ..  }
+        )
+}
+
+/// Creates a `mir::Body` with a few disconnected basic blocks.
+///
+/// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not
+/// important.
+fn mock_body() -> mir::Body<'static> {
+    let source_info = mir::SourceInfo { scope: mir::OUTERMOST_SOURCE_SCOPE, span: DUMMY_SP };
+
+    let mut blocks = IndexVec::new();
+    let mut block = |n, kind| {
+        let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop };
+
+        blocks.push(mir::BasicBlockData {
+            statements: std::iter::repeat(&nop).cloned().take(n).collect(),
+            terminator: Some(mir::Terminator { source_info, kind }),
+            is_cleanup: false,
+        })
+    };
+
+    let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() };
+
+    block(4, mir::TerminatorKind::Return);
+    block(1, mir::TerminatorKind::Return);
+    block(
+        2,
+        mir::TerminatorKind::Call {
+            func: mir::Operand::Copy(dummy_place.clone()),
+            args: vec![],
+            destination: Some((dummy_place.clone(), mir::START_BLOCK)),
+            cleanup: None,
+            from_hir_call: false,
+        },
+    );
+    block(3, mir::TerminatorKind::Return);
+    block(0, mir::TerminatorKind::Return);
+    block(
+        4,
+        mir::TerminatorKind::Call {
+            func: mir::Operand::Copy(dummy_place.clone()),
+            args: vec![],
+            destination: Some((dummy_place.clone(), mir::START_BLOCK)),
+            cleanup: None,
+            from_hir_call: false,
+        },
+    );
+
+    mir::Body::new_cfg_only(blocks)
+}
+
+/// A dataflow analysis whose state is unique at every possible `SeekTarget`.
+///
+/// Uniqueness is achieved by having a *locally* unique effect before and after each statement and
+/// terminator (see `effect_at_target`) while ensuring that the entry set for each block is
+/// *globally* unique (see `mock_entry_set`).
+///
+/// For example, a `BasicBlock` with ID `2` and a `Call` terminator has the following state at each
+/// location ("+x" indicates that "x" is added to the state).
+///
+/// | Location               | Before            | After  |
+/// |------------------------|-------------------|--------|
+/// | (on_entry)             | {102}                     ||
+/// | Statement 0            | +0                | +1     |
+/// | statement 1            | +2                | +3     |
+/// | `Call` terminator      | +4                | +5     |
+/// | (on unwind)            | {102,0,1,2,3,4,5}         ||
+/// | (on successful return) | +6                        ||
+///
+/// The `102` in the block's entry set is derived from the basic block index and ensures that the
+/// expected state is unique across all basic blocks. Remember, it is generated by
+/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint.
+struct MockAnalysis<'tcx> {
+    body: &'tcx mir::Body<'tcx>,
+}
+
+impl MockAnalysis<'tcx> {
+    const BASIC_BLOCK_OFFSET: usize = 100;
+
+    /// The entry set for each `BasicBlock` is the ID of that block offset by a fixed amount to
+    /// avoid colliding with the statement/terminator effects.
+    fn mock_entry_set(&self, bb: BasicBlock) -> BitSet<usize> {
+        let mut ret = BitSet::new_empty(self.bits_per_block(self.body));
+        ret.insert(Self::BASIC_BLOCK_OFFSET + bb.index());
+        ret
+    }
+
+    fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
+        let empty = BitSet::new_empty(self.bits_per_block(self.body));
+        let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks());
+
+        for (bb, _) in self.body.basic_blocks().iter_enumerated() {
+            ret[bb] = self.mock_entry_set(bb);
+        }
+
+        ret
+    }
+
+    /// Returns the index that should be added to the dataflow state at the given target.
+    ///
+    /// This index is only unique within a given basic block. `SeekAfter` and
+    /// `SeekAfterAssumeCallReturns` have the same effect unless `target` is a `Call` terminator.
+    fn effect_at_target(&self, target: SeekTarget) -> Option<usize> {
+        use SeekTarget::*;
+
+        let idx = match target {
+            BlockStart(_) => return None,
+
+            AfterAssumeCallReturns(loc) if is_call_terminator_non_diverging(self.body, loc) => {
+                loc.statement_index * 2 + 2
+            }
+
+            Before(loc) => loc.statement_index * 2,
+            After(loc) | AfterAssumeCallReturns(loc) => loc.statement_index * 2 + 1,
+        };
+
+        assert!(idx < Self::BASIC_BLOCK_OFFSET, "Too many statements in basic block");
+        Some(idx)
+    }
+
+    /// Returns the expected state at the given `SeekTarget`.
+    ///
+    /// This is the union of index of the target basic block, the index assigned to the
+    /// target statement or terminator, and the indices of all preceding statements in the target
+    /// basic block.
+    ///
+    /// For example, the expected state when calling
+    /// `seek_before(Location { block: 2, statement_index: 2 })` would be `[102, 0, 1, 2, 3, 4]`.
+    fn expected_state_at_target(&self, target: SeekTarget) -> BitSet<usize> {
+        let mut ret = BitSet::new_empty(self.bits_per_block(self.body));
+        ret.insert(Self::BASIC_BLOCK_OFFSET + target.block().index());
+
+        if let Some(target_effect) = self.effect_at_target(target) {
+            for i in 0..=target_effect {
+                ret.insert(i);
+            }
+        }
+
+        ret
+    }
+}
+
+impl BottomValue for MockAnalysis<'tcx> {
+    const BOTTOM_VALUE: bool = false;
+}
+
+impl AnalysisDomain<'tcx> for MockAnalysis<'tcx> {
+    type Idx = usize;
+
+    const NAME: &'static str = "mock";
+
+    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
+        Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len()
+    }
+
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
+        unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint");
+    }
+}
+
+impl Analysis<'tcx> for MockAnalysis<'tcx> {
+    fn apply_statement_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        let idx = self.effect_at_target(SeekTarget::After(location)).unwrap();
+        assert!(state.insert(idx));
+    }
+
+    fn apply_before_statement_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        let idx = self.effect_at_target(SeekTarget::Before(location)).unwrap();
+        assert!(state.insert(idx));
+    }
+
+    fn apply_terminator_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        let idx = self.effect_at_target(SeekTarget::After(location)).unwrap();
+        assert!(state.insert(idx));
+    }
+
+    fn apply_before_terminator_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        let idx = self.effect_at_target(SeekTarget::Before(location)).unwrap();
+        assert!(state.insert(idx));
+    }
+
+    fn apply_call_return_effect(
+        &self,
+        state: &mut BitSet<Self::Idx>,
+        block: BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
+        _return_place: &mir::Place<'tcx>,
+    ) {
+        let location = self.body.terminator_loc(block);
+        let idx = self.effect_at_target(SeekTarget::AfterAssumeCallReturns(location)).unwrap();
+        assert!(state.insert(idx));
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum SeekTarget {
+    BlockStart(BasicBlock),
+    Before(Location),
+    After(Location),
+    AfterAssumeCallReturns(Location),
+}
+
+impl SeekTarget {
+    fn block(&self) -> BasicBlock {
+        use SeekTarget::*;
+
+        match *self {
+            BlockStart(block) => block,
+            Before(loc) | After(loc) | AfterAssumeCallReturns(loc) => loc.block,
+        }
+    }
+
+    /// An iterator over all possible `SeekTarget`s in a given block in order, starting with
+    /// `BlockStart`.
+    ///
+    /// This includes both `After` and `AfterAssumeCallReturns` for every `Location`.
+    fn iter_in_block(body: &mir::Body<'_>, block: BasicBlock) -> impl Iterator<Item = Self> {
+        let statements_and_terminator = (0..=body[block].statements.len())
+            .flat_map(|i| (0..3).map(move |j| (i, j)))
+            .map(move |(i, kind)| {
+                let loc = Location { block, statement_index: i };
+                match kind {
+                    0 => SeekTarget::Before(loc),
+                    1 => SeekTarget::After(loc),
+                    2 => SeekTarget::AfterAssumeCallReturns(loc),
+                    _ => unreachable!(),
+                }
+            });
+
+        std::iter::once(SeekTarget::BlockStart(block)).chain(statements_and_terminator)
+    }
+}
+
+#[test]
+fn cursor_seek() {
+    let body = mock_body();
+    let body = &body;
+    let analysis = MockAnalysis { body };
+
+    let mut cursor =
+        Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+
+    // Sanity check: the mock call return effect is unique and actually being applied.
+    let call_terminator_loc = Location { block: BasicBlock::from_usize(2), statement_index: 2 };
+    assert!(is_call_terminator_non_diverging(body, call_terminator_loc));
+
+    let call_return_effect = cursor
+        .analysis()
+        .effect_at_target(SeekTarget::AfterAssumeCallReturns(call_terminator_loc))
+        .unwrap();
+    assert_ne!(
+        call_return_effect,
+        cursor.analysis().effect_at_target(SeekTarget::After(call_terminator_loc)).unwrap()
+    );
+
+    cursor.seek_after(call_terminator_loc);
+    assert!(!cursor.get().contains(call_return_effect));
+    cursor.seek_after_assume_call_returns(call_terminator_loc);
+    assert!(cursor.get().contains(call_return_effect));
+
+    let every_target = || {
+        body.basic_blocks()
+            .iter_enumerated()
+            .flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb))
+    };
+
+    let mut seek_to_target = |targ| {
+        use SeekTarget::*;
+
+        match targ {
+            BlockStart(block) => cursor.seek_to_block_start(block),
+            Before(loc) => cursor.seek_before(loc),
+            After(loc) => cursor.seek_after(loc),
+            AfterAssumeCallReturns(loc) => cursor.seek_after_assume_call_returns(loc),
+        }
+
+        assert_eq!(cursor.get(), &cursor.analysis().expected_state_at_target(targ));
+    };
+
+    // Seek *to* every possible `SeekTarget` *from* every possible `SeekTarget`.
+    //
+    // By resetting the cursor to `from` each time it changes, we end up checking some edges twice.
+    // What we really want is an Eulerian cycle for the complete digraph over all possible
+    // `SeekTarget`s, but it's not worth spending the time to compute it.
+    for from in every_target() {
+        seek_to_target(from);
+
+        for to in every_target() {
+            seek_to_target(to);
+            seek_to_target(from);
+        }
+    }
+}
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 01cecdd..b846161 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -31,9 +31,13 @@
 
     let mut result = match instance {
         ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
-        ty::InstanceDef::VtableShim(def_id) => {
-            build_call_shim(tcx, instance, Adjustment::DerefMove, CallKind::Direct(def_id), None)
-        }
+        ty::InstanceDef::VtableShim(def_id) => build_call_shim(
+            tcx,
+            instance,
+            Some(Adjustment::DerefMove),
+            CallKind::Direct(def_id),
+            None,
+        ),
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
             let trait_ = tcx.trait_of_item(def_id).unwrap();
             let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
@@ -50,7 +54,7 @@
             let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
             let arg_tys = sig.inputs();
 
-            build_call_shim(tcx, instance, adjustment, CallKind::Indirect, Some(arg_tys))
+            build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
         }
         // We are generating a call back to our def-id, which the
         // codegen backend knows to turn to an actual call, be it
@@ -58,7 +62,7 @@
         // indirect calls must be codegen'd differently than direct ones
         // (such as `#[track_caller]`).
         ty::InstanceDef::ReifyShim(def_id) => {
-            build_call_shim(tcx, instance, Adjustment::Identity, CallKind::Direct(def_id), None)
+            build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
         }
         ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
             let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
@@ -68,7 +72,13 @@
                 .unwrap()
                 .def_id;
 
-            build_call_shim(tcx, instance, Adjustment::RefMut, CallKind::Direct(call_mut), None)
+            build_call_shim(
+                tcx,
+                instance,
+                Some(Adjustment::RefMut),
+                CallKind::Direct(call_mut),
+                None,
+            )
         }
         ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
         ty::InstanceDef::CloneShim(def_id, ty) => {
@@ -648,7 +658,7 @@
 fn build_call_shim<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
-    rcvr_adjustment: Adjustment,
+    rcvr_adjustment: Option<Adjustment>,
     call_kind: CallKind,
     untuple_args: Option<&[Ty<'tcx>]>,
 ) -> BodyAndCache<'tcx> {
@@ -680,14 +690,16 @@
     let mut local_decls = local_decls_for_sig(&sig, span);
     let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
 
-    let rcvr_arg = Local::new(1 + 0);
-    let rcvr_l = Place::from(rcvr_arg);
+    let rcvr_place = || {
+        assert!(rcvr_adjustment.is_some());
+        Place::from(Local::new(1 + 0))
+    };
     let mut statements = vec![];
 
-    let rcvr = match rcvr_adjustment {
-        Adjustment::Identity => Operand::Move(rcvr_l),
-        Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
-        Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_l)),
+    let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
+        Adjustment::Identity => Operand::Move(rcvr_place()),
+        Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_place())),
+        Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(temp_decl(
@@ -703,15 +715,15 @@
                 source_info,
                 kind: StatementKind::Assign(box (
                     Place::from(ref_rcvr),
-                    Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l),
+                    Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
                 )),
             });
             Operand::Move(Place::from(ref_rcvr))
         }
-    };
+    });
 
     let (callee, mut args) = match call_kind {
-        CallKind::Indirect => (rcvr, vec![]),
+        CallKind::Indirect => (rcvr.unwrap(), vec![]),
         CallKind::Direct(def_id) => {
             let ty = tcx.type_of(def_id);
             (
@@ -720,21 +732,35 @@
                     user_ty: None,
                     literal: ty::Const::zero_sized(tcx, ty),
                 }),
-                vec![rcvr],
+                rcvr.into_iter().collect::<Vec<_>>(),
             )
         }
     };
 
-    if let Some(untuple_args) = untuple_args {
-        args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
-            let arg_place = Place::from(Local::new(1 + 1));
-            Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
-        }));
-    } else {
-        args.extend((1..sig.inputs().len()).map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
+    let mut arg_range = 0..sig.inputs().len();
+
+    // Take the `self` ("receiver") argument out of the range (it's adjusted above).
+    if rcvr_adjustment.is_some() {
+        arg_range.start += 1;
     }
 
-    let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 };
+    // Take the last argument, if we need to untuple it (handled below).
+    if untuple_args.is_some() {
+        arg_range.end -= 1;
+    }
+
+    // Pass all of the non-special arguments directly.
+    args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
+
+    // Untuple the last argument, if we have to.
+    if let Some(untuple_args) = untuple_args {
+        let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
+        args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
+            Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity))
+        }));
+    }
+
+    let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
     let mut blocks = IndexVec::with_capacity(n_blocks);
     let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
         blocks.push(BasicBlockData {
@@ -752,7 +778,7 @@
             func: callee,
             args,
             destination: Some((Place::return_place(), BasicBlock::new(1))),
-            cleanup: if let Adjustment::RefMut = rcvr_adjustment {
+            cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
                 Some(BasicBlock::new(3))
             } else {
                 None
@@ -762,13 +788,13 @@
         false,
     );
 
-    if let Adjustment::RefMut = rcvr_adjustment {
+    if let Some(Adjustment::RefMut) = rcvr_adjustment {
         // BB #1 - drop for Self
         block(
             &mut blocks,
             vec![],
             TerminatorKind::Drop {
-                location: Place::from(rcvr_arg),
+                location: rcvr_place(),
                 target: BasicBlock::new(2),
                 unwind: None,
             },
@@ -777,13 +803,13 @@
     }
     // BB #1/#2 - return
     block(&mut blocks, vec![], TerminatorKind::Return, false);
-    if let Adjustment::RefMut = rcvr_adjustment {
+    if let Some(Adjustment::RefMut) = rcvr_adjustment {
         // BB #3 - drop if closure panics
         block(
             &mut blocks,
             vec![],
             TerminatorKind::Drop {
-                location: Place::from(rcvr_arg),
+                location: rcvr_place(),
                 target: BasicBlock::new(4),
                 unwind: None,
             },
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index edb4eb4..3263905 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -10,8 +10,6 @@
 
 use super::{ConstKind, Item};
 
-use rustc_error_codes::*;
-
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
     /// Whether this operation can be evaluated by miri.
diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs
index c445568..2cd2495 100644
--- a/src/librustc_mir/transform/check_consts/resolver.rs
+++ b/src/librustc_mir/transform/check_consts/resolver.rs
@@ -158,7 +158,7 @@
     const BOTTOM_VALUE: bool = false;
 }
 
-impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
@@ -173,7 +173,12 @@
     fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
         self.transfer_function(state).initialize_state();
     }
+}
 
+impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+where
+    Q: Qualif,
+{
     fn apply_statement_effect(
         &self,
         state: &mut BitSet<Self::Idx>,
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 10a4b7d..44b2a90 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -6,7 +6,6 @@
 use rustc::traits::{self, TraitEngine};
 use rustc::ty::cast::CastTy;
 use rustc::ty::{self, TyCtxt};
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir::{def_id::DefId, HirId};
 use rustc_index::bit_set::BitSet;
@@ -33,11 +32,10 @@
 }
 
 impl<Q: Qualif> QualifCursor<'a, 'mir, 'tcx, Q> {
-    pub fn new(q: Q, item: &'a Item<'mir, 'tcx>, dead_unwinds: &BitSet<BasicBlock>) -> Self {
+    pub fn new(q: Q, item: &'a Item<'mir, 'tcx>) -> Self {
         let analysis = FlowSensitiveAnalysis::new(q, item);
-        let results =
-            dataflow::Engine::new(item.tcx, &item.body, item.def_id, dead_unwinds, analysis)
-                .iterate_to_fixpoint();
+        let results = dataflow::Engine::new_generic(item.tcx, &item.body, item.def_id, analysis)
+            .iterate_to_fixpoint();
         let cursor = dataflow::ResultsCursor::new(*item.body, results);
 
         let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
@@ -146,12 +144,10 @@
 
 impl Validator<'a, 'mir, 'tcx> {
     pub fn new(item: &'a Item<'mir, 'tcx>) -> Self {
+        let needs_drop = QualifCursor::new(NeedsDrop, item);
+        let has_mut_interior = QualifCursor::new(HasMutInterior, item);
+
         let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len());
-
-        let needs_drop = QualifCursor::new(NeedsDrop, item, &dead_unwinds);
-
-        let has_mut_interior = QualifCursor::new(HasMutInterior, item, &dead_unwinds);
-
         let indirectly_mutable = old_dataflow::do_dataflow(
             item.tcx,
             &*item.body,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 072cdf2..4e94354 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -18,8 +18,6 @@
 use crate::const_eval::{is_const_fn, is_min_const_fn};
 use crate::util;
 
-use rustc_error_codes::*;
-
 pub struct UnsafetyChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
     const_context: bool,
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index bd398c6..d645f6c 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -14,7 +14,7 @@
     SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
     UnOp, RETURN_PLACE,
 };
-use rustc::traits::TraitQueryMode;
+use rustc::traits;
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
 };
@@ -90,28 +90,28 @@
         // If there are unsatisfiable where clauses, then all bets are
         // off, and we just give up.
         //
-        // Note that we use TraitQueryMode::Canonical here, which causes
-        // us to treat overflow like any other error. This is because we
-        // are "speculatively" evaluating this item with the default substs.
-        // While this usually succeeds, it may fail with tricky impls
-        // (e.g. the typenum crate). Const-propagation is fundamentally
-        // "best-effort", and does not affect correctness in any way.
-        // Therefore, it's perfectly fine to just "give up" if we're
-        // unable to check the bounds with the default substs.
+        // We manually filter the predicates, skipping anything that's not
+        // "global". We are in a potentially generic context
+        // (e.g. we are evaluating a function without substituting generic
+        // parameters, so this filtering serves two purposes:
         //
-        // False negatives (failing to run const-prop on something when we actually
-        // could) are fine. However, false positives (running const-prop on
-        // an item with unsatisfiable bounds) can lead to us generating invalid
-        // MIR.
-        if !tcx.substitute_normalize_and_test_predicates((
-            source.def_id(),
-            InternalSubsts::identity_for_item(tcx, source.def_id()),
-            TraitQueryMode::Canonical,
-        )) {
-            trace!(
-                "ConstProp skipped for item with unsatisfiable predicates: {:?}",
-                source.def_id()
-            );
+        // 1. We skip evaluating any predicates that we would
+        // never be able prove are unsatisfiable (e.g. `<T as Foo>`
+        // 2. We avoid trying to normalize predicates involving generic
+        // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
+        // the normalization code (leading to cycle errors), since
+        // it's usually never invoked in this way.
+        let predicates = tcx
+            .predicates_of(source.def_id())
+            .predicates
+            .iter()
+            .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None })
+            .collect();
+        if !traits::normalize_and_test_predicates(
+            tcx,
+            traits::elaborate_predicates(tcx, predicates).collect(),
+        ) {
+            trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", source.def_id());
             return;
         }
 
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index d927553..b047e53 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -5,7 +5,7 @@
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
-use syntax::attr;
+use syntax::{ast, attr};
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
@@ -27,12 +27,19 @@
                     bug!("closure kind predicate on function: {:#?}", predicate)
                 }
                 Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
-                Predicate::Trait(pred) => {
+                Predicate::Trait(pred, constness) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
                     }
                     match pred.skip_binder().self_ty().kind {
                         ty::Param(ref p) => {
+                            // Allow `T: ?const Trait`
+                            if *constness == ast::Constness::NotConst
+                                && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out)
+                            {
+                                continue;
+                            }
+
                             let generics = tcx.generics_of(current);
                             let def = generics.type_param(p, tcx);
                             let span = tcx.def_span(def.def_id);
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index c275eec..d8ee059 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -1,5 +1,4 @@
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId};
 use rustc_span::{MultiSpan, Span};
 
diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml
index 79c7303..a22c4d1 100644
--- a/src/librustc_mir_build/Cargo.toml
+++ b/src/librustc_mir_build/Cargo.toml
@@ -21,8 +21,8 @@
 rustc_hir = { path = "../librustc_hir" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
+rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index 8fcaa1e..20183fd 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -582,15 +582,12 @@
 }
 
 impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
-    crate fn create_and_enter<F, R>(
+    crate fn create_and_enter<R>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         module: DefId,
-        f: F,
-    ) -> R
-    where
-        F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
-    {
+        f: impl for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
+    ) -> R {
         let pattern_arena = TypedArena::default();
 
         f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena })
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index 84d57a8..49b7c2d 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -5,17 +5,17 @@
 use super::{PatCtxt, PatKind, PatternError};
 
 use rustc::hir::map::Map;
-use rustc::lint;
-use rustc::session::parse::feature_err;
-use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_error_codes::*;
 use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{HirId, Pat};
+use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
+use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
+use rustc_session::parse::feature_err;
+use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{MultiSpan, Span};
 use syntax::ast::Mutability;
@@ -68,18 +68,13 @@
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-
-        // Check legality of move bindings and `@` patterns.
         self.check_patterns(false, &loc.pat);
     }
 
-    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
-        intravisit::walk_body(self, body);
-
-        for param in body.params {
-            self.check_irrefutable(&param.pat, "function argument", None);
-            self.check_patterns(false, &param.pat);
-        }
+    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+        intravisit::walk_param(self, param);
+        self.check_irrefutable(&param.pat, "function argument", None);
+        self.check_patterns(false, &param.pat);
     }
 }
 
@@ -124,6 +119,25 @@
         if !self.tcx.features().bindings_after_at {
             check_legality_of_bindings_in_at_patterns(self, pat);
         }
+        check_for_bindings_named_same_as_variants(self, pat);
+    }
+
+    fn lower_pattern<'p>(
+        &self,
+        cx: &mut MatchCheckCtxt<'p, 'tcx>,
+        pat: &'tcx hir::Pat<'tcx>,
+        have_errors: &mut bool,
+    ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) {
+        let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
+        patcx.include_lint_checks();
+        let pattern = patcx.lower_pattern(pat);
+        let pattern_ty = pattern.ty;
+        let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
+        if !patcx.errors.is_empty() {
+            *have_errors = true;
+            patcx.report_inlining_errors(pat.span);
+        }
+        (pattern, pattern_ty)
     }
 
     fn check_match(
@@ -133,11 +147,8 @@
         source: hir::MatchSource,
     ) {
         for arm in arms {
-            // First, check legality of move bindings.
+            // Check the arm for some things unrelated to exhaustiveness.
             self.check_patterns(arm.guard.is_some(), &arm.pat);
-
-            // Second, perform some lints.
-            check_for_bindings_named_same_as_variants(self, &arm.pat);
         }
 
         let module = self.tcx.hir().get_module_parent(scrut.hir_id);
@@ -146,16 +157,8 @@
 
             let inlined_arms: Vec<_> = arms
                 .iter()
-                .map(|arm| {
-                    let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
-                    patcx.include_lint_checks();
-                    let pattern = patcx.lower_pattern(&arm.pat);
-                    let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
-                    if !patcx.errors.is_empty() {
-                        patcx.report_inlining_errors(arm.pat.span);
-                        have_errors = true;
-                    }
-                    (pattern, &*arm.pat, arm.guard.is_some())
+                .map(|hir::Arm { pat, guard, .. }| {
+                    (self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
                 })
                 .collect();
 
@@ -179,11 +182,7 @@
     fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
         let module = self.tcx.hir().get_module_parent(pat.hir_id);
         MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
-            let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
-            patcx.include_lint_checks();
-            let pattern = patcx.lower_pattern(pat);
-            let pattern_ty = pattern.ty;
-            let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
+            let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false);
             let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
 
             let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
@@ -286,7 +285,7 @@
                         let ty_path = cx.tcx.def_path_str(edef.did);
                         cx.tcx
                             .struct_span_lint_hir(
-                                lint::builtin::BINDINGS_WITH_VARIANT_NAME,
+                                BINDINGS_WITH_VARIANT_NAME,
                                 p.hir_id,
                                 p.span,
                                 &format!(
@@ -311,79 +310,63 @@
 }
 
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
-fn pat_is_catchall(pat: &Pat<'_>) -> bool {
-    match pat.kind {
-        hir::PatKind::Binding(.., None) => true,
-        hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
-        hir::PatKind::Ref(ref s, _) => pat_is_catchall(s),
-        hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)),
+fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
+    use super::PatKind::*;
+    match &*pat.kind {
+        Binding { subpattern: None, .. } => true,
+        Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
+        Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)),
         _ => false,
     }
 }
 
+fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
+    let mut err = tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern");
+    if let Some(catchall) = catchall {
+        // We had a catchall pattern, hint at that.
+        err.span_label(span, "unreachable pattern");
+        err.span_label(catchall, "matches any value");
+    }
+    err.emit();
+}
+
+fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
+    let msg = match source {
+        hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
+        hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
+        _ => bug!(),
+    };
+    tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg);
+}
+
 /// Check for unreachable patterns.
 fn check_arms<'p, 'tcx>(
     cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)],
+    arms: &[(&'p super::Pat<'tcx>, HirId, bool)],
     source: hir::MatchSource,
 ) -> Matrix<'p, 'tcx> {
     let mut seen = Matrix::empty();
     let mut catchall = None;
-    for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
+    for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() {
         let v = PatStack::from_pattern(pat);
-
-        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
+        match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) {
             NotUseful => {
                 match source {
                     hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
 
                     hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
-                        // check which arm we're on.
+                        // Check which arm we're on.
                         match arm_index {
                             // The arm with the user-specified pattern.
-                            0 => {
-                                cx.tcx.lint_hir(
-                                    lint::builtin::UNREACHABLE_PATTERNS,
-                                    hir_pat.hir_id,
-                                    pat.span,
-                                    "unreachable pattern",
-                                );
-                            }
+                            0 => unreachable_pattern(cx.tcx, pat.span, id, None),
                             // The arm with the wildcard pattern.
-                            1 => {
-                                let msg = match source {
-                                    hir::MatchSource::IfLetDesugar { .. } => {
-                                        "irrefutable if-let pattern"
-                                    }
-                                    hir::MatchSource::WhileLetDesugar => {
-                                        "irrefutable while-let pattern"
-                                    }
-                                    _ => bug!(),
-                                };
-                                cx.tcx.lint_hir(
-                                    lint::builtin::IRREFUTABLE_LET_PATTERNS,
-                                    hir_pat.hir_id,
-                                    pat.span,
-                                    msg,
-                                );
-                            }
+                            1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source),
                             _ => bug!(),
                         }
                     }
 
                     hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                        let mut err = cx.tcx.struct_span_lint_hir(
-                            lint::builtin::UNREACHABLE_PATTERNS,
-                            hir_pat.hir_id,
-                            pat.span,
-                            "unreachable pattern",
-                        );
-                        // if we had a catchall pattern, hint at that
-                        if let Some(catchall) = catchall {
-                            err.span_label(pat.span, "unreachable pattern");
-                            err.span_label(catchall, "matches any value");
-                        }
-                        err.emit();
+                        unreachable_pattern(cx.tcx, pat.span, id, catchall);
                     }
 
                     // Unreachable patterns in try and await expressions occur when one of
@@ -393,19 +376,14 @@
             }
             Useful(unreachable_subpatterns) => {
                 for pat in unreachable_subpatterns {
-                    cx.tcx.lint_hir(
-                        lint::builtin::UNREACHABLE_PATTERNS,
-                        hir_pat.hir_id,
-                        pat.span,
-                        "unreachable pattern",
-                    );
+                    unreachable_pattern(cx.tcx, pat.span, id, None);
                 }
             }
             UsefulWithWitness(_) => bug!(),
         }
         if !has_guard {
             seen.push(v);
-            if catchall.is_none() && pat_is_catchall(hir_pat) {
+            if catchall.is_none() && pat_is_catchall(pat) {
                 catchall = Some(pat.span);
             }
         }
diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs
index 205e25f..2657050 100644
--- a/src/librustc_mir_build/hair/pattern/mod.rs
+++ b/src/librustc_mir_build/hair/pattern/mod.rs
@@ -28,8 +28,6 @@
 use std::cmp::Ordering;
 use std::fmt;
 
-use rustc_error_codes::*;
-
 #[derive(Clone, Debug)]
 crate enum PatternError {
     AssocConstInPattern(Span),
diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml
index aa159c5..8071bc6 100644
--- a/src/librustc_parse/Cargo.toml
+++ b/src/librustc_parse/Cargo.toml
@@ -16,7 +16,6 @@
 rustc_feature = { path = "../librustc_feature" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_errors = { path = "../librustc_errors" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 8467acc..bf696fa 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -10,7 +10,6 @@
 
 use crate::{parse_in, validate_attr};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_error_codes::*;
 use rustc_errors::{error_code, struct_span_err, Applicability, Handler};
 use rustc_feature::{Feature, Features, State as FeatureState};
 use rustc_feature::{
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 6a18c63..80bc5c1 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1,7 +1,6 @@
 use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_error_codes::*;
 use rustc_errors::{pluralize, struct_span_err};
 use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
 use rustc_span::source_map::Spanned;
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 1921a6c..31db7fc 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -3,9 +3,8 @@
 
 use crate::maybe_whole;
 
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
-use rustc_span::source_map::{self, respan, Span, Spanned};
+use rustc_span::source_map::{self, respan, Span};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::BytePos;
 use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
@@ -566,9 +565,9 @@
         let constness = if self.eat_keyword(kw::Const) {
             let span = self.prev_span;
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            Some(respan(span, Constness::Const))
+            Constness::Const
         } else {
-            None
+            Constness::NotConst
         };
 
         // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
@@ -631,13 +630,13 @@
                         err_path(ty_first.span)
                     }
                 };
-                let constness = constness.map(|c| c.node);
-                let trait_ref = TraitRef { path, constness, ref_id: ty_first.id };
+                let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
                 ItemKind::Impl {
                     unsafety,
                     polarity,
                     defaultness,
+                    constness,
                     generics,
                     of_trait: Some(trait_ref),
                     self_ty: ty_second,
@@ -645,18 +644,12 @@
                 }
             }
             None => {
-                // Reject `impl const Type {}` here
-                if let Some(Spanned { node: Constness::Const, span }) = constness {
-                    self.struct_span_err(span, "`const` cannot modify an inherent impl")
-                        .help("only a trait impl can be `const`")
-                        .emit();
-                }
-
                 // impl Type
                 ItemKind::Impl {
                     unsafety,
                     polarity,
                     defaultness,
+                    constness,
                     generics,
                     of_trait: None,
                     self_ty: ty_first,
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 1368230..4a90163 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -33,8 +33,6 @@
 use std::path::PathBuf;
 use std::{cmp, mem, slice};
 
-use rustc_error_codes::*;
-
 bitflags::bitflags! {
     struct Restrictions: u8 {
         const STMT_EXPR         = 1 << 0;
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 549acf6..edb9044 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -659,7 +659,6 @@
     }
 
     pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) {
-        use rustc_error_codes::E0586;
         struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
             .span_suggestion_short(
                 span,
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 065a3b1..a4cc9fa 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -3,7 +3,6 @@
 
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
-use rustc_error_codes::*;
 use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym};
@@ -27,10 +26,12 @@
 }
 
 impl BoundModifiers {
-    fn trait_bound_modifier(&self) -> TraitBoundModifier {
-        match self.maybe {
-            Some(_) => TraitBoundModifier::Maybe,
-            None => TraitBoundModifier::None,
+    fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
+        match (self.maybe, self.maybe_const) {
+            (None, None) => TraitBoundModifier::None,
+            (Some(_), None) => TraitBoundModifier::Maybe,
+            (None, Some(_)) => TraitBoundModifier::MaybeConst,
+            (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
         }
     }
 }
@@ -215,7 +216,7 @@
     ) -> PResult<'a, TyKind> {
         assert_ne!(self.token, token::Question);
 
-        let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
+        let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
         let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
         if parse_plus {
             self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
@@ -557,9 +558,9 @@
             self.expect(&token::CloseDelim(token::Paren))?;
         }
 
-        let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
-        let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
-        Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
+        let modifier = modifiers.to_trait_bound_modifier();
+        let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        Ok(GenericBound::Trait(poly_trait, modifier))
     }
 
     /// Optionally parses `for<$generic_params>`.
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index 639d863..338808f 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -20,4 +20,3 @@
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 39ba2fb..faa85f6 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -12,7 +12,6 @@
 use rustc::session::parse::feature_err;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs
index 028d7c6..d36114f 100644
--- a/src/librustc_passes/entry.rs
+++ b/src/librustc_passes/entry.rs
@@ -12,8 +12,6 @@
 use syntax::attr;
 use syntax::entry::EntryPointType;
 
-use rustc_error_codes::*;
-
 struct EntryContext<'a, 'tcx> {
     session: &'a Session,
 
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
index 2c26707..7821990 100644
--- a/src/librustc_passes/intrinsicck.rs
+++ b/src/librustc_passes/intrinsicck.rs
@@ -11,8 +11,6 @@
 use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 
-use rustc_error_codes::*;
-
 fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
 }
diff --git a/src/librustc_passes/lib_features.rs b/src/librustc_passes/lib_features.rs
index 8ae7291..2e306a1 100644
--- a/src/librustc_passes/lib_features.rs
+++ b/src/librustc_passes/lib_features.rs
@@ -15,8 +15,6 @@
 use rustc_span::{sym, Span};
 use syntax::ast::{Attribute, MetaItem, MetaItemKind};
 
-use rustc_error_codes::*;
-
 fn new_lib_features() -> LibFeatures {
     LibFeatures { stable: Default::default(), unstable: Default::default() }
 }
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 5ad5795..69d6b38 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -1,7 +1,5 @@
 use Context::*;
 
-use rustc::session::Session;
-
 use rustc::hir::map::Map;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
@@ -10,10 +8,9 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Destination, Movability, Node};
+use rustc_session::Session;
 use rustc_span::Span;
 
-use rustc_error_codes::*;
-
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index b649f36..320b433 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -26,8 +26,6 @@
 use std::mem::replace;
 use std::num::NonZeroU32;
 
-use rustc_error_codes::*;
-
 #[derive(PartialEq)]
 enum AnnotationKind {
     // Annotation is required if not inherited from unstable parents
diff --git a/src/librustc_plugin_impl/Cargo.toml b/src/librustc_plugin_impl/Cargo.toml
index 41e6c69..2214838 100644
--- a/src/librustc_plugin_impl/Cargo.toml
+++ b/src/librustc_plugin_impl/Cargo.toml
@@ -18,4 +18,3 @@
 rustc_metadata = { path = "../librustc_metadata" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_plugin_impl/load.rs b/src/librustc_plugin_impl/load.rs
index 65661ec..84549c0 100644
--- a/src/librustc_plugin_impl/load.rs
+++ b/src/librustc_plugin_impl/load.rs
@@ -3,7 +3,6 @@
 use crate::Registry;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::session::Session;
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_metadata::locator;
 use rustc_span::symbol::sym;
diff --git a/src/librustc_privacy/Cargo.toml b/src/librustc_privacy/Cargo.toml
index 795b6c1..4f341b5 100644
--- a/src/librustc_privacy/Cargo.toml
+++ b/src/librustc_privacy/Cargo.toml
@@ -16,5 +16,4 @@
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
 rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 log = "0.4"
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 90a422a..60bf271 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -27,8 +27,6 @@
 use std::marker::PhantomData;
 use std::{cmp, fmt, mem};
 
-use rustc_error_codes::*;
-
 ////////////////////////////////////////////////////////////////////////////////
 /// Generic infrastructure used to implement specific visitors below.
 ////////////////////////////////////////////////////////////////////////////////
@@ -93,7 +91,7 @@
         let ty::GenericPredicates { parent: _, predicates } = predicates;
         for (predicate, _span) in predicates {
             match predicate {
-                ty::Predicate::Trait(poly_predicate) => {
+                ty::Predicate::Trait(poly_predicate, _) => {
                     let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
                     if self.visit_trait(trait_ref) {
                         return true;
@@ -1237,7 +1235,7 @@
             // The traits' privacy in bodies is already checked as a part of trait object types.
             let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
 
-            for (trait_predicate, _) in bounds.trait_bounds {
+            for (trait_predicate, _, _) in bounds.trait_bounds {
                 if self.visit_trait(*trait_predicate.skip_binder()) {
                     return;
                 }
diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml
index af37e7b..c4cc6b0 100644
--- a/src/librustc_resolve/Cargo.toml
+++ b/src/librustc_resolve/Cargo.toml
@@ -23,7 +23,6 @@
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_metadata = { path = "../librustc_metadata" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 40a89ef..7ff0762 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -21,7 +21,6 @@
 use rustc::middle::cstore::CrateStore;
 use rustc::ty;
 use rustc_data_structures::sync::Lrc;
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::SyntaxExtension;
 use rustc_expand::expand::AstFragment;
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index a433ae8..77dfe3d 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -5,8 +5,9 @@
 use rustc::session::Session;
 use rustc::ty::{self, DefIdTree};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_feature::BUILTIN_ATTRIBUTES;
+use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -25,8 +26,6 @@
 use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};
 
-use rustc_error_codes::*;
-
 type Res = def::Res<ast::NodeId>;
 
 /// A vector of spans and replacements, a message and applicability.
@@ -1447,3 +1446,74 @@
         }
     }
 }
+
+crate fn report_missing_lifetime_specifiers(
+    sess: &Session,
+    span: Span,
+    count: usize,
+) -> DiagnosticBuilder<'_> {
+    struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count))
+}
+
+crate fn add_missing_lifetime_specifiers_label(
+    err: &mut DiagnosticBuilder<'_>,
+    span: Span,
+    count: usize,
+    lifetime_names: &FxHashSet<ast::Ident>,
+    snippet: Option<&str>,
+    missing_named_lifetime_spots: &[&hir::Generics<'_>],
+) {
+    if count > 1 {
+        err.span_label(span, format!("expected {} lifetime parameters", count));
+    } else {
+        let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
+            err.span_suggestion(
+                span,
+                "consider using the named lifetime",
+                sugg,
+                Applicability::MaybeIncorrect,
+            );
+        };
+        let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| {
+            err.span_label(span, "expected named lifetime parameter");
+
+            if let Some(generics) = missing_named_lifetime_spots.iter().last() {
+                let mut introduce_suggestion = vec![];
+                introduce_suggestion.push(match &generics.params {
+                    [] => (generics.span, "<'lifetime>".to_string()),
+                    [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()),
+                });
+                introduce_suggestion.push((span, sugg));
+                err.multipart_suggestion(
+                    "consider introducing a named lifetime parameter",
+                    introduce_suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        };
+
+        match (lifetime_names.len(), lifetime_names.iter().next(), snippet) {
+            (1, Some(name), Some("&")) => {
+                suggest_existing(err, format!("&{} ", name));
+            }
+            (1, Some(name), Some("'_")) => {
+                suggest_existing(err, name.to_string());
+            }
+            (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => {
+                suggest_existing(err, format!("{}<{}>", snippet, name));
+            }
+            (0, _, Some("&")) => {
+                suggest_new(err, "&'lifetime ".to_string());
+            }
+            (0, _, Some("'_")) => {
+                suggest_new(err, "'lifetime".to_string());
+            }
+            (0, _, Some(snippet)) if !snippet.ends_with(">") => {
+                suggest_new(err, format!("{}<'lifetime>", snippet));
+            }
+            _ => {
+                err.span_label(span, "expected lifetime parameter");
+            }
+        }
+    }
+}
diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs
index 9f45983..55ce51e 100644
--- a/src/librustc_resolve/imports.rs
+++ b/src/librustc_resolve/imports.rs
@@ -29,8 +29,6 @@
 use syntax::unwrap_or;
 use syntax::util::lev_distance::find_best_match_for_name;
 
-use rustc_error_codes::*;
-
 use log::*;
 
 use std::cell::Cell;
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 08cd9c4..5e08ac8 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -31,8 +31,6 @@
 use std::collections::BTreeSet;
 use std::mem::replace;
 
-use rustc_error_codes::*;
-
 mod diagnostics;
 
 type Res = def::Res<NodeId>;
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index 151f3e8..6a98c9e 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -6,7 +6,6 @@
 
 use rustc::session::config::nightly_options;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_error_codes::*;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind};
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 60a0049..0e6f40f 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -11,6 +11,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(nll)]
+#![cfg_attr(bootstrap, feature(slice_patterns))]
 #![recursion_limit = "256"]
 
 pub use rustc_hir::def::{Namespace, PerNS};
@@ -61,8 +62,6 @@
 use late::{HasGenericParams, PathSource, Rib, RibKind::*};
 use macros::{LegacyBinding, LegacyScope};
 
-use rustc_error_codes::*;
-
 type Res = def::Res<NodeId>;
 
 mod build_reduced_graph;
diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs
index 5fae8f3..6e9ed5f 100644
--- a/src/librustc_resolve/lifetimes.rs
+++ b/src/librustc_resolve/lifetimes.rs
@@ -5,14 +5,16 @@
 //! used between functions, and they operate in a purely top-down
 //! way. Therefore, we break lifetime name resolution into a separate pass.
 
+use crate::diagnostics::{
+    add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers,
+};
 use rustc::hir::map::Map;
 use rustc::lint;
 use rustc::middle::resolve_lifetime::*;
-use rustc::session::Session;
 use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
 use rustc::{bug, span_bug};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@@ -30,8 +32,6 @@
 
 use log::debug;
 
-use rustc_error_codes::*;
-
 // This counts the no of times a lifetime is used
 #[derive(Clone, Copy, Debug)]
 pub enum LifetimeUseSet<'tcx> {
@@ -183,6 +183,10 @@
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
     lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
+
+    /// When encountering an undefined named lifetime, we will suggest introducing it in these
+    /// places.
+    missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -342,6 +346,7 @@
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: Default::default(),
             lifetime_uses: &mut Default::default(),
+            missing_named_lifetime_spots: vec![],
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -384,9 +389,11 @@
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match item.kind {
             hir::ItemKind::Fn(ref sig, ref generics, _) => {
+                self.missing_named_lifetime_spots.push(generics);
                 self.visit_early_late(None, &sig.decl, generics, |this| {
                     intravisit::walk_item(this, item);
                 });
+                self.missing_named_lifetime_spots.pop();
             }
 
             hir::ItemKind::ExternCrate(_)
@@ -417,6 +424,8 @@
             | hir::ItemKind::Trait(_, _, ref generics, ..)
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl { ref generics, .. } => {
+                self.missing_named_lifetime_spots.push(generics);
+
                 // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
                 // This is not true for other kinds of items.x
                 let track_lifetime_uses = match item.kind {
@@ -454,6 +463,7 @@
                     this.check_lifetime_params(old_scope, &generics.params);
                     intravisit::walk_item(this, item);
                 });
+                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -686,6 +696,7 @@
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
+        self.missing_named_lifetime_spots.push(&trait_item.generics);
         match trait_item.kind {
             Method(ref sig, _) => {
                 let tcx = self.tcx;
@@ -737,10 +748,12 @@
                 intravisit::walk_trait_item(self, trait_item);
             }
         }
+        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
+        self.missing_named_lifetime_spots.push(&impl_item.generics);
         match impl_item.kind {
             Method(ref sig, _) => {
                 let tcx = self.tcx;
@@ -824,6 +837,7 @@
                 intravisit::walk_impl_item(self, impl_item);
             }
         }
+        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
@@ -1309,6 +1323,7 @@
         let LifetimeContext { tcx, map, lifetime_uses, .. } = self;
         let labels_in_fn = take(&mut self.labels_in_fn);
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
+        let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
         let mut this = LifetimeContext {
             tcx: *tcx,
             map: map,
@@ -1317,7 +1332,8 @@
             is_in_fn_syntax: self.is_in_fn_syntax,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses: lifetime_uses,
+            lifetime_uses,
+            missing_named_lifetime_spots,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
@@ -1325,6 +1341,7 @@
         debug!("exiting scope {:?}", this.scope);
         self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+        self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
     }
 
     /// helper method to determine the span to remove when suggesting the
@@ -1807,15 +1824,29 @@
 
             self.insert_lifetime(lifetime_ref, def);
         } else {
-            struct_span_err!(
+            let mut err = struct_span_err!(
                 self.tcx.sess,
                 lifetime_ref.span,
                 E0261,
                 "use of undeclared lifetime name `{}`",
                 lifetime_ref
-            )
-            .span_label(lifetime_ref.span, "undeclared lifetime")
-            .emit();
+            );
+            err.span_label(lifetime_ref.span, "undeclared lifetime");
+            if !self.is_in_fn_syntax {
+                for generics in &self.missing_named_lifetime_spots {
+                    let (span, sugg) = match &generics.params {
+                        [] => (generics.span, format!("<{}>", lifetime_ref)),
+                        [param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)),
+                    };
+                    err.span_suggestion(
+                        span,
+                        &format!("consider introducing lifetime `{}` here", lifetime_ref),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+            err.emit();
         }
     }
 
@@ -2369,6 +2400,7 @@
                 lifetime_refs.len(),
                 &lifetime_names,
                 self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
+                &self.missing_named_lifetime_spots,
             );
         }
 
@@ -2864,34 +2896,3 @@
         }
     }
 }
-
-fn report_missing_lifetime_specifiers(
-    sess: &Session,
-    span: Span,
-    count: usize,
-) -> DiagnosticBuilder<'_> {
-    struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count))
-}
-
-fn add_missing_lifetime_specifiers_label(
-    err: &mut DiagnosticBuilder<'_>,
-    span: Span,
-    count: usize,
-    lifetime_names: &FxHashSet<ast::Ident>,
-    snippet: Option<&str>,
-) {
-    if count > 1 {
-        err.span_label(span, format!("expected {} lifetime parameters", count));
-    } else if let (1, Some(name), Some("&")) =
-        (lifetime_names.len(), lifetime_names.iter().next(), snippet)
-    {
-        err.span_suggestion(
-            span,
-            "consider using the named lifetime",
-            format!("&{} ", name),
-            Applicability::MaybeIncorrect,
-        );
-    } else {
-        err.span_label(span, "expected lifetime parameter");
-    }
-}
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 779d3f5..a9d2bfa 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -486,6 +486,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 ref generics,
                 ref of_trait,
                 ref self_ty,
@@ -499,6 +500,9 @@
                     text.push_str("unsafe ");
                 }
                 text.push_str("impl");
+                if constness == ast::Constness::Const {
+                    text.push_str(" const");
+                }
 
                 let generics_sig = generics.make(offset + text.len(), id, scx)?;
                 text.push_str(&generics_sig.text);
diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml
index 377ea14..47c23bc 100644
--- a/src/librustc_session/Cargo.toml
+++ b/src/librustc_session/Cargo.toml
@@ -10,7 +10,6 @@
 
 [dependencies]
 log = "0.4"
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs
index a98cf92..72c68fc 100644
--- a/src/librustc_session/parse.rs
+++ b/src/librustc_session/parse.rs
@@ -6,7 +6,6 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{Lock, Lrc, Once};
-use rustc_error_codes::E0658;
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 889f609..e4f8b5a 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -167,6 +167,7 @@
         bindings_after_at,
         block,
         bool,
+        borrowck_graphviz_format,
         borrowck_graphviz_postflow,
         borrowck_graphviz_preflow,
         box_patterns,
@@ -337,6 +338,7 @@
         FxHashSet,
         FxHashMap,
         gen_future,
+        gen_kill,
         generators,
         generic_associated_types,
         generic_param_attrs,
@@ -735,6 +737,7 @@
         try_trait,
         tt,
         tuple_indexing,
+        two_phase,
         Ty,
         ty,
         type_alias_impl_trait,
diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs
index 4b4fa4b..b77c603 100644
--- a/src/librustc_traits/lowering/mod.rs
+++ b/src/librustc_traits/lowering/mod.rs
@@ -94,7 +94,7 @@
         use rustc::ty::Predicate;
 
         match self {
-            Predicate::Trait(predicate) => predicate.lower(),
+            Predicate::Trait(predicate, _) => predicate.lower(),
             Predicate::RegionOutlives(predicate) => predicate.lower(),
             Predicate::TypeOutlives(predicate) => predicate.lower(),
             Predicate::Projection(predicate) => predicate.lower(),
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index d47e543..8b62403 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -2,7 +2,7 @@
 use rustc::session::CrateDisambiguator;
 use rustc::traits::{self};
 use rustc::ty::subst::Subst;
-use rustc::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
@@ -58,6 +58,7 @@
                 def_id: sized_trait,
                 substs: tcx.mk_substs_trait(ty, &[]),
             })
+            .without_const()
             .to_predicate();
             let predicates = tcx.predicates_of(adtdef.did).predicates;
             if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 84e5f56..4b27d86 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -22,4 +22,3 @@
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
 rustc_index = { path = "../librustc_index" }
-rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 173bb29..89eeed8 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -3,6 +3,8 @@
 //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
 //! instance of `AstConv`.
 
+// ignore-tidy-filelength
+
 use crate::collect::PlaceholderHirTyCollector;
 use crate::lint;
 use crate::middle::lang_items::SizedTraitLangItem;
@@ -17,7 +19,7 @@
 use rustc::traits::error_reporting::report_object_safety_error;
 use rustc::traits::wf::object_region_bounds;
 use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
-use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
@@ -31,7 +33,7 @@
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use smallvec::SmallVec;
-use syntax::ast;
+use syntax::ast::{self, Constness};
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use std::collections::BTreeSet;
@@ -39,7 +41,6 @@
 use std::slice;
 
 use rustc::mir::interpret::LitToConstInput;
-use rustc_error_codes::*;
 
 #[derive(Debug)]
 pub struct PathSeg(pub DefId, pub usize);
@@ -49,6 +50,8 @@
 
     fn item_def_id(&self) -> Option<DefId>;
 
+    fn default_constness_for_trait_bounds(&self) -> Constness;
+
     /// Returns predicates in scope of the form `X: Foo`, where `X` is
     /// a type parameter `X` with the given id `def_id`. This is a
     /// subset of the full set of predicates.
@@ -919,6 +922,7 @@
         &self,
         trait_ref: &hir::TraitRef<'_>,
         span: Span,
+        constness: Constness,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
@@ -947,7 +951,7 @@
         );
         let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
 
-        bounds.trait_bounds.push((poly_trait_ref, span));
+        bounds.trait_bounds.push((poly_trait_ref, span, constness));
 
         let mut dup_bindings = FxHashMap::default();
         for binding in &assoc_bindings {
@@ -993,12 +997,14 @@
     pub fn instantiate_poly_trait_ref(
         &self,
         poly_trait_ref: &hir::PolyTraitRef<'_>,
+        constness: Constness,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
     ) -> Option<Vec<Span>> {
         self.instantiate_poly_trait_ref_inner(
             &poly_trait_ref.trait_ref,
             poly_trait_ref.span,
+            constness,
             self_ty,
             bounds,
             false,
@@ -1181,18 +1187,22 @@
         let mut trait_bounds = Vec::new();
         let mut region_bounds = Vec::new();
 
+        let constness = self.default_constness_for_trait_bounds();
         for ast_bound in ast_bounds {
             match *ast_bound {
                 hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
-                    trait_bounds.push(b)
+                    trait_bounds.push((b, constness))
+                }
+                hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => {
+                    trait_bounds.push((b, Constness::NotConst))
                 }
                 hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
                 hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
             }
         }
 
-        for bound in trait_bounds {
-            let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds);
+        for (bound, constness) in trait_bounds {
+            let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds);
         }
 
         bounds.region_bounds.extend(
@@ -1226,7 +1236,7 @@
         let mut bounds = Bounds::default();
 
         self.add_bounds(param_ty, ast_bounds, &mut bounds);
-        bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
+        bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
 
         bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
             if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
@@ -1417,15 +1427,21 @@
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
         for trait_bound in trait_bounds.iter().rev() {
-            let cur_potential_assoc_types =
-                self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds);
+            let cur_potential_assoc_types = self.instantiate_poly_trait_ref(
+                trait_bound,
+                Constness::NotConst,
+                dummy_self,
+                &mut bounds,
+            );
             potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
         }
 
         // Expand trait aliases recursively and check that only one regular (non-auto) trait
         // is used and no 'maybe' bounds are used.
-        let expanded_traits =
-            traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
+        let expanded_traits = traits::expand_trait_aliases(
+            tcx,
+            bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)),
+        );
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
             expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
@@ -1481,16 +1497,18 @@
         let regular_traits_refs_spans = bounds
             .trait_bounds
             .into_iter()
-            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+            .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
-        for (base_trait_ref, span) in regular_traits_refs_spans {
+        for (base_trait_ref, span, constness) in regular_traits_refs_spans {
+            assert_eq!(constness, ast::Constness::NotConst);
+
             for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
                 debug!(
                     "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
                     trait_ref
                 );
                 match trait_ref {
-                    ty::Predicate::Trait(pred) => {
+                    ty::Predicate::Trait(pred, _) => {
                         associated_types.entry(span).or_default().extend(
                             tcx.associated_items(pred.def_id())
                                 .filter(|item| item.kind == ty::AssocKind::Type)
@@ -2949,7 +2967,7 @@
 
     /// A list of trait bounds. So if you had `T: Debug` this would be
     /// `T: Debug`. Note that the self-type is explicit here.
-    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,
 
     /// A list of projection equality bounds. So if you had `T:
     /// Iterator<Item = u32>` this would include `<T as
@@ -2980,7 +2998,7 @@
                     def_id: sized,
                     substs: tcx.mk_substs_trait(param_ty, &[]),
                 });
-                (trait_ref.to_predicate(), span)
+                (trait_ref.without_const().to_predicate(), span)
             })
         });
 
@@ -2997,11 +3015,10 @@
                         let outlives = ty::OutlivesPredicate(param_ty, region_bound);
                         (ty::Binder::bind(outlives).to_predicate(), span)
                     })
-                    .chain(
-                        self.trait_bounds
-                            .iter()
-                            .map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)),
-                    )
+                    .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+                        let predicate = bound_trait_ref.with_constness(constness).to_predicate();
+                        (predicate, span)
+                    }))
                     .chain(
                         self.projection_bounds
                             .iter()
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index bd84547..686cdfb 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -50,30 +50,13 @@
 
         self.warn_arms_when_scrutinee_diverges(arms, match_src);
 
-        // Otherwise, we have to union together the types that the
-        // arms produce and so forth.
-        let scrut_diverges = self.diverges.get();
-        self.diverges.set(Diverges::Maybe);
+        // Otherwise, we have to union together the types that the arms produce and so forth.
+        let scrut_diverges = self.diverges.replace(Diverges::Maybe);
 
-        // rust-lang/rust#55810: Typecheck patterns first (via eager
-        // collection into `Vec`), so we get types for all bindings.
-        let all_arm_pats_diverge: Vec<_> = arms
-            .iter()
-            .map(|arm| {
-                let mut all_pats_diverge = Diverges::WarnedAlways;
-                self.diverges.set(Diverges::Maybe);
-                self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true);
-                all_pats_diverge &= self.diverges.get();
-
-                // As discussed with @eddyb, this is for disabling unreachable_code
-                // warnings on patterns (they're now subsumed by unreachable_patterns
-                // warnings).
-                match all_pats_diverge {
-                    Diverges::Maybe => Diverges::Maybe,
-                    Diverges::Always { .. } | Diverges::WarnedAlways => Diverges::WarnedAlways,
-                }
-            })
-            .collect();
+        // #55810: Type check patterns first so we get types for all bindings.
+        for arm in arms {
+            self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true);
+        }
 
         // Now typecheck the blocks.
         //
@@ -104,11 +87,11 @@
             CoerceMany::with_coercion_sites(coerce_first, arms)
         };
 
-        let mut other_arms = vec![]; // used only for diagnostics
+        let mut other_arms = vec![]; // Used only for diagnostics.
         let mut prior_arm_ty = None;
-        for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
+        for (i, arm) in arms.iter().enumerate() {
             if let Some(g) = &arm.guard {
-                self.diverges.set(pats_diverge);
+                self.diverges.set(Diverges::Maybe);
                 match g {
                     hir::Guard::If(e) => {
                         self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {})
@@ -116,7 +99,7 @@
                 };
             }
 
-            self.diverges.set(pats_diverge);
+            self.diverges.set(Diverges::Maybe);
             let arm_ty = if source_if
                 && if_no_else
                 && i != 0
@@ -200,16 +183,14 @@
         arms: &'tcx [hir::Arm<'tcx>],
         source: hir::MatchSource,
     ) {
-        if self.diverges.get().is_always() {
-            use hir::MatchSource::*;
-            let msg = match source {
-                IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression",
-                WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
-                _ => "arm",
-            };
-            for arm in arms {
-                self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
-            }
+        use hir::MatchSource::*;
+        let msg = match source {
+            IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression",
+            WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
+            _ => "arm",
+        };
+        for arm in arms {
+            self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
         }
     }
 
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 8d6b74c..e4dec97 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -5,7 +5,7 @@
 use rustc::session::DiagnosticMessageId;
 use rustc::traits::{self, TraitEngine};
 use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc::ty::{self, TraitRef, Ty, TyCtxt};
+use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -13,8 +13,6 @@
 use rustc_span::Span;
 use syntax::ast::Ident;
 
-use rustc_error_codes::*;
-
 use std::iter;
 
 #[derive(Copy, Clone, Debug)]
@@ -124,8 +122,11 @@
 
         let cause = traits::ObligationCause::misc(self.span, self.body_id);
 
-        let obligation =
-            traits::Obligation::new(cause.clone(), self.param_env, trait_ref.to_predicate());
+        let obligation = traits::Obligation::new(
+            cause.clone(),
+            self.param_env,
+            trait_ref.without_const().to_predicate(),
+        );
         if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 58f407b..b33cc52 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -8,7 +8,6 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::{infer, traits};
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index cbbfe2d..d254a84 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -49,8 +49,6 @@
 use rustc_span::Span;
 use syntax::ast;
 
-use rustc_error_codes::*;
-
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
 pub struct CastCheck<'tcx> {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index a32fbff..54b32c3 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -65,7 +65,6 @@
 use rustc::ty::relate::RelateResult;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeAndMut};
-use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -565,7 +564,7 @@
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
             let trait_ref = match obligation.predicate {
-                ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
+                ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => {
                     if unsize_did == tr.def_id() {
                         let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind;
                         if let ty::Tuple(..) = sty {
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index c35661a..414f80d 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -15,8 +15,6 @@
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
 
-use rustc_error_codes::*;
-
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
 ///
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 88e7a26..32773e2 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -14,8 +14,6 @@
 
 use rustc_span::Span;
 
-use rustc_error_codes::*;
-
 /// This function confirms that the `Drop` implementation identified by
 /// `drop_impl_did` is not any more specialized than the type it is
 /// attached to (Issue #8142).
@@ -234,7 +232,7 @@
         let predicate_matches_closure = |p: &'_ Predicate<'tcx>| {
             let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
             match (predicate, p) {
-                (Predicate::Trait(a), Predicate::Trait(b)) => relator.relate(a, b).is_ok(),
+                (Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(),
                 (Predicate::Projection(a), Predicate::Projection(b)) => {
                     relator.relate(a, b).is_ok()
                 }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 35342de..b4c2b85 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -38,8 +38,6 @@
 use syntax::ast;
 use syntax::util::lev_distance::find_best_match_for_name;
 
-use rustc_error_codes::*;
-
 use std::fmt::Display;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -167,10 +165,8 @@
         }
 
         // Hide the outer diverging and has_errors flags.
-        let old_diverges = self.diverges.get();
-        let old_has_errors = self.has_errors.get();
-        self.diverges.set(Diverges::Maybe);
-        self.has_errors.set(false);
+        let old_diverges = self.diverges.replace(Diverges::Maybe);
+        let old_has_errors = self.has_errors.replace(false);
 
         let ty = self.check_expr_kind(expr, expected, needs);
 
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 0441514..3572eda 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -6,7 +6,6 @@
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_span::symbol::Symbol;
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 636ea5b..2012a2a 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -569,7 +569,7 @@
 
         traits::elaborate_predicates(self.tcx, predicates.predicates.clone())
             .filter_map(|predicate| match predicate {
-                ty::Predicate::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
+                ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
                     Some(trait_pred)
                 }
                 _ => None,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 711c285..c1cf352 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -17,7 +17,7 @@
 use rustc::ty::subst::Subst;
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::ty::GenericParamDefKind;
-use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable};
+use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -322,7 +322,7 @@
             span,
             self.body_id,
             self.param_env,
-            poly_trait_ref.to_predicate(),
+            poly_trait_ref.without_const().to_predicate(),
         );
 
         // Now we want to know if this can be matched
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index b2542cc..2adf125 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -25,6 +25,7 @@
 use rustc::ty::GenericParamDefKind;
 use rustc::ty::{
     self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
+    WithConstness,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
@@ -38,8 +39,6 @@
 use syntax::ast;
 use syntax::util::lev_distance::{find_best_match_for_name, lev_distance};
 
-use rustc_error_codes::*;
-
 use smallvec::{smallvec, SmallVec};
 
 use self::CandidateKind::*;
@@ -826,7 +825,7 @@
         // FIXME: do we want to commit to this behavior for param bounds?
 
         let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate {
-            ty::Predicate::Trait(ref trait_predicate) => {
+            ty::Predicate::Trait(ref trait_predicate, _) => {
                 match trait_predicate.skip_binder().trait_ref.self_ty().kind {
                     ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()),
                     _ => None,
@@ -1396,7 +1395,7 @@
                 }
 
                 TraitCandidate(trait_ref) => {
-                    let predicate = trait_ref.to_predicate();
+                    let predicate = trait_ref.without_const().to_predicate();
                     let obligation = traits::Obligation::new(cause, self.param_env, predicate);
                     if !self.predicate_may_hold(&obligation) {
                         if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
@@ -1430,7 +1429,7 @@
                 let o = self.resolve_vars_if_possible(&o);
                 if !self.predicate_may_hold(&o) {
                     result = ProbeResult::NoMatch;
-                    if let &ty::Predicate::Trait(ref pred) = &o.predicate {
+                    if let &ty::Predicate::Trait(ref pred, _) = &o.predicate {
                         possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref);
                     }
                 }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index d6c0d9c..e9942fa 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -9,7 +9,7 @@
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::traits::Obligation;
 use rustc::ty::print::with_crate_prefix;
-use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -21,8 +21,6 @@
 use syntax::ast;
 use syntax::util::lev_distance;
 
-use rustc_error_codes::*;
-
 use std::cmp::Ordering;
 
 use super::probe::Mode;
@@ -59,7 +57,7 @@
                             span,
                             self.body_id,
                             self.param_env,
-                            poly_trait_ref.to_predicate(),
+                            poly_trait_ref.without_const().to_predicate(),
                         );
                         self.predicate_may_hold(&obligation)
                     })
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4affdc4..2dc198b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -90,6 +90,7 @@
 use crate::astconv::{AstConv, PathSeg};
 use crate::middle::lang_items;
 use crate::namespace::Namespace;
+use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::map::Map;
 use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
@@ -112,7 +113,7 @@
 use rustc::ty::util::{Discr, IntTypeExt, Representability};
 use rustc::ty::{
     self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
-    ToPredicate, Ty, TyCtxt, UserType,
+    ToPredicate, Ty, TyCtxt, UserType, WithConstness,
 };
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -133,8 +134,6 @@
 use syntax::attr;
 use syntax::util::parser::ExprPrecedence;
 
-use rustc_error_codes::*;
-
 use std::cell::{Cell, Ref, RefCell, RefMut};
 use std::cmp;
 use std::collections::hash_map::Entry;
@@ -1423,7 +1422,7 @@
                 inherited.register_predicate(traits::Obligation::new(
                     cause,
                     param_env,
-                    trait_ref.to_predicate(),
+                    trait_ref.without_const().to_predicate(),
                 ));
             }
         }
@@ -2612,6 +2611,16 @@
         None
     }
 
+    fn default_constness_for_trait_bounds(&self) -> ast::Constness {
+        // FIXME: refactor this into a method
+        let node = self.tcx.hir().get(self.body_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness()
+        } else {
+            ast::Constness::NotConst
+        }
+    }
+
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
         let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
@@ -2623,7 +2632,7 @@
             parent: None,
             predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map(
                 |&predicate| match predicate {
-                    ty::Predicate::Trait(ref data)
+                    ty::Predicate::Trait(ref data, _)
                         if data.skip_binder().self_ty().is_param(index) =>
                     {
                         // HACK(eddyb) should get the original `Span`.
@@ -3695,7 +3704,7 @@
                 ty::Predicate::Projection(ref data) => {
                     Some((data.to_poly_trait_ref(self.tcx), obligation))
                 }
-                ty::Predicate::Trait(ref data) => Some((data.to_poly_trait_ref(), obligation)),
+                ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)),
                 ty::Predicate::Subtype(..) => None,
                 ty::Predicate::RegionOutlives(..) => None,
                 ty::Predicate::TypeOutlives(..) => None,
@@ -3998,7 +4007,7 @@
                 continue;
             }
 
-            if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+            if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
                 // Collect the argument position for all arguments that could have caused this
                 // `FulfillmentError`.
                 let mut referenced_in = final_arg_types
@@ -4042,7 +4051,7 @@
             if let hir::ExprKind::Path(qpath) = &path.kind {
                 if let hir::QPath::Resolved(_, path) = &qpath {
                     for error in errors {
-                        if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+                        if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
                             // If any of the type arguments in this path segment caused the
                             // `FullfillmentError`, point at its span (#61860).
                             for arg in path
@@ -4420,10 +4429,8 @@
         self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
 
         // Hide the outer diverging and `has_errors` flags.
-        let old_diverges = self.diverges.get();
-        let old_has_errors = self.has_errors.get();
-        self.diverges.set(Diverges::Maybe);
-        self.has_errors.set(false);
+        let old_diverges = self.diverges.replace(Diverges::Maybe);
+        let old_has_errors = self.has_errors.replace(false);
 
         match stmt.kind {
             hir::StmtKind::Local(ref l) => {
@@ -4433,7 +4440,6 @@
             hir::StmtKind::Item(_) => {}
             hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
-
                 self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
                     self.suggest_semicolon_at_end(expr.span, err);
                 });
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index edf9d19..91e1731 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -11,8 +11,6 @@
 use rustc_span::Span;
 use syntax::ast::Ident;
 
-use rustc_error_codes::*;
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
     pub fn check_binop_assign(
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 1478b35..f9dee0e 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -15,8 +15,6 @@
 use syntax::ast;
 use syntax::util::lev_distance::find_best_match_for_name;
 
-use rustc_error_codes::*;
-
 use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 5e91e98..8281182 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -6,7 +6,9 @@
 use rustc::session::parse::feature_err;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::{InternalSubsts, Subst};
-use rustc::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{
+    self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir::def_id::DefId;
@@ -18,8 +20,6 @@
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ParItemLikeVisitor;
 
-use rustc_error_codes::*;
-
 /// Helper type of a temporary returned by `.for_item(...)`.
 /// This is necessary because we can't write the following bound:
 ///
@@ -955,7 +955,8 @@
         substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
     };
 
-    let obligation = traits::Obligation::new(cause, fcx.param_env, trait_ref.to_predicate());
+    let obligation =
+        traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate());
 
     if fcx.predicate_must_hold_modulo_regions(&obligation) {
         true
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 516dc16..79a006a 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -12,7 +12,6 @@
 use rustc::ty::adjustment::CoerceUnsizedInfo;
 use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index d313e32..d4c89b7 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -16,8 +16,6 @@
 use rustc_span::Span;
 use syntax::ast;
 
-use rustc_error_codes::*;
-
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
 pub fn crate_inherent_impls(tcx: TyCtxt<'_>, crate_num: CrateNum) -> &CrateInherentImpls {
     assert_eq!(crate_num, LOCAL_CRATE);
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index a9228c7..d60c3cf 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -6,8 +6,6 @@
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 
-use rustc_error_codes::*;
-
 pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     assert_eq!(crate_num, LOCAL_CRATE);
     let krate = tcx.hir().krate();
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index fd685e7..5583e34 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -8,7 +8,6 @@
 use rustc::traits;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc_error_codes::*;
 use rustc_errors::struct_span_err;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::HirId;
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 9ba8fa4..8052166 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -7,8 +7,6 @@
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 
-use rustc_error_codes::*;
-
 pub fn check(tcx: TyCtxt<'_>) {
     let mut orphan = OrphanChecker { tcx };
     tcx.hir().krate().visit_all_item_likes(&mut orphan);
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 48b9688..a604421 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -7,8 +7,6 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Unsafety;
 
-use rustc_error_codes::*;
-
 pub fn check(tcx: TyCtxt<'_>) {
     let mut unsafety = UnsafetyChecker { tcx };
     tcx.hir().krate().visit_all_item_likes(&mut unsafety);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a03b9f7..5821977 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -20,6 +20,7 @@
 use crate::lint;
 use crate::middle::resolve_lifetime as rl;
 use crate::middle::weak_lang_items;
+use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::map::Map;
 use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc::mir::mono::Linkage;
@@ -30,7 +31,7 @@
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::util::Discr;
 use rustc::ty::util::IntTypeExt;
-use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness};
 use rustc::ty::{ReprOptions, ToPredicate};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
@@ -47,8 +48,6 @@
 use syntax::ast::{Ident, MetaItemKind};
 use syntax::attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
 
-use rustc_error_codes::*;
-
 struct OnlySelfBounds(bool);
 
 ///////////////////////////////////////////////////////////////////////////
@@ -288,6 +287,22 @@
         Some(self.item_def_id)
     }
 
+    fn default_constness_for_trait_bounds(&self) -> ast::Constness {
+        // FIXME: refactor this into a method
+        let hir_id = self
+            .tcx
+            .hir()
+            .as_local_hir_id(self.item_def_id)
+            .expect("Non-local call to local provider is_const_fn");
+
+        let node = self.tcx.hir().get(hir_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness()
+        } else {
+            ast::Constness::NotConst
+        }
+    }
+
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
     }
@@ -411,7 +426,8 @@
                     // Implied `Self: Trait` and supertrait bounds.
                     if param_id == item_hir_id {
                         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
-                        extend = Some((identity_trait_ref.to_predicate(), item.span));
+                        extend =
+                            Some((identity_trait_ref.without_const().to_predicate(), item.span));
                     }
                     generics
                 }
@@ -432,7 +448,7 @@
         icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
             .into_iter()
             .filter(|(predicate, _)| match predicate {
-                ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index),
+                ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index),
                 _ => false,
             }),
     );
@@ -453,6 +469,7 @@
         ty: Ty<'tcx>,
         only_self_bounds: OnlySelfBounds,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        let constness = self.default_constness_for_trait_bounds();
         let from_ty_params = ast_generics
             .params
             .iter()
@@ -461,7 +478,7 @@
                 _ => None,
             })
             .flat_map(|bounds| bounds.iter())
-            .flat_map(|b| predicates_from_bound(self, ty, b));
+            .flat_map(|b| predicates_from_bound(self, ty, b, constness));
 
         let from_where_clauses = ast_generics
             .where_clause
@@ -481,7 +498,7 @@
                 };
                 bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
             })
-            .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
+            .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
@@ -857,7 +874,7 @@
     // which will, in turn, reach indirect supertraits.
     for &(pred, span) in superbounds {
         debug!("superbound: {:?}", pred);
-        if let ty::Predicate::Trait(bound) = pred {
+        if let ty::Predicate::Trait(bound, _) = pred {
             tcx.at(span).super_predicates_of(bound.def_id());
         }
     }
@@ -2056,7 +2073,7 @@
         let span = tcx.def_span(def_id);
         result.predicates =
             tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).to_predicate(),
+                ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(),
                 span,
             ))));
     }
@@ -2106,6 +2123,7 @@
     let mut is_default_impl_trait = None;
 
     let icx = ItemCtxt::new(tcx, def_id);
+    let constness = icx.default_constness_for_trait_bounds();
 
     const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
 
@@ -2230,7 +2248,10 @@
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.push((trait_ref.to_poly_trait_ref().to_predicate(), tcx.def_span(def_id)));
+        predicates.push((
+            trait_ref.to_poly_trait_ref().without_const().to_predicate(),
+            tcx.def_span(def_id),
+        ));
     }
 
     // Collect the region predicates that were declared inline as
@@ -2304,11 +2325,18 @@
 
                 for bound in bound_pred.bounds.iter() {
                     match bound {
-                        &hir::GenericBound::Trait(ref poly_trait_ref, _) => {
+                        &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
+                            let constness = match modifier {
+                                hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+                                hir::TraitBoundModifier::None => constness,
+                                hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
+                            };
+
                             let mut bounds = Bounds::default();
                             let _ = AstConv::instantiate_poly_trait_ref(
                                 &icx,
                                 poly_trait_ref,
+                                constness,
                                 ty,
                                 &mut bounds,
                             );
@@ -2484,11 +2512,18 @@
     astconv: &dyn AstConv<'tcx>,
     param_ty: Ty<'tcx>,
     bound: &'tcx hir::GenericBound<'tcx>,
+    constness: ast::Constness,
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     match *bound {
-        hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
+        hir::GenericBound::Trait(ref tr, modifier) => {
+            let constness = match modifier {
+                hir::TraitBoundModifier::Maybe => return vec![],
+                hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+                hir::TraitBoundModifier::None => constness,
+            };
+
             let mut bounds = Bounds::default();
-            let _ = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
+            let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
             bounds.predicates(astconv.tcx(), param_ty)
         }
         hir::GenericBound::Outlives(ref lifetime) => {
@@ -2496,7 +2531,6 @@
             let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
             vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)]
         }
-        hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![],
     }
 }
 
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 9ee4e7c..e9c18b5 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -20,8 +20,6 @@
 
 use rustc_span::Span;
 
-use rustc_error_codes::*;
-
 /// Checks that all the type/lifetime parameters on an impl also
 /// appear in the trait ref or self type (or are constrained by a
 /// where-clause). These rules are needed to ensure that, given a
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 95cd3c6..3d27f91 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -109,8 +109,6 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 
-use rustc_error_codes::*;
-
 use std::iter;
 
 use astconv::{AstConv, Bounds};
@@ -382,6 +380,7 @@
         &item_cx,
         hir_trait,
         DUMMY_SP,
+        syntax::ast::Constness::NotConst,
         tcx.types.err,
         &mut bounds,
         true,
diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs
index 908429c..980d58a 100644
--- a/src/librustc_typeck/outlives/test.rs
+++ b/src/librustc_typeck/outlives/test.rs
@@ -4,8 +4,6 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_span::symbol::sym;
 
-use rustc_error_codes::*;
-
 pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
     tcx.hir().krate().visit_all_item_likes(&mut OutlivesTest { tcx });
 }
diff --git a/src/librustc_typeck/structured_errors.rs b/src/librustc_typeck/structured_errors.rs
index 0688147..99b7b20 100644
--- a/src/librustc_typeck/structured_errors.rs
+++ b/src/librustc_typeck/structured_errors.rs
@@ -3,8 +3,6 @@
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_span::Span;
 
-use rustc_error_codes::*;
-
 pub trait StructuredDiagnostic<'tcx> {
     fn session(&self) -> &Session;
 
diff --git a/src/librustc_typeck/variance/test.rs b/src/librustc_typeck/variance/test.rs
index 2f41bee1..ee94b10 100644
--- a/src/librustc_typeck/variance/test.rs
+++ b/src/librustc_typeck/variance/test.rs
@@ -4,8 +4,6 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_span::symbol::sym;
 
-use rustc_error_codes::*;
-
 pub fn test_variance(tcx: TyCtxt<'_>) {
     tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx });
 }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index f37f692..27f8059 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -462,7 +462,7 @@
             .filter(|p| {
                 !orig_bounds.contains(p)
                     || match p {
-                        &&ty::Predicate::Trait(pred) => pred.def_id() == sized_trait,
+                        ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait,
                         _ => false,
                     }
             })
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 525b1b2..18ebd25 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,7 +1,7 @@
 use rustc::infer::InferOk;
 use rustc::traits;
 use rustc::ty::subst::Subst;
-use rustc::ty::ToPredicate;
+use rustc::ty::{ToPredicate, WithConstness};
 use rustc_hir as hir;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_span::DUMMY_SP;
@@ -64,7 +64,7 @@
                         match infcx.evaluate_obligation(&traits::Obligation::new(
                             cause,
                             param_env,
-                            trait_ref.to_predicate(),
+                            trait_ref.without_const().to_predicate(),
                         )) {
                             Ok(eval_result) => eval_result.may_apply(),
                             Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 20a5a6c..7a7d69c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -482,7 +482,7 @@
         use rustc::ty::Predicate;
 
         match *self {
-            Predicate::Trait(ref pred) => Some(pred.clean(cx)),
+            Predicate::Trait(ref pred, _) => Some(pred.clean(cx)),
             Predicate::Subtype(ref pred) => Some(pred.clean(cx)),
             Predicate::RegionOutlives(ref pred) => pred.clean(cx),
             Predicate::TypeOutlives(ref pred) => pred.clean(cx),
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index c7b12d3..2b59c60 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -141,7 +141,7 @@
         .predicates
         .iter()
         .filter_map(|(pred, _)| {
-            if let ty::Predicate::Trait(ref pred) = *pred {
+            if let ty::Predicate::Trait(ref pred, _) = *pred {
                 if pred.skip_binder().trait_ref.self_ty() == self_ty {
                     Some(pred.def_id())
                 } else {
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 178ba69..218674b 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -203,6 +203,7 @@
     pub unsafety: hir::Unsafety,
     pub polarity: hir::ImplPolarity,
     pub defaultness: hir::Defaultness,
+    pub constness: ast::Constness,
     pub generics: &'hir hir::Generics<'hir>,
     pub trait_: &'hir Option<hir::TraitRef<'hir>>,
     pub for_: &'hir hir::Ty<'hir>,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6434dcc..79923fc 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -361,6 +361,7 @@
                 let modifier_str = match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
+                    hir::TraitBoundModifier::MaybeConst => "?const",
                 };
                 if f.alternate() {
                     write!(f, "{}{:#}", modifier_str, ty.print())
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index aa52b76..5bea1b5 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -41,7 +41,7 @@
     let fm = sess
         .source_map()
         .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned());
-    let highlight_result = {
+    let highlight_result = rustc_driver::catch_fatal_errors(|| {
         let lexer = lexer::StringReader::new(&sess, fm, None);
         let mut classifier = Classifier::new(lexer, sess.source_map());
 
@@ -51,7 +51,8 @@
         } else {
             Ok(String::from_utf8_lossy(&highlighted_source).into_owned())
         }
-    };
+    })
+    .unwrap_or(Err(()));
 
     match highlight_result {
         Ok(highlighted_source) => {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 9406803..ab38eec 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2321,8 +2321,8 @@
         "{}{}{}{}{:#}fn {}{:#}",
         it.visibility.print_with_space(),
         f.header.constness.print_with_space(),
-        f.header.unsafety.print_with_space(),
         f.header.asyncness.print_with_space(),
+        f.header.unsafety.print_with_space(),
         print_abi_with_space(f.header.abi),
         it.name.as_ref().unwrap(),
         f.generics.print()
@@ -2332,12 +2332,12 @@
     render_attributes(w, it, false);
     write!(
         w,
-        "{vis}{constness}{unsafety}{asyncness}{abi}fn \
+        "{vis}{constness}{asyncness}{unsafety}{abi}fn \
            {name}{generics}{decl}{where_clause}</pre>",
         vis = it.visibility.print_with_space(),
         constness = f.header.constness.print_with_space(),
-        unsafety = f.header.unsafety.print_with_space(),
         asyncness = f.header.asyncness.print_with_space(),
+        unsafety = f.header.unsafety.print_with_space(),
         abi = print_abi_with_space(f.header.abi),
         name = it.name.as_ref().unwrap(),
         generics = f.generics.print(),
@@ -2832,8 +2832,8 @@
             "{}{}{}{}{}{:#}fn {}{:#}",
             meth.visibility.print_with_space(),
             header.constness.print_with_space(),
-            header.unsafety.print_with_space(),
             header.asyncness.print_with_space(),
+            header.unsafety.print_with_space(),
             print_default_space(meth.is_default()),
             print_abi_with_space(header.abi),
             name,
@@ -2854,8 +2854,8 @@
             if parent == ItemType::Trait { "    " } else { "" },
             meth.visibility.print_with_space(),
             header.constness.print_with_space(),
-            header.unsafety.print_with_space(),
             header.asyncness.print_with_space(),
+            header.unsafety.print_with_space(),
             print_default_space(meth.is_default()),
             print_abi_with_space(header.abi),
             href = href,
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 1da00e3..403c8d0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -23,7 +23,6 @@
 extern crate rustc;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
-extern crate rustc_error_codes;
 extern crate rustc_errors;
 extern crate rustc_expand;
 extern crate rustc_feature;
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 0bab442..2903fd9 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -40,7 +40,7 @@
             dox[code_block.code].to_owned(),
         );
 
-        let validation_status = {
+        let validation_status = rustc_driver::catch_fatal_errors(|| {
             let mut has_syntax_errors = false;
             let mut only_whitespace = true;
             // even if there is a syntax error, we need to run the lexer over the whole file
@@ -61,7 +61,8 @@
             } else {
                 None
             }
-        };
+        })
+        .unwrap_or(Some(CodeBlockInvalid::SyntaxError));
 
         if let Some(code_block_invalid) = validation_status {
             let mut diag = if let Some(sp) =
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 05d4141..d89dc2a 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -43,7 +43,7 @@
     let crate_types = if options.proc_macro_crate {
         vec![config::CrateType::ProcMacro]
     } else {
-        vec![config::CrateType::Dylib]
+        vec![config::CrateType::Rlib]
     };
 
     let sessopts = config::Options {
@@ -117,12 +117,16 @@
                     intravisit::walk_crate(this, krate);
                 });
             });
+            compiler.session().abort_if_errors();
 
             let ret: Result<_, ErrorReported> = Ok(collector.tests);
             ret
         })
-    })
-    .expect("compiler aborted in rustdoc!");
+    });
+    let tests = match tests {
+        Ok(tests) => tests,
+        Err(ErrorReported) => return 1,
+    };
 
     test_args.insert(0, "rustdoctest".to_string());
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index fdff187..d3d45cc 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -562,6 +562,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 ref generics,
                 ref of_trait,
                 self_ty,
@@ -576,6 +577,7 @@
                         unsafety,
                         polarity,
                         defaultness,
+                        constness,
                         generics,
                         trait_: of_trait,
                         for_: self_ty,
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index c8fae91..dc93ac9 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -275,7 +275,6 @@
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(log_syntax)]
-#![feature(manually_drop_take)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(needs_panic_runtime)]
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index c7d4828..135e830 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -13,75 +13,43 @@
 
 use libc::{c_int, c_void};
 
-#[cfg(not(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "l4re"
-)))]
-use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
-#[cfg(not(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "l4re"
-)))]
-use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "l4re"
-))]
-use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "l4re"
-))]
-use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "ios", target_os = "macos",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
+        use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
+        use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+    } else {
+        use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
+        use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
+    }
+}
 
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "haiku"
-))]
-use libc::MSG_NOSIGNAL;
-#[cfg(not(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "haiku"
-)))]
-const MSG_NOSIGNAL: c_int = 0x0;
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux", target_os = "android",
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "haiku"))] {
+        use libc::MSG_NOSIGNAL;
+    } else {
+        const MSG_NOSIGNAL: c_int = 0x0;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris"))] {
+        use libc::c_uchar;
+        type IpV4MultiCastType = c_uchar;
+    } else {
+        type IpV4MultiCastType = c_int;
+    }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // sockaddr and misc bindings
@@ -566,20 +534,30 @@
     }
 
     pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
-        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
+        setsockopt(
+            &self.inner,
+            c::IPPROTO_IP,
+            c::IP_MULTICAST_LOOP,
+            multicast_loop_v4 as IpV4MultiCastType,
+        )
     }
 
     pub fn multicast_loop_v4(&self) -> io::Result<bool> {
-        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
+        let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
         Ok(raw != 0)
     }
 
     pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
-        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
+        setsockopt(
+            &self.inner,
+            c::IPPROTO_IP,
+            c::IP_MULTICAST_TTL,
+            multicast_ttl_v4 as IpV4MultiCastType,
+        )
     }
 
     pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
-        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
+        let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
         Ok(raw as u32)
     }
 
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index 7d9f715..2e647d2a 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -21,5 +21,4 @@
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_macros = { path = "../librustc_macros" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a5a4eb1..5f38ac4 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -266,12 +266,24 @@
 /// small, positive ids.
 pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
 
-/// A modifier on a bound, currently this is only used for `?Sized`, where the
-/// modifier is `Maybe`. Negative bounds should also be handled here.
+/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
+///
+/// Negative bounds should also be handled here.
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
 pub enum TraitBoundModifier {
+    /// No modifiers
     None,
+
+    /// `?Trait`
     Maybe,
+
+    /// `?const Trait`
+    MaybeConst,
+
+    /// `?const ?Trait`
+    //
+    // This parses but will be rejected during AST validation.
+    MaybeConstMaybe,
 }
 
 /// The AST represents all type param bounds as types.
@@ -1033,7 +1045,7 @@
     pub fn to_bound(&self) -> Option<GenericBound> {
         match &self.kind {
             ExprKind::Path(None, path) => Some(GenericBound::Trait(
-                PolyTraitRef::new(Vec::new(), path.clone(), None, self.span),
+                PolyTraitRef::new(Vec::new(), path.clone(), self.span),
                 TraitBoundModifier::None,
             )),
             _ => None,
@@ -2158,7 +2170,8 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(HashStable_Generic)]
 pub enum Constness {
     Const,
     NotConst,
@@ -2376,15 +2389,6 @@
 pub struct TraitRef {
     pub path: Path,
     pub ref_id: NodeId,
-
-    /// The `const` modifier, if any, that appears before this trait.
-    ///
-    /// |                | `constness`                 |
-    /// |----------------|-----------------------------|
-    /// | `Trait`        | `None`                      |
-    /// | `const Trait`  | `Some(Constness::Const)`    |
-    /// | `?const Trait` | `Some(Constness::NotConst)` |
-    pub constness: Option<Constness>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -2399,15 +2403,10 @@
 }
 
 impl PolyTraitRef {
-    pub fn new(
-        generic_params: Vec<GenericParam>,
-        path: Path,
-        constness: Option<Constness>,
-        span: Span,
-    ) -> Self {
+    pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
         PolyTraitRef {
             bound_generic_params: generic_params,
-            trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID },
+            trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
             span,
         }
     }
@@ -2618,6 +2617,7 @@
         unsafety: Unsafety,
         polarity: ImplPolarity,
         defaultness: Defaultness,
+        constness: Constness,
         generics: Generics,
 
         /// The trait being implemented, if any.
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 70f4f47..6cfe4f2 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -12,8 +12,6 @@
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
 
-use rustc_error_codes::*;
-
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
 }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 750d054..4a460c5 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -838,8 +838,7 @@
     }
 }
 
-pub fn noop_visit_trait_ref<T: MutVisitor>(tr: &mut TraitRef, vis: &mut T) {
-    let TraitRef { path, ref_id, constness: _ } = tr;
+pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
     vis.visit_path(path);
     vis.visit_id(ref_id);
 }
@@ -922,6 +921,7 @@
             unsafety: _,
             polarity: _,
             defaultness: _,
+            constness: _,
             generics,
             of_trait,
             self_ty,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index bc67980..3927e4f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1230,6 +1230,7 @@
                 unsafety,
                 polarity,
                 defaultness,
+                constness,
                 ref generics,
                 ref of_trait,
                 ref self_ty,
@@ -1240,6 +1241,7 @@
                 self.print_defaultness(defaultness);
                 self.print_unsafety(unsafety);
                 self.word_nbsp("impl");
+                self.print_constness(constness);
 
                 if !generics.params.is_empty() {
                     self.print_generic_params(&generics.params);
@@ -2773,6 +2775,13 @@
         }
     }
 
+    crate fn print_constness(&mut self, s: ast::Constness) {
+        match s {
+            ast::Constness::Const => self.word_nbsp("const"),
+            ast::Constness::NotConst => {}
+        }
+    }
+
     crate fn print_is_auto(&mut self, s: ast::IsAuto) {
         match s {
             ast::IsAuto::Yes => self.word_nbsp("auto"),
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d03a9df..946a0d2 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -312,6 +312,7 @@
             unsafety: _,
             polarity: _,
             defaultness: _,
+            constness: _,
             ref generics,
             ref of_trait,
             ref self_ty,
diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
index d5ddfb5..27fb3cb 100644
--- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -4,7 +4,7 @@
 
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic-cgu.0[Internal]
 struct StructWithDtor(u32);
 
 impl Drop for StructWithDtor {
@@ -16,7 +16,7 @@
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
     drop_slice_in_place(&x);
@@ -31,7 +31,6 @@
         // not have drop-glue for the unsized [StructWithDtor]. This has to be
         // generated though when the drop_in_place() intrinsic is used.
         //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal]
-        //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal]
         ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]);
     }
 }
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index 94e79f0..675bdfd 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -37,7 +37,7 @@
 struct NonGenericNoDrop(i32);
 
 struct NonGenericWithDrop(i32);
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue-cgu.0[Internal]
 
 impl Drop for NonGenericWithDrop {
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
@@ -47,11 +47,11 @@
 //~ MONO_ITEM fn generic_drop_glue::start[0]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
     let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
 
@@ -60,17 +60,17 @@
 
     // This is supposed to generate drop-glue because it contains a field that
     // needs to be dropped.
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue-cgu.0[Internal]
     let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
     let _ = match EnumWithDrop::A::<i32, i64>(0) {
         EnumWithDrop::A(x) => x,
         EnumWithDrop::B(x) => x as i32
     };
 
-    //~MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue-cgu.0[Internal]
+    //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
     let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
         EnumWithDrop::A(x) => x,
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index e79b069..db0390b 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -24,13 +24,13 @@
 fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable-cgu.0[Internal]
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
     let _ = &s1 as &Trait;
 
     let s1 = Struct { _a: 0u64 };
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable-cgu.0[Internal]
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
     let _ = &s1 as &Trait;
diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
index f13952b..a899b8b 100644
--- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -5,7 +5,7 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
 struct StructWithDrop {
     x: i32
 }
@@ -19,7 +19,7 @@
     x: i32
 }
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
 enum EnumWithDrop {
     A(i32)
 }
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index 14545a3..7e29af4 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -5,11 +5,11 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Root(Intermediate);
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Intermediate(Leaf);
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Leaf;
 
 impl Drop for Leaf {
@@ -30,15 +30,15 @@
 fn start(_: isize, _: *const *const u8) -> isize {
     let _ = Root(Intermediate(Leaf));
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
     let _ = RootGen(IntermediateGen(LeafGen(0u32)));
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
     let _ = RootGen(IntermediateGen(LeafGen(0i16)));
 
diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
index 54aff57..d77de53 100644
--- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
@@ -5,7 +5,7 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue-cgu.0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue-cgu.0[Internal]
 struct Dropped;
 
 impl Drop for Dropped {
@@ -16,11 +16,11 @@
 //~ MONO_ITEM fn tuple_drop_glue::start[0]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0u32, Dropped);
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0i16, (Dropped, true));
 
     0
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index fd794df..1ed60dc 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -48,13 +48,13 @@
 fn start(_: isize, _: *const *const u8) -> isize {
     // simple case
     let bool_sized = &true;
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<bool> @@ unsizing-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0]
     let _bool_unsized = bool_sized as &Trait;
 
     let char_sized = &'a';
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<char> @@ unsizing-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0]
     let _char_unsized = char_sized as &Trait;
 
@@ -64,13 +64,13 @@
         _b: 2,
         _c: 3.0f64
     };
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<f64> @@ unsizing-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0]
     let _struct_unsized = struct_sized as &Struct<Trait>;
 
     // custom coercion
     let wrapper_sized = Wrapper(&0u32);
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<u32> @@ unsizing-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0]
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
 
diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs
index 0f3d72d..f85ae0c 100644
--- a/src/test/codegen-units/partitioning/extern-drop-glue.rs
+++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs
@@ -11,14 +11,14 @@
 // aux-build:cgu_extern_drop_glue.rs
 extern crate cgu_extern_drop_glue;
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<cgu_extern_drop_glue::Struct[0]> @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<cgu_extern_drop_glue::Struct[0]> @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal]
 
 struct LocalStruct(cgu_extern_drop_glue::Struct);
 
 //~ MONO_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External]
 pub fn user()
 {
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<extern_drop_glue::LocalStruct[0]> @@ extern_drop_glue[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<extern_drop_glue::LocalStruct[0]> @@ extern_drop_glue[Internal]
     let _ = LocalStruct(cgu_extern_drop_glue::Struct(0));
 }
 
@@ -30,7 +30,7 @@
     //~ MONO_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External]
     pub fn user()
     {
-        //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<extern_drop_glue::mod1[0]::LocalStruct[0]> @@ extern_drop_glue-mod1[Internal]
+        //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<extern_drop_glue::mod1[0]::LocalStruct[0]> @@ extern_drop_glue-mod1[Internal]
         let _ = LocalStruct(cgu_extern_drop_glue::Struct(0));
     }
 }
diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs
index 938d4ffb..366af4d 100644
--- a/src/test/codegen-units/partitioning/local-drop-glue.rs
+++ b/src/test/codegen-units/partitioning/local-drop-glue.rs
@@ -7,7 +7,7 @@
 #![allow(dead_code)]
 #![crate_type="rlib"]
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<local_drop_glue::Struct[0]> @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<local_drop_glue::Struct[0]> @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal]
 struct Struct {
     _a: u32
 }
@@ -17,7 +17,7 @@
     fn drop(&mut self) {}
 }
 
-//~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<local_drop_glue::Outer[0]> @@ local_drop_glue[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<local_drop_glue::Outer[0]> @@ local_drop_glue[Internal]
 struct Outer {
     _a: Struct
 }
@@ -36,10 +36,10 @@
 {
     use super::Struct;
 
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<local_drop_glue::mod1[0]::Struct2[0]> @@ local_drop_glue-mod1[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<local_drop_glue::mod1[0]::Struct2[0]> @@ local_drop_glue-mod1[Internal]
     struct Struct2 {
         _a: Struct,
-        //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal]
+        //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal]
         _b: (u32, Struct),
     }
 
diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs
index 5d23a4e..06e2ef6 100644
--- a/src/test/codegen-units/partitioning/vtable-through-const.rs
+++ b/src/test/codegen-units/partitioning/vtable-through-const.rs
@@ -66,7 +66,7 @@
 //~ MONO_ITEM fn vtable_through_const::start[0]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn core::ptr[0]::real_drop_in_place[0]<u32> @@ vtable_through_const[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ vtable_through_const[Internal]
 
     // Since Trait1::do_something() is instantiated via its default implementation,
     // it is considered a generic and is instantiated here only because it is
diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs
index 959929f..0c7f3bb 100644
--- a/src/test/codegen/drop.rs
+++ b/src/test/codegen/drop.rs
@@ -21,7 +21,7 @@
 // regular function exit. We used to have problems with quadratic growths of drop calls in such
 // functions.
 // FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
-// comment, that's `; call core::ptr::real_drop_in_place::<drop::SomeUniqueName>`
+// comment, that's `; call core::intrinsics::drop_in_place::<drop::SomeUniqueName>`
 // for the `v0` mangling, should switch to matching on that once `legacy` is gone.
 // CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index ccecaea..1c88a9e 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -113,8 +113,8 @@
 //     }
 // }
 // END rustc.main-{{closure}}.EraseRegions.after.mir
-// START rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
-// fn  std::ptr::real_drop_in_place(_1: &mut Test) -> () {
+// START rustc.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
+// fn  std::intrinsics::drop_in_place(_1: *mut Test) -> () {
 //     ...
 //     bb0: {
 //         Retag([raw] _1);
@@ -126,4 +126,4 @@
 //         return;
 //     }
 // }
-// END rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
+// END rustc.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs
index 5a37b67..a253755 100644
--- a/src/test/mir-opt/slice-drop-shim.rs
+++ b/src/test/mir-opt/slice-drop-shim.rs
@@ -6,7 +6,7 @@
 
 // END RUST SOURCE
 
-// START rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
+// START rustc.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
 // let mut _2: usize;
 // let mut _3: usize;
 // let mut _4: usize;
@@ -87,4 +87,4 @@
 //     _3 = Len((*_1));
 //     switchInt(move _2) -> [0usize: bb8, otherwise: bb14];
 // }
-// END rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
+// END rustc.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index f4d848d..88cfb62 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -45,7 +45,7 @@
 // }
 // END rustc.E-V-{{constant}}.mir_map.0.mir
 
-// START rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
+// START rustc.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
 //     bb0: {
 //     goto -> bb7;
 // }
@@ -71,7 +71,7 @@
 //     _2 = &mut (*_1);
 //     _3 = const <std::vec::Vec<i32> as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5];
 // }
-// END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
+// END rustc.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
 
 // START rustc.Test-X-{{constructor}}.mir_map.0.mir
 // fn Test::X(_1: usize) -> Test {
diff --git a/src/test/run-make-fulldeps/issue64319/Makefile b/src/test/run-make-fulldeps/issue64319/Makefile
new file mode 100644
index 0000000..5592f5a
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue64319/Makefile
@@ -0,0 +1,39 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# Different optimization levels imply different values for `-Zshare-generics`,
+# so try out a whole bunch of combinations to make sure everything is compatible
+all:
+	# First up, try some defaults
+	$(RUSTC) --crate-type rlib foo.rs
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
+
+	# Next try mixing up some things explicitly
+	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
+	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
+	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
+	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
+
+	# Now combine a whole bunch of options together
+	$(RUSTC) --crate-type rlib foo.rs
+	$(RUSTC) --crate-type dylib bar.rs
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no
+	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes
diff --git a/src/test/run-make-fulldeps/issue64319/bar.rs b/src/test/run-make-fulldeps/issue64319/bar.rs
new file mode 100644
index 0000000..3895c0b
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue64319/bar.rs
@@ -0,0 +1,5 @@
+extern crate foo;
+
+pub fn bar() {
+    foo::foo();
+}
diff --git a/src/test/run-make-fulldeps/issue64319/foo.rs b/src/test/run-make-fulldeps/issue64319/foo.rs
new file mode 100644
index 0000000..c54a238
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue64319/foo.rs
@@ -0,0 +1,9 @@
+pub fn foo() {
+    bar::<usize>();
+}
+
+pub fn bar<T>() {
+    baz();
+}
+
+fn baz() {}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/Makefile b/src/test/run-make-fulldeps/share-generics-dylib/Makefile
new file mode 100644
index 0000000..c6b5efc
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/Makefile
@@ -0,0 +1,22 @@
+# This test makes sure all generic instances get re-exported from Rust dylibs for use by
+# `-Zshare-generics`. There are two rlibs (`instance_provider_a` and `instance_provider_b`)
+# which both provide an instance of `Cell<i32>::set`. There is `instance_user_dylib` which is
+# supposed to re-export both these instances, and then there are `instance_user_a_rlib` and
+# `instance_user_b_rlib` which each rely on a specific instance to be available.
+#
+# In the end everything is linked together into `linked_leaf`. If `instance_user_dylib` does
+# not export both then we'll get an `undefined reference` error for one of the instances.
+#
+# This is regression test for https://github.com/rust-lang/rust/issues/67276.
+
+-include ../../run-make-fulldeps/tools.mk
+
+COMMON_ARGS=-Cprefer-dynamic -Zshare-generics=yes -Ccodegen-units=1 -Zsymbol-mangling-version=v0
+
+all:
+	$(RUSTC) instance_provider_a.rs $(COMMON_ARGS) --crate-type=rlib
+	$(RUSTC) instance_provider_b.rs $(COMMON_ARGS) --crate-type=rlib
+	$(RUSTC) instance_user_dylib.rs $(COMMON_ARGS) --crate-type=dylib
+	$(RUSTC) instance_user_a_rlib.rs $(COMMON_ARGS) --crate-type=rlib
+	$(RUSTC) instance_user_b_rlib.rs $(COMMON_ARGS) --crate-type=rlib
+	$(RUSTC) linked_leaf.rs $(COMMON_ARGS) --crate-type=bin
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_a.rs b/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_a.rs
new file mode 100644
index 0000000..b4e125a
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_a.rs
@@ -0,0 +1,6 @@
+use std::cell::Cell;
+
+pub fn foo() {
+    let a: Cell<i32> = Cell::new(1);
+    a.set(123);
+}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_b.rs b/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_b.rs
new file mode 100644
index 0000000..f613db8
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/instance_provider_b.rs
@@ -0,0 +1,6 @@
+use std::cell::Cell;
+
+pub fn foo() {
+    let b: Cell<i32> = Cell::new(1);
+    b.set(123);
+}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/instance_user_a_rlib.rs b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_a_rlib.rs
new file mode 100644
index 0000000..c8e6ab9
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_a_rlib.rs
@@ -0,0 +1,9 @@
+extern crate instance_provider_a as upstream;
+use std::cell::Cell;
+
+pub fn foo() {
+    upstream::foo();
+
+    let b: Cell<i32> = Cell::new(1);
+    b.set(123);
+}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/instance_user_b_rlib.rs b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_b_rlib.rs
new file mode 100644
index 0000000..7c34af6
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_b_rlib.rs
@@ -0,0 +1,9 @@
+extern crate instance_provider_b as upstream;
+use std::cell::Cell;
+
+pub fn foo() {
+    upstream::foo();
+
+    let b: Cell<i32> = Cell::new(1);
+    b.set(123);
+}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/instance_user_dylib.rs b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_dylib.rs
new file mode 100644
index 0000000..7c8368e
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/instance_user_dylib.rs
@@ -0,0 +1,7 @@
+extern crate instance_provider_a;
+extern crate instance_provider_b;
+
+pub fn foo() {
+    instance_provider_a::foo();
+    instance_provider_b::foo();
+}
diff --git a/src/test/run-make-fulldeps/share-generics-dylib/linked_leaf.rs b/src/test/run-make-fulldeps/share-generics-dylib/linked_leaf.rs
new file mode 100644
index 0000000..e510dad
--- /dev/null
+++ b/src/test/run-make-fulldeps/share-generics-dylib/linked_leaf.rs
@@ -0,0 +1,15 @@
+extern crate instance_user_dylib;
+extern crate instance_user_a_rlib;
+extern crate instance_user_b_rlib;
+
+use std::cell::Cell;
+
+fn main() {
+
+    instance_user_a_rlib::foo();
+    instance_user_b_rlib::foo();
+    instance_user_dylib::foo();
+
+    let a: Cell<i32> = Cell::new(1);
+    a.set(123);
+}
diff --git a/src/test/run-make/thumb-none-cortex-m/Makefile b/src/test/run-make/thumb-none-cortex-m/Makefile
index 6791c8c..36e51bc 100644
--- a/src/test/run-make/thumb-none-cortex-m/Makefile
+++ b/src/test/run-make/thumb-none-cortex-m/Makefile
@@ -10,10 +10,7 @@
 # - thumbv7em-none-eabihf (Bare Cortex-M4F, M7F, FPU, hardfloat)
 # - thumbv7m-none-eabi (Bare Cortex-M3)
 
-# only-thumbv6m-none-eabi
-# only-thumbv7em-none-eabi
-# only-thumbv7em-none-eabihf
-# only-thumbv7m-none-eabi
+# only-thumb
 
 # For cargo setting
 RUSTC := $(RUSTC_ORIGINAL)
@@ -27,7 +24,8 @@
 CRATE_URL := https://github.com/rust-embedded/cortex-m
 CRATE_SHA1 := a448e9156e2cb1e556e5441fd65426952ef4b927 # 0.5.0
 
-export RUSTFLAGS := --cap-lints=allow
+# Don't make lints fatal, but they need to at least warn or they break Cargo's target info parsing.
+export RUSTFLAGS := --cap-lints=warn
 
 all:
 	env
diff --git a/src/test/run-make/thumb-none-qemu/Makefile b/src/test/run-make/thumb-none-qemu/Makefile
index cb1ff85..ab8b90e 100644
--- a/src/test/run-make/thumb-none-qemu/Makefile
+++ b/src/test/run-make/thumb-none-qemu/Makefile
@@ -1,7 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-thumbv7m-none-eabi
-# only-thumbv6m-none-eabi
+# only-thumb
 
 # How to run this
 # $ ./x.py clean
diff --git a/src/test/run-make/thumb-none-qemu/example/.cargo/config b/src/test/run-make/thumb-none-qemu/example/.cargo/config
index 0d6b19c..8b30310 100644
--- a/src/test/run-make/thumb-none-qemu/example/.cargo/config
+++ b/src/test/run-make/thumb-none-qemu/example/.cargo/config
@@ -1,12 +1,26 @@
-[target.thumbv7m-none-eabi]
-# uncomment this to make `cargo run` execute programs on QEMU
+[target.thumbv6m-none-eabi]
+# FIXME: Should be Cortex-M0, but Qemu used by CI is too old
 runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
 
-[target.thumbv6m-none-eabi]
-# uncomment this to make `cargo run` execute programs on QEMU
-# For now, we use cortex-m3 instead of cortex-m0 which are not supported by QEMU
+[target.thumbv7m-none-eabi]
 runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
 
+[target.thumbv7em-none-eabi]
+runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
+[target.thumbv7em-none-eabihf]
+runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
+[target.thumbv8m.base-none-eabi]
+# FIXME: Should be the Cortex-M23, bt Qemu does not currently support it
+runner = "qemu-system-arm -cpu cortex-m33 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
+[target.thumbv8m.main-none-eabi]
+runner = "qemu-system-arm -cpu cortex-m33 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
+[target.thumbv8m.main-none-eabihf]
+runner = "qemu-system-arm -cpu cortex-m33 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
 [target.'cfg(all(target_arch = "arm", target_os = "none"))']
 # uncomment ONE of these three option to make `cargo run` start a GDB session
 # which option to pick depends on your system
@@ -28,4 +42,4 @@
   # "-C", "linker=arm-none-eabi-gcc",
   # "-C", "link-arg=-Wl,-Tlink.x",
   # "-C", "link-arg=-nostartfiles",
-]
\ No newline at end of file
+]
diff --git a/src/test/run-make/thumb-none-qemu/example/Cargo.lock b/src/test/run-make/thumb-none-qemu/example/Cargo.lock
new file mode 100644
index 0000000..687b962
--- /dev/null
+++ b/src/test/run-make/thumb-none-qemu/example/Cargo.lock
@@ -0,0 +1,199 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aligned"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "as-slice 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "as-slice"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bare-metal"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cortex-m"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aligned 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bare-metal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cortex-m-rt"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cortex-m-rt-macros 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cortex-m-rt-macros"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cortex-m-semihosting"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "example"
+version = "0.1.0"
+dependencies = [
+ "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cortex-m-rt 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cortex-m-semihosting 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "panic-halt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "r0"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "typenum"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vcell"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "volatile-register"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum aligned 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eb1ce8b3382016136ab1d31a1b5ce807144f8b7eb2d5f16b2108f0f07edceb94"
+"checksum as-slice 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be6b7e95ac49d753f19cab5a825dea99a1149a04e4e3230b33ae16e120954c04"
+"checksum bare-metal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
+"checksum cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2954942fbbdd49996704e6f048ce57567c3e1a4e2dc59b41ae9fde06a01fc763"
+"checksum cortex-m-rt 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "33a716cd7d8627fae3892c2eede9249e50d2d79aedfb43ca28dad9a2b23876d9"
+"checksum cortex-m-rt-macros 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "72b1073338d1e691b3b7aaf6bd61993e589ececce9242a02dfa5453e1b98918d"
+"checksum cortex-m-semihosting 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "113ef0ecffee2b62b58f9380f4469099b30e9f9cbee2804771b4203ba1762cfa"
+"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+"checksum generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd"
+"checksum panic-halt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
+"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
+"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
+"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+"checksum vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
+"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
diff --git a/src/test/run-make/thumb-none-qemu/example/Cargo.toml b/src/test/run-make/thumb-none-qemu/example/Cargo.toml
index 73fdee7..051d41b 100644
--- a/src/test/run-make/thumb-none-qemu/example/Cargo.toml
+++ b/src/test/run-make/thumb-none-qemu/example/Cargo.toml
@@ -5,7 +5,7 @@
 edition = "2018"
 
 [dependencies]
-cortex-m = "0.5.4"
-cortex-m-rt = "=0.5.4"
+cortex-m = "0.6.2"
+cortex-m-rt = "0.6.11"
 panic-halt = "0.2.0"
 cortex-m-semihosting = "0.3.1"
diff --git a/src/test/run-make/thumb-none-qemu/example/src/main.rs b/src/test/run-make/thumb-none-qemu/example/src/main.rs
index 4a08419..2abfde8 100644
--- a/src/test/run-make/thumb-none-qemu/example/src/main.rs
+++ b/src/test/run-make/thumb-none-qemu/example/src/main.rs
@@ -1,4 +1,3 @@
-// #![feature(stdsimd)]
 #![no_main]
 #![no_std]
 use core::fmt::Write;
@@ -6,12 +5,9 @@
 use cortex_m_rt::entry;
 use cortex_m_semihosting as semihosting;
 
-//FIXME: This imports the provided #[panic_handler].
-#[allow(rust_2018_idioms)]
-extern crate panic_halt;
+use panic_halt as _;
 
-entry!(main);
-
+#[entry]
 fn main() -> ! {
     let x = 42;
 
diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs
index 34e92c4..72037dd 100644
--- a/src/test/rustdoc-ui/invalid-syntax.rs
+++ b/src/test/rustdoc-ui/invalid-syntax.rs
@@ -93,3 +93,9 @@
 ///
 pub fn indent_after_fenced() {}
 //~^^^ WARNING could not parse code block as Rust code
+
+/// ```
+/// "invalid
+/// ```
+pub fn invalid() {}
+//~^^^^ WARNING could not parse code block as Rust code
diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr
index 32cc207..a90d3bb 100644
--- a/src/test/rustdoc-ui/invalid-syntax.stderr
+++ b/src/test/rustdoc-ui/invalid-syntax.stderr
@@ -132,3 +132,18 @@
    |
    = note: error from rustc: unknown start of token: \
 
+warning: could not parse code block as Rust code
+  --> $DIR/invalid-syntax.rs:97:5
+   |
+LL |   /// ```
+   |  _____^
+LL | | /// "invalid
+LL | | /// ```
+   | |_______^
+   |
+   = note: error from rustc: unterminated double quote string
+help: mark blocks that do not contain Rust code as text
+   |
+LL | /// ```text
+   |     ^^^^^^^
+
diff --git a/src/test/rustdoc-ui/test-compile-fail1.rs b/src/test/rustdoc-ui/test-compile-fail1.rs
new file mode 100644
index 0000000..a053902
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail1.rs
@@ -0,0 +1,8 @@
+// compile-flags:--test
+
+/// ```
+/// assert!(true)
+/// ```
+pub fn f() {}
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-compile-fail1.stderr b/src/test/rustdoc-ui/test-compile-fail1.stderr
new file mode 100644
index 0000000..2b38ba9
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail1.stderr
@@ -0,0 +1,14 @@
+error[E0428]: the name `f` is defined multiple times
+ --> $DIR/test-compile-fail1.rs:8:1
+  |
+6 | pub fn f() {}
+  | ---------- previous definition of the value `f` here
+7 | 
+8 | pub fn f() {}
+  | ^^^^^^^^^^ `f` redefined here
+  |
+  = note: `f` must be defined only once in the value namespace of this module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/rustdoc-ui/test-compile-fail2.rs b/src/test/rustdoc-ui/test-compile-fail2.rs
new file mode 100644
index 0000000..651ded0
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail2.rs
@@ -0,0 +1,3 @@
+// compile-flags:--test
+
+fail
diff --git a/src/test/rustdoc-ui/test-compile-fail2.stderr b/src/test/rustdoc-ui/test-compile-fail2.stderr
new file mode 100644
index 0000000..cee5b63
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail2.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found `<eof>`
+ --> $DIR/test-compile-fail2.rs:3:1
+  |
+3 | fail
+  | ^^^^ expected one of `!` or `::`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/test-compile-fail3.rs b/src/test/rustdoc-ui/test-compile-fail3.rs
new file mode 100644
index 0000000..faa30ad
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail3.rs
@@ -0,0 +1,3 @@
+// compile-flags:--test
+
+"fail
diff --git a/src/test/rustdoc-ui/test-compile-fail3.stderr b/src/test/rustdoc-ui/test-compile-fail3.stderr
new file mode 100644
index 0000000..7a2f181
--- /dev/null
+++ b/src/test/rustdoc-ui/test-compile-fail3.stderr
@@ -0,0 +1,8 @@
+error: unterminated double quote string
+ --> $DIR/test-compile-fail3.rs:3:1
+  |
+3 | "fail
+  | ^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/test-no_std.rs b/src/test/rustdoc-ui/test-no_std.rs
new file mode 100644
index 0000000..166a873
--- /dev/null
+++ b/src/test/rustdoc-ui/test-no_std.rs
@@ -0,0 +1,12 @@
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// build-pass
+
+#![no_std]
+
+extern crate alloc;
+
+/// ```
+/// assert!(true)
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-no_std.stdout b/src/test/rustdoc-ui/test-no_std.stdout
new file mode 100644
index 0000000..9cdcac2
--- /dev/null
+++ b/src/test/rustdoc-ui/test-no_std.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/test-no_std.rs - f (line 9) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+
diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs
index 5f9708a..5a03e82 100644
--- a/src/test/rustdoc/async-fn.rs
+++ b/src/test/rustdoc/async-fn.rs
@@ -15,6 +15,11 @@
     a
 }
 
+// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char'
+pub async unsafe fn qux() -> char {
+    'âš '
+}
+
 trait Bar {}
 
 impl Bar for () {}
@@ -26,8 +31,10 @@
 
 // @has async_fn/struct.Foo.html
 // @matches - '//code' 'pub async fn f\(\)$'
+// @matches - '//code' 'pub async unsafe fn g\(\)$'
 pub struct Foo;
 
 impl Foo {
     pub async fn f() {}
+    pub async unsafe fn g() {}
 }
diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs
index ae8fbe4..afef86e 100644
--- a/src/test/rustdoc/bad-codeblock-syntax.rs
+++ b/src/test/rustdoc/bad-codeblock-syntax.rs
@@ -33,3 +33,10 @@
 /// <script>alert("not valid Rust");</script>
 /// ```
 pub fn escape() {}
+
+// @has bad_codeblock_syntax/fn.unterminated.html
+// @has - '//*[@class="docblock"]/pre/code' '"unterminated'
+/// ```
+/// "unterminated
+/// ```
+pub fn unterminated() {}
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index 645c903..ceeebbc 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -2,15 +2,15 @@
 // edition:2018
 // compile-flags: --crate-type lib
 
-use std::{
-    cell::RefCell,
-    fmt::Debug,
-    rc::Rc,
-};
+use std::{cell::RefCell, fmt::Debug, rc::Rc};
 
-fn non_sync() -> impl Debug { RefCell::new(()) }
+fn non_sync() -> impl Debug {
+    RefCell::new(())
+}
 
-fn non_send() -> impl Debug { Rc::new(()) }
+fn non_send() -> impl Debug {
+    Rc::new(())
+}
 
 fn take_ref<T>(_: &T) {}
 
@@ -53,5 +53,4 @@
     //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call());
     //~^ ERROR future cannot be sent between threads safely
-    //~^^ ERROR future cannot be sent between threads safely
 }
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index 5c870ca..105fd23 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -62,27 +62,5 @@
 LL | }
    | - `f` is later dropped here
 
-error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:54:5
-   |
-LL | fn assert_send(_: impl Send) {}
-   |    -----------         ---- required by this bound in `assert_send`
-...
-LL |     assert_send(non_sync_with_method_call());
-   |     ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
-   |
-   = help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
-note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:43:9
-   |
-LL |     let f: &mut std::fmt::Formatter = panic!();
-   |         - has type `&mut std::fmt::Formatter<'_>`
-LL |     if non_sync().fmt(f).unwrap() == () {
-LL |         fut().await;
-   |         ^^^^^^^^^^^ await occurs here, with `f` maybe used later
-LL |     }
-LL | }
-   | - `f` is later dropped here
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs
index 64aeb46..af63d1f 100644
--- a/src/test/ui/consts/array-literal-index-oob.rs
+++ b/src/test/ui/consts/array-literal-index-oob.rs
@@ -1,4 +1,5 @@
 // build-pass
+// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
 
 #![warn(const_err)]
 
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index 50ad8e8..e93aa32 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -1,17 +1,17 @@
 warning: index out of bounds: the len is 3 but the index is 4
-  --> $DIR/array-literal-index-oob.rs:6:8
+  --> $DIR/array-literal-index-oob.rs:7:8
    |
 LL |     &{ [1, 2, 3][4] };
    |        ^^^^^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/array-literal-index-oob.rs:3:9
+  --> $DIR/array-literal-index-oob.rs:4:9
    |
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
 warning: reaching this expression at runtime will panic or abort
-  --> $DIR/array-literal-index-oob.rs:6:8
+  --> $DIR/array-literal-index-oob.rs:7:8
    |
 LL |     &{ [1, 2, 3][4] };
    |     ---^^^^^^^^^^^^--
@@ -19,7 +19,7 @@
    |        indexing out of bounds: the len is 3 but the index is 4
 
 warning: erroneous constant used
-  --> $DIR/array-literal-index-oob.rs:6:5
+  --> $DIR/array-literal-index-oob.rs:7:5
    |
 LL |     &{ [1, 2, 3][4] };
    |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index fee2321..22f863f 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -1,4 +1,5 @@
 // build-pass
+// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
 // compile-flags: -O
 
 #![warn(const_err)]
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 4de22fd..b4330de 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -1,59 +1,59 @@
 warning: this expression will panic at runtime
-  --> $DIR/promoted_errors.rs:8:14
+  --> $DIR/promoted_errors.rs:9:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^ attempt to subtract with overflow
    |
 note: lint level defined here
-  --> $DIR/promoted_errors.rs:4:9
+  --> $DIR/promoted_errors.rs:5:9
    |
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:10:20
+  --> $DIR/promoted_errors.rs:11:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^
 
 warning: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors.rs:10:20
+  --> $DIR/promoted_errors.rs:11:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^ dividing by zero
 
 warning: erroneous constant used
-  --> $DIR/promoted_errors.rs:10:20
+  --> $DIR/promoted_errors.rs:11:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^ referenced constant has errors
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:14:14
+  --> $DIR/promoted_errors.rs:15:14
    |
 LL |     let _x = 1 / (1 - 1);
    |              ^^^^^^^^^^^
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:16:20
+  --> $DIR/promoted_errors.rs:17:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^
 
 warning: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors.rs:16:20
+  --> $DIR/promoted_errors.rs:17:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
 warning: erroneous constant used
-  --> $DIR/promoted_errors.rs:16:20
+  --> $DIR/promoted_errors.rs:17:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:20:14
+  --> $DIR/promoted_errors.rs:21:14
    |
 LL |     let _x = 1 / (false as u32);
    |              ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index 41a989d..62c77f7 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -1,4 +1,5 @@
 // build-pass
+// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
 // compile-flags: -C overflow-checks=on -O
 
 #![warn(const_err)]
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 4f7ba8b..a4dad29 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -1,65 +1,65 @@
 warning: attempt to subtract with overflow
-  --> $DIR/promoted_errors2.rs:7:20
+  --> $DIR/promoted_errors2.rs:8:20
    |
 LL |     println!("{}", 0u32 - 1);
    |                    ^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/promoted_errors2.rs:4:9
+  --> $DIR/promoted_errors2.rs:5:9
    |
 LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
 warning: attempt to subtract with overflow
-  --> $DIR/promoted_errors2.rs:9:14
+  --> $DIR/promoted_errors2.rs:10:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:11:20
+  --> $DIR/promoted_errors2.rs:12:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^
 
 warning: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors2.rs:11:20
+  --> $DIR/promoted_errors2.rs:12:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^ dividing by zero
 
 warning: erroneous constant used
-  --> $DIR/promoted_errors2.rs:11:20
+  --> $DIR/promoted_errors2.rs:12:20
    |
 LL |     println!("{}", 1 / (1 - 1));
    |                    ^^^^^^^^^^^ referenced constant has errors
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:15:14
+  --> $DIR/promoted_errors2.rs:16:14
    |
 LL |     let _x = 1 / (1 - 1);
    |              ^^^^^^^^^^^
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:17:20
+  --> $DIR/promoted_errors2.rs:18:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^
 
 warning: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors2.rs:17:20
+  --> $DIR/promoted_errors2.rs:18:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
 warning: erroneous constant used
-  --> $DIR/promoted_errors2.rs:17:20
+  --> $DIR/promoted_errors2.rs:18:20
    |
 LL |     println!("{}", 1 / (false as u32));
    |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:21:14
+  --> $DIR/promoted_errors2.rs:22:14
    |
 LL |     let _x = 1 / (false as u32);
    |              ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/issue-68264-overflow.rs b/src/test/ui/consts/issue-68264-overflow.rs
new file mode 100644
index 0000000..8f21e06
--- /dev/null
+++ b/src/test/ui/consts/issue-68264-overflow.rs
@@ -0,0 +1,43 @@
+// check-pass
+// compile-flags: --emit=mir,link
+// Regression test for issue #68264
+// Checks that we don't encounter overflow
+// when running const-prop on functions with
+// complicated bounds
+pub trait Query {}
+
+pub trait AsQuery {
+    type Query: Query;
+}
+pub trait Table: AsQuery + Sized {}
+
+pub trait LimitDsl {
+    type Output;
+}
+
+pub(crate) trait LoadQuery<Conn, U>: RunQueryDsl<Conn> {}
+
+impl<T: Query> AsQuery for T {
+    type Query = Self;
+}
+
+impl<T> LimitDsl for T
+where
+    T: Table,
+    T::Query: LimitDsl,
+{
+    type Output = <T::Query as LimitDsl>::Output;
+}
+
+pub(crate) trait RunQueryDsl<Conn>: Sized {
+    fn first<U>(self, _conn: &Conn) -> U
+    where
+        Self: LimitDsl,
+        Self::Output: LoadQuery<Conn, U>,
+    {
+        // Overflow is caused by this function body
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr
index 2cdeb59..2439d52 100644
--- a/src/test/ui/consts/miri_unleashed/drop.stderr
+++ b/src/test/ui/consts/miri_unleashed/drop.stderr
@@ -7,17 +7,17 @@
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
    |
-LL | / unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) {
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 LL | |     // Code here does not matter - this is replaced by the
 LL | |     // real drop glue by the compiler.
-LL | |     real_drop_in_place(to_drop)
+LL | |     drop_in_place(to_drop)
 LL | | }
    | |_^ calling non-const function `<std::vec::Vec<i32> as std::ops::Drop>::drop`
    | 
   ::: $DIR/drop.rs:23:1
    |
 LL |   };
-   |   - inside call to `std::ptr::real_drop_in_place::<std::vec::Vec<i32>> - shim(Some(std::vec::Vec<i32>))` at $DIR/drop.rs:23:1
+   |   - inside call to `std::intrinsics::drop_in_place::<std::vec::Vec<i32>> - shim(Some(std::vec::Vec<i32>))` at $DIR/drop.rs:23:1
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0106.rs b/src/test/ui/error-codes/E0106.rs
index d6537d1..cc34387 100644
--- a/src/test/ui/error-codes/E0106.rs
+++ b/src/test/ui/error-codes/E0106.rs
@@ -16,7 +16,7 @@
 struct Quux {
     baz: Baz,
     //~^ ERROR E0106
-    //~| expected lifetime parameter
+    //~| expected named lifetime parameter
     buzz: Buzz,
     //~^ ERROR E0106
     //~| expected 2 lifetime parameters
diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr
index cea9581..e01e0a6 100644
--- a/src/test/ui/error-codes/E0106.stderr
+++ b/src/test/ui/error-codes/E0106.stderr
@@ -2,25 +2,49 @@
   --> $DIR/E0106.rs:2:8
    |
 LL |     x: &bool,
-   |        ^ expected lifetime parameter
+   |        ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Foo<'lifetime> {
+LL |     x: &'lifetime bool,
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/E0106.rs:7:7
    |
 LL |     B(&bool),
-   |       ^ expected lifetime parameter
+   |       ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | enum Bar<'lifetime> {
+LL |     A(u8),
+LL |     B(&'lifetime bool),
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/E0106.rs:10:14
    |
 LL | type MyStr = &str;
-   |              ^ expected lifetime parameter
+   |              ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | type MyStr<'lifetime> = &'lifetime str;
+   |           ^^^^^^^^^^^   ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/E0106.rs:17:10
    |
 LL |     baz: Baz,
-   |          ^^^ expected lifetime parameter
+   |          ^^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Quux<'lifetime> {
+LL |     baz: Baz<'lifetime>,
+   |
 
 error[E0106]: missing lifetime specifiers
   --> $DIR/E0106.rs:20:11
diff --git a/src/test/ui/error-codes/E0261.stderr b/src/test/ui/error-codes/E0261.stderr
index 3bf5e9d..0eab2dc 100644
--- a/src/test/ui/error-codes/E0261.stderr
+++ b/src/test/ui/error-codes/E0261.stderr
@@ -2,11 +2,15 @@
   --> $DIR/E0261.rs:1:12
    |
 LL | fn foo(x: &'a str) { }
-   |            ^^ undeclared lifetime
+   |       -    ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/E0261.rs:5:9
    |
+LL | struct Foo {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     x: &'a str,
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
index 5c64bf6..bbf3ea8 100644
--- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
+++ b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
@@ -2,103 +2,207 @@
   --> $DIR/feature-gate-in_band_lifetimes.rs:3:12
    |
 LL | fn foo(x: &'x u8) -> &'x u8 { x }
-   |            ^^ undeclared lifetime
+   |       -    ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'x` here: `<'x>`
 
 error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/feature-gate-in_band_lifetimes.rs:3:23
    |
 LL | fn foo(x: &'x u8) -> &'x u8 { x }
-   |                       ^^ undeclared lifetime
+   |       -               ^^ undeclared lifetime
+   |       |
+   |       help: consider introducing lifetime `'x` here: `<'x>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:15:12
    |
 LL | impl<'a> X<'b> {
-   |            ^^ undeclared lifetime
+   |      -     ^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'b` here: `'b,`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:17:27
    |
 LL |     fn inner_2(&self) -> &'b u8 {
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> X<'b> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn inner_2<'b>(&self) -> &'b u8 {
+   |               ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:23:8
    |
 LL | impl X<'b> {
-   |        ^^ undeclared lifetime
+   |     -  ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'b` here: `<'b>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:25:27
    |
 LL |     fn inner_3(&self) -> &'b u8 {
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> X<'b> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn inner_3<'b>(&self) -> &'b u8 {
+   |               ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:33:9
    |
 LL | impl Y<&'a u8> {
-   |         ^^ undeclared lifetime
+   |     -   ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:35:25
    |
 LL |     fn inner(&self) -> &'a u8 {
    |                         ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn inner<'a>(&self) -> &'a u8 {
+   |             ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:43:27
    |
 LL |     fn any_lifetime() -> &'b u8;
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn any_lifetime<'b>() -> &'b u8;
+   |                    ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:45:27
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8;
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:45:40
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8;
    |                                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait MyTrait<'b, 'a> {
+   |               ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:50:14
    |
 LL | impl MyTrait<'a> for Y<&'a u8> {
-   |              ^^ undeclared lifetime
+   |     -        ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:50:25
    |
 LL | impl MyTrait<'a> for Y<&'a u8> {
-   |                         ^^ undeclared lifetime
+   |     -                   ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/feature-gate-in_band_lifetimes.rs:53:31
    |
 LL |     fn my_lifetime(&self) -> &'a u8 { self.0 }
    |                               ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
+   |                   ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:55:27
    |
 LL |     fn any_lifetime() -> &'b u8 { &0 }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn any_lifetime<'b>() -> &'b u8 { &0 }
+   |                    ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:57:27
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:57:40
    |
 LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    |                                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ^^^^
 
 error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
index 81137e8..fc2ce1c 100644
--- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
+++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
@@ -3,12 +3,30 @@
    |
 LL |         + Deref<Target = Self::Item<'b>>;
    |                                     ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Iterable<'b> {
+   |               ^^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
+   |               ^^^
 
 error[E0261]: use of undeclared lifetime name `'undeclared`
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:12:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
    |                                         ^^^^^^^^^^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'undeclared` here
+   |
+LL | trait Iterable<'undeclared> {
+   |               ^^^^^^^^^^^^^
+help: consider introducing lifetime `'undeclared` here
+   |
+LL |     fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
+   |             ^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
index 492ca87..14c53f9 100644
--- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
@@ -2,13 +2,23 @@
   --> $DIR/assoc-type.rs:11:19
    |
 LL |     type Output = &i32;
-   |                   ^ expected lifetime parameter
+   |                   ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type Output<'lifetime> = &'lifetime i32;
+   |                ^^^^^^^^^^^   ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/assoc-type.rs:16:20
    |
 LL |     type Output = &'_ i32;
-   |                    ^^ expected lifetime parameter
+   |                    ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type Output<'lifetime> = &'lifetime i32;
+   |                ^^^^^^^^^^^    ^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr
index 9579abb..5f101a2 100644
--- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr
+++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr
@@ -2,7 +2,12 @@
   --> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19
    |
 LL | struct Heartbreak(Betrayal);
-   |                   ^^^^^^^^ expected lifetime parameter
+   |                   ^^^^^^^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>);
+   |                  ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
index a270dd0..fe656f7 100644
--- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
+++ b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
@@ -1,12 +1,16 @@
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_in_band_in_struct.rs:5:9
    |
+LL | struct Foo {
+   |           - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     x: &'test u32,
    |         ^^^^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_in_band_in_struct.rs:9:10
    |
+LL | enum Bar {
+   |         - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     Baz(&'test u32),
    |          ^^^^^ undeclared lifetime
 
diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
index c307066..bfb20ad 100644
--- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
+++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr
@@ -1,6 +1,8 @@
 error[E0261]: use of undeclared lifetime name `'test`
   --> $DIR/no_introducing_in_band_in_locals.rs:5:13
    |
+LL | fn foo(x: &u32) {
+   |       - help: consider introducing lifetime `'test` here: `<'test>`
 LL |     let y: &'test u32 = x;
    |             ^^^^^ undeclared lifetime
 
diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr
index c85ce0e..8a627bc 100644
--- a/src/test/ui/issues/issue-19707.stderr
+++ b/src/test/ui/issues/issue-19707.stderr
@@ -2,17 +2,25 @@
   --> $DIR/issue-19707.rs:3:28
    |
 LL | type Foo = fn(&u8, &u8) -> &u8;
-   |                            ^ expected lifetime parameter
+   |                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+help: consider introducing a named lifetime parameter
+   |
+LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8;
+   |         ^^^^^^^^^^^                   ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-19707.rs:5:27
    |
 LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
-   |                           ^ expected lifetime parameter
+   |                           ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+help: consider introducing a named lifetime parameter
+   |
+LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {}
+   |        ^^^^^^^^^^                    ^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr
index 6d7c1b0..85d5d9c 100644
--- a/src/test/ui/issues/issue-26638.stderr
+++ b/src/test/ui/issues/issue-26638.stderr
@@ -2,9 +2,13 @@
   --> $DIR/issue-26638.rs:1:62
    |
 LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
-   |                                                              ^ expected lifetime parameter
+   |                                                              ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn parse_type<'lifetime>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'lifetime str { iter.next() }
+   |              ^^^^^^^^^^^                                                ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-26638.rs:4:40
diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr
index c53129b..c940227 100644
--- a/src/test/ui/issues/issue-30255.stderr
+++ b/src/test/ui/issues/issue-30255.stderr
@@ -2,25 +2,37 @@
   --> $DIR/issue-30255.rs:9:24
    |
 LL | fn f(a: &S, b: i32) -> &i32 {
-   |                        ^ expected lifetime parameter
+   |                        ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 {
+   |     ^^^^^^^^^^^                   ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:14:34
    |
 LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
-   |                                  ^ expected lifetime parameter
+   |                                  ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 {
+   |     ^^^^^^^^^^^                             ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:19:44
    |
 LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
-   |                                            ^ expected lifetime parameter
+   |                                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 {
+   |     ^^^^^^^^^^^                                       ^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
index 3f7c393..1d5eeac 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
@@ -10,17 +10,25 @@
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
    |
 LL | fn g(_x: &isize, _y: &isize) -> &isize {
-   |                                 ^ expected lifetime parameter
+   |                                 ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize {
+   |     ^^^^^^^^^^^                            ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19
    |
 LL | fn h(_x: &Foo) -> &isize {
-   |                   ^ expected lifetime parameter
+   |                   ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize {
+   |     ^^^^^^^^^^^              ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
index a4e0d71..2990ab8 100644
--- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
@@ -2,9 +2,13 @@
   --> $DIR/ex1b-return-no-names-if-else.rs:1:29
    |
 LL | fn foo(x: &i32, y: &i32) -> &i32 {
-   |                             ^ expected lifetime parameter
+   |                             ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 {
+   |       ^^^^^^^^^^^                      ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs
index 86a3950..a98b4f2 100644
--- a/src/test/ui/lint/lint-uppercase-variables.rs
+++ b/src/test/ui/lint/lint-uppercase-variables.rs
@@ -25,6 +25,16 @@
 //~^^^ WARN unused variable: `Foo`
     }
 
+    let Foo = foo::Foo::Foo;
+    //~^ ERROR variable `Foo` should have a snake case name
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^^ WARN unused variable: `Foo`
+
+    fn in_param(Foo: foo::Foo) {}
+    //~^ ERROR variable `Foo` should have a snake case name
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^^ WARN unused variable: `Foo`
+
     test(1);
 
     let _ = Something { X: 0 };
diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr
index b937832..a38f3e7 100644
--- a/src/test/ui/lint/lint-uppercase-variables.stderr
+++ b/src/test/ui/lint/lint-uppercase-variables.stderr
@@ -6,6 +6,18 @@
    |
    = note: `#[warn(bindings_with_variant_name)]` on by default
 
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
+  --> $DIR/lint-uppercase-variables.rs:28:9
+   |
+LL |     let Foo = foo::Foo::Foo;
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
+
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
+  --> $DIR/lint-uppercase-variables.rs:33:17
+   |
+LL |     fn in_param(Foo: foo::Foo) {}
+   |                 ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
+
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
@@ -19,6 +31,18 @@
    |         ^^^^^^
    = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
 
+warning: unused variable: `Foo`
+  --> $DIR/lint-uppercase-variables.rs:28:9
+   |
+LL |     let Foo = foo::Foo::Foo;
+   |         ^^^ help: consider prefixing with an underscore: `_Foo`
+
+warning: unused variable: `Foo`
+  --> $DIR/lint-uppercase-variables.rs:33:17
+   |
+LL |     fn in_param(Foo: foo::Foo) {}
+   |                 ^^^ help: consider prefixing with an underscore: `_Foo`
+
 error: structure field `X` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:10:5
    |
@@ -49,6 +73,18 @@
 LL |         Foo => {}
    |         ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
 
-error: aborting due to 4 previous errors
+error: variable `Foo` should have a snake case name
+  --> $DIR/lint-uppercase-variables.rs:28:9
+   |
+LL |     let Foo = foo::Foo::Foo;
+   |         ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
+
+error: variable `Foo` should have a snake case name
+  --> $DIR/lint-uppercase-variables.rs:33:17
+   |
+LL |     fn in_param(Foo: foo::Foo) {}
+   |                 ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0170`.
diff --git a/src/test/ui/marker_trait_attr/issue-61651-type-mismatch.rs b/src/test/ui/marker_trait_attr/issue-61651-type-mismatch.rs
new file mode 100644
index 0000000..0af7066
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/issue-61651-type-mismatch.rs
@@ -0,0 +1,17 @@
+// check-pass
+// Regression test for issue #61651
+// Verifies that we don't try to constrain inference
+// variables due to the presence of multiple applicable
+// marker trait impls
+
+#![feature(marker_trait_attr)]
+
+#[marker] // Remove this line and it works?!?
+trait Foo<T> {}
+impl Foo<u16> for u8 {}
+impl Foo<[u8; 1]> for u8 {}
+fn foo<T: Foo<U>, U>(_: T) -> U { unimplemented!() }
+
+fn main() {
+    let _: u16 = foo(0_u8);
+}
diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
index 67fd8d7..c9f235c 100644
--- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
+++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
@@ -1,6 +1,8 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/method-call-lifetime-args-unresolved.rs:2:15
    |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     0.clone::<'a>();
    |               ^^ undeclared lifetime
 
diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr
index 03fb764..4b9f494 100644
--- a/src/test/ui/parser/trait-object-trait-parens.stderr
+++ b/src/test/ui/parser/trait-object-trait-parens.stderr
@@ -33,6 +33,9 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/trait-object-trait-parens.rs:11:31
    |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
+...
 LL |     let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
    |                               ^^ undeclared lifetime
 
diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs
new file mode 100644
index 0000000..95ead6b
--- /dev/null
+++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs
@@ -0,0 +1,26 @@
+pub enum EFoo {
+    A,
+}
+
+pub trait Foo {
+    const X: EFoo;
+}
+
+struct Abc;
+
+impl Foo for Abc {
+    const X: EFoo = EFoo::A;
+}
+
+struct Def;
+impl Foo for Def {
+    const X: EFoo = EFoo::A;
+}
+
+pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
+    //~^ ERROR associated consts cannot be referenced in patterns
+    let A::X = arg;
+    //~^ ERROR associated consts cannot be referenced in patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
new file mode 100644
index 0000000..54ecc24
--- /dev/null
+++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
@@ -0,0 +1,15 @@
+error[E0158]: associated consts cannot be referenced in patterns
+  --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
+   |
+LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
+   |                                        ^^^^
+
+error[E0158]: associated consts cannot be referenced in patterns
+  --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9
+   |
+LL |     let A::X = arg;
+   |         ^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0158`.
diff --git a/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs
new file mode 100644
index 0000000..f10a7f2
--- /dev/null
+++ b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let x = 255u8;
+    let 0u8..=x = 0;
+    //~^ ERROR runtime values cannot be referenced in patterns
+}
diff --git a/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr
new file mode 100644
index 0000000..c1508bd
--- /dev/null
+++ b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr
@@ -0,0 +1,9 @@
+error[E0080]: runtime values cannot be referenced in patterns
+  --> $DIR/issue-68394-let-pat-runtime-value.rs:3:15
+   |
+LL |     let 0u8..=x = 0;
+   |               ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/pattern/issue-68396-let-float-bug.rs b/src/test/ui/pattern/issue-68396-let-float-bug.rs
new file mode 100644
index 0000000..afc599a
--- /dev/null
+++ b/src/test/ui/pattern/issue-68396-let-float-bug.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let 1234567890123456789012345678901234567890e-340: f64 = 0.0;
+    //~^ ERROR could not evaluate float literal (see issue #31407)
+
+    fn param(1234567890123456789012345678901234567890e-340: f64) {}
+    //~^ ERROR could not evaluate float literal (see issue #31407)
+}
diff --git a/src/test/ui/pattern/issue-68396-let-float-bug.stderr b/src/test/ui/pattern/issue-68396-let-float-bug.stderr
new file mode 100644
index 0000000..618aa4b
--- /dev/null
+++ b/src/test/ui/pattern/issue-68396-let-float-bug.stderr
@@ -0,0 +1,15 @@
+error[E0080]: could not evaluate float literal (see issue #31407)
+  --> $DIR/issue-68396-let-float-bug.rs:2:9
+   |
+LL |     let 1234567890123456789012345678901234567890e-340: f64 = 0.0;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate float literal (see issue #31407)
+  --> $DIR/issue-68396-let-float-bug.rs:5:14
+   |
+LL |     fn param(1234567890123456789012345678901234567890e-340: f64) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr
index 5b0c930..0115fc0 100644
--- a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr
+++ b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr
@@ -1,8 +1,10 @@
 error: unreachable pattern
   --> $DIR/struct-pattern-match-useless.rs:12:9
    |
+LL |         Foo { x: _x, y: _y } => (),
+   |         -------------------- matches any value
 LL |         Foo { .. } => ()
-   |         ^^^^^^^^^^
+   |         ^^^^^^^^^^ unreachable pattern
    |
 note: lint level defined here
   --> $DIR/struct-pattern-match-useless.rs:1:9
diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr
index e801c26..01eadbe 100644
--- a/src/test/ui/proc-macro/item-error.stderr
+++ b/src/test/ui/proc-macro/item-error.stderr
@@ -2,7 +2,13 @@
   --> $DIR/item-error.rs:10:8
    |
 LL |     a: &u64
-   |        ^ expected lifetime parameter
+   |        ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct A<'lifetime> {
+LL |     a: &'lifetime u64
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
index 0fcf77d..d9996b8 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
@@ -1,6 +1,6 @@
 // Dropck shouldn't hit a recursion limit from checking `S<u32>` since it has
 // no free regions or type parameters.
-// Codegen however, has to error for the infinitely many `real_drop_in_place`
+// Codegen however, has to error for the infinitely many `drop_in_place`
 // functions it has been asked to create.
 // build-fail
 
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
index 77309a8..de6df4c 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
@@ -1,4 +1,4 @@
-error: reached the recursion limit while instantiating `std::ptr::real_drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr
index ae06e76..41655a2 100644
--- a/src/test/ui/regions/regions-in-enums-anon.stderr
+++ b/src/test/ui/regions/regions-in-enums-anon.stderr
@@ -2,7 +2,13 @@
   --> $DIR/regions-in-enums-anon.rs:4:9
    |
 LL |     Bar(&isize)
-   |         ^ expected lifetime parameter
+   |         ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | enum Foo<'lifetime> {
+LL |     Bar(&'lifetime isize)
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr
index cfed9fe..6653765 100644
--- a/src/test/ui/regions/regions-in-enums.stderr
+++ b/src/test/ui/regions/regions-in-enums.stderr
@@ -1,12 +1,16 @@
 error[E0261]: use of undeclared lifetime name `'foo`
   --> $DIR/regions-in-enums.rs:13:9
    |
+LL | enum No0 {
+   |         - help: consider introducing lifetime `'foo` here: `<'foo>`
 LL |     X5(&'foo usize)
    |         ^^^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-enums.rs:17:9
    |
+LL | enum No1 {
+   |         - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     X6(&'a usize)
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr
index a1d4ebb..fbe8036 100644
--- a/src/test/ui/regions/regions-in-structs-anon.stderr
+++ b/src/test/ui/regions/regions-in-structs-anon.stderr
@@ -2,7 +2,13 @@
   --> $DIR/regions-in-structs-anon.rs:4:8
    |
 LL |     x: &isize
-   |        ^ expected lifetime parameter
+   |        ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Foo<'lifetime> {
+LL |     x: &'lifetime isize
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr
index 8314942..5dfdc2e 100644
--- a/src/test/ui/regions/regions-in-structs.stderr
+++ b/src/test/ui/regions/regions-in-structs.stderr
@@ -1,12 +1,17 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-structs.rs:10:9
    |
+LL | struct StructDecl {
+   |                  - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     a: &'a isize,
    |         ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-in-structs.rs:11:9
    |
+LL | struct StructDecl {
+   |                  - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     a: &'a isize,
 LL |     b: &'a isize,
    |         ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr
index 5f6a48a..79ebef4 100644
--- a/src/test/ui/regions/regions-name-undeclared.stderr
+++ b/src/test/ui/regions/regions-name-undeclared.stderr
@@ -3,34 +3,67 @@
    |
 LL |     fn m4(&self, arg: &'b isize) { }
    |                        ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m4<'b>(&self, arg: &'b isize) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:16:12
    |
 LL |     fn m5(&'b self) { }
    |            ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m5<'b>(&'b self) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:17:27
    |
 LL |     fn m6(&self, arg: Foo<'b>) { }
    |                           ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      ^^^
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn m6<'b>(&self, arg: Foo<'b>) { }
+   |          ^^^^
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:25:22
    |
 LL |     type X = Option<&'a isize>;
-   |                      ^^ undeclared lifetime
+   |           -          ^^ undeclared lifetime
+   |           |
+   |           help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:27:13
    |
+LL |     enum E {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
 LL |         E1(&'a isize)
    |             ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:30:13
    |
+LL |     struct S {
+   |             - help: consider introducing lifetime `'a` here: `<'a>`
 LL |         f: &'a isize
    |             ^^ undeclared lifetime
 
@@ -38,13 +71,17 @@
   --> $DIR/regions-name-undeclared.rs:32:14
    |
 LL |     fn f(a: &'a isize) { }
-   |              ^^ undeclared lifetime
+   |         -    ^^ undeclared lifetime
+   |         |
+   |         help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:40:17
    |
 LL | fn fn_types(a: &'a isize,
-   |                 ^^ undeclared lifetime
+   |            -    ^^ undeclared lifetime
+   |            |
+   |            help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:42:36
@@ -61,6 +98,9 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:46:17
    |
+LL | fn fn_types(a: &'a isize,
+   |            - help: consider introducing lifetime `'a` here: `<'a>`
+...
 LL |             c: &'a isize)
    |                 ^^ undeclared lifetime
 
diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr
index 495aec3..6bfde55 100644
--- a/src/test/ui/regions/regions-undeclared.stderr
+++ b/src/test/ui/regions/regions-undeclared.stderr
@@ -7,12 +7,17 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:4:10
    |
+LL | enum EnumDecl {
+   |              - help: consider introducing lifetime `'a` here: `<'a>`
 LL |     Foo(&'a isize),
    |          ^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:5:10
    |
+LL | enum EnumDecl {
+   |              - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     Foo(&'a isize),
 LL |     Bar(&'a isize),
    |          ^^ undeclared lifetime
 
@@ -20,11 +25,15 @@
   --> $DIR/regions-undeclared.rs:8:15
    |
 LL | fn fnDecl(x: &'a isize,
-   |               ^^ undeclared lifetime
+   |          -    ^^ undeclared lifetime
+   |          |
+   |          help: consider introducing lifetime `'a` here: `<'a>`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-undeclared.rs:9:15
    |
+LL | fn fnDecl(x: &'a isize,
+   |          - help: consider introducing lifetime `'a` here: `<'a>`
 LL |           y: &'a isize)
    |               ^^ undeclared lifetime
 
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
new file mode 100644
index 0000000..0407eaf
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+#![feature(track_caller)]
+
+fn pass_to_ptr_call<T>(f: fn(T), x: T) {
+    f(x);
+}
+
+#[track_caller]
+fn tracked_unit(_: ()) {
+    let expected_line = line!() - 1;
+    let location = std::panic::Location::caller();
+    assert_eq!(location.file(), file!());
+    assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
+}
+
+fn main() {
+    pass_to_ptr_call(tracked_unit, ());
+}
diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
new file mode 100644
index 0000000..a4baaa2
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+#![feature(track_caller)]
+
+fn ptr_call(f: fn()) {
+    f();
+}
+
+#[track_caller]
+fn tracked() {
+    let expected_line = line!() - 1;
+    let location = std::panic::Location::caller();
+    assert_eq!(location.file(), file!());
+    assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
+}
+
+fn main() {
+    ptr_call(tracked);
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
index 0bf337a..e4f4d42 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
@@ -1,8 +1,8 @@
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/feature-gate.rs:11:29
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/feature-gate.rs:16:1
    |
-LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
-   |                             ^^^^^^^^
+LL | fn main() {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
index cf1ed30..d600b53 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
@@ -3,6 +3,7 @@
 
 #![cfg_attr(gated, feature(const_trait_bound_opt_out))]
 #![allow(incomplete_features)]
+#![feature(rustc_attrs)]
 
 trait T {
     const CONST: i32;
@@ -10,6 +11,6 @@
 
 const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
 //[stock]~^ ERROR `?const` on trait bounds is experimental
-//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented
 
-fn main() {}
+#[rustc_error]
+fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
index 6438800..fbd3840 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `?const` on trait bounds is experimental
-  --> $DIR/feature-gate.rs:11:29
+  --> $DIR/feature-gate.rs:12:29
    |
 LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
    |                             ^^^^^^
@@ -7,12 +7,6 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/67794
    = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable
 
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/feature-gate.rs:11:29
-   |
-LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
-   |                             ^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs
index e4e6bed..f5561a9 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs
@@ -8,18 +8,14 @@
 
 fn rpit() -> impl ?const T { S }
 //~^ ERROR `?const` is not permitted in `impl Trait`
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn apit(_: impl ?const T) {}
 //~^ ERROR `?const` is not permitted in `impl Trait`
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
 //~^ ERROR `?const` is not permitted in `impl Trait`
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
 //~^ ERROR `?const` is not permitted in `impl Trait`
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr
index f4abd4b..06cd00a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr
@@ -5,46 +5,22 @@
    |                   ^^^^^^^^
 
 error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:13:17
+  --> $DIR/in-impl-trait.rs:12:17
    |
 LL | fn apit(_: impl ?const T) {}
    |                 ^^^^^^^^
 
 error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:17:50
+  --> $DIR/in-impl-trait.rs:15:50
    |
 LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
    |                                                  ^^^^^^^^
 
 error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:21:48
+  --> $DIR/in-impl-trait.rs:18:48
    |
 LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
    |                                                ^^^^^^^^
 
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-impl-trait.rs:9:19
-   |
-LL | fn rpit() -> impl ?const T { S }
-   |                   ^^^^^^^^
-
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-impl-trait.rs:13:17
-   |
-LL | fn apit(_: impl ?const T) {}
-   |                 ^^^^^^^^
-
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-impl-trait.rs:17:50
-   |
-LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
-   |                                                  ^^^^^^^^
-
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-impl-trait.rs:21:48
-   |
-LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
-   |                                                ^^^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs
index 4523b46..fc9ed5b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs
@@ -4,6 +4,5 @@
 trait Super {}
 trait T: ?const Super {}
 //~^ ERROR `?const` is not permitted in supertraits
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr
index 8003361..a0d8f95 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr
@@ -4,11 +4,5 @@
 LL | trait T: ?const Super {}
    |          ^^^^^^^^^^^^
 
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-trait-bounds.rs:5:10
-   |
-LL | trait T: ?const Super {}
-   |          ^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs
index 6cfca71..b3d1f48 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs
@@ -9,14 +9,11 @@
 // An inherent impl for the trait object `?const T`.
 impl ?const T {}
 //~^ ERROR `?const` is not permitted in trait objects
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn trait_object() -> &'static dyn ?const T { &S }
 //~^ ERROR `?const` is not permitted in trait objects
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
 //~^ ERROR `?const` is not permitted in trait objects
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr
index c059f16..331fe04 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr
@@ -5,34 +5,16 @@
    |      ^^^^^^^^
 
 error: `?const` is not permitted in trait objects
-  --> $DIR/in-trait-object.rs:14:35
+  --> $DIR/in-trait-object.rs:13:35
    |
 LL | fn trait_object() -> &'static dyn ?const T { &S }
    |                                   ^^^^^^^^
 
 error: `?const` is not permitted in trait objects
-  --> $DIR/in-trait-object.rs:18:61
+  --> $DIR/in-trait-object.rs:16:61
    |
 LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
    |                                                             ^^^^^^^^
 
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-trait-object.rs:10:6
-   |
-LL | impl ?const T {}
-   |      ^^^^^^^^
-
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-trait-object.rs:14:35
-   |
-LL | fn trait_object() -> &'static dyn ?const T { &S }
-   |                                   ^^^^^^^^
-
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/in-trait-object.rs:18:61
-   |
-LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
-   |                                                             ^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs
index 425784f..c2c8689 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs
@@ -3,6 +3,5 @@
 
 struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
 //~^ ERROR `?const` and `?` are mutually exclusive
-//~| ERROR `?const` on trait bounds is not yet implemented
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr
index 44f6d46..e8e9d6c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr
@@ -4,11 +4,5 @@
 LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
    |             ^^^^^^^^^^^^^
 
-error: `?const` on trait bounds is not yet implemented
-  --> $DIR/with-maybe-sized.rs:4:13
-   |
-LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
-   |             ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
index 9cffe75..7f064c0 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
@@ -1,5 +1,3 @@
-// compile-flags: -Z parse-only
-
 #![feature(const_trait_impl)]
 #![feature(const_trait_bound_opt_out)]
 #![allow(incomplete_features)]
@@ -8,7 +6,12 @@
 struct S;
 trait T {}
 
+impl const S {}
+//~^ ERROR inherent impls cannot be `const`
+//~| ERROR const trait impls are not yet implemented
+
 impl const T {}
-//~^ ERROR `const` cannot modify an inherent impl
+//~^ ERROR inherent impls cannot be `const`
+//~| ERROR const trait impls are not yet implemented
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
index 1d24557..508c6f4 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
@@ -1,10 +1,30 @@
-error: `const` cannot modify an inherent impl
-  --> $DIR/inherent-impl.rs:11:6
+error: inherent impls cannot be `const`
+  --> $DIR/inherent-impl.rs:9:1
+   |
+LL | impl const S {}
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: only trait implementations may be annotated with `const`
+
+error: inherent impls cannot be `const`
+  --> $DIR/inherent-impl.rs:13:1
    |
 LL | impl const T {}
-   |      ^^^^^
+   | ^^^^^^^^^^^^^^^
    |
-   = help: only a trait impl can be `const`
+   = note: only trait implementations may be annotated with `const`
 
-error: aborting due to previous error
+error: const trait impls are not yet implemented
+  --> $DIR/inherent-impl.rs:9:1
+   |
+LL | impl const S {}
+   | ^^^^^^^^^^^^^^^
+
+error: const trait impls are not yet implemented
+  --> $DIR/inherent-impl.rs:13:1
+   |
+LL | impl const T {}
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr
index 171c00b..5b665e1 100644
--- a/src/test/ui/rfc1623.stderr
+++ b/src/test/ui/rfc1623.stderr
@@ -2,7 +2,7 @@
   --> $DIR/rfc1623.rs:8:42
    |
 LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
-   |                                          ^ expected lifetime parameter
+   |                                          ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
 
@@ -10,7 +10,7 @@
   --> $DIR/rfc1623.rs:10:39
    |
 LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
-   |                                       ^ expected lifetime parameter
+   |                                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
index 9fb9a07..0a028e4 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
@@ -2,9 +2,18 @@
   --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39
    |
 LL |     let _: dyn Foo(&isize, &usize) -> &usize;
-   |                                       ^ expected lifetime parameter
+   |                                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+help: consider introducing a named lifetime parameter
+   |
+LL | fn main<'lifetime>() {
+LL |     eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>,
+LL |           dyn Foo(&isize) -> &isize                                   >();
+LL |     eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>,
+LL |           dyn Foo(&isize) -> (&isize, &isize)                           >();
+LL | 
+ ...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
index b20c23a..04df2e4 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
@@ -2,7 +2,13 @@
   --> $DIR/dyn-trait-underscore-in-struct.rs:9:24
    |
 LL |     x: Box<dyn Debug + '_>,
-   |                        ^^ expected lifetime parameter
+   |                        ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Foo<'lifetime> {
+LL |     x: Box<dyn Debug + 'lifetime>,
+   |
 
 error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
   --> $DIR/dyn-trait-underscore-in-struct.rs:9:12
diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr
index ed61bdf..cf82024 100644
--- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr
+++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr
@@ -2,9 +2,13 @@
   --> $DIR/in-fn-return-illegal.rs:5:30
    |
 LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } }
-   |                              ^^ expected lifetime parameter
+   |                              ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } }
+   |       ^^^^^^^^^^^                       ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr
index 6bbdc71..e01b39a 100644
--- a/src/test/ui/underscore-lifetime/in-struct.stderr
+++ b/src/test/ui/underscore-lifetime/in-struct.stderr
@@ -2,13 +2,25 @@
   --> $DIR/in-struct.rs:6:9
    |
 LL |     x: &'_ u32,
-   |         ^^ expected lifetime parameter
+   |         ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Foo<'lifetime> {
+LL |     x: &'lifetime u32,
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/in-struct.rs:10:14
    |
 LL |     Variant(&'_ u32),
-   |              ^^ expected lifetime parameter
+   |              ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | enum Bar<'lifetime> {
+LL |     Variant(&'lifetime u32),
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index ef9e7e3..517904e 100644
--- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -14,7 +14,7 @@
   --> $DIR/underscore-lifetime-binders.rs:2:17
    |
 LL | struct Baz<'a>(&'_ &'a u8);
-   |                 ^^ expected lifetime parameter
+   |                 ^^ help: consider using the named lifetime: `'a`
 
 error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:10:33
@@ -28,9 +28,13 @@
   --> $DIR/underscore-lifetime-binders.rs:16:35
    |
 LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y }
-   |                                   ^^ expected lifetime parameter
+   |                                   ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y`
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y }
+   |        ^^^^^^^^^^^                           ^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
index 0081ae0..49799a9 100644
--- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
@@ -1,6 +1,9 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/where-lifetime-resolution.rs:6:38
    |
+LL | fn f() where
+   |     - help: consider introducing lifetime `'a` here: `<'a>`
+LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
 
@@ -13,6 +16,9 @@
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
+LL | fn f() where
+   |     - help: consider introducing lifetime `'b` here: `<'b>`
+...
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime
 
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 481163a..cff04e1 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -110,6 +110,7 @@
     "riscv32imac-unknown-none-elf",
     "riscv64imac-unknown-none-elf",
     "riscv64gc-unknown-none-elf",
+    "riscv64gc-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "sparcv9-sun-solaris",
diff --git a/src/tools/cargo b/src/tools/cargo
index ad3dbe1..f6449ba 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit ad3dbe10e1e654fb1f032a5dd9481d7cbaa00d65
+Subproject commit f6449ba236db31995255ac5e4cad4ab88296a7c6
diff --git a/src/tools/clippy b/src/tools/clippy
index a8d90f6..3e74853 160000
--- a/src/tools/clippy
+++ b/src/tools/clippy
@@ -1 +1 @@
-Subproject commit a8d90f6a57925d204efb21b3f6d9726d6674f9bd
+Subproject commit 3e74853d1f9893cf2a47f28b658711d8f9f97b6b
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index efa9d05..1f0b42d 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -624,7 +624,8 @@
 
     // Check timestamps.
     let mut inputs = inputs.clone();
-    inputs.add_path(&testpaths.file);
+    // Use `add_dir` to account for run-make tests, which use their individual directory
+    inputs.add_dir(&testpaths.file);
 
     for aux in &props.aux {
         let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
index 4664e2e..408be83 100644
--- a/src/tools/tidy/src/debug_artifacts.rs
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -2,7 +2,7 @@
 
 use std::path::{Path, PathBuf};
 
-const GRAPHVIZ_POSTFLOW_MSG: &'static str = "`borrowck_graphviz_postflow` attribute in test";
+const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
 
 pub fn check(path: &Path, bad: &mut bool) {
     let test_dir: PathBuf = path.join("test");
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index ebaa81d..428c57d 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -53,7 +53,7 @@
                     error_codes.insert(err_code.clone(), false);
                 }
                 // Now we extract the tests from the markdown file!
-                let md = some_or_continue!(s.splitn(2, "include_str!(\"").skip(1).next());
+                let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1));
                 let md_file_name = some_or_continue!(md.splitn(2, "\")").next());
                 let path = some_or_continue!(path.parent()).join(md_file_name);
                 match read_to_string(&path) {
@@ -84,7 +84,7 @@
         let s = line.trim();
         if s.starts_with("error[E") || s.starts_with("warning[E") {
             if let Some(err_code) = s.splitn(2, ']').next() {
-                if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() {
+                if let Some(err_code) = err_code.splitn(2, '[').nth(1) {
                     let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
                     *nb = true;
                 }
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 325b45e..12f93a8 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -232,7 +232,7 @@
             }
         }
     }
-    return false;
+    false
 }
 
 pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
@@ -344,7 +344,7 @@
                 }
                 None
             } else {
-                let s = issue_str.split('(').nth(1).unwrap().split(')').nth(0).unwrap();
+                let s = issue_str.split('(').nth(1).unwrap().split(')').next().unwrap();
                 Some(s.parse().unwrap())
             };
             Some((name.to_owned(), Feature { level, since, has_gate_test: false, tracking_issue }))
diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs
index c8c39ad..620be2f 100644
--- a/src/tools/tidy/src/features/version.rs
+++ b/src/tools/tidy/src/features/version.rs
@@ -38,7 +38,7 @@
 
         let parts = [part()?, part()?, part()?];
 
-        if let Some(_) = iter.next() {
+        if iter.next().is_some() {
             // Ensure we don't have more than 3 parts.
             return Err(ParseVersionError::WrongNumberOfParts);
         }
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index b15c299..4247fcb3b 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -58,7 +58,7 @@
 fn line_is_url(columns: usize, line: &str) -> bool {
     // more basic check for error_codes.rs, to avoid complexity in implementing two state machines
     if columns == ERROR_CODE_COLS {
-        return line.starts_with("[") && line.contains("]:") && line.contains("http");
+        return line.starts_with('[') && line.contains("]:") && line.contains("http");
     }
 
     use self::LIUState::*;