diff --git a/RELEASES.md b/RELEASES.md
index 83c44774da283..841467b69c986 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,151 @@
+Version 1.33.0 (2019-02-28)
+==========================
+
+Language
+--------
+- [You can now use the `cfg(target_vendor)` attribute.][57465] E.g.
+  `#[cfg(target_vendor="linux")] fn main() { println!("Hello Linux!"); }`
+- [Integer patterns such as in a match expression can now be exhaustive.][56362]
+  E.g. You can have match statement on a `u8` that covers `0..=255` and
+  you would no longer be required to have a `_ => unreachable!()` case. 
+- [You can now have multiple patterns in `if let` and `while let`
+  expressions.][57532] You can do this with the same syntax as a `match`
+  expression. E.g.
+  ```rust
+  enum Creature {
+      Crab(String),
+      Lobster(String),
+      Person(String),
+  }
+
+  fn main() {
+      let state = Creature::Crab("Ferris");
+
+      if let Creature::Crab(name) | Creature::Person(name) = state {
+          println!("This creature's name is: {}", name);
+      }
+  }
+  ```
+- [You can now have irrefutable `if let` and `while let` patterns.][57535] Using
+  this feature will by default produce a warning as this behaviour can be
+  unintuitive. E.g. `if let _ = 5 {}`
+- [You can now use `let` bindings, assignments, expression statements,
+  and irrefutable pattern destructuring in const functions.][57175]
+- [You can now call unsafe const functions.][57067] E.g.
+  ```rust
+  const unsafe fn foo() -> i32 { 5 }
+  const fn bar() -> i32 {
+      unsafe { foo() }
+  }
+  ```
+- [You can now specify multiple attributes in a `cfg_attr` attribute.][57332]
+  E.g. `#[cfg_attr(all(), must_use, optimize)]`
+- [You can now specify a specific alignment with the `#[repr(packed)]`
+  attribute.][57049] E.g. `#[repr(packed(2))] struct Foo(i16, i32);` is a struct
+  with an alignment of 2 bytes and a size of 6 bytes.
+- [You can now import an item from a module as an `_`.][56303] This allows you to
+  import a trait's impls, and not have the name in the namespace. E.g.
+  ```rust
+  use std::io::Read as _;
+
+  // Allowed as there is only one `Read` in the module.
+  pub trait Read {}
+  ```
+- [`extern` functions will now abort by default when panicking.][55982]
+  This was previously undefined behaviour.
+
+Compiler
+--------
+- [You can now set a linker flavor for `rustc` with the `-Clinker-flavor`
+  command line argument.][56351]
+- [The mininum required LLVM version has been bumped to 6.0.][56642]
+- [Added support for the PowerPC64 architecture on FreeBSD.][57615]
+- [The `x86_64-fortanix-unknown-sgx` target support has been upgraded to
+  tier 2 support.][57130] Visit the [platform support][platform-support] page for
+  information on Rust's platform support.
+- [Added support for the `thumbv7neon-linux-androideabi` and
+  `thumbv7neon-unknown-linux-gnueabihf` targets.][56947]
+- [Added support for the `x86_64-unknown-uefi` target.][56769]
+
+Libraries
+---------
+- [The methods `overflowing_{add, sub, mul, shl, shr}` are now `const`
+  functions for all numeric types.][57566]
+- [The methods `rotate_left`, `rotate_right`, and `wrapping_{add, sub, mul, shl, shr}`
+  are now `const` functions for all numeric types.][57105]
+- [The methods `is_positive` and `is_negative` are now `const` functions for
+  all signed numeric types.][57105]
+- [The `get` method for all `NonZero` types is now `const`.][57167]
+- [The methods `count_ones`, `count_zeros`, `leading_zeros`, `trailing_zeros`,
+  `swap_bytes`, `from_be`, `from_le`, `to_be`, `to_le` are now `const` for all
+  numeric types.][57234]
+- [`Ipv4Addr::new` is now a `const` function][57234]
+
+Stabilized APIs
+---------------
+- [`unix::FileExt::read_exact_at`]
+- [`unix::FileExt::write_all_at`]
+- [`Option::transpose`]
+- [`Result::transpose`]
+- [`convert::identity`]
+- [`pin::Pin`]
+- [`marker::Unpin`]
+- [`marker::PhantomPinned`]
+- [`Vec::resize_with`]
+- [`VecDeque::resize_with`]
+- [`Duration::as_millis`]
+- [`Duration::as_micros`]
+- [`Duration::as_nanos`]
+
+
+Cargo
+-----
+- [Cargo should now rebuild a crate if a file was modified during the initial
+  build.][cargo/6484]
+
+Compatibility Notes
+-------------------
+- The methods `str::{trim_left, trim_right, trim_left_matches, trim_right_matches}`
+  are now deprecated in the standard library, and their usage will now produce a warning.
+  Please use the `str::{trim_start, trim_end, trim_start_matches, trim_end_matches}`
+  methods instead.
+
+[57615]: https://github.com/rust-lang/rust/pull/57615/
+[57465]: https://github.com/rust-lang/rust/pull/57465/
+[57532]: https://github.com/rust-lang/rust/pull/57532/
+[57535]: https://github.com/rust-lang/rust/pull/57535/
+[57566]: https://github.com/rust-lang/rust/pull/57566/
+[57130]: https://github.com/rust-lang/rust/pull/57130/
+[57167]: https://github.com/rust-lang/rust/pull/57167/
+[57175]: https://github.com/rust-lang/rust/pull/57175/
+[57234]: https://github.com/rust-lang/rust/pull/57234/
+[57332]: https://github.com/rust-lang/rust/pull/57332/
+[56947]: https://github.com/rust-lang/rust/pull/56947/
+[57049]: https://github.com/rust-lang/rust/pull/57049/
+[57067]: https://github.com/rust-lang/rust/pull/57067/
+[56769]: https://github.com/rust-lang/rust/pull/56769/
+[56642]: https://github.com/rust-lang/rust/pull/56642/
+[56303]: https://github.com/rust-lang/rust/pull/56303/
+[56351]: https://github.com/rust-lang/rust/pull/56351/
+[55982]: https://github.com/rust-lang/rust/pull/55982/
+[56362]: https://github.com/rust-lang/rust/pull/56362
+[57105]: https://github.com/rust-lang/rust/pull/57105
+[cargo/6484]: https://github.com/rust-lang/cargo/pull/6484/
+[`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at
+[`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at
+[`Option::transpose`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.transpose
+[`Result::transpose`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose
+[`convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html
+[`pin::Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html
+[`marker::Unpin`]: https://doc.rust-lang.org/stable/std/marker/trait.Unpin.html
+[`marker::PhantomPinned`]: https://doc.rust-lang.org/nightly/std/marker/struct.PhantomPinned.html
+[`Vec::resize_with`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize_with
+[`VecDeque::resize_with`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.resize_with
+[`Duration::as_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_millis
+[`Duration::as_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_micros
+[`Duration::as_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_nanos
+[platform-support]: https://forge.rust-lang.org/platform-support.html
+
 Version 1.32.0 (2019-01-17)
 ==========================
 
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 65752ba032104..4fd386c16d96d 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -597,34 +597,43 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
 
 /// Types which can be safely moved after being pinned.
 ///
-/// Since Rust itself has no notion of immovable types, and will consider moves to always be safe,
+/// Since Rust itself has no notion of immovable types, and considers moves
+/// (e.g. through assignment or [`mem::replace`]) to always be safe,
 /// this trait cannot prevent types from moving by itself.
 ///
-/// Instead it can be used to prevent moves through the type system,
-/// by controlling the behavior of pointers wrapped in the [`Pin`] wrapper,
+/// Instead it is used to prevent moves through the type system,
+/// by controlling the behavior of pointers `P` wrapped in the [`Pin<P>`] wrapper,
 /// which "pin" the type in place by not allowing it to be moved out of them.
 /// See the [`pin module`] documentation for more information on pinning.
 ///
 /// Implementing this trait lifts the restrictions of pinning off a type,
-/// which then allows it to move out with functions such as [`replace`].
+/// which then allows it to move out with functions such as [`mem::replace`].
+///
+/// `Unpin` has no consequence at all for non-pinned data. In particular,
+/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not
+/// just when `T: Unpin`). However, you cannot use
+/// [`mem::replace`] on data wrapped inside a [`Pin<P>`] because you cannot get the
+/// `&mut T` you need for that, and *that* is what makes this system work.
 ///
 /// So this, for example, can only be done on types implementing `Unpin`:
 ///
 /// ```rust
-/// use std::mem::replace;
+/// use std::mem;
 /// use std::pin::Pin;
 ///
 /// let mut string = "this".to_string();
 /// let mut pinned_string = Pin::new(&mut string);
 ///
-/// // dereferencing the pointer mutably is only possible because String implements Unpin
-/// replace(&mut *pinned_string, "other".to_string());
+/// // We need a mutable reference to call `mem::replace`.
+/// // We can obtain such a reference by (implicitly) invoking `Pin::deref_mut`,
+/// // but that is only possible because `String` implements `Unpin`.
+/// mem::replace(&mut *pinned_string, "other".to_string());
 /// ```
 ///
 /// This trait is automatically implemented for almost every type.
 ///
-/// [`replace`]: ../../std/mem/fn.replace.html
-/// [`Pin`]: ../pin/struct.Pin.html
+/// [`mem::replace`]: ../../std/mem/fn.replace.html
+/// [`Pin<P>`]: ../pin/struct.Pin.html
 /// [`pin module`]: ../../std/pin/index.html
 #[stable(feature = "pin", since = "1.33.0")]
 pub auto trait Unpin {}
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 762e07549a52a..b68b2f39d6bd9 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -2,45 +2,63 @@
 //!
 //! It is sometimes useful to have objects that are guaranteed to not move,
 //! in the sense that their placement in memory does not change, and can thus be relied upon.
-//!
 //! A prime example of such a scenario would be building self-referential structs,
 //! since moving an object with pointers to itself will invalidate them,
 //! which could cause undefined behavior.
 //!
+//! A [`Pin<P>`] ensures that the pointee of any pointer type `P` has a stable location in memory,
+//! meaning it cannot be moved elsewhere and its memory cannot be deallocated
+//! until it gets dropped. We say that the pointee is "pinned".
+//!
 //! By default, all types in Rust are movable. Rust allows passing all types by-value,
-//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
-//! moving the values they contain. In order to prevent objects from moving, they must
-//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
-//! Doing this prohibits moving the value behind the pointer.
-//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
-//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
-//! but the value behind it cannot.
-//!
-//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
-//! changing the location of the underlying data, [`Pin`] prohibits accessing the
-//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
-//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
-//! functions will move the pointed-to value. This allows for the creation of
-//! self-references and other special behaviors that are only possible for unmovable
-//! values.
+//! and common smart-pointer types such as `Box<T>` and `&mut T` allow replacing and
+//! moving the values they contain: you can move out of a `Box<T>`, or you can use [`mem::swap`].
+//! [`Pin<P>`] wraps a pointer type `P`, so `Pin<Box<T>>` functions much like a regular `Box<T>`:
+//! when a `Pin<Box<T>>` gets dropped, so do its contents, and the memory gets deallocated.
+//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does not let clients
+//! actually obtain a `Box<T>` or `&mut T` to pinned data, which implies that you cannot use
+//! operations such as [`mem::swap`]:
+//! ```
+//! use std::pin::Pin;
+//! fn swap_pins<T>(x: Pin<&mut T>, y: Pin<&mut T>) {
+//!     // `mem::swap` needs `&mut T`, but we cannot get it.
+//!     // We are stuck, we cannot swap the contents of these references.
+//!     // We could use `Pin::get_unchecked_mut`, but that is unsafe for a reason:
+//!     // we are not allowed to use it for moving things out of the `Pin`.
+//! }
+//! ```
 //!
-//! However, these restrictions are usually not necessary. Many types are always freely
-//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect
-//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
-//! `Pin<&mut T>` and `&mut T`.
+//! It is worth reiterating that [`Pin<P>`] does *not* change the fact that a Rust compiler
+//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin<P>`
+//! prevents certain *values* (pointed to by pointers wrapped in `Pin<P>`) from being
+//! moved by making it impossible to call methods that require `&mut T` on them
+//! (like [`mem::swap`]).
 //!
-//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
-//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
-//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
-//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
-//! are always freely movable, even if the data they point to isn't.
+//! [`Pin<P>`] can be used to wrap any pointer type `P`, and as such it interacts with
+//! [`Deref`] and [`DerefMut`]. A `Pin<P>` where `P: Deref` should be considered
+//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin<Box<T>>` is
+//! an owned pointer to a pinned `T`, and a `Pin<Rc<T>>` is a reference-counted
+//! pointer to a pinned `T`.
+//! For correctness, [`Pin<P>`] relies on the [`Deref`] and [`DerefMut`] implementations
+//! to not move out of their `self` parameter, and to only ever return a pointer
+//! to pinned data when they are called on a pinned pointer.
 //!
-//! [`Pin`]: struct.Pin.html
-//! [`Unpin`]: ../../std/marker/trait.Unpin.html
-//! [`swap`]: ../../std/mem/fn.swap.html
-//! [`Box`]: ../../std/boxed/struct.Box.html
+//! # `Unpin`
+//!
+//! However, these restrictions are usually not necessary. Many types are always freely
+//! movable, even when pinned, because they do not rely on having a stable address.
+//! This includes all the basic types (like `bool`, `i32`, references)
+//! as well as types consisting solely of these types.
+//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which
+//! cancels the effect of [`Pin<P>`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function
+//! identically, as do `Pin<&mut T>` and `&mut T`.
+//!
+//! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer
+//! type `P` itself that got wrapped in `Pin<P>`. For example, whether or not `Box<T>` is
+//! `Unpin` has no effect on the behavior of `Pin<Box<T>>` (here, `T` is the
+//! pointed-to type).
 //!
-//! # Examples
+//! # Example: self-referential struct
 //!
 //! ```rust
 //! use std::pin::Pin;
@@ -94,6 +112,150 @@
 //! // let new_unmoved = Unmovable::new("world".to_string());
 //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
 //! ```
+//!
+//! # Example: intrusive doubly-linked list
+//!
+//! In an intrusive doubly-linked list, the collection does not actually allocate
+//! the memory for the elements itself. Allocation is controlled by the clients,
+//! and elements can live on a stack frame that lives shorter than the collection does.
+//!
+//! To make this work, every element has pointers to its predecessor and successor in
+//! the list. Elements can only be added when they are pinned, because moving the elements
+//! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked
+//! list element will patch the pointers of its predecessor and successor to remove itself
+//! from the list.
+//!
+//! Crucially, we have to be able to rely on `drop` being called. If an element
+//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it
+//! from its neighbouring elements would become invalid, which would break the data structure.
+//!
+//! Therefore, pinning also comes with a `drop`-related guarantee.
+//!
+//! # `Drop` guarantee
+//!
+//! The purpose of pinning is to be able to rely on the placement of some data in memory.
+//! To make this work, not just moving the data is restricted; deallocating, repurposing, or
+//! otherwise invalidating the memory used to store the data is restricted, too.
+//! Concretely, for pinned data you have to maintain the invariant
+//! that *its memory will not get invalidated from the moment it gets pinned until
+//! when `drop` is called*. Memory can be invalidated by deallocation, but also by
+//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
+//! off of a vector.
+//!
+//! This is exactly the kind of guarantee that the intrusive linked list from the previous
+//! section needs to function correctly.
+//!
+//! Notice that this guarantee does *not* mean that memory does not leak! It is still
+//! completely okay not to ever call `drop` on a pinned element (e.g., you can still
+//! call [`mem::forget`] on a `Pin<Box<T>>`). In the example of the doubly-linked
+//! list, that element would just stay in the list. However you may not free or reuse the storage
+//! *without calling `drop`*.
+//!
+//! # `Drop` implementation
+//!
+//! If your type uses pinning (such as the two examples above), you have to be careful
+//! when implementing `Drop`. The `drop` function takes `&mut self`, but this
+//! is called *even if your type was previously pinned*! It is as if the
+//! compiler automatically called `get_unchecked_mut`.
+//!
+//! This can never cause a problem in safe code because implementing a type that relies on pinning
+//! requires unsafe code, but be aware that deciding to make use of pinning
+//! in your type (for example by implementing some operation on `Pin<&[mut] Self>`)
+//! has consequences for your `Drop` implementation as well: if an element
+//! of your type could have been pinned, you must treat Drop as implicitly taking
+//! `Pin<&mut Self>`.
+//!
+//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically
+//! move fields around to be able to drop them. As a consequence, you cannot use
+//! pinning with a `#[repr(packed)]` type.
+//!
+//! # Projections and Structural Pinning
+//!
+//! One interesting question arises when considering the interaction of pinning and
+//! the fields of a struct. When can a struct have a "pinning projection", i.e.,
+//! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`?
+//! In a similar vein, when can a generic wrapper type (such as `Vec<T>`, `Box<T>`, or `RefCell<T>`)
+//! have an operation with type `fn(Pin<&[mut] Wrapper<T>>) -> Pin<&[mut] T>`?
+//!
+//! Having a pinning projection for some field means that pinning is "structural":
+//! when the wrapper is pinned, the field must be considered pinned, too.
+//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`.
+//!
+//! However, structural pinning comes with a few extra requirements, so not all
+//! wrappers can be structural and hence not all wrappers can offer pinning projections:
+//!
+//! 1.  The wrapper must only be [`Unpin`] if all the structural fields are
+//!     `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
+//!     the wrapper it is your responsibility *not* to add something like
+//!     `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
+//!     requires unsafe code, so the fact that `Unpin` is a safe trait  does not break
+//!     the principle that you only have to worry about any of this if you use `unsafe`.)
+//! 2.  The destructor of the wrapper must not move structural fields out of its argument. This
+//!     is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
+//!     `&mut self`, but the wrapper (and hence its fields) might have been pinned before.
+//!     You have to guarantee that you do not move a field inside your `Drop` implementation.
+//!     In particular, as explained previously, this means that your wrapper type must *not*
+//!     be `#[repr(packed)]`.
+//! 3.  You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
+//!     once your wrapper is pinned, the memory that contains the
+//!     content is not overwritten or deallocated without calling the content's destructors.
+//!     This can be tricky, as witnessed by `VecDeque<T>`: the destructor of `VecDeque<T>` can fail
+//!     to call `drop` on all elements if one of the destructors panics. This violates the
+//!     `Drop` guarantee, because it can lead to elements being deallocated without
+//!     their destructor being called. (`VecDeque` has no pinning projections, so this
+//!     does not cause unsoundness.)
+//! 4.  You must not offer any other operations that could lead to data being moved out of
+//!     the fields when your type is pinned. For example, if the wrapper contains an
+//!     `Option<T>` and there is a `take`-like operation with type
+//!     `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
+//!     that operation can be used to move a `T` out of a pinned `Wrapper<T>` -- which means
+//!     pinning cannot be structural.
+//!
+//!     For a more complex example of moving data out of a pinned type, imagine if `RefCell<T>`
+//!     had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
+//!     Then we could do the following:
+//!     ```compile_fail
+//!     fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) {
+//!         { let p = rc.as_mut().get_pin_mut(); } // Here we get pinned access to the `T`.
+//!         let rc_shr: &RefCell<T> = rc.into_ref().get_ref();
+//!         let b = rc_shr.borrow_mut();
+//!         let content = &mut *b; // And here we have `&mut T` to the same data.
+//!     }
+//!     ```
+//!     This is catastrophic, it means we can first pin the content of the `RefCell<T>`
+//!     (using `RefCell::get_pin_mut`) and then move that content using the mutable
+//!     reference we got later.
+//!
+//! For a type like `Vec<T>`, both possibilites (structural pinning or not) make sense,
+//! and the choice is up to the author. A `Vec<T>` with structural pinning could
+//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling
+//! `pop` on a pinned `Vec<T>` because that would move the (structurally pinned) contents!
+//! Nor could it allow `push`, which might reallocate and thus also move the contents.
+//! A `Vec<T>` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
+//! are never pinned and the `Vec<T>` itself is fine with being moved as well.
+//!
+//! In the standard library, pointer types generally do not have structural pinning,
+//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
+//! It makes sense to do this for pointer types, because moving the `Box<T>`
+//! does not actually move the `T`: the `Box<T>` can be freely movable (aka `Unpin`) even if the `T`
+//! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves,
+//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves
+//! can be moved without moving the pinned data. For both `Box<T>` and `Pin<Box<T>>`,
+//! whether the content is pinned is entirely independent of whether the pointer is
+//! pinned, meaning pinning is *not* structural.
+//!
+//! [`Pin<P>`]: struct.Pin.html
+//! [`Unpin`]: ../../std/marker/trait.Unpin.html
+//! [`Deref`]: ../../std/ops/trait.Deref.html
+//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html
+//! [`mem::swap`]: ../../std/mem/fn.swap.html
+//! [`mem::forget`]: ../../std/mem/fn.forget.html
+//! [`Box<T>`]: ../../std/boxed/struct.Box.html
+//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
+//! [`None`]: ../../std/option/enum.Option.html#variant.None
+//! [`Some(v)`]: ../../std/option/enum.Option.html#variant.Some
+//! [drop-impl]: #drop-implementation
+//! [drop-guarantee]: #drop-guarantee
 
 #![stable(feature = "pin", since = "1.33.0")]
 
@@ -126,8 +288,13 @@ impl<P: Deref> Pin<P>
 where
     P::Target: Unpin,
 {
-    /// Construct a new `Pin` around a pointer to some data of a type that
-    /// implements `Unpin`.
+    /// Construct a new `Pin<P>` around a pointer to some data of a type that
+    /// implements [`Unpin`].
+    ///
+    /// Unlike `Pin::new_unchecked`, this method is safe because the pointer
+    /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
+    ///
+    /// [`Unpin`]: ../../std/marker/trait.Unpin.html
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn new(pointer: P) -> Pin<P> {
@@ -138,25 +305,83 @@ where
 }
 
 impl<P: Deref> Pin<P> {
-    /// Construct a new `Pin` around a reference to some data of a type that
+    /// Construct a new `Pin<P>` around a reference to some data of a type that
     /// may or may not implement `Unpin`.
     ///
+    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
+    /// instead.
+    ///
     /// # Safety
     ///
     /// This constructor is unsafe because we cannot guarantee that the data
-    /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
-    /// not guarantee that the data `P` points to is pinned, constructing a
-    /// `Pin<P>` is undefined behavior.
+    /// pointed to by `pointer` is pinned, meaning that the data will not be moved or
+    /// its storage invalidated until it gets dropped. If the constructed `Pin<P>` does
+    /// not guarantee that the data `P` points to is pinned, that is a violation of
+    /// the API contract and may lead to undefined behavior in later (safe) operations.
     ///
-    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
-    /// instead.
+    /// By using this method, you are making a promise about the `P::Deref` and
+    /// `P::DerefMut` implementations, if they exist. Most importantly, they
+    /// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref`
+    /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pinned pointer*
+    /// and expect these methods to uphold the pinning invariants.
+    /// Moreover, by calling this method you promise that the reference `P`
+    /// dereferences to will not be moved out of again; in particular, it
+    /// must not be possible to obtain a `&mut P::Target` and then
+    /// move out of that reference (using, for example [`mem::swap`]).
+    ///
+    /// For example, calling `Pin::new_unchecked` on an `&'a mut T` is unsafe because
+    /// while you are able to pin it for the given lifetime `'a`, you have no control
+    /// over whether it is kept pinned once `'a` ends:
+    /// ```
+    /// use std::mem;
+    /// use std::pin::Pin;
+    ///
+    /// fn move_pinned_ref<T>(mut a: T, mut b: T) {
+    ///     unsafe {
+    ///         let p: Pin<&mut T> = Pin::new_unchecked(&mut a);
+    ///         // This should mean the pointee `a` can never move again.
+    ///     }
+    ///     mem::swap(&mut a, &mut b);
+    ///     // The address of `a` changed to `b`'s stack slot, so `a` got moved even
+    ///     // though we have previously pinned it! We have violated the pinning API contract.
+    /// }
+    /// ```
+    /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`).
+    ///
+    /// Similarily, calling `Pin::new_unchecked` on an `Rc<T>` is unsafe because there could be
+    /// aliases to the same data that are not subject to the pinning restrictions:
+    /// ```
+    /// use std::rc::Rc;
+    /// use std::pin::Pin;
+    ///
+    /// fn move_pinned_rc<T>(mut x: Rc<T>) {
+    ///     let pinned = unsafe { Pin::new_unchecked(x.clone()) };
+    ///     {
+    ///         let p: Pin<&T> = pinned.as_ref();
+    ///         // This should mean the pointee can never move again.
+    ///     }
+    ///     drop(pinned);
+    ///     let content = Rc::get_mut(&mut x).unwrap();
+    ///     // Now, if `x` was the only reference, we have a mutable reference to
+    ///     // data that we pinned above, which we could use to move it as we have
+    ///     // seen in the previous example. We have violated the pinning API contract.
+    ///  }
+    ///  ```
+    ///
+    /// [`mem::swap`]: ../../std/mem/fn.swap.html
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
         Pin { pointer }
     }
 
-    /// Get a pinned shared reference from this pinned pointer.
+    /// Gets a pinned shared reference from this pinned pointer.
+    ///
+    /// This is a generic method to go from `&Pin<Pointer<T>>` to `Pin<&T>`.
+    /// It is safe because, as part of the contract of `Pin::new_unchecked`,
+    /// the pointee cannot move after `Pin<Pointer<T>>` got created.
+    /// "Malicious" implementations of `Pointer::Deref` are likewise
+    /// ruled out by the contract of `Pin::new_unchecked`.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> {
@@ -165,14 +390,23 @@ impl<P: Deref> Pin<P> {
 }
 
 impl<P: DerefMut> Pin<P> {
-    /// Get a pinned mutable reference from this pinned pointer.
+    /// Gets a pinned mutable reference from this pinned pointer.
+    ///
+    /// This is a generic method to go from `&mut Pin<Pointer<T>>` to `Pin<&mut T>`.
+    /// It is safe because, as part of the contract of `Pin::new_unchecked`,
+    /// the pointee cannot move after `Pin<Pointer<T>>` got created.
+    /// "Malicious" implementations of `Pointer::DerefMut` are likewise
+    /// ruled out by the contract of `Pin::new_unchecked`.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn as_mut(self: &mut Pin<P>) -> Pin<&mut P::Target> {
         unsafe { Pin::new_unchecked(&mut *self.pointer) }
     }
 
-    /// Assign a new value to the memory behind the pinned reference.
+    /// Assigns a new value to the memory behind the pinned reference.
+    ///
+    /// This overwrites pinned data, but that is okay: its destructor gets
+    /// run before being overwritten, so no pinning guarantee is violated.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn set(self: &mut Pin<P>, value: P::Target)
@@ -184,10 +418,12 @@ impl<P: DerefMut> Pin<P> {
 }
 
 impl<'a, T: ?Sized> Pin<&'a T> {
-    /// Construct a new pin by mapping the interior value.
+    /// Constructs a new pin by mapping the interior value.
     ///
     /// For example, if you  wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
+    /// However, there are several gotchas with these "pinning projections";
+    /// see the [`pin` module] documentation for further details on that topic.
     ///
     /// # Safety
     ///
@@ -195,6 +431,8 @@ impl<'a, T: ?Sized> Pin<&'a T> {
     /// will not move so long as the argument value does not move (for example,
     /// because it is one of the fields of that value), and also that you do
     /// not move out of the argument you receive to the interior function.
+    ///
+    /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
     pub unsafe fn map_unchecked<U, F>(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
         F: FnOnce(&T) -> &U,
@@ -206,11 +444,21 @@ impl<'a, T: ?Sized> Pin<&'a T> {
 
     /// Get a shared reference out of a pin.
     ///
+    /// This is safe because it is not possible to move out of a shared reference.
+    /// It may seem like there is an issue here with interior mutability: in fact,
+    /// it *is* possible to move a `T` out of a `&RefCell<T>`. However, this is
+    /// not a problem as long as there does not also exist a `Pin<&T>` pointing
+    /// to the same data, and `RefCell<T>` does not let you create a pinned reference
+    /// to its contents. See the discussion on ["pinning projections"] for further
+    /// details.
+    ///
     /// Note: `Pin` also implements `Deref` to the target, which can be used
     /// to access the inner value. However, `Deref` only provides a reference
     /// that lives for as long as the borrow of the `Pin`, not the lifetime of
     /// the `Pin` itself. This method allows turning the `Pin` into a reference
     /// with the same lifetime as the original `Pin`.
+    ///
+    /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn get_ref(self: Pin<&'a T>) -> &'a T {
@@ -263,6 +511,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
     ///
     /// For example, if you  wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
+    /// However, there are several gotchas with these "pinning projections";
+    /// see the [`pin` module] documentation for further details on that topic.
     ///
     /// # Safety
     ///
@@ -270,6 +520,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
     /// will not move so long as the argument value does not move (for example,
     /// because it is one of the fields of that value), and also that you do
     /// not move out of the argument you receive to the interior function.
+    ///
+    /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
     pub unsafe fn map_unchecked_mut<U, F>(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
         F: FnOnce(&mut T) -> &mut U,
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index 408cba42ae04b..5a2686718185c 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -191,7 +191,16 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
                 // response should be executing in a fully
                 // canonicalized environment, so there shouldn't be
                 // any other region names it can come up.
-                bug!("unexpected region in query response: `{:?}`", r)
+                //
+                // rust-lang/rust#57464: `impl Trait` can leak local
+                // scopes (in manner violating typeck). Therefore, use
+                // `delay_span_bug` to allow type error over an ICE.
+                ty::tls::with_context(|c| {
+                    c.tcx.sess.delay_span_bug(
+                        syntax_pos::DUMMY_SP,
+                        &format!("unexpected region in query response: `{:?}`", r));
+                });
+                r
             }
         }
     }
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 40c11695d51e2..97f9c2ceba005 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -255,10 +255,24 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
             RelationDir::SupertypeOf => ty::Contravariant,
         };
 
+        debug!("generalize: ambient_variance = {:?}", ambient_variance);
+
+        let for_universe = match self.infcx.type_variables.borrow_mut().probe(for_vid) {
+            v @ TypeVariableValue::Known { .. } => panic!(
+                "instantiating {:?} which has a known value {:?}",
+                for_vid,
+                v,
+            ),
+            TypeVariableValue::Unknown { universe } => universe,
+        };
+
+        debug!("generalize: for_universe = {:?}", for_universe);
+
         let mut generalize = Generalizer {
             infcx: self.infcx,
             span: self.trace.cause.span,
             for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
+            for_universe,
             ambient_variance,
             needs_wf: false,
             root_ty: ty,
@@ -288,6 +302,11 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     /// that means we would have created a cyclic type.
     for_vid_sub_root: ty::TyVid,
 
+    /// The universe of the type variable that is in the process of
+    /// being instantiated. Any fresh variables that we create in this
+    /// process should be in that same universe.
+    for_universe: ty::UniverseIndex,
+
     /// Track the variance as we descend into the type.
     ambient_variance: ty::Variance,
 
@@ -386,6 +405,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
     fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
+        debug!("generalize: t={:?}", t);
+
         // Check to see whether the type we are genealizing references
         // any other type variable related to `vid` via
         // subtyping. This is basically our "occurs check", preventing
@@ -403,12 +424,17 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                     match variables.probe(vid) {
                         TypeVariableValue::Known { value: u } => {
                             drop(variables);
+                            debug!("generalize: known value {:?}", u);
                             self.relate(&u, &u)
                         }
                         TypeVariableValue::Unknown { universe } => {
                             match self.ambient_variance {
                                 // Invariant: no need to make a fresh type variable.
-                                ty::Invariant => return Ok(t),
+                                ty::Invariant => {
+                                    if self.for_universe.can_name(universe) {
+                                        return Ok(t);
+                                    }
+                                }
 
                                 // Bivariant: make a fresh var, but we
                                 // may need a WF predicate. See
@@ -422,7 +448,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                             }
 
                             let origin = *variables.var_origin(vid);
-                            let new_var_id = variables.new_var(universe, false, origin);
+                            let new_var_id = variables.new_var(self.for_universe, false, origin);
                             let u = self.tcx().mk_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}",
                                    vid, u);
@@ -448,6 +474,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                -> RelateResult<'tcx, ty::Region<'tcx>> {
         assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
+        debug!("generalize: regions r={:?}", r);
+
         match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
@@ -456,37 +484,40 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                 return Ok(r);
             }
 
-            // Always make a fresh region variable for placeholder
-            // regions; the higher-ranked decision procedures rely on
-            // this.
-            ty::RePlaceholder(..) => { }
+            ty::ReClosureBound(..) => {
+                span_bug!(
+                    self.span,
+                    "encountered unexpected ReClosureBound: {:?}",
+                    r,
+                );
+            }
 
-            // For anything else, we make a region variable, unless we
-            // are *equating*, in which case it's just wasteful.
+            ty::RePlaceholder(..) |
+            ty::ReVar(..) |
             ty::ReEmpty |
             ty::ReStatic |
             ty::ReScope(..) |
-            ty::ReVar(..) |
             ty::ReEarlyBound(..) |
             ty::ReFree(..) => {
-                match self.ambient_variance {
-                    ty::Invariant => return Ok(r),
-                    ty::Bivariant | ty::Covariant | ty::Contravariant => (),
-                }
+                // see common code below
             }
+        }
 
-            ty::ReClosureBound(..) => {
-                span_bug!(
-                    self.span,
-                    "encountered unexpected ReClosureBound: {:?}",
-                    r,
-                );
+        // If we are in an invariant context, we can re-use the region
+        // as is, unless it happens to be in some universe that we
+        // can't name. (In the case of a region *variable*, we could
+        // use it if we promoted it into our universe, but we don't
+        // bother.)
+        if let ty::Invariant = self.ambient_variance {
+            let r_universe = self.infcx.universe_of_region(r);
+            if self.for_universe.can_name(r_universe) {
+                return Ok(r);
             }
         }
 
         // FIXME: This is non-ideal because we don't give a
         // very descriptive origin for this region variable.
-        Ok(self.infcx.next_region_var(MiscVariable(self.span)))
+        Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
     }
 }
 
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 709e8c0ba9b24..70ab5a9b3c05e 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -4,6 +4,7 @@
 use super::combine::CombineFields;
 use super::{HigherRankedType, InferCtxt, PlaceholderMap};
 
+use infer::CombinedSnapshot;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 use ty::{self, Binder, TypeFoldable};
 
@@ -29,27 +30,32 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         let span = self.trace.cause.span;
 
-        // First, we instantiate each bound region in the supertype with a
-        // fresh placeholder region.
-        let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
+        return self.infcx.commit_if_ok(|snapshot| {
+            // First, we instantiate each bound region in the supertype with a
+            // fresh placeholder region.
+            let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
 
-        // Next, we instantiate each bound region in the subtype
-        // with a fresh region variable. These region variables --
-        // but no other pre-existing region variables -- can name
-        // the placeholders.
-        let (a_prime, _) =
-            self.infcx
-                .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+            // Next, we instantiate each bound region in the subtype
+            // with a fresh region variable. These region variables --
+            // but no other pre-existing region variables -- can name
+            // the placeholders.
+            let (a_prime, _) =
+                self.infcx
+                    .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+
+            debug!("a_prime={:?}", a_prime);
+            debug!("b_prime={:?}", b_prime);
 
-        debug!("a_prime={:?}", a_prime);
-        debug!("b_prime={:?}", b_prime);
+            // Compare types now that bound regions have been replaced.
+            let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-        // Compare types now that bound regions have been replaced.
-        let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
+            self.infcx
+                .leak_check(!a_is_expected, &placeholder_map, snapshot)?;
 
-        debug!("higher_ranked_sub: OK result={:?}", result);
+            debug!("higher_ranked_sub: OK result={:?}", result);
 
-        Ok(ty::Binder::bind(result))
+            Ok(ty::Binder::bind(result))
+        });
     }
 }
 
@@ -72,10 +78,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
     pub fn replace_bound_vars_with_placeholders<T>(
         &self,
-        binder: &ty::Binder<T>
+        binder: &ty::Binder<T>,
     ) -> (T, PlaceholderMap<'tcx>)
     where
-        T: TypeFoldable<'tcx>
+        T: TypeFoldable<'tcx>,
     {
         let next_universe = self.create_next_universe();
 
@@ -96,12 +102,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t);
 
         debug!(
-            "replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})",
+            "replace_bound_vars_with_placeholders(\
+             next_universe={:?}, \
+             binder={:?}, \
+             result={:?}, \
+             map={:?})",
+            next_universe,
             binder,
             result,
-            map
+            map,
         );
 
         (result, map)
     }
+
+    /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
+    pub fn leak_check(
+        &self,
+        overly_polymorphic: bool,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> RelateResult<'tcx, ()> {
+        self.borrow_region_constraints()
+            .leak_check(self.tcx, overly_polymorphic, placeholder_map, snapshot)
+    }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 958982545750f..a831c46ce7245 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -935,32 +935,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return None;
         }
 
-        let (
-            ty::SubtypePredicate {
-                a_is_expected,
-                a,
-                b,
-            },
-            _,
-        ) = self.replace_bound_vars_with_placeholders(predicate);
+        Some(self.commit_if_ok(|snapshot| {
+            let (
+                ty::SubtypePredicate {
+                    a_is_expected,
+                    a,
+                    b,
+                },
+                placeholder_map,
+            ) = self.replace_bound_vars_with_placeholders(predicate);
 
-        Some(
-            self.at(cause, param_env)
-                .sub_exp(a_is_expected, a, b)
-                .map(|ok| ok.unit()),
-        )
+            let ok = self.at(cause, param_env)
+                .sub_exp(a_is_expected, a, b)?;
+
+            self.leak_check(false, &placeholder_map, snapshot)?;
+
+            Ok(ok.unit())
+        }))
     }
 
     pub fn region_outlives_predicate(
         &self,
         cause: &traits::ObligationCause<'tcx>,
         predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
-    ) {
-        let (ty::OutlivesPredicate(r_a, r_b), _) =
-            self.replace_bound_vars_with_placeholders(predicate);
-        let origin =
-            SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
-        self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
+    ) -> UnitResult<'tcx> {
+        self.commit_if_ok(|snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+                self.replace_bound_vars_with_placeholders(predicate);
+            let origin = SubregionOrigin::from_obligation_cause(
+                cause,
+                || RelateRegionParamBound(cause.span),
+            );
+            self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
+            self.leak_check(false, &placeholder_map, snapshot)?;
+            Ok(())
+        })
     }
 
     pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
@@ -1016,6 +1025,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.mk_region(ty::ReVar(region_var))
     }
 
+    /// Return the universe that the region `r` was created in.  For
+    /// most regions (e.g., `'static`, named regions from the user,
+    /// etc) this is the root universe U0. For inference variables or
+    /// placeholders, however, it will return the universe which which
+    /// they are associated.
+    fn universe_of_region(
+        &self,
+        r: ty::Region<'tcx>,
+    ) -> ty::UniverseIndex {
+        self.borrow_region_constraints().universe(r)
+    }
+
     /// Number of region variables created so far.
     pub fn num_region_vars(&self) -> usize {
         self.borrow_region_constraints().num_region_vars()
diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc/infer/region_constraints/leak_check.rs
new file mode 100644
index 0000000000000..8085258610d84
--- /dev/null
+++ b/src/librustc/infer/region_constraints/leak_check.rs
@@ -0,0 +1,174 @@
+use super::*;
+use crate::infer::{CombinedSnapshot, PlaceholderMap};
+use crate::ty::error::TypeError;
+use crate::ty::relate::RelateResult;
+
+impl<'tcx> RegionConstraintCollector<'tcx> {
+    /// Searches region constraints created since `snapshot` that
+    /// affect one of the placeholders in `placeholder_map`, returning
+    /// an error if any of the placeholders are related to another
+    /// placeholder or would have to escape into some parent universe
+    /// that cannot name them.
+    ///
+    /// This is a temporary backwards compatibility measure to try and
+    /// retain the older (arguably incorrect) behavior of the
+    /// compiler.
+    ///
+    /// NB. The use of snapshot here is mostly an efficiency thing --
+    /// we could search *all* region constraints, but that'd be a
+    /// bigger set and the data structures are not setup for that. If
+    /// we wind up keeping some form of this check long term, it would
+    /// probably be better to remove the snapshot parameter and to
+    /// refactor the constraint set.
+    pub fn leak_check(
+        &mut self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        overly_polymorphic: bool,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> RelateResult<'tcx, ()> {
+        debug!("leak_check(placeholders={:?})", placeholder_map);
+
+        assert!(self.in_snapshot());
+
+        // If the user gave `-Zno-leak-check`, then skip the leak
+        // check completely. This is wildly unsound and also not
+        // unlikely to cause an ICE or two. It is intended for use
+        // only during a transition period, in which the MIR typeck
+        // uses the "universe-style" check, and the rest of typeck
+        // uses the more conservative leak check.  Since the leak
+        // check is more conservative, we can't test the
+        // universe-style check without disabling it.
+        if tcx.sess.opts.debugging_opts.no_leak_check {
+            return Ok(());
+        }
+
+        // Go through each placeholder that we created.
+        for (_, &placeholder_region) in placeholder_map {
+            // Find the universe this placeholder inhabits.
+            let placeholder = match placeholder_region {
+                ty::RePlaceholder(p) => p,
+                _ => bug!(
+                    "leak_check: expected placeholder found {:?}",
+                    placeholder_region,
+                ),
+            };
+
+            // Find all regions that are related to this placeholder
+            // in some way. This means any region that either outlives
+            // or is outlived by a placeholder.
+            let mut taint_set = TaintSet::new(
+                TaintDirections::both(),
+                placeholder_region,
+            );
+            taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys);
+            let tainted_regions = taint_set.into_set();
+
+            // Report an error if two placeholders in the same universe
+            // are related to one another, or if a placeholder is related
+            // to something from a parent universe.
+            for &tainted_region in &tainted_regions {
+                if let ty::RePlaceholder(_) = tainted_region {
+                    // Two placeholders cannot be related:
+                    if tainted_region == placeholder_region {
+                        continue;
+                    }
+                } else if self.universe(tainted_region).can_name(placeholder.universe) {
+                    continue;
+                }
+
+                return Err(if overly_polymorphic {
+                    debug!("Overly polymorphic!");
+                    TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
+                } else {
+                    debug!("Not as polymorphic!");
+                    TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
+                });
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug)]
+struct TaintSet<'tcx> {
+    directions: TaintDirections,
+    regions: FxHashSet<ty::Region<'tcx>>,
+}
+
+impl<'tcx> TaintSet<'tcx> {
+    fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
+        let mut regions = FxHashSet::default();
+        regions.insert(initial_region);
+        TaintSet {
+            directions: directions,
+            regions: regions,
+        }
+    }
+
+    fn fixed_point(
+        &mut self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        undo_log: &[UndoLog<'tcx>],
+        verifys: &[Verify<'tcx>],
+    ) {
+        let mut prev_len = 0;
+        while prev_len < self.len() {
+            debug!(
+                "tainted: prev_len = {:?} new_len = {:?}",
+                prev_len,
+                self.len()
+            );
+
+            prev_len = self.len();
+
+            for undo_entry in undo_log {
+                match undo_entry {
+                    &AddConstraint(Constraint::VarSubVar(a, b)) => {
+                        self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+                    }
+                    &AddConstraint(Constraint::RegSubVar(a, b)) => {
+                        self.add_edge(a, tcx.mk_region(ReVar(b)));
+                    }
+                    &AddConstraint(Constraint::VarSubReg(a, b)) => {
+                        self.add_edge(tcx.mk_region(ReVar(a)), b);
+                    }
+                    &AddConstraint(Constraint::RegSubReg(a, b)) => {
+                        self.add_edge(a, b);
+                    }
+                    &AddGiven(a, b) => {
+                        self.add_edge(a, tcx.mk_region(ReVar(b)));
+                    }
+                    &AddVerify(i) => span_bug!(
+                        verifys[i].origin.span(),
+                        "we never add verifications while doing higher-ranked things",
+                    ),
+                    &Purged | &AddCombination(..) | &AddVar(..) => {}
+                }
+            }
+        }
+    }
+
+    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
+        self.regions
+    }
+
+    fn len(&self) -> usize {
+        self.regions.len()
+    }
+
+    fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
+        if self.directions.incoming {
+            if self.regions.contains(&target) {
+                self.regions.insert(source);
+            }
+        }
+
+        if self.directions.outgoing {
+            if self.regions.contains(&source) {
+                self.regions.insert(target);
+            }
+        }
+    }
+}
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 56ae850226c91..07a676a86d3d7 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -17,6 +17,8 @@ use ty::{Region, RegionVid};
 use std::collections::BTreeMap;
 use std::{cmp, fmt, mem, u32};
 
+mod leak_check;
+
 #[derive(Default)]
 pub struct RegionConstraintCollector<'tcx> {
     /// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
@@ -814,7 +816,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         new_r
     }
 
-    fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
+    pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
         match *region {
             ty::ReScope(..)
             | ty::ReStatic
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 92004ece26d00..f96c4e9014b36 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -771,7 +771,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     }
                 }
                 &ty::Predicate::RegionOutlives(ref binder) => {
-                    let () = select.infcx().region_outlives_predicate(&dummy_cause, binder);
+                    if select
+                        .infcx()
+                        .region_outlives_predicate(&dummy_cause, binder)
+                        .is_err()
+                    {
+                        return false;
+                    }
                 }
                 &ty::Predicate::TypeOutlives(ref binder) => {
                     match (
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 367a7eacdfcaf..c40af035c7273 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -726,9 +726,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     }
 
                     ty::Predicate::RegionOutlives(ref predicate) => {
-                        // These errors should show up as region
-                        // inference failures.
-                        panic!("region outlives {:?} failed", predicate);
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.region_outlives_predicate(&obligation.cause,
+                                                                 &predicate).err().unwrap();
+                        struct_span_err!(
+                            self.tcx.sess, span, E0279,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err,
+                        )
                     }
 
                     ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 2e00d4d4b7c3b..219e971b3c927 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -331,8 +331,10 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
             }
 
             ty::Predicate::RegionOutlives(ref binder) => {
-                let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder);
-                ProcessResult::Changed(vec![])
+                match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
+                    Ok(()) => ProcessResult::Changed(vec![]),
+                    Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
+                }
             }
 
             ty::Predicate::TypeOutlives(ref binder) => {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 21151276e7299..39b2d118fddfd 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -191,12 +191,15 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
            obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|_| {
-        let (placeholder_predicate, _) =
+    infcx.commit_if_ok(|snapshot| {
+        let (placeholder_predicate, placeholder_map) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
-        project_and_unify_type(selcx, &placeholder_obligation)
+        let result = project_and_unify_type(selcx, &placeholder_obligation)?;
+        infcx.leak_check(false, &placeholder_map, snapshot)
+            .map_err(|err| MismatchedProjectionTypes { err })?;
+        Ok(result)
     })
 }
 
@@ -1427,9 +1430,8 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    poly_cache_entry: ty::PolyProjectionPredicate<'tcx>)
-    -> Progress<'tcx>
-{
+    poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
+) -> Progress<'tcx> {
     let infcx = selcx.infcx();
     let cause = &obligation.cause;
     let param_env = obligation.param_env;
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 6db6fe31fba70..1c84603e9da07 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -29,7 +29,7 @@ use super::{
 
 use dep_graph::{DepKind, DepNodeIndex};
 use hir::def_id::DefId;
-use infer::{InferCtxt, InferOk, TypeFreshener};
+use infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
 use middle::lang_items;
 use mir::interpret::GlobalId;
 use ty::fast_reject;
@@ -1624,8 +1624,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             _ => return,
         }
 
-        let result = self.infcx.probe(|_| {
-            self.match_projection_obligation_against_definition_bounds(obligation)
+        let result = self.infcx.probe(|snapshot| {
+            self.match_projection_obligation_against_definition_bounds(
+                obligation,
+                snapshot,
+            )
         });
 
         if result {
@@ -1636,18 +1639,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx()
             .resolve_type_vars_if_possible(&obligation.predicate);
-        let (skol_trait_predicate, _) = self.infcx()
+        let (placeholder_trait_predicate, placeholder_map) = self.infcx()
             .replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
-             skol_trait_predicate={:?}",
-            skol_trait_predicate,
+             placeholder_trait_predicate={:?}",
+            placeholder_trait_predicate,
         );
 
-        let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
+        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().sty {
             ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
             ty::Opaque(def_id, substs) => (def_id, substs),
             _ => {
@@ -1655,7 +1659,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     obligation.cause.span,
                     "match_projection_obligation_against_definition_bounds() called \
                      but self-ty is not a projection: {:?}",
-                    skol_trait_predicate.trait_ref.self_ty()
+                    placeholder_trait_predicate.trait_ref.self_ty()
                 );
             }
         };
@@ -1680,7 +1684,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     self.match_projection(
                         obligation,
                         bound.clone(),
-                        skol_trait_predicate.trait_ref.clone(),
+                        placeholder_trait_predicate.trait_ref.clone(),
+                        &placeholder_map,
+                        snapshot,
                     )
                 })
             });
@@ -1697,7 +1703,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 let result = self.match_projection(
                     obligation,
                     bound,
-                    skol_trait_predicate.trait_ref.clone(),
+                    placeholder_trait_predicate.trait_ref.clone(),
+                    &placeholder_map,
+                    snapshot,
                 );
 
                 assert!(result);
@@ -1710,13 +1718,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
-        skol_trait_ref: ty::TraitRef<'tcx>,
+        placeholder_trait_ref: ty::TraitRef<'tcx>,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
-        debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
+        debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
+            .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
+            &&
+            self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
     }
 
     /// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller
@@ -1917,8 +1929,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|_| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation)
+                self.infcx.probe(|snapshot| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot)
                     {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
@@ -2697,9 +2709,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.in_snapshot(|_| {
+        self.infcx.in_snapshot(|snapshot| {
             let result =
-                self.match_projection_obligation_against_definition_bounds(obligation);
+                self.match_projection_obligation_against_definition_bounds(
+                    obligation,
+                    snapshot,
+                );
             assert!(result);
         })
     }
@@ -2851,8 +2866,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.in_snapshot(|_| {
-            let substs = self.rematch_impl(impl_def_id, obligation);
+        self.infcx.in_snapshot(|snapshot| {
+            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             self.vtable_impl(
@@ -3239,9 +3254,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     tcx.mk_existential_predicates(iter)
                 });
                 let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+                // Require that the traits involved in this upcast are **equal**;
+                // only the **lifetime bound** is changed.
+                //
+                // FIXME: This condition is arguably too strong -- it
+                // would suffice for the source trait to be a
+                // *subtype* of the target trait. In particular
+                // changing from something like `for<'a, 'b> Foo<'a,
+                // 'b>` to `for<'a> Foo<'a, 'a>` should be
+                // permitted. And, indeed, in the in commit
+                // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
+                // condition was loosened. However, when the leak check was added
+                // back, using subtype here actually guies the coercion code in
+                // such a way that it accepts `old-lub-glb-object.rs`. This is probably
+                // a good thing, but I've modified this to `.eq` because I want
+                // to continue rejecting that test (as we have done for quite some time)
+                // before we are firmly comfortable with what our behavior
+                // should be there. -nikomatsakis
                 let InferOk { obligations, .. } = self.infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(target, source_trait)
+                    .eq(target, source_trait) // FIXME -- see below
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
@@ -3443,8 +3476,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Normalized<'tcx, &'tcx Substs<'tcx>> {
-        match self.match_impl(impl_def_id, obligation) {
+        match self.match_impl(impl_def_id, obligation, snapshot) {
             Ok(substs) => substs,
             Err(()) => {
                 bug!(
@@ -3460,6 +3494,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -3470,7 +3505,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return Err(());
         }
 
-        let (skol_obligation, _) = self.infcx()
+        let (skol_obligation, placeholder_map) = self.infcx()
             .replace_bound_vars_with_placeholders(&obligation.predicate);
         let skol_obligation_trait_ref = skol_obligation.trait_ref;
 
@@ -3502,6 +3537,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
 
+        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
+            debug!("match_impl: failed leak check due to `{}`", e);
+            return Err(());
+        }
+
         debug!("match_impl: success impl_substs={:?}", impl_substs);
         Ok(Normalized {
             value: impl_substs,
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 834b541d4c01b..774c538500b2d 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -1,5 +1,5 @@
 use hir::def_id::DefId;
-use ty::{self, Region, Ty, TyCtxt};
+use ty::{self, BoundRegion, Region, Ty, TyCtxt};
 use std::borrow::Cow;
 use std::fmt;
 use rustc_target::spec::abi;
@@ -27,6 +27,8 @@ pub enum TypeError<'tcx> {
     ArgCount,
 
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
+    RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
+    RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
     RegionsPlaceholderMismatch,
 
     Sorts(ExpectedFound<Ty<'tcx>>),
@@ -101,6 +103,18 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
             RegionsDoesNotOutlive(..) => {
                 write!(f, "lifetime mismatch")
             }
+            RegionsInsufficientlyPolymorphic(br, _) => {
+                write!(f,
+                       "expected bound lifetime parameter{}{}, found concrete lifetime",
+                       if br.is_named() { " " } else { "" },
+                       br)
+            }
+            RegionsOverlyPolymorphic(br, _) => {
+                write!(f,
+                       "expected concrete lifetime, found bound lifetime parameter{}{}",
+                       if br.is_named() { " " } else { "" },
+                       br)
+            }
             RegionsPlaceholderMismatch => {
                 write!(f, "one type is more general than the other")
             }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index dd9ffd08a4ef5..b09437813bd03 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -434,6 +434,12 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             RegionsDoesNotOutlive(a, b) => {
                 return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
             }
+            RegionsInsufficientlyPolymorphic(a, b) => {
+                return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
+            }
+            RegionsOverlyPolymorphic(a, b) => {
+                return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
+            }
             RegionsPlaceholderMismatch => RegionsPlaceholderMismatch,
             IntMismatch(x) => IntMismatch(x),
             FloatMismatch(x) => FloatMismatch(x),
@@ -1021,6 +1027,8 @@ EnumTypeFoldableImpl! {
         (ty::error::TypeError::FixedArraySize)(x),
         (ty::error::TypeError::ArgCount),
         (ty::error::TypeError::RegionsDoesNotOutlive)(a, b),
+        (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b),
+        (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b),
         (ty::error::TypeError::RegionsPlaceholderMismatch),
         (ty::error::TypeError::IntMismatch)(x),
         (ty::error::TypeError::FloatMismatch)(x),
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 8a8b7adcf7d4a..36765496ff4e9 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -391,10 +391,6 @@ h4 > code, h3 > code, .invisible > code {
 	display: block;
 }
 
-.in-band, code {
-	z-index: -5;
-}
-
 .invisible {
 	width: 100%;
 	display: inline-block;
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index 52a30967a2310..6935ecde791f8 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -410,10 +410,6 @@ kbd {
 	color: #ccc;
 }
 
-.impl-items code {
-	background-color: rgba(0, 0, 0, 0);
-}
-
 #sidebar-toggle {
 	background-color: #565656;
 }
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index d20fea666e61d..306e8dc15d893 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -405,10 +405,6 @@ kbd {
 	color: #999;
 }
 
-.impl-items code {
-	background-color: rgba(0, 0, 0, 0);
-}
-
 #sidebar-toggle {
 	background-color: #F1F1F1;
 }
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs
index 55b1667da50b1..2e2a124db9a5d 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.rs
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs
@@ -1,15 +1,26 @@
 fn main() {
     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
 }
 
 // Basic
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
index d2c722e32b210..378f352cb9228 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -7,13 +7,27 @@ LL |     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _`
    |
 note: required by `f1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1
    |
 LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5
+   |
+LL |     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &()) -> _`
+   |
+note: required by `f1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1
+   |
+LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
    |
 LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -21,7 +35,7 @@ LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _`
    |
 note: required by `f2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:17:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1
    |
 LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,19 +43,47 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
    |
+LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'a (), &()) -> _`
+   |
+note: required by `f2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1
+   |
+LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+   |
 LL |     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
    |     |
    |     expected signature of `for<'r> fn(&(), &'r ()) -> _`
    |
 note: required by `f3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
    |
 LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+   |
+LL |     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &()) -> _`
+   |
+note: required by `f3`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
+   |
+LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
    |
 LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -49,13 +91,27 @@ LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _`
    |
 note: required by `f4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:19:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
    |
 LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+   |
+LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &'r ()) -> _`
+   |
+note: required by `f4`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
+   |
+LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
    |
 LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -63,13 +119,27 @@ LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), &'r ()) -> _`
    |
 note: required by `f5`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1
    |
 LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+   |
+LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'r (), &'r ()) -> _`
+   |
+note: required by `f5`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1
+   |
+LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
    |
 LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -77,13 +147,27 @@ LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _`
    |
 note: required by `g1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:23:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1
    |
 LL | fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+   |
+LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
+   |
+note: required by `g1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1
+   |
+LL | fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
    |
 LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -91,13 +175,27 @@ LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _`
    |
 note: required by `g2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:24:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1
    |
 LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
+   |
+LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
+   |
+note: required by `g2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1
+   |
+LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
    |
 LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -105,13 +203,27 @@ LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
    |
 note: required by `g3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:25:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1
    |
 LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
+   |
+LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
+   |
+note: required by `g3`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1
+   |
+LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
    |
 LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -119,13 +231,27 @@ LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _`
    |
 note: required by `g4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:26:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1
+   |
+LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
+   |
+LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
+   |
+note: required by `g4`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1
    |
 LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
    |
 LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -133,13 +259,27 @@ LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _`
    |
 note: required by `h1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1
    |
 LL | fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
+   |
+LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   |
+note: required by `h1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1
+   |
+LL | fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
    |
 LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -147,11 +287,25 @@ LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _`
    |
 note: required by `h2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1
+   |
+LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
+   |
+LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   |
+note: required by `h2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1
    |
 LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 22 previous errors
 
 For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs
index 20fa1e7a48db1..e6afa3f71c2f0 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.rs
+++ b/src/test/ui/associated-types/associated-types-eq-hr.rs
@@ -89,12 +89,14 @@ pub fn call_bar() {
 
 pub fn call_tuple_one() {
     tuple_one::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
+    //~| ERROR type mismatch
 }
 
 pub fn call_tuple_two() {
     tuple_two::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
+    //~| ERROR type mismatch
 }
 
 pub fn call_tuple_three() {
@@ -103,7 +105,7 @@ pub fn call_tuple_three() {
 
 pub fn call_tuple_four() {
     tuple_four::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
 }
 
 fn main() { }
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr
index d3eaa894b5043..3721b69898876 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr
@@ -34,36 +34,93 @@ LL | |     // ok for UintStruct, but not IntStruct
 LL | | }
    | |_^
 
-error: implementation of `TheTrait` is not general enough
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
   --> $DIR/associated-types-eq-hr.rs:91:5
    |
 LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
    |
-   = note: Due to a where-clause on `tuple_one`,
-   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
-   = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_one`
+  --> $DIR/associated-types-eq-hr.rs:56:1
+   |
+LL | / fn tuple_one<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick first
+LL | | }
+   | |_^
 
-error: implementation of `TheTrait` is not general enough
-  --> $DIR/associated-types-eq-hr.rs:96:5
+error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
+  --> $DIR/associated-types-eq-hr.rs:91:5
+   |
+LL |     tuple_one::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |
+note: required by `tuple_one`
+  --> $DIR/associated-types-eq-hr.rs:56:1
+   |
+LL | / fn tuple_one<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick first
+LL | | }
+   | |_^
+
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
+  --> $DIR/associated-types-eq-hr.rs:97:5
    |
 LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+   |
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_two`
+  --> $DIR/associated-types-eq-hr.rs:62:1
    |
-   = note: Due to a where-clause on `tuple_two`,
-   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
-   = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
+LL | / fn tuple_two<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick second
+LL | | }
+   | |_^
+
+error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
+  --> $DIR/associated-types-eq-hr.rs:97:5
+   |
+LL |     tuple_two::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |
+note: required by `tuple_two`
+  --> $DIR/associated-types-eq-hr.rs:62:1
+   |
+LL | / fn tuple_two<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick second
+LL | | }
+   | |_^
 
-error: implementation of `TheTrait` is not general enough
-  --> $DIR/associated-types-eq-hr.rs:105:5
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
+  --> $DIR/associated-types-eq-hr.rs:107:5
    |
 LL |     tuple_four::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+   |
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_four`
+  --> $DIR/associated-types-eq-hr.rs:74:1
    |
-   = note: Due to a where-clause on `tuple_four`,
-   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
-   = note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
+LL | / fn tuple_four<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes, and lifetime matching is invariant
+LL | | }
+   | |_^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+Some errors occurred: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
index 46901b44c4b6d..fa831ea81dcfb 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
@@ -9,15 +9,15 @@ LL |    let a = bar(foo, y); //[krisskross]~ ERROR E0623
    |                     ^ ...but data from `x` is returned here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:55:8
+  --> $DIR/project-fn-ret-invariant.rs:54:21
    |
 LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                                     --------     --------------------
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-...
-LL |    (a, b) //[krisskross]~ ERROR E0623
-   |        ^ ...but data from `x` is returned here
+   |                        --------                  --------------------
+   |                        |
+   |                        this parameter and the return type are declared with different lifetimes...
+LL |    let a = bar(foo, y); //[krisskross]~ ERROR E0623
+LL |    let b = bar(foo, x); //[krisskross]~ ERROR E0623
+   |                     ^ ...but data from `y` is returned here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
index dfcf31b3b1f26..54b6e3642c2ea 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
@@ -51,8 +51,8 @@ fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
 fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
    let a = bar(foo, y); //[krisskross]~ ERROR E0623
-   let b = bar(foo, x);
-   (a, b) //[krisskross]~ ERROR E0623
+   let b = bar(foo, x); //[krisskross]~ ERROR E0623
+   (a, b)
 }
 
 #[rustc_error]
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 947844c45c408..dd1212eaac91d 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -1,4 +1,4 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/project-fn-ret-invariant.rs:48:8
    |
 LL |    bar(foo, x) //[transmute]~ ERROR E0495
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
index e4704494e1492..cc69e849fe144 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
@@ -1,12 +1,17 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
   --> $DIR/higher-ranked-projection.rs:25:5
    |
 LL |     foo(());
-   |     ^^^ one type is more general than the other
+   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
    |
-   = note: expected type `Mirror`
-              found type `Mirror`
+note: required by `foo`
+  --> $DIR/higher-ranked-projection.rs:14:1
+   |
+LL | / fn foo<U, T>(_t: T)
+LL | |     where for<'a> &'a T: Mirror<Image=U>
+LL | | {}
+   | |__^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
index db15ec51d87c6..165e5213e0d34 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
@@ -3,7 +3,7 @@ error: compilation successful
    |
 LL | / fn main() { //[good]~ ERROR compilation successful
 LL | |     foo(());
-LL | |     //[bad]~^ ERROR E0308
+LL | |     //[bad]~^ ERROR type mismatch
 LL | | }
    | |_^
 
diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs
index 5b380c982f041..a2ea6d8f206b6 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.rs
+++ b/src/test/ui/associated-types/higher-ranked-projection.rs
@@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
 #[rustc_error]
 fn main() { //[good]~ ERROR compilation successful
     foo(());
-    //[bad]~^ ERROR E0308
+    //[bad]~^ ERROR type mismatch
 }
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
index 6977fd47a2e85..a4e43da91baf8 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
@@ -28,14 +28,14 @@ fn expect_free_supply_bound() {
     // Here, we are given a function whose region is bound at closure level,
     // but we expect one bound in the argument. Error results.
     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-    //~^ ERROR mismatched types
+    //~^ ERROR type mismatch
 }
 
 fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
     // Here, we are given a `fn(&u32)` but we expect a `fn(&'x
     // u32)`. In principle, this could be ok, but we demand equality.
     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-    //~^ ERROR mismatched types
+    //~^ ERROR type mismatch
 }
 
 fn expect_bound_supply_free_from_closure() {
@@ -44,7 +44,7 @@ fn expect_bound_supply_free_from_closure() {
     // the argument level.
     type Foo<'a> = fn(&'a u32);
     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-    //~^ ERROR mismatched types
+    //~^ ERROR type mismatch
     });
 }
 
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index b1cfd6cef1022..ab35aeff697b7 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -36,33 +36,58 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:30:52
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:30:5
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |                                                    ^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
    |
-   = note: expected type `fn(&u32)`
-              found type `for<'r> fn(&'r u32)`
+note: required by `with_closure_expecting_fn_with_free_region`
+  --> $DIR/expect-fn-supply-fn.rs:1:1
+   |
+LL | / fn with_closure_expecting_fn_with_free_region<F>(_: F)
+LL | |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:37:53
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:37:5
    |
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |                                                     ^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
    |
-   = note: expected type `for<'r> fn(&'r u32)`
-              found type `fn(&'x u32)`
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
+   |
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:46:53
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:46:5
    |
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |                                                     ^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
    |
-   = note: expected type `for<'r> fn(&'r u32)`
-              found type `fn(&u32)`
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors occurred: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coherence/coherence-subtyping.old.stderr b/src/test/ui/coherence/coherence-subtyping.old.stderr
deleted file mode 100644
index db9f9f7665374..0000000000000
--- a/src/test/ui/coherence/coherence-subtyping.old.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:15:1
-   |
-LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
-   | --------------------------------------------------------- first implementation here
-...
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-subtyping.re.stderr b/src/test/ui/coherence/coherence-subtyping.re.stderr
deleted file mode 100644
index db9f9f7665374..0000000000000
--- a/src/test/ui/coherence/coherence-subtyping.re.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:15:1
-   |
-LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
-   | --------------------------------------------------------- first implementation here
-...
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-subtyping.rs b/src/test/ui/coherence/coherence-subtyping.rs
index f27e14eab63da..e74067578069e 100644
--- a/src/test/ui/coherence/coherence-subtyping.rs
+++ b/src/test/ui/coherence/coherence-subtyping.rs
@@ -1,7 +1,11 @@
 // Test that two distinct impls which match subtypes of one another
 // yield coherence errors (or not) depending on the variance.
+//
+// Note: This scenario is currently accepted, but as part of the
+// universe transition (#56105) may eventually become an error.
 
 // revisions: old re
+// compile-pass
 
 #![cfg_attr(re, feature(re_rebalance_coherence))]
 
@@ -13,8 +17,6 @@ impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
 }
 
 impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-    //[old]~^ ERROR
-    //[re]~^^ ERROR
 }
 
 fn main() { }
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
index bdfabdabbebb7..8e2b0b8c60045 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
 LL | |                                             for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
index 25b74d855bb48..dbb5018139076 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
@@ -1,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |               gimme::<$t1>(None::<$t2>);
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+...
+LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
+LL | |                                 for<'a>    fn(&'a u32, &'a u32)) }
+   | |__________________________________________________________________- in this macro invocation
+   |
+   = note: expected type `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
+              found type `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
index 25b74d855bb48..5fcb63e17bf31 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
@@ -1,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
index 25b74d855bb48..5fcb63e17bf31 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
@@ -1,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
index 74b8c89b6e86f..db9892b48a6f7 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
 LL | |                              fn(&'x u32)) }
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
index 25b74d855bb48..e9fb73411bd39 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
@@ -1,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |               gimme::<$t1>(None::<$t2>);
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+...
+LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
+LL | |                                       for<'a>    fn(Co<'a>, Co<'a>)) }
+   | |______________________________________________________________________- in this macro invocation
+   |
+   = note: expected type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
+              found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
index 25b74d855bb48..d0e80faa68e8b 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
@@ -1,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |               gimme::<$t1>(None::<$t2>);
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+...
+LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
+LL | |                                         for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+   | |______________________________________________________________________________________- in this macro invocation
+   |
+   = note: expected type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
+              found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
index 25b74d855bb48..5fcb63e17bf31 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
@@ -1,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
index 25b74d855bb48..3605ecf4f8667 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
@@ -1,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |               gimme::<$t1>(None::<$t2>);
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+...
+LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
+LL | |                                             for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+   | |______________________________________________________________________________________________- in this macro invocation
+   |
+   = note: expected type `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
+              found type `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
index 8168941e2777c..fae6e9b5c89ca 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
 LL | |                                         for<'a>    fn(Inv<'a>, Inv<'a>)) }
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
index 25b74d855bb48..5fcb63e17bf31 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
@@ -1,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
index 25b74d855bb48..5fcb63e17bf31 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
@@ -1,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs
index ad4f39f840528..2f7c1e6fd8c0d 100644
--- a/src/test/ui/hr-subtype/hr-subtype.rs
+++ b/src/test/ui/hr-subtype/hr-subtype.rs
@@ -42,6 +42,10 @@ macro_rules! check {
             //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
             //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
             //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
+            //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
+            //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
+            //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR
+            //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR
         }
     }
 }
@@ -99,8 +103,4 @@ fn main() {
 //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
 //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
 //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
-//[bound_a_b_vs_bound_a]~^^^^^^ ERROR compilation successful
-//[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR compilation successful
-//[bound_co_a_b_vs_bound_co_a]~^^^^^^^^ ERROR compilation successful
-//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
 }
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
index 2ee398e3dd3b2..50e1af8f14231 100644
--- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
@@ -1,12 +1,20 @@
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
   --> $DIR/hrtb-conflate-regions.rs:28:10
    |
 LL | fn b() { want_foo2::<SomeStruct>(); } //~ ERROR
-   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
    |
-   = note: Due to a where-clause on `want_foo2`,
-   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
-   = note: but `SomeStruct` only implements `Foo<(&'2 isize, &'2 isize)>` for some lifetime `'2`
+   = help: the following implementations were found:
+             <SomeStruct as Foo<(&'a isize, &'a isize)>>
+note: required by `want_foo2`
+  --> $DIR/hrtb-conflate-regions.rs:8:1
+   |
+LL | / fn want_foo2<T>()
+LL | |     where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
index 6301ed45ac277..8e8892552b701 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-exists-forall-fn.rs:17:34
    |
 LL |     let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
-   |                                  ^^^^^ one type is more general than the other
+   |                                  ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
    |
    = note: expected type `for<'b> fn(&'b u32)`
               found type `fn(&u32)`
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
index 8801760056ecb..4c1d4d28a09b0 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
@@ -1,9 +1,7 @@
-// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+// Test a case where variance and higher-ranked types interact in surprising ways.
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
-//
-// compile-pass
 
 trait Trait<T> {}
 
@@ -30,6 +28,9 @@ fn main() {
     //     - `?a: ?b` -- solveable if `?b` is also inferred to `'empty`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'empty`.
+    //
+    // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
+    //~^ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
new file mode 100644
index 0000000000000..7f2ca037f0f49
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Trait<fn(&'a u32)>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:8:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(&'b u32)>,
+LL | | {
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
index da1bb7cd5fd0b..95b57d6c5bb5e 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
@@ -1,9 +1,7 @@
-// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+// Test a case where variance and higher-ranked types interact in surprising ways.
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
-//
-// compile-pass
 
 trait Trait<T> {}
 
@@ -32,6 +30,9 @@ fn main() {
     //         - `?b: ?a` -- solveable if `?b` is inferred to `'static`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'static`.
+    //
+    // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
+    //~^ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
new file mode 100644
index 0000000000000..cd5982e7588a7
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
+  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^ the trait `Trait<for<'b> fn(fn(&'b u32))>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Trait<fn(fn(&'a u32))>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-covariant.rs:8:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(fn(&'b u32))>,
+LL | | {
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
index da3f8ad1b8957..827a68beee8bd 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
@@ -25,5 +25,5 @@ fn main() {
     //     yielding `fn(&!b u32)`, in a fresh universe U1
     //   - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
 
-    foo::<()>(); //~ ERROR not general enough
+    foo::<()>(); //~ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
index 6a61181e2407c..f56b81759fede 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
@@ -1,12 +1,21 @@
-error: implementation of `Trait` is not general enough
+error[E0277]: the trait bound `(): Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not satisfied
   --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
-LL |     foo::<()>(); //~ ERROR not general enough
-   |     ^^^^^^^^^
+LL |     foo::<()>(); //~ ERROR not satisfied
+   |     ^^^^^^^^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
    |
-   = note: Due to a where-clause on `foo`,
-   = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
-   = note: but `()` only implements `Trait<fn(std::cell::Cell<&'0 u32>)>` for some lifetime `'0`
+   = help: the following implementations were found:
+             <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:10:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(Cell<&'b u32>)>,
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
index 0d7b5cbf82348..77c1789852e52 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -1,12 +1,19 @@
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
    |
 LL |     want_bar_for_any_ccx(b); //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
    |
-   = note: expected type `for<'ccx> Bar<'ccx>`
-              found type `Bar<'static>`
+   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
+note: required by `want_bar_for_any_ccx`
+  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:31:1
+   |
+LL | / fn want_bar_for_any_ccx<B>(b: &B)
+LL | |     where B : for<'ccx> Bar<'ccx>
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
index 3d2d403462d8b..48ebe5017aa62 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
@@ -15,7 +15,7 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F)
     where F : Foo<'x>
 {
     want_foo_for_some_tcx(f);
-    want_foo_for_any_tcx(f); //~ ERROR E0308
+    want_foo_for_any_tcx(f); //~ ERROR not satisfied
 }
 
 fn want_foo_for_any_tcx<F>(f: &F)
@@ -32,7 +32,7 @@ fn want_bar_for_some_ccx<'x,B>(b: &B)
     want_foo_for_any_tcx(b);
 
     want_bar_for_some_ccx(b);
-    want_bar_for_any_ccx(b); //~ ERROR E0308
+    want_bar_for_any_ccx(b); //~ ERROR not satisfied
 }
 
 fn want_bar_for_any_ccx<B>(b: &B)
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
index 31dbeec2a551b..5914cb3eaa494 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
@@ -1,21 +1,40 @@
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5
    |
-LL |     want_foo_for_any_tcx(f); //~ ERROR E0308
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+LL |     want_foo_for_any_tcx(f); //~ ERROR not satisfied
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
    |
-   = note: expected type `for<'tcx> Foo<'tcx>`
-              found type `Foo<'x>`
+   = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound
+note: required by `want_foo_for_any_tcx`
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
+   |
+LL | / fn want_foo_for_any_tcx<F>(f: &F)
+LL | |     where F : for<'tcx> Foo<'tcx>
+LL | | {
+LL | |     want_foo_for_some_tcx(f);
+LL | |     want_foo_for_any_tcx(f);
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5
    |
-LL |     want_bar_for_any_ccx(b); //~ ERROR E0308
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+LL |     want_bar_for_any_ccx(b); //~ ERROR not satisfied
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
+   |
+   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
+note: required by `want_bar_for_any_ccx`
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
    |
-   = note: expected type `for<'ccx> Bar<'ccx>`
-              found type `Bar<'x>`
+LL | / fn want_bar_for_any_ccx<B>(b: &B)
+LL | |     where B : for<'ccx> Bar<'ccx>
+LL | | {
+LL | |     want_foo_for_some_tcx(b);
+...  |
+LL | |     want_bar_for_any_ccx(b);
+LL | | }
+   | |_^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr
index 094c449802415..fe2bc1f222504 100644
--- a/src/test/ui/hrtb/hrtb-just-for-static.stderr
+++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr
@@ -1,22 +1,37 @@
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
   --> $DIR/hrtb-just-for-static.rs:24:5
    |
 LL |     want_hrtb::<StaticInt>() //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
    |
-   = note: Due to a where-clause on `want_hrtb`,
-   = note: `StaticInt` must implement `Foo<&'0 isize>` for any lifetime `'0`
-   = note: but `StaticInt` only implements `Foo<&'1 isize>` for some lifetime `'1`
+   = help: the following implementations were found:
+             <StaticInt as Foo<&'static isize>>
+note: required by `want_hrtb`
+  --> $DIR/hrtb-just-for-static.rs:8:1
+   |
+LL | / fn want_hrtb<T>()
+LL | |     where T : for<'a> Foo<&'a isize>
+LL | | {
+LL | | }
+   | |_^
 
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
   --> $DIR/hrtb-just-for-static.rs:30:5
    |
 LL |     want_hrtb::<&'a u32>() //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+   |
+   = help: the following implementations were found:
+             <&'a u32 as Foo<&'a isize>>
+note: required by `want_hrtb`
+  --> $DIR/hrtb-just-for-static.rs:8:1
    |
-   = note: Due to a where-clause on `want_hrtb`,
-   = note: `&'a u32` must implement `Foo<&'0 isize>` for any lifetime `'0`
-   = note: but `&'1 u32` only implements `Foo<&'1 isize>` for the lifetime `'1`
+LL | / fn want_hrtb<T>()
+LL | |     where T : for<'a> Foo<&'a isize>
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
index ec3bf8a1a1be3..439a5ffcff59d 100644
--- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     foo_hrtb_bar_not(&mut t); //~ ERROR E0308
    |     ^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `Foo<&'a isize>`
-              found type `Foo<&isize>`
+   = note: expected type `Bar<&'a isize>`
+              found type `Bar<&'b isize>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs
new file mode 100644
index 0000000000000..2c85905545807
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.rs
@@ -0,0 +1,42 @@
+// Regression test for #46989:
+//
+// In the move to universes, this test started passing.
+// It is not necessarily WRONG to do so, but it was a bit
+// surprising. The reason that it passed is that when we were
+// asked to prove that
+//
+//     for<'a> fn(&'a i32): Foo
+//
+// we were able to use the impl below to prove
+//
+//     fn(&'empty i32): Foo
+//
+// and then we were able to prove that
+//
+//     fn(&'empty i32) = for<'a> fn(&'a i32)
+//
+// This last fact is somewhat surprising, but essentially "falls out"
+// from handling variance correctly. In particular, consider the subtyping
+// relations. First:
+//
+//     fn(&'empty i32) <: for<'a> fn(&'a i32)
+//
+// This holds because -- intuitively -- a fn that takes a reference but doesn't use
+// it can be given a reference with any lifetime. Similarly, the opposite direction:
+//
+//     for<'a> fn(&'a i32) <: fn(&'empty i32)
+//
+// holds because 'a can be instantiated to 'empty.
+
+trait Foo {
+
+}
+
+impl<A> Foo for fn(A) { }
+
+fn assert_foo<T: Foo>() {}
+
+fn main() {
+    assert_foo::<fn(&i32)>();
+    //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+}
diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr
new file mode 100644
index 0000000000000..b308291d5c0eb
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+  --> $DIR/issue-46989.rs:40:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+   |
+   = help: the following implementations were found:
+             <fn(A) as Foo>
+note: required by `assert_foo`
+  --> $DIR/issue-46989.rs:37:1
+   |
+LL | fn assert_foo<T: Foo>() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/issue-57639.rs b/src/test/ui/hrtb/issue-57639.rs
new file mode 100644
index 0000000000000..4bcaef3616bd5
--- /dev/null
+++ b/src/test/ui/hrtb/issue-57639.rs
@@ -0,0 +1,29 @@
+// Regression test for #57639:
+//
+// In the move to universes, this test stopped working. The problem
+// was that when the trait solver was asked to prove `for<'a> T::Item:
+// Foo<'a>` as part of WF checking, it wound up "eagerly committing"
+// to the where clause, which says that `T::Item: Foo<'a>`, but it
+// should instead have been using the bound found in the trait
+// declaration. Pre-universe, this used to work out ok because we got
+// "eager errors" due to the leak check.
+//
+// See [this comment on GitHub][c] for more details.
+//
+// run-pass
+//
+// [c]: https://github.com/rust-lang/rust/issues/57639#issuecomment-455685861
+
+trait Foo<'a> {}
+
+trait Bar {
+    type Item: for<'a> Foo<'a>;
+}
+
+fn foo<'a, T>(_: T)
+where
+    T: Bar,
+    T::Item: Foo<'a>,
+{}
+
+fn main() { }
diff --git a/src/test/ui/hrtb/issue-58451.rs b/src/test/ui/hrtb/issue-58451.rs
new file mode 100644
index 0000000000000..229e505767879
--- /dev/null
+++ b/src/test/ui/hrtb/issue-58451.rs
@@ -0,0 +1,13 @@
+// Regression test for #58451:
+//
+// Error reporting here encountered an ICE in the shift to universes.
+
+fn f<I>(i: I)
+where
+    I: IntoIterator,
+    I::Item: for<'a> Into<&'a ()>,
+{}
+
+fn main() {
+    f(&[f()]); //~ ERROR this function takes 1 parameter
+}
diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr
new file mode 100644
index 0000000000000..79c24855dc96c
--- /dev/null
+++ b/src/test/ui/hrtb/issue-58451.stderr
@@ -0,0 +1,16 @@
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/issue-58451.rs:12:9
+   |
+LL | / fn f<I>(i: I)
+LL | | where
+LL | |     I: IntoIterator,
+LL | |     I::Item: for<'a> Into<&'a ()>,
+LL | | {}
+   | |__- defined here
+...
+LL |       f(&[f()]); //~ ERROR this function takes 1 parameter
+   |           ^^^ expected 1 parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr
index d7966cea52bb0..ce0c44c147563 100644
--- a/src/test/ui/issues/issue-40000.stderr
+++ b/src/test/ui/issues/issue-40000.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/issue-40000.rs:6:9
    |
 LL |     foo(bar); //~ ERROR E0308
-   |         ^^^ one type is more general than the other
+   |         ^^^ expected concrete lifetime, found bound lifetime parameter
    |
-   = note: expected type `dyn for<'r> std::ops::Fn(&'r i32)`
-              found type `dyn std::ops::Fn(&i32)`
+   = note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
+              found type `std::boxed::Box<dyn std::ops::Fn(_)>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-57843.rs b/src/test/ui/issues/issue-57843.rs
new file mode 100644
index 0000000000000..466082552667b
--- /dev/null
+++ b/src/test/ui/issues/issue-57843.rs
@@ -0,0 +1,24 @@
+// Regression test for an ICE that occurred with the universes code:
+//
+// The signature of the closure `|_|` was being inferred to
+// `exists<'r> fn(&'r u8)`. This should result in a type error since
+// the signature `for<'r> fn(&'r u8)` is required. However, due to a
+// bug in the type variable generalization code, the placeholder for
+// `'r` was leaking out into the writeback phase, causing an ICE.
+
+trait ClonableFn<T> {
+    fn clone(&self) -> Box<dyn Fn(T)>;
+}
+
+impl<T, F: 'static> ClonableFn<T> for F
+where F: Fn(T) + Clone {
+    fn clone(&self) -> Box<dyn Fn(T)> {
+        Box::new(self.clone())
+    }
+}
+
+struct Foo(Box<dyn for<'a> ClonableFn<&'a bool>>);
+
+fn main() {
+    Foo(Box::new(|_| ())); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr
new file mode 100644
index 0000000000000..4ef884cb3f589
--- /dev/null
+++ b/src/test/ui/issues/issue-57843.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-57843.rs:23:9
+   |
+LL |     Foo(Box::new(|_| ())); //~ ERROR mismatched types
+   |         ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(&'a bool,)>`
+              found type `std::ops::FnOnce<(&bool,)>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs
index 324dc86bd92b8..0ce87bf6ffe64 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs
@@ -4,13 +4,14 @@
 // longer get an error, because we recognize these two types as
 // equivalent!
 //
-// compile-pass
+// Whoops -- now that we reinstituted the leak-check, we get an error
+// again.
 
 fn foo(
     x: fn(&u8, &u8),
     y: for<'a> fn(&'a u8, &'a u8),
 ) {
-    let z = match 22 {
+    let z = match 22 { //~ ERROR match arms have incompatible types
         0 => x,
         _ => y,
     };
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
new file mode 100644
index 0000000000000..28a366bca014c
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
@@ -0,0 +1,17 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/old-lub-glb-hr.rs:14:13
+   |
+LL |       let z = match 22 { //~ ERROR match arms have incompatible types
+   |  _____________^
+LL | |         0 => x,
+LL | |         _ => y,
+   | |              - match arm with an incompatible type
+LL | |     };
+   | |_____^ expected bound lifetime parameter, found concrete lifetime
+   |
+   = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
+              found type `for<'a> fn(&'a u8, &'a u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs
index 9be7a813603d4..f45696bcaad70 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-object.rs
@@ -7,7 +7,7 @@ fn foo(
     x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
     y: &for<'a> Foo<&'a u8, &'a u8>,
 ) {
-    let z = match 22 { //~ ERROR E0308
+    let z = match 22 { //~ ERROR match arms have incompatible types
         0 => x,
         _ => y,
     };
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr
index 17d3648156b51..a31cd6f7a1900 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -1,15 +1,16 @@
-error[E0308]: mismatched types
+error[E0308]: match arms have incompatible types
   --> $DIR/old-lub-glb-object.rs:10:13
    |
-LL |       let z = match 22 { //~ ERROR E0308
+LL |       let z = match 22 { //~ ERROR match arms have incompatible types
    |  _____________^
 LL | |         0 => x,
 LL | |         _ => y,
+   | |              - match arm with an incompatible type
 LL | |     };
-   | |_____^ one type is more general than the other
+   | |_____^ expected bound lifetime parameter 'a, found concrete lifetime
    |
-   = note: expected type `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
-              found type `dyn for<'a> Foo<&'a u8, &'a u8>`
+   = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found type `&dyn for<'a> Foo<&'a u8, &'a u8>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
index 437150666be0c..521bd3695dfe5 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
@@ -7,6 +7,6 @@ fn main() {
 
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
-    baz(f); //~ ERROR mismatched types
-     //~| ERROR mismatched types
+    baz(f); //~ ERROR type mismatch
+     //~| ERROR type mismatch
 }
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
index a6628006587c1..5dd6887005e83 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -22,25 +22,34 @@ LL |     a.iter().map(|_: (u16, u16)| 45); //~ ERROR type mismatch
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
 
-error[E0308]: mismatched types
+error[E0631]: type mismatch in function arguments
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL |     baz(f); //~ ERROR mismatched types
-   |     ^^^ one type is more general than the other
+LL |     baz(f); //~ ERROR type mismatch
+   |     ^^^
+   |     |
+   |     expected signature of `for<'r> fn(*mut &'r u32) -> _`
+   |     found signature of `fn(*mut &'a u32) -> _`
    |
-   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
-              found type `std::ops::Fn<(*mut &'a u32,)>`
+note: required by `baz`
+  --> $DIR/closure-arg-type-mismatch.rs:8:1
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL |     baz(f); //~ ERROR mismatched types
-   |     ^^^ one type is more general than the other
+LL |     baz(f); //~ ERROR type mismatch
+   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |
+note: required by `baz`
+  --> $DIR/closure-arg-type-mismatch.rs:8:1
    |
-   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
-              found type `std::ops::FnOnce<(*mut &'a u32,)>`
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
-Some errors occurred: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+Some errors occurred: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
index 152a525493732..40a4641fe7196 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -5,5 +5,6 @@ impl<T: Fn(&())> Foo for T {}
 fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    baz(|_| ()); //~ ERROR E0308
+    baz(|_| ()); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
 }
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index 0d87bc228755f..e55047e96c297 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -1,12 +1,32 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
   --> $DIR/closure-mismatch.rs:8:5
    |
-LL |     baz(|_| ()); //~ ERROR E0308
-   |     ^^^ one type is more general than the other
+LL |     baz(|_| ()); //~ ERROR type mismatch
+   |     ^^^ expected bound lifetime parameter, found concrete lifetime
    |
-   = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
-              found type `std::ops::Fn<(&(),)>`
+   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+note: required by `baz`
+  --> $DIR/closure-mismatch.rs:5:1
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ()); //~ ERROR type mismatch
+   |     ^^^ ------ found signature of `fn(_) -> _`
+   |     |
+   |     expected signature of `for<'r> fn(&'r ()) -> _`
+   |
+   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+note: required by `baz`
+  --> $DIR/closure-mismatch.rs:5:1
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors occurred: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs
index 9035e3380b0c5..9edfebcd49471 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.rs
+++ b/src/test/ui/mismatched_types/issue-36053-2.rs
@@ -7,4 +7,5 @@ fn main() {
     once::<&str>("str").fuse().filter(|a: &str| true).count();
     //~^ ERROR no method named `count`
     //~| ERROR type mismatch in closure arguments
+    //~| ERROR type mismatch in closure arguments
 }
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index e53e8c520e0c4..c5c67e6bd9bd9 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -16,7 +16,15 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                |
    |                                expected signature of `for<'r> fn(&'r &str) -> _`
 
-error: aborting due to 2 previous errors
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-36053-2.rs:7:32
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                |
+   |                                expected signature of `fn(&&str) -> _`
+
+error: aborting due to 3 previous errors
 
 Some errors occurred: E0599, E0631.
 For more information about an error, try `rustc --explain E0599`.
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
index 242119cc201da..2dd0c9796e258 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar);
+    want_F(bar); //~ ERROR mismatched types
 
     want_F(baz);
 }
@@ -45,7 +45,7 @@ fn supply_F() {
 fn supply_G() {
     want_G(foo);
     want_G(bar);
-    want_G(baz); //~ ERROR
+    want_G(baz); //~ ERROR mismatched types
 }
 
 pub fn main() {
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
index a9234e43191ea..66e6a615b33bc 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
@@ -1,12 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
+   |
+LL |     want_F(bar); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |
+   = note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
+              found type `for<'a> fn(&'a S) -> &S {bar::<'_>}`
+
 error[E0308]: mismatched types
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
    |
-LL |     want_G(baz); //~ ERROR
-   |            ^^^ one type is more general than the other
+LL |     want_G(baz); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
    |
    = note: expected type `for<'cx> fn(&'cx S) -> &'static S`
-              found type `for<'r> fn(&'r S) -> &'r S`
+              found type `for<'r> fn(&'r S) -> &'r S {baz}`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
index 47e1d0efdc77b..5c8b3d3ba6922 100644
--- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
@@ -20,10 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types
-   |                                           ^ one type is more general than the other
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
index 1e7b99053f77f..f36885f7aeb99 100644
--- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
@@ -31,10 +31,10 @@ error[E0308]: mismatched types
   --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308
-   |                                                        ^ one type is more general than the other
+   |                                                        ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-              found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
+              found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.rs b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
index 9010770f1dc82..fa2cc37d05b2b 100644
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
@@ -5,8 +5,6 @@
 // *ANY* lifetime and returns a reference with the 'static lifetime.
 // This can safely be considered to be an instance of `F` because all
 // lifetimes are sublifetimes of 'static.
-//
-// compile-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
@@ -40,7 +38,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar);
+    want_F(bar); //~ ERROR mismatched types
 
     want_F(baz);
 }
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
new file mode 100644
index 0000000000000..42a5a7c806e08
--- /dev/null
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
+   |
+LL |     want_F(bar); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |
+   = note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
+              found type `for<'a> fn(&'a S) -> &S {bar::<'_>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
index a43ee7ec3ace0..99d85e9e4b5a6 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -20,10 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308
-   |                                           ^ one type is more general than the other
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
index 12626fe69cb14..a6e26614a6a50 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
@@ -11,11 +11,13 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn c() {
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
index 29f276711c745..ca0298283661f 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:13
+   |
+LL |     let x = call_it(&square, 22);
+   |             ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:7:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:17:13
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:22:13
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13
+   |
+LL |     let y = call_it_mut(&mut square, 22);
+   |             ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:8:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:13
    |
 LL |     let z = call_it_once(square, 22);
    |             ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
index 7c3152c87c461..dd3b1afc39f31 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
@@ -11,11 +11,13 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn c() {
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
index e382457860579..0abc58aeebfe5 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+  --> $DIR/unboxed-closures-wrong-abi.rs:12:13
+   |
+LL |     let x = call_it(&square, 22);
+   |             ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-wrong-abi.rs:7:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:17:13
+  --> $DIR/unboxed-closures-wrong-abi.rs:18:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:22:13
+  --> $DIR/unboxed-closures-wrong-abi.rs:18:13
+   |
+LL |     let y = call_it_mut(&mut square, 22);
+   |             ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-wrong-abi.rs:8:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+  --> $DIR/unboxed-closures-wrong-abi.rs:24:13
    |
 LL |     let z = call_it_once(square, 22);
    |             ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-wrong-abi.rs:9:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
index 61d46869cbbf2..c689d79266187 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
@@ -12,11 +12,13 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
+    //~| ERROR expected
 }
 
 fn c() {
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
index da511f091bf6a..19b87ad171a51 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:13
+   |
+LL |     let x = call_it(&square, 22);
+   |             ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:8:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:18:13
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:23:13
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13
+   |
+LL |     let y = call_it_mut(&mut square, 22);
+   |             ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
+   |
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:9:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:13
    |
 LL |     let z = call_it_once(square, 22);
    |             ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
-   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs
index 0ce38e69f6b0f..31174fd4cf163 100644
--- a/src/test/ui/where-clauses/where-for-self-2.rs
+++ b/src/test/ui/where-clauses/where-for-self-2.rs
@@ -18,5 +18,5 @@ fn foo<T>(x: &T)
 {}
 
 fn main() {
-    foo(&X); //~ ERROR implementation of `Bar` is not general enough
+    foo(&X); //~ ERROR trait bound
 }
diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr
index afc80bf4d8ee6..bbcb61a856d8d 100644
--- a/src/test/ui/where-clauses/where-for-self-2.stderr
+++ b/src/test/ui/where-clauses/where-for-self-2.stderr
@@ -1,12 +1,19 @@
-error: implementation of `Bar` is not general enough
+error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
   --> $DIR/where-for-self-2.rs:21:5
    |
-LL |     foo(&X); //~ ERROR implementation of `Bar` is not general enough
-   |     ^^^
+LL |     foo(&X); //~ ERROR trait bound
+   |     ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
    |
-   = note: Due to a where-clause on `foo`,
-   = note: `&'0 _` must implement `Bar` for any lifetime `'0`
-   = note: but `&'1 u32` only implements `Bar` for the lifetime `'1`
+   = help: the following implementations were found:
+             <&'static u32 as Bar>
+note: required by `foo`
+  --> $DIR/where-for-self-2.rs:16:1
+   |
+LL | / fn foo<T>(x: &T)
+LL | |     where for<'a> &'a T: Bar
+LL | | {}
+   | |__^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.