about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/bootstrap.py14
-rw-r--r--src/doc/rustc/src/command-line-arguments.md12
-rw-r--r--src/liballoc/raw_vec.rs2
-rw-r--r--src/libcore/intrinsics.rs16
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/ptr/const_ptr.rs66
-rw-r--r--src/libcore/ptr/mut_ptr.rs66
-rw-r--r--src/libcore/slice/mod.rs17
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs12
-rw-r--r--src/librustc_error_codes/error_codes/E0689.md19
-rw-r--r--src/librustc_feature/active.rs3
-rw-r--r--src/librustc_feature/removed.rs5
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs2
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs18
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs76
-rw-r--r--src/librustc_infer/infer/higher_ranked/mod.rs23
-rw-r--r--src/librustc_infer/infer/mod.rs11
-rw-r--r--src/librustc_infer/infer/nll_relate/mod.rs8
-rw-r--r--src/librustc_infer/infer/region_constraints/leak_check.rs522
-rw-r--r--src/librustc_infer/lib.rs3
-rw-r--r--src/librustc_middle/ty/context.rs33
-rw-r--r--src/librustc_middle/ty/diagnostics.rs31
-rw-r--r--src/librustc_mir/borrow_check/type_check/relate_tys.rs2
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs5
-rw-r--r--src/librustc_mir/monomorphize/collector.rs6
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs33
-rw-r--r--src/librustc_mir/transform/check_consts/post_drop_elaboration.rs2
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs5
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs15
-rw-r--r--src/librustc_span/symbol.rs2
-rw-r--r--src/librustc_trait_selection/traits/coherence.rs10
-rw-r--r--src/librustc_trait_selection/traits/project.rs7
-rw-r--r--src/librustc_trait_selection/traits/select/candidate_assembly.rs10
-rw-r--r--src/librustc_trait_selection/traits/select/confirmation.rs25
-rw-r--r--src/librustc_trait_selection/traits/select/mod.rs42
-rw-r--r--src/librustc_typeck/astconv.rs73
-rw-r--r--src/librustc_typeck/check/coercion.rs20
-rw-r--r--src/librustc_typeck/check/intrinsic.rs9
-rw-r--r--src/librustc_typeck/collect/type_of.rs26
-rw-r--r--src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir4
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.nll.stderr33
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.rs37
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.stderr125
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr20
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr30
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr6
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr22
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr14
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.rs41
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr8
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr26
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr8
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.stderr14
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.rs2
-rw-r--r--src/test/ui/check-static-values-constraints.stderr4
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr63
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.rs17
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr71
-rw-r--r--src/test/ui/closures/issue-41366.rs3
-rw-r--r--src/test/ui/closures/issue-41366.stderr21
-rw-r--r--src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs26
-rw-r--r--src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr13
-rw-r--r--src/test/ui/coherence/coherence-fn-implied-bounds.rs26
-rw-r--r--src/test/ui/coherence/coherence-fn-implied-bounds.stderr20
-rw-r--r--src/test/ui/coherence/coherence-fn-inputs.rs25
-rw-r--r--src/test/ui/coherence/coherence-fn-inputs.stderr13
-rw-r--r--src/test/ui/coherence/coherence-free-vs-bound-region.rs21
-rw-r--r--src/test/ui/coherence/coherence-free-vs-bound-region.stderr20
-rw-r--r--src/test/ui/coherence/coherence-wasm-bindgen.rs37
-rw-r--r--src/test/ui/coherence/coherence-wasm-bindgen.stderr32
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.stderr1
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.rs7
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.stderr18
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.rs11
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr41
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.rs7
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.stderr18
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.rs6
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.stderr14
-rw-r--r--src/test/ui/consts/const-eval/const_let.stderr16
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops.rs15
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr44
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs13
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr28
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.stderr3
-rw-r--r--src/test/ui/consts/const-eval/livedrop.rs20
-rw-r--r--src/test/ui/consts/const-eval/livedrop.stderr12
-rw-r--r--src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs2
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.stock.stderr12
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr12
-rw-r--r--src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr4
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.stderr2
-rw-r--r--src/test/ui/consts/miri_unleashed/slice_eq.rs17
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.stderr6
-rw-r--r--src/test/ui/error-codes/E0395.rs4
-rw-r--r--src/test/ui/error-codes/E0395.stderr6
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr10
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.nll.stderr8
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.rs3
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.stderr28
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr26
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr20
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr56
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr10
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr28
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.rs66
-rw-r--r--src/test/ui/hr-subtype/return-static.rs13
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr14
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.stderr21
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.stderr4
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs2
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs5
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs2
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.nll.stderr24
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.stderr41
-rw-r--r--src/test/ui/hrtb/issue-30786.migrate.stderr50
-rw-r--r--src/test/ui/hrtb/issue-30786.nll.stderr99
-rw-r--r--src/test/ui/hrtb/issue-30786.rs102
-rw-r--r--src/test/ui/hrtb/issue-46989.nll.stderr8
-rw-r--r--src/test/ui/hrtb/issue-46989.rs8
-rw-r--r--src/test/ui/hrtb/issue-46989.stderr15
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr16
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs4
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr45
-rw-r--r--src/test/ui/issues/issue-25826.rs2
-rw-r--r--src/test/ui/issues/issue-25826.stderr4
-rw-r--r--src/test/ui/issues/issue-40000.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-40000.stderr6
-rw-r--r--src/test/ui/issues/issue-43623.rs7
-rw-r--r--src/test/ui/issues/issue-43623.stderr29
-rw-r--r--src/test/ui/issues/issue-57362-2.stderr2
-rw-r--r--src/test/ui/issues/issue-60283.rs8
-rw-r--r--src/test/ui/issues/issue-60283.stderr29
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-eq.rs (renamed from src/test/ui/lub-glb/old-lub-glb-hr.rs)21
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr8
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs24
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs33
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.nll.stderr14
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.rs18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.stderr15
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr27
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.rs7
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr49
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.nll.stderr14
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.rs3
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr28
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr8
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.rs11
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.stderr15
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr44
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr6
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr50
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr6
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static.rs13
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static.stderr12
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr44
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr6
-rw-r--r--src/test/ui/rfc1623.nll.stderr68
-rw-r--r--src/test/ui/rfc1623.rs8
-rw-r--r--src/test/ui/rfc1623.stderr46
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr5
-rw-r--r--src/test/ui/span/E0493.stderr4
-rw-r--r--src/test/ui/static/static-drop-scope.stderr31
-rw-r--r--src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr53
-rw-r--r--src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs68
-rw-r--r--src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr95
-rw-r--r--src/test/ui/suggestions/suggest-move-types.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr23
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr44
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr44
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr44
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.rs8
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.stderr8
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.nll.stderr8
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.rs8
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.stderr21
-rw-r--r--src/tools/tidy/src/features.rs5
206 files changed, 3091 insertions, 1578 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 969d16d11e8..82a755c7892 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -893,15 +893,18 @@ def bootstrap(help_triggered):
     build.verbose = args.verbose
     build.clean = args.clean
 
-    try:
-        toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config or 'config.toml'
+    # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
+    # exists).
+    toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
+    if not toml_path and os.path.exists('config.toml'):
+        toml_path = 'config.toml'
+
+    if toml_path:
         if not os.path.exists(toml_path):
             toml_path = os.path.join(build.rust_root, toml_path)
 
         with open(toml_path) as config:
             build.config_toml = config.read()
-    except (OSError, IOError):
-        pass
 
     config_verbose = build.get_toml('verbose', 'build')
     if config_verbose is not None:
@@ -947,11 +950,12 @@ def bootstrap(help_triggered):
     env["SRC"] = build.rust_root
     env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
     env["BOOTSTRAP_PYTHON"] = sys.executable
-    env["BOOTSTRAP_CONFIG"] = toml_path
     env["BUILD_DIR"] = build.build_dir
     env["RUSTC_BOOTSTRAP"] = '1'
     env["CARGO"] = build.cargo()
     env["RUSTC"] = build.rustc()
+    if toml_path:
+        env["BOOTSTRAP_CONFIG"] = toml_path
     if build.rustfmt():
         env["RUSTFMT"] = build.rustfmt()
     run(args, env=env, verbose=build.verbose)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 7a7838d965b..30b18eb56a1 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -273,10 +273,18 @@ This flag, when combined with other flags, makes them produce extra output.
 This flag allows you to pass the name and location for an external crate of a
 direct dependency. Indirect dependencies (dependencies of dependencies) are
 located using the [`-L` flag](#option-l-search-path). The given crate name is
-added to the [extern prelude], which is the same as specifying `extern crate`
-within the root module. The given crate name does not need to match the name
+added to the [extern prelude], similar to specifying `extern crate` within the
+root module. The given crate name does not need to match the name
 the library was built with.
 
+Specifying `--extern` has one behavior difference from `extern crate`:
+`--extern` merely makes the crate a _candidate_ for being linked; it does not
+actually link it unless it's actively used. In rare occasions you may wish
+to ensure a crate is linked even if you don't actively use it from your
+code: for example, if it changes the global allocator or if it contains
+`#[no_mangle]` symbols for use by other programming languages. In such
+cases you'll need to use `extern crate`.
+
 This flag may be specified multiple times. This flag takes an argument with
 either of the following formats:
 
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 15e81f92887..67ebdcc9f33 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -60,7 +60,7 @@ impl<T> RawVec<T, Global> {
     /// `#[rustc_force_min_const_fn]` attribute which requires conformance
     /// with `min_const_fn` but does not necessarily allow calling it in
     /// `stable(...) const fn` / user code not enabling `foo` when
-    /// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
+    /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
     pub const NEW: Self = Self::new();
 
     /// Creates the biggest possible `RawVec` (on the system heap)
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 9061145a695..50e321f9c71 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1012,7 +1012,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::type_name`](../../std/any/fn.type_name.html)
-    #[rustc_const_unstable(feature = "const_type_name", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
     /// Gets an identifier which is globally unique to the specified type. This
@@ -1021,7 +1021,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
-    #[rustc_const_unstable(feature = "const_type_id", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
     /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -1931,7 +1931,7 @@ extern "rust-intrinsic" {
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
     /// See documentation of `<*const T>::offset_from` for details.
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal hook used by Miri to implement unwinding.
@@ -1948,6 +1948,16 @@ extern "rust-intrinsic" {
     #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
     pub fn count_code_region(index: u32);
+
+    /// See documentation of `<*const T>::guaranteed_eq` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
+
+    /// See documentation of `<*const T>::guaranteed_ne` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 0115c4df2fd..4eb2fdbd078 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -87,6 +87,7 @@
 #![feature(const_generics)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
+#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
 #![feature(const_result)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index acc09ddc014..395b3879cfd 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -295,6 +295,72 @@ impl<T: ?Sized> *const T {
         intrinsics::ptr_offset_from(self, origin)
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self, other)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_ne(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self, other)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 2bbeb95965e..b86ef5b13b3 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -273,6 +273,72 @@ impl<T: ?Sized> *mut T {
         if self.is_null() { None } else { Some(&mut *self) }
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 21ba2b5abcf..c69aafe687c 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -5956,10 +5956,18 @@ where
             return false;
         }
 
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
 
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
+
         self.iter().zip(other.iter()).all(|(x, y)| x == y)
     }
 }
@@ -5973,9 +5981,18 @@ where
         if self.len() != other.len() {
             return false;
         }
+
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
+
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
         unsafe {
             let size = mem::size_of_val(self);
             memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 95465939070..0a8525f06fa 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -12,7 +12,7 @@ use log::debug;
 use rustc_ast::ast;
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
-use rustc_codegen_ssa::common::TypeKind;
+use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -731,6 +731,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 return;
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                let a = args[0].immediate();
+                let b = args[1].immediate();
+                if name == "ptr_guaranteed_eq" {
+                    self.icmp(IntPredicate::IntEQ, a, b)
+                } else {
+                    self.icmp(IntPredicate::IntNE, a, b)
+                }
+            }
+
             "ptr_offset_from" => {
                 let ty = substs.type_at(0);
                 let pointee_size = self.size_of(ty);
diff --git a/src/librustc_error_codes/error_codes/E0689.md b/src/librustc_error_codes/error_codes/E0689.md
index 26c2c15ccfa..a680a204211 100644
--- a/src/librustc_error_codes/error_codes/E0689.md
+++ b/src/librustc_error_codes/error_codes/E0689.md
@@ -1,13 +1,16 @@
-This error indicates that the numeric value for the method being passed exists
-but the type of the numeric value or binding could not be identified.
+A method was called on an ambiguous numeric type.
 
-The error happens on numeric literals:
+Erroneous code example:
 
 ```compile_fail,E0689
-2.0.neg();
+2.0.neg(); // error!
 ```
 
-and on numeric bindings without an identified concrete type:
+This error indicates that the numeric value for the method being passed exists
+but the type of the numeric value or binding could not be identified.
+
+The error happens on numeric literals and on numeric bindings without an
+identified concrete type:
 
 ```compile_fail,E0689
 let x = 2.0;
@@ -19,8 +22,8 @@ Because of this, you must give the numeric literal or binding a type:
 ```
 use std::ops::Neg;
 
-let _ = 2.0_f32.neg();
+let _ = 2.0_f32.neg(); // ok!
 let x: f32 = 2.0;
-let _ = x.neg();
-let _ = (2.0 as f32).neg();
+let _ = x.neg(); // ok!
+let _ = (2.0 as f32).neg(); // ok!
 ```
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 7aadf58243f..e2d497a3ada 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -401,9 +401,6 @@ declare_features! (
     /// Allows dereferencing raw pointers during const eval.
     (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
 
-    /// Allows comparing raw pointers during const eval.
-    (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
-
     /// Allows `#[doc(alias = "...")]`.
     (active, doc_alias, "1.27.0", Some(50146), None),
 
diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs
index 4e348054fbd..8d410894e8b 100644
--- a/src/librustc_feature/removed.rs
+++ b/src/librustc_feature/removed.rs
@@ -113,6 +113,11 @@ declare_features! (
      Some("removed in favor of `#![feature(marker_trait_attr)]`")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+
+    /// Allows comparing raw pointers during const eval.
+    (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
+     Some("cannot be allowed in const eval in any meaningful way")),
+
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
index de71363cbde..6677c0e59f6 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -26,7 +26,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         &self,
         region: Region<'tcx>,
         br: &ty::BoundRegion,
-    ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> {
+    ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
         if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
             let def_id = anon_reg.def_id;
             if let Some(def_id) = def_id.as_local() {
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index a56401ebb90..3012928a098 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -2,7 +2,8 @@
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_hir::{FnRetTy, TyKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::FnRetTy;
 use rustc_middle::ty;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -80,16 +81,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
 
             if let FnRetTy::Return(ty) = &fndecl.output {
-                let mut v = ty::TraitObjectVisitor(vec![]);
-                rustc_hir::intravisit::walk_ty(&mut v, ty);
+                let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
+                v.visit_ty(ty);
 
                 debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
                 if sub == &ty::ReStatic
-                    && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1)
+                    && v.0
+                        .into_iter()
+                        .filter(|t| t.span.desugaring_kind().is_none())
+                        .next()
+                        .is_some()
                 {
+                    // If the failure is due to a `'static` requirement coming from a `dyn` or
+                    // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
+                    // better in `static_impl_trait`.
                     debug!("try_report_named_anon_conflict: impl Trait + 'static");
-                    // This is an `impl Trait` or `dyn Trait` return that evaluates de need of
-                    // `'static`. We handle this case better in `static_impl_trait`.
                     return None;
                 }
             }
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 82feebc8029..46dad81a099 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -26,8 +26,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 );
                 let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
                 debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
-                let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
-                debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
+                let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+                if fn_returns.is_empty() {
+                    return None;
+                }
+                debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
                 if **sub_r == RegionKind::ReStatic {
                     let sp = var_origin.span();
                     let return_sp = sub_origin.span();
@@ -98,25 +101,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                         );
                     }
 
-                    // only apply this suggestion onto functions with
-                    // explicit non-desugar'able return.
-                    if fn_return.span.desugaring_kind().is_none() {
-                        // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-
-                        let consider = "consider changing the";
-                        let declare = "to declare that the";
-                        let arg = match param_info.param.pat.simple_ident() {
-                            Some(simple_ident) => format!("argument `{}`", simple_ident),
-                            None => "the argument".to_string(),
-                        };
-                        let explicit =
-                            format!("you can add an explicit `{}` lifetime bound", lifetime_name);
-                        let explicit_static =
-                            format!("explicit `'static` bound to the lifetime of {}", arg);
-                        let captures = format!("captures data from {}", arg);
-                        let add_static_bound =
-                            "alternatively, add an explicit `'static` bound to this reference";
-                        let plus_lt = format!(" + {}", lifetime_name);
+                    // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+                    let consider = "consider changing the";
+                    let declare = "to declare that the";
+                    let arg = match param_info.param.pat.simple_ident() {
+                        Some(simple_ident) => format!("argument `{}`", simple_ident),
+                        None => "the argument".to_string(),
+                    };
+                    let explicit =
+                        format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+                    let explicit_static =
+                        format!("explicit `'static` bound to the lifetime of {}", arg);
+                    let captures = format!("captures data from {}", arg);
+                    let add_static_bound =
+                        "alternatively, add an explicit `'static` bound to this reference";
+                    let plus_lt = format!(" + {}", lifetime_name);
+                    for fn_return in fn_returns {
+                        if fn_return.span.desugaring_kind().is_some() {
+                            // Skip `async` desugaring `impl Future`.
+                            continue;
+                        }
                         match fn_return.kind {
                             TyKind::OpaqueDef(item_id, _) => {
                                 let item = self.tcx().hir().item(item_id.id);
@@ -143,7 +147,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                     err.span_suggestion_verbose(
                                         span,
                                         &format!("{} `impl Trait`'s {}", consider, explicit_static),
-                                        lifetime_name,
+                                        lifetime_name.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                     err.span_suggestion_verbose(
@@ -152,6 +156,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                         param_info.param_ty.to_string(),
                                         Applicability::MaybeIncorrect,
                                     );
+                                } else if let Some(_) = opaque
+                                    .bounds
+                                    .iter()
+                                    .filter_map(|arg| match arg {
+                                        GenericBound::Outlives(Lifetime { name, span, .. })
+                                            if name.ident().to_string() == lifetime_name =>
+                                        {
+                                            Some(*span)
+                                        }
+                                        _ => None,
+                                    })
+                                    .next()
+                                {
                                 } else {
                                     err.span_suggestion_verbose(
                                         fn_return.span.shrink_to_hi(),
@@ -161,10 +178,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                             captures = captures,
                                             explicit = explicit,
                                         ),
-                                        plus_lt,
+                                        plus_lt.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
-                                };
+                                }
                             }
                             TyKind::TraitObject(_, lt) => match lt.name {
                                 LifetimeName::ImplicitObjectLifetimeDefault => {
@@ -176,15 +193,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                             captures = captures,
                                             explicit = explicit,
                                         ),
-                                        plus_lt,
+                                        plus_lt.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                 }
-                                _ => {
+                                name if name.ident().to_string() != lifetime_name => {
+                                    // With this check we avoid suggesting redundant bounds. This
+                                    // would happen if there are nested impl/dyn traits and only
+                                    // one of them has the bound we'd suggest already there, like
+                                    // in `impl Foo<X = dyn Bar> + '_`.
                                     err.span_suggestion_verbose(
                                         lt.span,
                                         &format!("{} trait object's {}", consider, explicit_static),
-                                        lifetime_name,
+                                        lifetime_name.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                     err.span_suggestion_verbose(
@@ -194,6 +215,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                         Applicability::MaybeIncorrect,
                                     );
                                 }
+                                _ => {}
                             },
                             _ => {}
                         }
diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs
index 0499dc9ed22..b6251e34008 100644
--- a/src/librustc_infer/infer/higher_ranked/mod.rs
+++ b/src/librustc_infer/infer/higher_ranked/mod.rs
@@ -30,10 +30,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
 
         let span = self.trace.cause.span;
 
-        self.infcx.commit_if_ok(|snapshot| {
+        self.infcx.commit_if_ok(|_| {
             // 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);
+            let (b_prime, _) = 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 --
@@ -48,8 +48,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
             // 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);
 
             Ok(ty::Binder::bind(result))
@@ -75,7 +73,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        let next_universe = self.create_next_universe();
+        // Figure out what the next universe will be, but don't actually create
+        // it until after we've done the substitution (in particular there may
+        // be no bound variables). This is a performance optimization, since the
+        // leak check for example can be skipped if no new universes are created
+        // (i.e., if there are no placeholders).
+        let next_universe = self.universe().next_universe();
 
         let fld_r = |br| {
             self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
@@ -103,6 +106,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
 
+        // If there were higher-ranked regions to replace, then actually create
+        // the next universe (this avoids needlessly creating universes).
+        if !map.is_empty() {
+            let n_u = self.create_next_universe();
+            assert_eq!(n_u, next_universe);
+        }
+
         debug!(
             "replace_bound_vars_with_placeholders(\
              next_universe={:?}, \
@@ -119,7 +129,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn leak_check(
         &self,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
         // If the user gave `-Zno-leak-check`, or we have been
@@ -135,7 +144,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.inner.borrow_mut().unwrap_region_constraints().leak_check(
             self.tcx,
             overly_polymorphic,
-            placeholder_map,
+            self.universe(),
             snapshot,
         )
     }
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index 91f4b3323f3..8f8ce03d638 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -991,14 +991,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             return None;
         }
 
-        Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+        Some(self.commit_if_ok(|_snapshot| {
+            let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
-            self.leak_check(false, &placeholder_map, snapshot)?;
-
             Ok(ok.unit())
         }))
     }
@@ -1008,14 +1006,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         cause: &traits::ObligationCause<'tcx>,
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+        self.commit_if_ok(|_snapshot| {
+            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`
-            self.leak_check(false, &placeholder_map, snapshot)?;
             Ok(())
         })
     }
diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 8de89251006..2350c28dfaa 100644
--- a/src/librustc_infer/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -522,7 +522,13 @@ where
         }
 
         if a == b {
-            return Ok(a);
+            // Subtle: if a or b has a bound variable that we are lazilly
+            // substituting, then even if a == b, it could be that the values we
+            // will substitute for those bound variables are *not* the same, and
+            // hence returning `Ok(a)` is incorrect.
+            if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
+                return Ok(a);
+            }
         }
 
         match (&a.kind, &b.kind) {
diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs
index 91c39a0e78f..32e708bf52b 100644
--- a/src/librustc_infer/infer/region_constraints/leak_check.rs
+++ b/src/librustc_infer/infer/region_constraints/leak_check.rs
@@ -1,158 +1,446 @@
 use super::*;
-use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use rustc_data_structures::undo_log::UndoLogs;
+use crate::infer::CombinedSnapshot;
+use rustc_data_structures::{
+    graph::{scc::Sccs, vec_graph::VecGraph},
+    undo_log::UndoLogs,
+};
+use rustc_index::vec::Idx;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::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.
+    /// Searches new universes created during `snapshot`, looking for
+    /// placeholders that may "leak" out from the universes they are contained
+    /// in. If any leaking placeholders are found, then an `Err` is returned
+    /// (typically leading to the snapshot being reversed).
     ///
-    /// This is a temporary backwards compatibility measure to try and
-    /// retain the older (arguably incorrect) behavior of the
-    /// compiler.
+    /// The leak check *used* to be the only way we had to handle higher-ranked
+    /// obligations. Now that we have integrated universes into the region
+    /// solvers, this is no longer the case, but we retain the leak check for
+    /// backwards compatibility purposes. In particular, it lets us make "early"
+    /// decisions about whether a region error will be reported that are used in
+    /// coherence and elsewhere -- see #56105 and #59490 for more details. The
+    /// eventual fate of the leak checker is not yet settled.
     ///
-    /// NB. Although `_snapshot` isn't used, it's passed in to prove
-    /// that we are in a snapshot, which guarantees that we can just
-    /// search the "undo log" for edges. This 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.
+    /// The leak checker works by searching for the following error patterns:
+    ///
+    /// * P1: P2, where P1 != P2
+    /// * P1: R, where R is in some universe that cannot name P1
+    ///
+    /// The idea here is that each of these patterns represents something that
+    /// the region solver would eventually report as an error, so we can detect
+    /// the error early. There is a fly in the ointment, though, in that this is
+    /// not entirely true. In particular, in the future, we may extend the
+    /// environment with implied bounds or other info about how placeholders
+    /// relate to regions in outer universes. In that case, `P1: R` for example
+    /// might become solveable.
+    ///
+    /// # Summary of the implementation
+    ///
+    /// The leak checks as follows. First, we construct a graph where `R2: R1`
+    /// implies `R2 -> R1`, and we compute the SCCs.
+    ///
+    /// For each SCC S, we compute:
+    ///
+    /// * what placeholder P it must be equal to, if any
+    ///   * if there are multiple placeholders that must be equal, report an error because `P1: P2`
+    /// * the minimum universe of its constituents
+    ///
+    /// Then we walk the SCCs in dependency order and compute
+    ///
+    /// * what placeholder they must outlive transitively
+    ///   * if they must also be equal to a placeholder, report an error because `P1: P2`
+    /// * minimum universe U of all SCCs they must outlive
+    ///   * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
+    ///     indicates `P: R` and `R` is in an incompatible universe
+    ///
+    /// # Historical note
+    ///
+    /// Older variants of the leak check used to report errors for these
+    /// patterns, but we no longer do:
+    ///
+    /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
+    /// * R: P1, R: P2, as above
     pub fn leak_check(
         &mut self,
         tcx: TyCtxt<'tcx>,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+        max_universe: ty::UniverseIndex,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
-        debug!("leak_check(placeholders={:?})", placeholder_map);
+        debug!(
+            "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
+            max_universe, snapshot.universe, overly_polymorphic
+        );
 
         assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
 
-        // Go through each placeholder that we created.
-        for &placeholder_region in placeholder_map.values() {
-            // 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.region_constraints(),
-                &self.storage.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)
-                });
-            }
+        let universe_at_start_of_snapshot = snapshot.universe;
+        if universe_at_start_of_snapshot == max_universe {
+            return Ok(());
         }
 
+        let mini_graph =
+            &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
+
+        let mut leak_check = LeakCheck::new(
+            tcx,
+            universe_at_start_of_snapshot,
+            max_universe,
+            overly_polymorphic,
+            mini_graph,
+            self,
+        );
+        leak_check.assign_placeholder_values()?;
+        leak_check.propagate_scc_value()?;
         Ok(())
     }
 }
 
-#[derive(Debug)]
-struct TaintSet<'tcx> {
-    directions: TaintDirections,
-    regions: FxHashSet<ty::Region<'tcx>>,
+struct LeakCheck<'me, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    universe_at_start_of_snapshot: ty::UniverseIndex,
+    overly_polymorphic: bool,
+    mini_graph: &'me MiniGraph<'tcx>,
+    rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+
+    // Initially, for each SCC S, stores a placeholder `P` such that `S = P`
+    // must hold.
+    //
+    // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
+    // is repurposed to store some placeholder `P` such that the weaker
+    // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
+    // = P`.)
+    scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
+
+    // For each SCC S, track the minimum universe that flows into it. Note that
+    // this is both the minimum of the universes for every region that is a
+    // member of the SCC, but also if you have `R1: R2`, then the universe of
+    // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
+    // see that, imagine that you have `P1: R` -- in that case, `R` must be
+    // either the placeholder `P1` or the empty region in that same universe.
+    //
+    // To detect errors, we look for an SCC S where the values in
+    // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
+    scc_universes: IndexVec<LeakCheckScc, SccUniverse<'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, regions }
+impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        universe_at_start_of_snapshot: ty::UniverseIndex,
+        max_universe: ty::UniverseIndex,
+        overly_polymorphic: bool,
+        mini_graph: &'me MiniGraph<'tcx>,
+        rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+    ) -> Self {
+        let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
+        Self {
+            tcx,
+            universe_at_start_of_snapshot,
+            overly_polymorphic,
+            mini_graph,
+            rcc,
+            scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
+            scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
+        }
+    }
+
+    /// Compute what placeholders (if any) each SCC must be equal to.
+    /// Also compute the minimum universe of all the regions in each SCC.
+    fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
+        // First walk: find each placeholder that is from a newly created universe.
+        for (region, leak_check_node) in &self.mini_graph.nodes {
+            let scc = self.mini_graph.sccs.scc(*leak_check_node);
+
+            // Set the universe of each SCC to be the minimum of its constituent universes
+            let universe = self.rcc.universe(region);
+            debug!(
+                "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
+                scc, universe, region
+            );
+            self.scc_universes[scc].take_min(universe, region);
+
+            // Detect those SCCs that directly contain a placeholder
+            if let ty::RePlaceholder(placeholder) = region {
+                if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
+                    self.assign_scc_value(scc, *placeholder)?;
+                }
+            }
+        }
+
+        Ok(())
     }
 
-    fn fixed_point<'a>(
+    // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
+    // This may create an error.
+    fn assign_scc_value(
         &mut self,
-        tcx: TyCtxt<'tcx>,
-        undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
-        verifys: &[Verify<'tcx>],
-    ) where
-        'tcx: 'a,
-    {
-        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.clone() {
-                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",
-                    ),
-                    &AddCombination(..) | &AddVar(..) => {}
+        scc: LeakCheckScc,
+        placeholder: ty::PlaceholderRegion,
+    ) -> RelateResult<'tcx, ()> {
+        match self.scc_placeholders[scc] {
+            Some(p) => {
+                assert_ne!(p, placeholder);
+                return Err(self.placeholder_error(p, placeholder));
+            }
+            None => {
+                self.scc_placeholders[scc] = Some(placeholder);
+            }
+        };
+
+        Ok(())
+    }
+
+    /// For each SCC S, iterate over each successor S1 where `S: S1`:
+    ///
+    /// * Compute
+    /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
+    /// `universe(S) <= universe(S1)`. This executes after
+    /// `assign_placeholder_values`, so `universe(S)` is already the minimum
+    /// universe of any of its direct constituents.
+    fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
+        // Loop invariants:
+        //
+        // On start of the loop iteration for `scc1`:
+        //
+        // * `scc_universes[scc1]` contains the minimum universe of the
+        //   constituents of `scc1`
+        // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
+        //   be equal to (if any)
+        //
+        // For each succssor `scc2` where `scc1: scc2`:
+        //
+        // * `scc_placeholder[scc2]` stores some placeholder `P` where
+        //   `scc2: P` (if any)
+        // * `scc_universes[scc2]` contains the minimum universe of the
+        //   constituents of `scc2` and any of its successors
+        for scc1 in self.mini_graph.sccs.all_sccs() {
+            debug!(
+                "propagate_scc_value: scc={:?} with universe {:?}",
+                scc1, self.scc_universes[scc1]
+            );
+
+            // Walk over each `scc2` such that `scc1: scc2` and compute:
+            //
+            // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
+            // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
+            //   we pick one arbitrarily)
+            let mut scc1_universe = self.scc_universes[scc1];
+            let mut succ_bound = None;
+            for &scc2 in self.mini_graph.sccs.successors(scc1) {
+                let SccUniverse { universe: scc2_universe, region: scc2_region } =
+                    self.scc_universes[scc2];
+
+                scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
+
+                if let Some(b) = self.scc_placeholders[scc2] {
+                    succ_bound = Some(b);
                 }
             }
+
+            // Update minimum universe of scc1.
+            self.scc_universes[scc1] = scc1_universe;
+
+            // At this point, `scc_placholder[scc1]` stores the placeholder that
+            // `scc1` must be equal to, if any.
+            if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
+                debug!(
+                    "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
+                    scc1, scc1_placeholder, scc1_universe
+                );
+
+                // Check if `P1: R` for some `R` in a universe that cannot name
+                // P1. That's an error.
+                if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
+                    return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
+                }
+
+                // Check if we have some placeholder where `S: P2`
+                // (transitively). In that case, since `S = P1`, that implies
+                // `P1: P2`, which is an error condition.
+                if let Some(scc2_placeholder) = succ_bound {
+                    assert_ne!(scc1_placeholder, scc2_placeholder);
+                    return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
+                }
+            } else {
+                // Otherwise, we can reach a placeholder if some successor can.
+                self.scc_placeholders[scc1] = succ_bound;
+            }
+
+            // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
         }
+        Ok(())
     }
 
-    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
-        self.regions
+    fn placeholder_error(
+        &self,
+        placeholder1: ty::PlaceholderRegion,
+        placeholder2: ty::PlaceholderRegion,
+    ) -> TypeError<'tcx> {
+        self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
     }
 
-    fn len(&self) -> usize {
-        self.regions.len()
+    fn error(
+        &self,
+        placeholder: ty::PlaceholderRegion,
+        other_region: ty::Region<'tcx>,
+    ) -> TypeError<'tcx> {
+        debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
+        if self.overly_polymorphic {
+            return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+        } else {
+            return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+        }
     }
+}
 
-    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);
-            }
+// States we need to distinguish:
+//
+// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
+//     * it could conflict with some other regions in the SCC in different universes
+//     * or a different placeholder
+// * `P1: S` and `S` must be equal to a placeholder
+// * `P1: S` and `S` is in an incompatible universe
+//
+// So if we
+//
+// (a) compute which placeholder (if any) each SCC must be equal to
+// (b) compute its minimum universe
+// (c) compute *some* placeholder where `S: P1` (any one will do)
+//
+// then we get an error if:
+//
+// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
+// - `S: P1` and minimum universe cannot name `P1`
+// - `S: P1` and we must be equal to `P2`
+//
+// So we want to track:
+//
+// * Equal placeholder (if any)
+// * Some bounding placeholder (if any)
+// * Minimum universe
+//
+// * We compute equal placeholder + minimum universe of constituents in first pass
+// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
+//   * bounding placeholder (if any)
+//   * minimum universe
+// * And if we must be equal to a placeholder then we check it against
+//   * minimum universe
+//   * no bounding placeholder
+
+/// Tracks the "minimum universe" for each SCC, along with some region that
+/// caused it to change.
+#[derive(Copy, Clone, Debug)]
+struct SccUniverse<'tcx> {
+    /// For some SCC S, the minimum universe of:
+    ///
+    /// * each region R in S
+    /// * each SCC S1 such that S: S1
+    universe: ty::UniverseIndex,
+
+    /// Some region that caused `universe` to be what it is.
+    region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> SccUniverse<'tcx> {
+    /// If `universe` is less than our current universe, then update
+    /// `self.universe` and `self.region`.
+    fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
+        if universe < self.universe || self.region.is_none() {
+            self.universe = universe;
+            self.region = Some(region);
         }
+    }
+}
+
+rustc_index::newtype_index! {
+    struct LeakCheckNode {
+        DEBUG_FORMAT = "LeakCheckNode({})"
+    }
+}
 
-        if self.directions.outgoing {
-            if self.regions.contains(&source) {
-                self.regions.insert(target);
+rustc_index::newtype_index! {
+    struct LeakCheckScc {
+        DEBUG_FORMAT = "LeakCheckScc({})"
+    }
+}
+
+/// Represents the graph of constraints. For each `R1: R2` constraint we create
+/// an edge `R1 -> R2` in the graph.
+struct MiniGraph<'tcx> {
+    /// Map from a region to the index of the node in the graph.
+    nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+
+    /// Map from node index to SCC, and stores the successors of each SCC. All
+    /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
+    /// then `S1: S2`.
+    sccs: Sccs<LeakCheckNode, LeakCheckScc>,
+}
+
+impl<'tcx> MiniGraph<'tcx> {
+    fn new<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+    ) -> Self
+    where
+        'tcx: 'a,
+    {
+        let mut nodes = FxHashMap::default();
+        let mut edges = Vec::new();
+
+        // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
+        Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
+            let source_node = Self::add_node(&mut nodes, source);
+            let target_node = Self::add_node(&mut nodes, target);
+            edges.push((source_node, target_node));
+        });
+        let graph = VecGraph::new(nodes.len(), edges);
+        let sccs = Sccs::new(&graph);
+        Self { nodes, sccs }
+    }
+
+    /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
+    fn iterate_undo_log<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+        mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
+    ) where
+        'tcx: 'a,
+    {
+        for undo_entry in undo_log {
+            match undo_entry {
+                &AddConstraint(Constraint::VarSubVar(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::RegSubVar(a, b)) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::VarSubReg(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), b);
+                }
+                &AddConstraint(Constraint::RegSubReg(a, b)) => {
+                    each_edge(a, b);
+                }
+                &AddGiven(a, b) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddVerify(i) => span_bug!(
+                    verifys[i].origin.span(),
+                    "we never add verifications while doing higher-ranked things",
+                ),
+                &AddCombination(..) | &AddVar(..) => {}
             }
         }
     }
+
+    fn add_node(
+        nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+        r: ty::Region<'tcx>,
+    ) -> LeakCheckNode {
+        let l = nodes.len();
+        *nodes.entry(r).or_insert(LeakCheckNode::new(l))
+    }
 }
diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs
index ed04ee02b72..0f3f3db8679 100644
--- a/src/librustc_infer/lib.rs
+++ b/src/librustc_infer/lib.rs
@@ -16,6 +16,9 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(const_fn)]
+#![feature(const_if_match)]
+#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(never_type)]
 #![feature(or_patterns)]
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index 56f4ae9e984..fb9565e4b98 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -38,6 +38,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::{self, PanicLocationLangItem};
 use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
@@ -1427,10 +1428,8 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    pub fn return_type_impl_or_dyn_trait(
-        &self,
-        scope_def_id: DefId,
-    ) -> Option<&'tcx hir::Ty<'tcx>> {
+    /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
+    pub fn return_type_impl_or_dyn_traits(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> {
         let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
         let hir_output = match self.hir().get(hir_id) {
             Node::Item(hir::Item {
@@ -1466,30 +1465,12 @@ impl<'tcx> TyCtxt<'tcx> {
                     ),
                 ..
             }) => ty,
-            _ => return None,
+            _ => return vec![],
         };
 
-        let ret_ty = self.type_of(scope_def_id);
-        match ret_ty.kind {
-            ty::FnDef(_, _) => {
-                let sig = ret_ty.fn_sig(*self);
-                let output = self.erase_late_bound_regions(&sig.output());
-                if output.is_impl_trait() {
-                    let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
-                    if let hir::FnRetTy::Return(ty) = fn_decl.output {
-                        return Some(ty);
-                    }
-                } else {
-                    let mut v = TraitObjectVisitor(vec![]);
-                    rustc_hir::intravisit::walk_ty(&mut v, hir_output);
-                    if v.0.len() == 1 {
-                        return Some(v.0[0]);
-                    }
-                }
-                None
-            }
-            _ => None,
-        }
+        let mut v = TraitObjectVisitor(vec![], self.hir());
+        v.visit_ty(hir_output);
+        v.0
     }
 
     pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {
diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs
index a2812e117ed..b22727bdd75 100644
--- a/src/librustc_middle/ty/diagnostics.rs
+++ b/src/librustc_middle/ty/diagnostics.rs
@@ -236,7 +236,9 @@ pub fn suggest_constraining_type_param(
     }
 }
 
-pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+
 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
     type Map = rustc_hir::intravisit::ErasedMap<'v>;
 
@@ -245,15 +247,24 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
     }
 
     fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
-        if let hir::TyKind::TraitObject(
-            _,
-            hir::Lifetime {
-                name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
-                ..
-            },
-        ) = ty.kind
-        {
-            self.0.push(ty);
+        match ty.kind {
+            hir::TyKind::TraitObject(
+                _,
+                hir::Lifetime {
+                    name:
+                        hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+                    ..
+                },
+            ) => {
+                self.0.push(ty);
+            }
+            hir::TyKind::OpaqueDef(item_id, _) => {
+                self.0.push(ty);
+                let item = self.1.expect_item(item_id.id);
+                hir::intravisit::walk_item(self, item);
+            }
+            _ => {}
         }
+        hir::intravisit::walk_ty(self, ty);
     }
 }
diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 7ff12820db8..285d9ed6469 100644
--- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>(
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<()> {
-    debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
+    debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 31bdc45a2ea..6ac1e6be036 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -296,6 +296,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
                 self.write_scalar(offset_ptr, dest)?;
             }
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+                // FIXME: return `true` for at least some comparisons where we can reliably
+                // determine the result of runtime (in)equality tests at compile-time.
+                self.write_scalar(Scalar::from_bool(false), dest)?;
+            }
             sym::ptr_offset_from => {
                 let a = self.read_immediate(args[0])?.to_scalar()?;
                 let b = self.read_immediate(args[1])?.to_scalar()?;
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 36f3947d830..e51d9ba9c02 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1,7 +1,7 @@
 //! Mono Item Collection
 //! ====================
 //!
-//! This module is responsible for discovering all items that will contribute to
+//! This module is responsible for discovering all items that will contribute
 //! to code generation of the crate. The important part here is that it not only
 //! needs to find syntax-level items (functions, structs, etc) but also all
 //! their monomorphized instantiations. Every non-generic, non-const function
@@ -79,7 +79,7 @@
 //! function or method call (represented by a CALL terminator in MIR). But
 //! calls are not the only thing that might introduce a reference between two
 //! function mono items, and as we will see below, they are just a
-//! specialized of the form described next, and consequently will don't get any
+//! specialization of the form described next, and consequently will not get any
 //! special treatment in the algorithm.
 //!
 //! #### Taking a reference to a function or method
@@ -158,7 +158,7 @@
 //! - Eager mode is meant to be used in conjunction with incremental compilation
 //!   where a stable set of mono items is more important than a minimal
 //!   one. Thus, eager mode will instantiate drop-glue for every drop-able type
-//!   in the crate, even of no drop call for that type exists (yet). It will
+//!   in the crate, even if no drop call for that type exists (yet). It will
 //!   also instantiate default implementations of trait methods, something that
 //!   otherwise is only done on demand.
 //!
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 733ae908451..676688daf1c 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -160,17 +160,20 @@ pub struct InlineAsm;
 impl NonConstOp for InlineAsm {}
 
 #[derive(Debug)]
-pub struct LiveDrop;
+pub struct LiveDrop(pub Option<Span>);
 impl NonConstOp for LiveDrop {
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        struct_span_err!(
+        let mut diagnostic = struct_span_err!(
             ccx.tcx.sess,
             span,
             E0493,
             "destructors cannot be evaluated at compile-time"
-        )
-        .span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()))
-        .emit();
+        );
+        diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
+        if let Some(span) = self.0 {
+            diagnostic.span_label(span, "value is dropped here");
+        }
+        diagnostic.emit();
     }
 }
 
@@ -296,18 +299,16 @@ impl NonConstOp for Panic {
 #[derive(Debug)]
 pub struct RawPtrComparison;
 impl NonConstOp for RawPtrComparison {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_compare_raw_pointers)
-    }
-
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_compare_raw_pointers,
-            span,
-            &format!("comparing raw pointers inside {}", ccx.const_kind()),
-        )
-        .emit();
+        let mut err = ccx
+            .tcx
+            .sess
+            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+        err.note(
+            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
+            for more information",
+        );
+        err.emit();
     }
 }
 
diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
index 124606fb423..1fd907f89fe 100644
--- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
+++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
@@ -58,7 +58,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
 
 impl CheckLiveDrops<'mir, 'tcx> {
     fn check_live_drop(&self, span: Span) {
-        ops::non_const(self.ccx, ops::LiveDrop, span);
+        ops::non_const(self.ccx, ops::LiveDrop(None), span);
     }
 }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 35a8df62cb8..d263bf12e88 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -588,7 +588,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 };
 
                 if needs_drop {
-                    self.check_op_spanned(ops::LiveDrop, err_span);
+                    self.check_op_spanned(
+                        ops::LiveDrop(Some(terminator.source_info.span)),
+                        err_span,
+                    );
                 }
             }
 
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 9898cde5207..b8f725e967d 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -171,21 +171,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     _ => {}
                 }
             }
-            // raw pointer and fn pointer operations are unsafe as it is not clear whether one
-            // pointer would be "less" or "equal" to another, because we cannot know where llvm
-            // or the linker will place various statics in memory. Without this information the
-            // result of a comparison of addresses would differ between runtime and compile-time.
-            Rvalue::BinaryOp(_, ref lhs, _)
-                if self.const_context && self.tcx.features().const_compare_raw_pointers =>
-            {
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
-                    self.require_unsafe(
-                        "pointer operation",
-                        "operations on pointers in constants",
-                        UnsafetyViolationKind::General,
-                    );
-                }
-            }
             _ => {}
         }
         self.super_rvalue(rvalue, location);
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 970a2632592..06d1f36622b 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -588,6 +588,8 @@ symbols! {
         proc_macro_non_items,
         proc_macro_path_invoc,
         profiler_runtime,
+        ptr_guaranteed_eq,
+        ptr_guaranteed_ne,
         ptr_offset_from,
         pub_restricted,
         pure,
diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs
index 706cbf058b7..3ec7fe2bf25 100644
--- a/src/librustc_trait_selection/traits/coherence.rs
+++ b/src/librustc_trait_selection/traits/coherence.rs
@@ -120,12 +120,13 @@ fn overlap<'cx, 'tcx>(
     debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
+        overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
     })
 }
 
 fn overlap_within_probe(
     selcx: &mut SelectionContext<'cx, 'tcx>,
+    skip_leak_check: SkipLeakCheck,
     a_def_id: DefId,
     b_def_id: DefId,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
@@ -180,6 +181,13 @@ fn overlap_within_probe(
         return None;
     }
 
+    if !skip_leak_check.is_yes() {
+        if let Err(_) = infcx.leak_check(true, snapshot) {
+            debug!("overlap: leak check failed");
+            return None;
+        }
+    }
+
     let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
     debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 574d50a4fcc..bc696214cbc 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -149,15 +149,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>(
     debug!("poly_project_and_unify_type(obligation={:?})", obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|snapshot| {
-        let (placeholder_predicate, placeholder_map) =
+    infcx.commit_if_ok(|_snapshot| {
+        let (placeholder_predicate, _) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
         let result = project_and_unify_type(selcx, &placeholder_obligation)?;
-        infcx
-            .leak_check(false, &placeholder_map, snapshot)
-            .map_err(|err| MismatchedProjectionTypes { err })?;
         Ok(result)
     })
 }
diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
index 9045451056b..4dab5814f7b 100644
--- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs
+++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
@@ -163,9 +163,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => return,
         }
 
-        let result = self.infcx.probe(|snapshot| {
-            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
-        });
+        let result = self
+            .infcx
+            .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
 
         if result {
             candidates.vec.push(ProjectionCandidate);
@@ -345,8 +345,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|snapshot| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
+                self.infcx.probe(|_| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
                 });
diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs
index 50c04e8fc34..834bf17227d 100644
--- a/src/librustc_trait_selection/traits/select/confirmation.rs
+++ b/src/librustc_trait_selection/traits/select/confirmation.rs
@@ -121,9 +121,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.commit_unconditionally(|snapshot| {
-            let result =
-                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let result = self.match_projection_obligation_against_definition_bounds(obligation);
             assert!(result);
         })
     }
@@ -265,8 +264,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_unconditionally(|snapshot| {
-            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let substs = self.rematch_impl(impl_def_id, obligation);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             ensure_sufficient_stack(|| {
@@ -612,24 +611,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // 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 guides 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)
-                    .eq(target, source_trait) // FIXME -- see below
+                    .sup(target, source_trait)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs
index 076bdad423a..cff5efbfd0f 100644
--- a/src/librustc_trait_selection/traits/select/mod.rs
+++ b/src/librustc_trait_selection/traits/select/mod.rs
@@ -21,7 +21,7 @@ use super::{Normalized, ProjectionCacheKey};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{Overflow, SelectionError, Unimplemented};
 
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectionCacheKeyExt;
 use rustc_ast::attr;
@@ -347,6 +347,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<EvaluationResult, OverflowError> {
         self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
             let result = op(self)?;
+
+            match self.infcx.leak_check(true, snapshot) {
+                Ok(()) => {}
+                Err(_) => return Ok(EvaluatedToErr),
+            }
+
             match self.infcx.region_constraints_added_in_snapshot(snapshot) {
                 None => Ok(result),
                 Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@@ -1262,10 +1268,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, placeholder_map) =
+        let (placeholder_trait_predicate, _) =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
@@ -1293,13 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
                 let bound = bound.to_poly_trait_ref();
                 if self.infcx.probe(|_| {
-                    self.match_projection(
-                        obligation,
-                        bound,
-                        placeholder_trait_predicate.trait_ref,
-                        &placeholder_map,
-                        snapshot,
-                    )
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
                 }) {
                     return Some(bound);
                 }
@@ -1316,13 +1315,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => false,
             Some(bound) => {
                 // Repeat the successful match, if any, this time outside of a probe.
-                let result = self.match_projection(
-                    obligation,
-                    bound,
-                    placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
-                    snapshot,
-                );
+                let result =
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
 
                 assert!(result);
                 true
@@ -1335,15 +1329,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
-            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
     }
 
     fn evaluate_where_clause<'o>(
@@ -1808,9 +1799,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        match self.match_impl(impl_def_id, obligation, snapshot) {
+        match self.match_impl(impl_def_id, obligation) {
             Ok(substs) => substs,
             Err(()) => {
                 bug!(
@@ -1826,7 +1816,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -1837,7 +1826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Err(());
         }
 
-        let (placeholder_obligation, placeholder_map) =
+        let (placeholder_obligation, _) =
             self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
@@ -1869,11 +1858,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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(());
-        }
-
         if !self.intercrate
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 33d57e25711..1b08bf2fc77 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -8,8 +8,7 @@
 use crate::collect::PlaceholderHirTyCollector;
 use crate::middle::resolve_lifetime as rl;
 use crate::require_c_abi_if_c_variadic;
-use rustc_ast::ast::ParamKindOrd;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError};
@@ -27,7 +26,7 @@ use rustc_middle::ty::{GenericParamDef, GenericParamDefKind};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
@@ -475,7 +474,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
     /// Report an error that a generic argument did not match the generic parameter that was
     /// expected.
-    fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) {
+    fn generic_arg_mismatch_err(
+        sess: &Session,
+        arg: &GenericArg<'_>,
+        kind: &'static str,
+        help: Option<&str>,
+    ) {
         let mut err = struct_span_err!(
             sess,
             arg.span(),
@@ -503,6 +507,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let (first, last) =
             if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
         err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+
+        if let Some(help) = help {
+            err.help(help);
+        }
         err.emit();
     }
 
@@ -648,7 +656,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 if arg_count.correct.is_ok()
                                     && arg_count.explicit_late_bound == ExplicitLateBound::No
                                 {
-                                    Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr());
+                                    // We're going to iterate over the parameters to sort them out, and
+                                    // show that order to the user as a possible order for the parameters
+                                    let mut param_types_present = defs
+                                        .params
+                                        .clone()
+                                        .into_iter()
+                                        .map(|param| {
+                                            (
+                                                match param.kind {
+                                                    GenericParamDefKind::Lifetime => {
+                                                        ParamKindOrd::Lifetime
+                                                    }
+                                                    GenericParamDefKind::Type { .. } => {
+                                                        ParamKindOrd::Type
+                                                    }
+                                                    GenericParamDefKind::Const => {
+                                                        ParamKindOrd::Const
+                                                    }
+                                                },
+                                                param,
+                                            )
+                                        })
+                                        .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
+                                    param_types_present.sort_by_key(|(ord, _)| *ord);
+                                    let (mut param_types_present, ordered_params): (
+                                        Vec<ParamKindOrd>,
+                                        Vec<GenericParamDef>,
+                                    ) = param_types_present.into_iter().unzip();
+                                    param_types_present.dedup();
+
+                                    Self::generic_arg_mismatch_err(
+                                        tcx.sess,
+                                        arg,
+                                        kind.descr(),
+                                        Some(&format!(
+                                            "reorder the arguments: {}: `<{}>`",
+                                            param_types_present
+                                                .into_iter()
+                                                .map(|ord| format!("{}s", ord.to_string()))
+                                                .collect::<Vec<String>>()
+                                                .join(", then "),
+                                            ordered_params
+                                                .into_iter()
+                                                .filter_map(|param| {
+                                                    if param.name == kw::SelfUpper {
+                                                        None
+                                                    } else {
+                                                        Some(param.name.to_string())
+                                                    }
+                                                })
+                                                .collect::<Vec<String>>()
+                                                .join(", ")
+                                        )),
+                                    );
                                 }
 
                                 // We've reported the error, but we want to make sure that this
@@ -680,7 +741,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             assert_eq!(kind, "lifetime");
                             let provided =
                                 force_infer_lt.expect("lifetimes ought to have been inferred");
-                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind);
+                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
                         }
 
                         break;
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index dec53c369bb..b6cd8da2362 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -895,7 +895,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let prev_ty = self.resolve_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_vars_with_obligations(new_ty);
-        debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
+        debug!(
+            "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
+            prev_ty,
+            new_ty,
+            exprs.len()
+        );
 
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
@@ -1001,6 +1006,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ok(ok) => {
                     let (adjustments, target) = self.register_infer_ok_obligations(ok);
                     self.apply_adjustments(new, adjustments);
+                    debug!(
+                        "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
+                        prev_ty, new_ty,
+                    );
                     return Ok(target);
                 }
                 Err(e) => first_error = Some(e),
@@ -1031,6 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             if !noop {
+                debug!(
+                    "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
+                    expr,
+                );
+
                 return self
                     .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
                     .map(|ok| self.register_infer_ok_obligations(ok));
@@ -1048,6 +1062,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Ok(ok) => {
+                debug!(
+                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
+                    prev_ty, new_ty,
+                );
                 let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 3ec6973a17d..ef6c7c14404 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
         | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
         | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
         | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
-        | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
-            hir::Unsafety::Normal
-        }
+        | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
+        | "maxnumf64" | "type_name" => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
 }
@@ -258,6 +257,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
+            }
+
             "ptr_offset_from" => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
             }
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index cf5f2ec69d8..3dd9c9c5c39 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -10,8 +10,7 @@ use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
@@ -303,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
             GenericParamKind::Const { ty: ref hir_ty, .. } => {
                 let ty = icx.to_ty(hir_ty);
-                if !tcx.features().const_compare_raw_pointers {
-                    let err = match ty.peel_refs().kind {
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => None,
-                    };
-                    if let Some(unsupported_type) = err {
-                        feature_err(
-                            &tcx.sess.parse_sess,
-                            sym::const_compare_raw_pointers,
+                let err = match ty.peel_refs().kind {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                };
+                if let Some(unsupported_type) = err {
+                    tcx.sess
+                        .struct_span_err(
                             hir_ty.span,
                             &format!(
-                                "using {} as const generic parameters is unstable",
+                                "using {} as const generic parameters is forbidden",
                                 unsupported_type
                             ),
                         )
                         .emit();
-                    };
-                }
+                };
                 if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
                     .is_some()
                 {
diff --git a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
index 9742530bd81..aeb38f3f910 100644
--- a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -12,7 +12,7 @@
 | 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18
-| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
+| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
 | 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28
@@ -22,7 +22,7 @@
 | 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16
-| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
+| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
 | 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
new file mode 100644
index 00000000000..25e9f726ba5
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
@@ -0,0 +1,33 @@
+error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
+  --> $DIR/associated-types-eq-hr.rs:87:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
+...
+LL |     foo::<UintStruct>();
+   |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+   |
+   = note: expected reference `&isize`
+              found reference `&usize`
+
+error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+  --> $DIR/associated-types-eq-hr.rs:91:5
+   |
+LL | fn bar<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
+...
+LL |     bar::<IntStruct>();
+   |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: expected reference `&usize`
+              found reference `&isize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
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 e6afa3f71c2..fb391913c32 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.rs
+++ b/src/test/ui/associated-types/associated-types-eq-hr.rs
@@ -7,7 +7,7 @@ pub trait TheTrait<T> {
 }
 
 struct IntStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for IntStruct {
@@ -19,7 +19,7 @@ impl<'a> TheTrait<&'a isize> for IntStruct {
 }
 
 struct UintStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for UintStruct {
@@ -30,8 +30,7 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
     }
 }
 
-struct Tuple {
-}
+struct Tuple {}
 
 impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
     type A = &'a isize;
@@ -42,37 +41,43 @@ impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
 }
 
 fn foo<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x isize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x isize>,
 {
     // ok for IntStruct, but not UintStruct
 }
 
 fn bar<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x usize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x usize>,
 {
     // ok for UintStruct, but not IntStruct
 }
 
 fn tuple_one<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>,
 {
     // not ok for tuple, two lifetimes and we pick first
 }
 
 fn tuple_two<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>,
 {
     // not ok for tuple, two lifetimes and we pick second
 }
 
 fn tuple_three<T>()
-    where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
+where
+    T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>,
 {
     // ok for tuple
 }
 
 fn tuple_four<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>,
 {
     // not ok for tuple, two lifetimes, and lifetime matching is invariant
 }
@@ -89,14 +94,14 @@ pub fn call_bar() {
 
 pub fn call_tuple_one() {
     tuple_one::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_two() {
     tuple_two::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_three() {
@@ -105,7 +110,7 @@ pub fn call_tuple_three() {
 
 pub fn call_tuple_four() {
     tuple_four::<Tuple>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `TheTrait` is not general enough
 }
 
-fn main() { }
+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 58d72746e76..127ab867355 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr
@@ -1,10 +1,11 @@
 error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
-  --> $DIR/associated-types-eq-hr.rs:82:5
+  --> $DIR/associated-types-eq-hr.rs:87:5
    |
 LL | fn foo<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x isize>
-   |                                           ------------- required by this bound in `foo`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
 ...
 LL |     foo::<UintStruct>();
    |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
@@ -13,12 +14,13 @@ LL |     foo::<UintStruct>();
               found reference `&usize`
 
 error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
-  --> $DIR/associated-types-eq-hr.rs:86:5
+  --> $DIR/associated-types-eq-hr.rs:91:5
    |
 LL | fn bar<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x usize>
-   |                                           ------------- required by this bound in `bar`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
 ...
 LL |     bar::<IntStruct>();
    |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
@@ -26,71 +28,86 @@ LL |     bar::<IntStruct>();
    = note: expected reference `&usize`
               found reference `&isize`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:91:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-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
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |                                                           ------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:97:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-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
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |                                                           ------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:107:18
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:112:5
    |
-LL | fn tuple_four<T>()
-   |    ---------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
-   |               ------------------------------------------- required by this bound in `tuple_four`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_four::<Tuple>();
-   |                  ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_four::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
index 71a533a36f4..4fc336122fa 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
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 5009e0868a7..9462121bdf2 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
@@ -1,23 +1,23 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:53:21
+  --> $DIR/project-fn-ret-invariant.rs:54:22
    |
-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 |    let a = bar(foo, y);
-   |                     ^ ...but data from `x` is returned here
+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 |     let a = bar(foo, y);
+   |                      ^ ...but data from `x` is returned here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:54:21
+  --> $DIR/project-fn-ret-invariant.rs:56:9
    |
-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 |    let a = bar(foo, y);
-LL |    let b = bar(foo, x);
-   |                     ^ ...but data from `y` is returned here
+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)
+   |         ^ ...but data from `x` is returned here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
index 8f445acf2b9..2156ecb1739 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
@@ -1,8 +1,8 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/project-fn-ret-invariant.rs:59:1
+  --> $DIR/project-fn-ret-invariant.rs:60:1
    |
-LL | fn main() { }
-   | ^^^^^^^^^^^^^
+LL | fn main() {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
index c39030fbed1..44850df7b2f 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:38:12
+  --> $DIR/project-fn-ret-invariant.rs:39:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
-LL |    let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL |    let a = bar(f, x);
-   |            ^^^^^^^^^ argument requires that `'a` must outlive `'b`
+LL |     let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL |     let a = bar(f, x);
+   |             ^^^^^^^^^ argument requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:39:12
+  --> $DIR/project-fn-ret-invariant.rs:40:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
 ...
-LL |    let b = bar(f, y);
-   |            ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+LL |     let b = bar(f, y);
+   |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
index 65d16440ac9..64b57223908 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
@@ -1,13 +1,13 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:39:19
+  --> $DIR/project-fn-ret-invariant.rs:40:20
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                               --------     --------------------
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                --------     --------------------
+   |                                |
+   |                                this parameter and the return type are declared with different lifetimes...
 ...
-LL |    let b = bar(f, y);
-   |                   ^ ...but data from `x` is returned here
+LL |     let b = bar(f, y);
+   |                    ^ ...but data from `x` is returned here
 
 error: aborting due to previous error
 
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 23d873212ed..0034d796826 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
@@ -1,60 +1,61 @@
 #![feature(unboxed_closures)]
 #![feature(rustc_attrs)]
-
 // Test for projection cache. We should be able to project distinct
 // lifetimes from `foo` as we reinstantiate it multiple times, but not
 // if we do it just once. In this variant, the region `'a` is used in
 // an invariant position, which affects the results.
 
 // revisions: ok oneuse transmute krisskross
-
 #![allow(dead_code, unused_variables)]
 
 use std::marker::PhantomData;
 
 struct Type<'a> {
     // Invariant
-    data: PhantomData<fn(&'a u32) -> &'a u32>
+    data: PhantomData<fn(&'a u32) -> &'a u32>,
 }
 
-fn foo<'a>() -> Type<'a> { loop { } }
+fn foo<'a>() -> Type<'a> {
+    loop {}
+}
 
 fn bar<T>(t: T, x: T::Output) -> T::Output
-    where T: FnOnce<()>
+where
+    T: FnOnce<()>,
 {
     t()
 }
 
 #[cfg(ok)] // two instantiations: OK
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
     let a = bar(foo, x);
     let b = bar(foo, y);
     (a, b)
 }
 
 #[cfg(oneuse)] // one instantiation: BAD
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   let f = foo; // <-- No consistent type can be inferred for `f` here.
-   let a = bar(f, x);
-   let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
-   (a, b)
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+    let f = foo; // <-- No consistent type can be inferred for `f` here.
+    let a = bar(f, x);
+    let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
+    (a, b)
 }
 
 #[cfg(transmute)] // one instantiations: BAD
-fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
-   // Cannot instantiate `foo` with any lifetime other than `'a`,
-   // since it is provided as input.
+fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
+    // Cannot instantiate `foo` with any lifetime other than `'a`,
+    // since it is provided as input.
 
-   bar(foo, x) //[transmute]~ ERROR E0495
+    bar(foo, x) //[transmute]~ ERROR E0495
 }
 
 #[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); //[krisskross]~ ERROR E0623
-   (a, b)
+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
 }
 
 #[rustc_error]
-fn main() { }
+fn main() {}
 //[ok]~^ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
index f74d4ba73bf..db82c9fd437 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
@@ -1,11 +1,11 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        -- lifetime `'a` defined here
 ...
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
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 0a05fc6bb82..ef57f9e0bc4 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,27 +1,27 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/project-fn-ret-invariant.rs:49:9
    |
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+LL |     bar(foo, x)
+   |         ^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
-  --> $DIR/project-fn-ret-invariant.rs:44:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
+  --> $DIR/project-fn-ret-invariant.rs:45:8
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        ^^
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:13
+  --> $DIR/project-fn-ret-invariant.rs:49:14
    |
-LL |    bar(foo, x)
-   |             ^
+LL |     bar(foo, x)
+   |              ^
    = note: expected `Type<'_>`
               found `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^
    = note: expected `Type<'static>`
               found `Type<'_>`
 
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
new file mode 100644
index 00000000000..2e03986a9ed
--- /dev/null
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/higher-ranked-projection.rs:25:5
+   |
+LL |     foo(());
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
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 3b3e4c3ea11..811c9a8f5e1 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
@@ -1,14 +1,12 @@
-error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+error[E0308]: mismatched types
   --> $DIR/higher-ranked-projection.rs:25:5
    |
-LL | fn foo<U, T>(_t: T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Mirror<Image=U>
-   |                                 ------- required by this bound in `foo`
-...
 LL |     foo(());
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `&'a ()`
+              found type `&()`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs
index 5315e21b0f5..1b5476d4c36 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 fatal error triggered by #[rustc_error]
     foo(());
-    //[bad]~^ ERROR type mismatch
+    //[bad]~^ ERROR mismatched types
 }
diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr
index 6b5a739899c..b00affdca85 100644
--- a/src/test/ui/check-static-values-constraints.stderr
+++ b/src/test/ui/check-static-values-constraints.stderr
@@ -5,7 +5,9 @@ LL |                                           ..SafeStruct{field1: SafeEnum::Va
    |  ___________________________________________^
 LL | |
 LL | |                                                      field2: SafeEnum::Variant1}};
-   | |________________________________________________________________________________^ statics cannot evaluate destructors
+   | |                                                                                ^- value is dropped here
+   | |________________________________________________________________________________|
+   |                                                                                  statics cannot evaluate destructors
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:79:33
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
index 97fdb76dd11..64a0b52a1fa 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
@@ -1,42 +1,43 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
-LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^
+   |                                                 |
+   |                                                 has type `fn(&'1 u32)`
+   |                                                 requires that `'1` must outlive `'x`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^ requires that `'x` must outlive `'static`
+   |
+   = help: consider replacing `'x` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:32:49
+   |
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+   |                                                 ^
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:39:50
+   |
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:48:50
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
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 a4e43da91ba..c81c40c18b4 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
@@ -1,10 +1,12 @@
 fn with_closure_expecting_fn_with_free_region<F>(_: F)
-    where F: for<'a> FnOnce(fn(&'a u32), &i32)
+where
+    F: for<'a> FnOnce(fn(&'a u32), &i32),
 {
 }
 
 fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-    where F: FnOnce(fn(&u32), &i32)
+where
+    F: FnOnce(fn(&u32), &i32),
 {
 }
 
@@ -28,14 +30,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 type mismatch
+    //~^ ERROR mismatched types
 }
 
 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 type mismatch
+    //~^ ERROR mismatched types
 }
 
 fn expect_bound_supply_free_from_closure() {
@@ -44,7 +46,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 type mismatch
+        //~^ ERROR mismatched types
     });
 }
 
@@ -52,8 +54,7 @@ fn expect_bound_supply_bound<'x>(x: &'x u32) {
     // No error in this case. The supplied type supplies the bound
     // regions, and hence we are able to figure out the type of `y`
     // from the expected type
-    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
-    });
+    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {});
 }
 
-fn main() { }
+fn main() {}
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 fae41c4114a..0de15dfa735 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
@@ -1,81 +1,68 @@
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the anonymous lifetime #2 defined on the body at 14:48...
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: the anonymous lifetime #2 defined on the body at 16:48...
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
 
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the lifetime `'x` as defined on the function body at 11:36...
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: the lifetime `'x` as defined on the function body at 13:36...
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:32:52
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
-...
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+   |                                                    ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `fn(&u32)`
+              found fn pointer `for<'r> fn(&'r u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:39:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&'x u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:48:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&u32)`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs
index 5cae0e76d1a..af1e37ba867 100644
--- a/src/test/ui/closures/issue-41366.rs
+++ b/src/test/ui/closures/issue-41366.rs
@@ -7,7 +7,6 @@ impl<'g> T<'g> for u32 {
 }
 
 fn main() {
-    (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+    (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
     //~^ ERROR: type mismatch in closure arguments
-    //~| ERROR: type mismatch resolving
 }
diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr
index 2f2871e9f0e..9c4b7d529ef 100644
--- a/src/test/ui/closures/issue-41366.stderr
+++ b/src/test/ui/closures/issue-41366.stderr
@@ -1,23 +1,14 @@
 error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-41366.rs:10:5
    |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^-----^
+LL |     (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |     ^^------^
    |     | |
-   |     | found signature of `fn(_) -> _`
-   |     expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
+   |     | found signature of `fn(u16) -> _`
+   |     expected signature of `fn(<u32 as T<'x>>::V) -> _`
    |
    = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
 
-error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
-  --> $DIR/issue-41366.rs:10:5
-   |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
-   |
-   = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs
new file mode 100644
index 00000000000..99f805f7f0f
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs
@@ -0,0 +1,26 @@
+// Test that impls for these two types are considered ovelapping:
+//
+// * `for<'r> fn(fn(&'r u32))`
+// * `fn(fn(&'a u32)` where `'a` is free
+//
+// This is because, for `'a = 'static`, the two types overlap.
+// Effectively for them to be equal to you get:
+//
+// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
+//   * true if `exists<'r> { 'r: 'static }` (obviously true)
+// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))`
+//   * true if `forall<'r> { 'static: 'r }` (also true)
+
+trait Trait {}
+
+impl Trait for for<'r> fn(fn(&'r ())) {}
+impl<'a> Trait for fn(fn(&'a ())) {}
+//~^ ERROR conflicting implementations
+//
+// Note in particular that we do NOT get a future-compatibility warning
+// here. This is because the new leak-check proposed in [MCP 295] does not
+// "error" when these two types are equated.
+//
+// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
new file mode 100644
index 00000000000..49271edf8e5
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`:
+  --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
+   |
+LL | impl Trait for for<'r> fn(fn(&'r ())) {}
+   | ------------------------------------- first implementation here
+LL | impl<'a> Trait for fn(fn(&'a ())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
+   |
+   = 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-fn-implied-bounds.rs b/src/test/ui/coherence/coherence-fn-implied-bounds.rs
new file mode 100644
index 00000000000..4539af9a32e
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-implied-bounds.rs
@@ -0,0 +1,26 @@
+// Test that our leak-check is not smart enough to take implied bounds
+// into account (yet). Here we have two types that look like they
+// should not be equivalent, but because of the rules on implied
+// bounds we ought to know that, in fact, `'a = 'b` must always hold,
+// and hence they are.
+//
+// Rustc can't figure this out and hence it accepts the impls but
+// gives a future-compatibility warning (because we'd like to make
+// this an error someday).
+//
+// Note that while we would like to make this a hard error, we also
+// give the same warning for `coherence-wasm-bindgen.rs`, which ought
+// to be accepted.
+
+#![deny(coherence_leak_check)]
+
+trait Trait {}
+
+impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+
+impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+    //~^ ERROR conflicting implementations
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr
new file mode 100644
index 00000000000..a3e7f0bcde3
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`:
+  --> $DIR/coherence-fn-implied-bounds.rs:21:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+   | ------------------------------------------------------------------ first implementation here
+LL | 
+LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-fn-implied-bounds.rs:15:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = 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
+
diff --git a/src/test/ui/coherence/coherence-fn-inputs.rs b/src/test/ui/coherence/coherence-fn-inputs.rs
new file mode 100644
index 00000000000..3afec5c5459
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-inputs.rs
@@ -0,0 +1,25 @@
+// Test that we consider these two types completely equal:
+//
+// * `for<'a, 'b> fn(&'a u32, &'b u32)`
+// * `for<'c> fn(&'c u32, &'c u32)`
+//
+// For a long time we considered these to be distinct types. But in fact they
+// are equivalent, if you work through the implications of subtyping -- this is
+// because:
+//
+// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
+// * `'a` and `'b` can both be equal to `'c`
+
+trait Trait {}
+impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+impl Trait for for<'c> fn(&'c u32, &'c u32) {
+    //~^ ERROR conflicting implementations
+    //
+    // Note in particular that we do NOT get a future-compatibility warning
+    // here. This is because the new leak-check proposed in [MCP 295] does not
+    // "error" when these two types are equated.
+    //
+    // [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-inputs.stderr b/src/test/ui/coherence/coherence-fn-inputs.stderr
new file mode 100644
index 00000000000..56ab873a393
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-inputs.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`:
+  --> $DIR/coherence-fn-inputs.rs:15:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+   | ----------------------------------------------- first implementation here
+LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
+   |
+   = 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-free-vs-bound-region.rs b/src/test/ui/coherence/coherence-free-vs-bound-region.rs
new file mode 100644
index 00000000000..2f5c49d293d
--- /dev/null
+++ b/src/test/ui/coherence/coherence-free-vs-bound-region.rs
@@ -0,0 +1,21 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait TheTrait {}
+
+impl<'a> TheTrait for fn(&'a u8) {}
+
+impl TheTrait for fn(&u8) {
+    //~^ ERROR conflicting implementations of trait
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.stderr b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr
new file mode 100644
index 00000000000..97aa4912721
--- /dev/null
+++ b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`:
+  --> $DIR/coherence-free-vs-bound-region.rs:16:1
+   |
+LL | impl<'a> TheTrait for fn(&'a u8) {}
+   | -------------------------------- first implementation here
+LL | 
+LL | impl TheTrait for fn(&u8) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-free-vs-bound-region.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = 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
+
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.rs b/src/test/ui/coherence/coherence-wasm-bindgen.rs
new file mode 100644
index 00000000000..ee09a72449b
--- /dev/null
+++ b/src/test/ui/coherence/coherence-wasm-bindgen.rs
@@ -0,0 +1,37 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait IntoWasmAbi {
+    fn some_method(&self) {}
+}
+
+trait FromWasmAbi {}
+trait RefFromWasmAbi {}
+trait ReturnWasmAbi {}
+
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+where
+    A: FromWasmAbi,
+    R: ReturnWasmAbi,
+{
+}
+
+// Explicitly writing the bound lifetime.
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+where
+    A: RefFromWasmAbi,
+    R: ReturnWasmAbi,
+{
+    //~^^^^^ ERROR conflicting implementation
+    //~| WARNING this was previously accepted
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.stderr b/src/test/ui/coherence/coherence-wasm-bindgen.stderr
new file mode 100644
index 00000000000..c77483bb847
--- /dev/null
+++ b/src/test/ui/coherence/coherence-wasm-bindgen.stderr
@@ -0,0 +1,32 @@
+error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`:
+  --> $DIR/coherence-wasm-bindgen.rs:28:1
+   |
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+LL | | where
+LL | |     A: FromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+LL | | {
+LL | | }
+   | |_- first implementation here
+...
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+LL | | where
+LL | |     A: RefFromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+...  |
+LL | |
+LL | | }
+   | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-wasm-bindgen.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: downstream crates may implement trait `FromWasmAbi` for type `&_`
+   = 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
+
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
index ad38b632b75..4a6241de1b4 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
@@ -14,6 +14,7 @@ LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
    |
    = note: type arguments must be provided before constant arguments
+   = help: reorder the arguments: types, then consts: `<T, N>`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs
index afa577fa67f..90c438b05cb 100644
--- a/src/test/ui/const-generics/fn-const-param-call.rs
+++ b/src/test/ui/const-generics/fn-const-param-call.rs
@@ -1,15 +1,14 @@
-// run-pass
-
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 fn function() -> u32 {
     17
 }
 
-struct Wrapper<const F: fn() -> u32>;
+struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
 
 impl<const F: fn() -> u32> Wrapper<F> {
+//~^ ERROR: using function pointers as const generic parameters
     fn call() -> u32 {
         F()
     }
diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr
index 9c0f7e3ab9b..b5811243caa 100644
--- a/src/test/ui/const-generics/fn-const-param-call.stderr
+++ b/src/test/ui/const-generics/fn-const-param-call.stderr
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-const-param-call.rs:3:12
+  --> $DIR/fn-const-param-call.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:8:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:10:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs
index 08f6e0db31c..14fa3b494b3 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.rs
+++ b/src/test/ui/const-generics/fn-const-param-infer.rs
@@ -1,7 +1,8 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 struct Checked<const F: fn(usize) -> bool>;
+//~^ ERROR: using function pointers as const generic parameters
 
 fn not_one(val: usize) -> bool { val != 1 }
 fn not_two(val: usize) -> bool { val != 2 }
@@ -13,14 +14,14 @@ fn generic<T>(val: usize) -> bool { val != 1 }
 fn main() {
     let _: Option<Checked<not_one>> = None;
     let _: Checked<not_one> = Checked::<not_one>;
-    let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
+    let _: Checked<not_one> = Checked::<not_two>;
 
     let _ = Checked::<generic_arg>;
     let _ = Checked::<{generic_arg::<usize>}>;
-    let _ = Checked::<{generic_arg::<u32>}>;  //~ mismatched types
+    let _ = Checked::<{generic_arg::<u32>}>;
 
-    let _ = Checked::<generic>; //~ type annotations needed
+    let _ = Checked::<generic>;
     let _ = Checked::<{generic::<u16>}>;
     let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
-    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
+    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
 }
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
index de41d2984a6..7aaa41eb7d7 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -1,46 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/fn-const-param-infer.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:16:31
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:4:25
    |
-LL |     let _: Checked<not_one> = Checked::<not_two>;
-   |                               ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
-   |
-   = note: expected type `{not_one as fn(usize) -> bool}`
-              found type `{not_two as fn(usize) -> bool}`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:20:24
-   |
-LL |     let _ = Checked::<{generic_arg::<u32>}>;
-   |                        ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
-   |
-   = note: expected fn pointer `fn(usize) -> _`
-                 found fn item `fn(u32) -> _ {generic_arg::<u32>}`
-
-error[E0282]: type annotations needed
-  --> $DIR/fn-const-param-infer.rs:22:23
-   |
-LL |     let _ = Checked::<generic>;
-   |                       ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:25:40
-   |
-LL |     let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
-   |
-   = note: expected type `{generic::<u32> as fn(usize) -> bool}`
-              found type `{generic::<u16> as fn(usize) -> bool}`
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
index c498bfe2e97..97ca9d6a44c 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
@@ -1,12 +1,11 @@
-// run-pass
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 const A: u32 = 3;
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
-impl<const P: *const u32> Const<P> {
+impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
     fn get() -> u32 {
         unsafe {
             *P
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
index 1ffc63ffdac..1ce8bb9c054 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-ptr-const-param-deref.rs:2:12
+  --> $DIR/raw-ptr-const-param-deref.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:6:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:8:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs
index d7d970e952b..237b410e073 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param.rs
@@ -1,9 +1,9 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
 fn main() {
-    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
+    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
     let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
 }
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr
index 7a665397c12..6e64f8a327f 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr
@@ -1,21 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/raw-ptr-const-param.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/raw-ptr-const-param.rs:7:40
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:4:23
    |
-LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
-   |
-   = note: expected type `{0xf as *const u32}`
-              found type `{0xa as *const u32}`
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/consts/const-eval/const_let.stderr b/src/test/ui/consts/const-eval/const_let.stderr
index 4753222a7c0..47f39b703e4 100644
--- a/src/test/ui/consts/const-eval/const_let.stderr
+++ b/src/test/ui/consts/const-eval/const_let.stderr
@@ -2,25 +2,33 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:16:32
    |
 LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-   |                                ^^^^^ constants cannot evaluate destructors
+   |                                ^^^^^                  - value is dropped here
+   |                                |
+   |                                constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:20:33
    |
 LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-   |                                 ^^^^^ constants cannot evaluate destructors
+   |                                 ^^^^^                     - value is dropped here
+   |                                 |
+   |                                 constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:24:21
    |
 LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
-   |                     ^^^^^ constants cannot evaluate destructors
+   |                     ^^^^^                                  - value is dropped here
+   |                     |
+   |                     constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:28:22
    |
 LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
-   |                      ^^^^^ constants cannot evaluate destructors
+   |                      ^^^^^                                     - value is dropped here
+   |                      |
+   |                      constants cannot evaluate destructors
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
index 9be1374f85d..e238e13b8e2 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
@@ -1,17 +1,6 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
-
 fn main() {}
 
 // unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
-// unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
-// unconst and fine
-const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
-// unconst and bad, will thus error in miri
-const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
-// unconst and fine
-const Z: i32 = unsafe { *(&1 as *const i32) };
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
 // unconst and bad, will thus error in miri
-const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
-const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
index cc40728e6b5..21d3f5e7e85 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
@@ -1,44 +1,18 @@
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:6:26
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:4:26
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
-   | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[deny(const_err)]` on by default
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:8:27
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:6:27
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
-   | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                           |
-   |                           "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:12:28
-   |
-LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
-   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
-   |                            |
-   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:16:26
-   |
-LL | const Z2: i32 = unsafe { *(42 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:17:26
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | const Z3: i32 = unsafe { *(44 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
new file mode 100644
index 00000000000..d2a7623837a
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
@@ -0,0 +1,13 @@
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+
+fn main() {}
+
+// unconst and fine
+const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
+// unconst and bad, will thus error in miri
+const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
+// unconst and fine
+const Z: i32 = unsafe { *(&1 as *const i32) };
+// unconst and bad, will thus error in miri
+const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
+const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
new file mode 100644
index 00000000000..93f2261745d
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
@@ -0,0 +1,28 @@
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:8:28
+   |
+LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
+   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
+   |                            |
+   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:12:26
+   |
+LL | const Z2: i32 = unsafe { *(42 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:13:26
+   |
+LL | const Z3: i32 = unsafe { *(44 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index f843a94fabd..771d368d783 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -9,6 +9,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
    |
 LL |     let mut x = Vec::<i32>::new();
    |         ^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/livedrop.rs b/src/test/ui/consts/const-eval/livedrop.rs
new file mode 100644
index 00000000000..f00d1c70659
--- /dev/null
+++ b/src/test/ui/consts/const-eval/livedrop.rs
@@ -0,0 +1,20 @@
+#![feature(const_if_match)]
+#![feature(const_loop)]
+
+const _: Option<Vec<i32>> = {
+    let mut never_returned = Some(Vec::new());
+    let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time
+
+    let mut i = 0;
+    loop {
+        always_returned = never_returned;
+        never_returned = None;
+
+        i += 1;
+        if i == 10 {
+            break always_returned;
+        }
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/livedrop.stderr b/src/test/ui/consts/const-eval/livedrop.stderr
new file mode 100644
index 00000000000..b802d23d9a8
--- /dev/null
+++ b/src/test/ui/consts/const-eval/livedrop.stderr
@@ -0,0 +1,12 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/livedrop.rs:6:9
+   |
+LL |     let mut always_returned = None;
+   |         ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+...
+LL |         always_returned = never_returned;
+   |         --------------- value is dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
index c6fb5eeab5a..d724fe3060b 100644
--- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
+++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
@@ -1,4 +1,4 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
 
 fn main() {
     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
diff --git a/src/test/ui/consts/control-flow/drop-fail.stock.stderr b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
index 77cded5c438..6a9ea91d20e 100644
--- a/src/test/ui/consts/control-flow/drop-fail.stock.stderr
+++ b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
@@ -3,24 +3,36 @@ error[E0493]: destructors cannot be evaluated at compile-time
    |
 LL |     let x = Some(Vec::new());
    |         ^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:23:9
    |
 LL |     let vec_tuple = (Vec::new(),);
    |         ^^^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:31:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
    |         ^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:41:9
    |
 LL |     let mut tmp = None;
    |         ^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index 512b343011b..4b0401ebf9d 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:37:25
    |
 LL |     const fn into_inner(self) -> T { self.0 }
-   |                         ^^^^ constant functions cannot evaluate destructors
+   |                         ^^^^                - value is dropped here
+   |                         |
+   |                         constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:39:36
@@ -17,7 +19,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:44:28
    |
 LL |     const fn into_inner_lt(self) -> T { self.0 }
-   |                            ^^^^ constant functions cannot evaluate destructors
+   |                            ^^^^                - value is dropped here
+   |                            |
+   |                            constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:46:42
@@ -32,7 +36,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:51:27
    |
 LL |     const fn into_inner_s(self) -> T { self.0 }
-   |                           ^^^^ constant functions cannot evaluate destructors
+   |                           ^^^^                - value is dropped here
+   |                           |
+   |                           constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:53:38
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
index 37016664ac5..0b6cb2fab46 100644
--- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
    |
 LL |     const F: u32 = (U::X, 42).1;
-   |                    ^^^^^^^^^^ constants cannot evaluate destructors
+   |                    ^^^^^^^^^^ - value is dropped here
+   |                    |
+   |                    constants cannot evaluate destructors
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
index 805ba9c6b03..21f11dda5a6 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -12,7 +12,7 @@ LL |     let _v = x + 0;
 
 warning: skipping const checks
    |
-help: skipping check for `const_compare_raw_pointers` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/ptr_arith.rs:9:14
    |
 LL |     let _v = x == x;
diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs
new file mode 100644
index 00000000000..fd843105daf
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/slice_eq.rs
@@ -0,0 +1,17 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+// run-pass
+
+#![feature(const_raw_ptr_comparison)]
+
+const EMPTY_SLICE: &[i32] = &[];
+const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
+const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
+const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
+const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
+
+fn main() {
+    assert!(!EMPTY_EQ);
+    assert!(!EMPTY_EQ2);
+    assert!(!EMPTY_NE);
+    assert!(!EMPTY_NE2);
+}
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
index a8455cefd01..928605356a1 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -9,12 +9,18 @@ error[E0493]: destructors cannot be evaluated at compile-time
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                                     ^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:47
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                               ^^^^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs
index bbefff27d7f..d2edd97efb2 100644
--- a/src/test/ui/error-codes/E0395.rs
+++ b/src/test/ui/error-codes/E0395.rs
@@ -1,10 +1,8 @@
-// gate-test-const_compare_raw_pointers
-
 static FOO: i32 = 42;
 static BAR: i32 = 42;
 
 static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR comparing raw pointers inside static
+//~^ ERROR pointers cannot be reliably compared during const eval
 
 fn main() {
 }
diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr
index 20c8622f337..674cc696450 100644
--- a/src/test/ui/error-codes/E0395.stderr
+++ b/src/test/ui/error-codes/E0395.stderr
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside static
-  --> $DIR/E0395.rs:6:29
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/E0395.rs:4:29
    |
 LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
index 1ab11ce3b44..dc602ba7e6f 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
@@ -1,9 +1,9 @@
 struct ConstFn<const F: fn()>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is unstable
+//~^^ ERROR using function pointers as const generic parameters is forbidden
 
 struct ConstPtr<const P: *const u32>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is unstable
+//~^^ ERROR using raw pointers as const generic parameters is forbidden
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
index dc7ef55e7ab..b2c96d3810f 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
@@ -16,23 +16,17 @@ LL | struct ConstPtr<const P: *const u32>;
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
-error[E0658]: using function pointers as const generic parameters is unstable
+error: using function pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:1:25
    |
 LL | struct ConstFn<const F: fn()>;
    |                         ^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
-error[E0658]: using raw pointers as const generic parameters is unstable
+error: using raw pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:5:26
    |
 LL | struct ConstPtr<const P: *const u32>;
    |                          ^^^^^^^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
new file mode 100644
index 00000000000..7d712191924
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/resume-arg-late-bound.rs b/src/test/ui/generator/resume-arg-late-bound.rs
index 87b1f1a065b..a8f657eaabe 100644
--- a/src/test/ui/generator/resume-arg-late-bound.rs
+++ b/src/test/ui/generator/resume-arg-late-bound.rs
@@ -13,5 +13,6 @@ fn main() {
         *arg = true;
     };
     test(gen);
-    //~^ ERROR type mismatch in function arguments
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr
index ffa440daed8..c379d9eae8e 100644
--- a/src/test/ui/generator/resume-arg-late-bound.stderr
+++ b/src/test/ui/generator/resume-arg-late-bound.stderr
@@ -1,15 +1,21 @@
-error[E0631]: type mismatch in function arguments
-  --> $DIR/resume-arg-late-bound.rs:15:10
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
    |
-LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
-   |                 ------------------------------- required by this bound in `test`
-...
 LL |     test(gen);
-   |          ^^^
-   |          |
-   |          expected signature of `for<'a> fn(&'a mut bool) -> _`
-   |          found signature of `fn(&mut bool) -> _`
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
+
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
new file mode 100644
index 00000000000..d5343566633
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+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) }
+   | |_____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
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 b91798fa123..92a85825030 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
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 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) }
-   | |_________________________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
               found enum `std::option::Option<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 45f53d4fe99..94837556610 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,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-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 enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
-              found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 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 6aba6466fad..94837556610 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,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 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 6aba6466fad..94837556610 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,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
new file mode 100644
index 00000000000..f1156093967
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
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 c3e4f6d2ed0..98f5bff7327 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
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-LL | |                              fn(&'x u32)) }
-   | |___________________________________________- in this macro invocation
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a> fn(&'a u32)>`
               found enum `std::option::Option<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 4d7b86027f5..94837556610 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,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-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 enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 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 7f0a4197dd7..94837556610 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,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-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 enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 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 6aba6466fad..94837556610 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,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 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 c12e543a44e..94837556610 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,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-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 enum `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
-              found enum `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 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.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
new file mode 100644
index 00000000000..4541c462ee0
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
@@ -0,0 +1,26 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+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>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+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>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
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 460356856bd..100ba6ac27e 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
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 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>)) }
-   | |__________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
               found enum `std::option::Option<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 6aba6466fad..94837556610 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,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
index 6b5e7a5a634..af5cf41be0a 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
@@ -1,33 +1,33 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:33:13
+  --> $DIR/hr-subtype.rs:39:13
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                      -- -- lifetime `'y` defined here
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                      --  -- lifetime `'y` defined here
    |                      |
    |                      lifetime `'x` defined here
 LL |               gimme::<$t2>(None::<$t1>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
index fc3643306e6..3c8af20e50c 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
@@ -1,65 +1,65 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:33:26
+  --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t2>(None::<$t1>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'y>)>`
               found enum `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime `'x` as defined on the function body at 32:20...
-  --> $DIR/hr-subtype.rs:32:20
+note: the lifetime `'x` as defined on the function body at 38:20...
+  --> $DIR/hr-subtype.rs:38:20
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
    |                      ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
-  --> $DIR/hr-subtype.rs:32:23
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24
+  --> $DIR/hr-subtype.rs:38:24
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                         ^^
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                          ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'x>)>`
               found enum `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
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 6aba6466fad..94837556610 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,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
index 7c0770924da..75d7e0e46b7 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
@@ -1,16 +1,16 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
index 0dde27788f6..7b4cdd4a419 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
@@ -1,33 +1,33 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(&'x u32)>`
               found enum `std::option::Option<fn(&'y u32)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs
index b31f198bd97..ad9500eedca 100644
--- a/src/test/ui/hr-subtype/hr-subtype.rs
+++ b/src/test/ui/hr-subtype/hr-subtype.rs
@@ -18,60 +18,62 @@
 // revisions: bound_inv_a_b_vs_bound_inv_a
 // revisions: bound_a_b_ret_a_vs_bound_a_ret_a
 
-fn gimme<T>(_: Option<T>) { }
+fn gimme<T>(_: Option<T>) {}
 
-struct Inv<'a> { x: *mut &'a u32 }
+struct Inv<'a> {
+    x: *mut &'a u32,
+}
 
-struct Co<'a> { x: fn(&'a u32) }
+struct Co<'a> {
+    x: fn(&'a u32),
+}
 
-struct Contra<'a> { x: &'a u32 }
+struct Contra<'a> {
+    x: &'a u32,
+}
 
 macro_rules! check {
     ($rev:ident: ($t1:ty, $t2:ty)) => {
         #[cfg($rev)]
-        fn subtype<'x,'y:'x,'z:'y>() {
+        fn subtype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t2>(None::<$t1>);
             //[free_inv_x_vs_free_inv_y]~^ ERROR
         }
 
         #[cfg($rev)]
-        fn supertype<'x,'y:'x,'z:'y>() {
+        fn supertype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t1>(None::<$t2>);
             //[bound_a_vs_free_x]~^ ERROR
             //[free_x_vs_free_y]~^^ ERROR
             //[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
         }
-    }
+    };
 }
 
 // If both have bound regions, they are equivalent, regardless of
 // variant.
 check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
-                              for<'a> fn(&'a u32)) }
+for<'a> fn(&'a u32)) }
 check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
-                              for<'b> fn(&'b u32)) }
+for<'b> fn(&'b u32)) }
 check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
-                                      for<'b> fn(Inv<'b>)) }
+for<'b> fn(Inv<'b>)) }
 check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
-                                    for<'b> fn(Co<'b>)) }
+for<'b> fn(Co<'b>)) }
 
 // Bound is a subtype of free.
 check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-                             fn(&'x u32)) }
+fn(&'x u32)) }
 
 // Two free regions are relatable if subtyping holds.
 check! { free_x_vs_free_x: (fn(&'x u32),
-                            fn(&'x u32)) }
+fn(&'x u32)) }
 check! { free_x_vs_free_y: (fn(&'x u32),
-                            fn(&'y u32)) }
+fn(&'y u32)) }
 check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-                                    fn(Inv<'y>)) }
+fn(Inv<'y>)) }
 
 // Somewhat surprisingly, a fn taking two distinct bound lifetimes and
 // a fn taking one bound lifetime can be interchangeable, but only if
@@ -82,25 +84,29 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
 //   intersection;
 // - if we are contravariant, then 'a can be inferred to 'static.
 check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-                                for<'a>    fn(&'a u32, &'a u32)) }
+for<'a>    fn(&'a u32, &'a u32)) }
 check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-                                      for<'a>    fn(Co<'a>, Co<'a>)) }
+for<'a>    fn(Co<'a>, Co<'a>)) }
 check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-                                            for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
 check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-                                        for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
 
 // If we make those lifetimes invariant, then the two types are not interchangeable.
 check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-                                        for<'a>    fn(Inv<'a>, Inv<'a>)) }
+for<'a>    fn(Inv<'a>, Inv<'a>)) }
 check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-                                            for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
 
 #[rustc_error]
 fn main() {
-//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
-//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
-//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR
+    //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
+    //[bound_a_b_vs_bound_a]~^^^^^^^^ ERROR
+    //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR
 }
diff --git a/src/test/ui/hr-subtype/return-static.rs b/src/test/ui/hr-subtype/return-static.rs
new file mode 100644
index 00000000000..6455854f34d
--- /dev/null
+++ b/src/test/ui/hr-subtype/return-static.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn make<T>() -> T {
+    panic!()
+}
+
+fn take<T>(x: T) {}
+
+fn main() {
+    let x: for<'a> fn(&'a u32) -> _ = make();
+    let y: &'static u32 = x(&22);
+    take::<for<'b> fn(&'b u32) -> &'b u32>(x);
+}
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
new file mode 100644
index 00000000000..f290a93326f
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
index 7250935ea29..45573814d13 100644
--- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
-  --> $DIR/hrtb-conflate-regions.rs:27:22
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-conflate-regions.rs:27:10
    |
-LL | fn want_foo2<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
-   |               -------------------------------------- required by this bound in `want_foo2`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL | fn b() { want_foo2::<SomeStruct>(); }
-   |                      ^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
+LL |   fn b() { want_foo2::<SomeStruct>(); }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <SomeStruct as Foo<(&'a isize, &'a isize)>>
+   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 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.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
new file mode 100644
index 00000000000..11390d9e2d2
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-fn.rs:17:12
+   |
+LL |     let _: for<'b> fn(&'b u32) = foo();
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
index 328e98657ef..9914783d976 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
@@ -2,9 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-exists-forall-fn.rs:17:34
    |
 LL |     let _: for<'b> fn(&'b u32) = foo();
-   |            -------------------   ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
-   |            |
-   |            expected due to this
+   |                                  ^^^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'b> fn(&'b u32)`
               found fn pointer `fn(&u32)`
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
new file mode 100644
index 00000000000..a4c3ffd1f6c
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 4c1d4d28a09..921061916fc 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
@@ -32,5 +32,5 @@ fn main() {
     // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `Trait` is not general enough
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
index 7a7285d3d76..fe8209d054c 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
@@ -1,18 +1,14 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(&'b u32)>,
-   |        -------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(&'a u32)>>
+   = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+   = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
 
 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 95b57d6c5bb..f95496a6c3c 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
@@ -2,6 +2,8 @@
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
+//
+// check-pass
 
 trait Trait<T> {}
 
@@ -30,9 +32,6 @@ 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
deleted file mode 100644
index 1e335f9ee96..00000000000
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11
-   |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(fn(&'b u32))>,
-   |        ------------------------------ required by this bound in `foo`
-...
-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))>>
-
-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.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
new file mode 100644
index 00000000000..e2a399b2faa
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 827a68beee8..b1b7ec6bcf1 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 satisfied
+    foo::<()>(); //~ ERROR implementation of `Trait` is not general enough
 }
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 9174ea4d841..720e2276d53 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
@@ -1,18 +1,14 @@
-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:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(Cell<&'b u32>)>,
-   |        -------------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+   = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
+   = note: ...but `()` actually implements `Trait<fn(std::cell::Cell<&'0 u32>)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
new file mode 100644
index 00000000000..8901a1b4681
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
@@ -0,0 +1,24 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:24:5
+   |
+LL |     want_hrtb::<StaticInt>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL | fn give_some<'a>() {
+   |              -- lifetime `'a` defined here
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr
index 4fa40462477..5e3014317f5 100644
--- a/src/test/ui/hrtb/hrtb-just-for-static.stderr
+++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr
@@ -1,31 +1,30 @@
-error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:24:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:24:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<StaticInt>()
-   |                 ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
+LL |       want_hrtb::<StaticInt>()
+   |       ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <StaticInt as Foo<&'static isize>>
+   = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
 
-error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:30:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<&'a u32>()
-   |                 ^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+LL |       want_hrtb::<&'a u32>()
+   |       ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <&'a u32 as Foo<&'a isize>>
+   = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
+   = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
index c0e3fd3cf46..90a7cadca41 100644
--- a/src/test/ui/hrtb/issue-30786.migrate.stderr
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -1,17 +1,43 @@
-error: implementation of `Stream` is not general enough
-  --> $DIR/issue-30786.rs:108:22
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
    |
-LL | / pub trait Stream {
-LL | |     type Item;
-LL | |     fn next(self) -> Option<Self::Item>;
-LL | | }
-   | |_- trait `Stream` defined here
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
 ...
-LL |       let map = source.map(|x: &_| x);
-   |                        ^^^ implementation of `Stream` is not general enough
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
    |
-   = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
-   = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
 
-error: aborting due to previous error
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
index c736c5479f8..90a7cadca41 100644
--- a/src/test/ui/hrtb/issue-30786.nll.stderr
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -1,56 +1,43 @@
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:108:15
-   |
-LL |     let map = source.map(|x: &_| x);
-   |               ^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
-
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
+   |
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
+   |
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
index c656f843065..8ce5c090b54 100644
--- a/src/test/ui/hrtb/issue-30786.rs
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -16,7 +16,7 @@
 
 //[nll]compile-flags: -Z borrowck=mir
 
-pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
+pub trait Stream {
     type Item;
     fn next(self) -> Option<Self::Item>;
 }
@@ -37,8 +37,9 @@ pub struct Map<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Map<A, F>
-where &'a mut A: Stream,
-      F: FnMut(<&'a mut A as Stream>::Item) -> T,
+where
+    &'a mut A: Stream,
+    F: FnMut(<&'a mut A as Stream>::Item) -> T,
 {
     type Item = T;
     fn next(self) -> Option<T> {
@@ -55,8 +56,9 @@ pub struct Filter<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
-where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
-      F: FnMut(&T) -> bool,
+where
+    for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+    F: FnMut(&T) -> bool,
 {
     type Item = <&'a mut A as Stream>::Item;
     fn next(self) -> Option<Self::Item> {
@@ -69,29 +71,29 @@ where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
     }
 }
 
-pub trait StreamExt where for<'b> &'b mut Self: Stream {
-    fn map<F>(self, func: F) -> Map<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Map<Self, F>: Stream,
+pub trait StreamExt
+where
+    for<'b> &'b mut Self: Stream,
+{
+    fn mapx<F>(self, func: F) -> Map<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Map<Self, F>: Stream,
     {
-        Map {
-            func: func,
-            stream: self,
-        }
+        Map { func: func, stream: self }
     }
 
-    fn filter<F>(self, func: F) -> Filter<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Filter<Self, F>: Stream,
+    fn filterx<F>(self, func: F) -> Filter<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Filter<Self, F>: Stream,
     {
-        Filter {
-            func: func,
-            stream: self,
-        }
+        Filter { func: func, stream: self }
     }
 
-    fn count(mut self) -> usize
-    where Self: Sized,
+    fn countx(mut self) -> usize
+    where
+        Self: Sized,
     {
         let mut count = 0;
         while let Some(_) = self.next() {
@@ -101,24 +103,44 @@ pub trait StreamExt where for<'b> &'b mut Self: Stream {
     }
 }
 
-impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
 
-fn main() {
+fn identity<T>(x: &T) -> &T {
+    x
+}
+
+fn variant1() {
     let source = Repeat(10);
-    let map = source.map(|x: &_| x);
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[migrate]~^^ ERROR implementation of `Stream` is not general enough
-    //[migrate]~| NOTE  `Stream` would have to be implemented for the type `&'0 mut Map
-    //[migrate]~| NOTE  but `Stream` is actually implemented for the type `&'1
-    //[migrate]~| NOTE  implementation of `Stream` is not general enough
-    let filter = map.filter(|x: &_| true);
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    let count = filter.count(); // Assert that we still have a valid stream.
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
+
+    // Here, the call to `mapx` returns a type `T` to which `StreamExt`
+    // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
+    //
+    // More concretely, the type `T` is `Map<Repeat, Closure>`, and
+    // the where clause doesn't hold because the signature of the
+    // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
+    // for some specific `'_`, rather than a more generic
+    // signature.
+    //
+    // Why *exactly* we opt for this signature is a bit unclear to me,
+    // we deduce it somehow from a reuqirement that `Map: Stream` I
+    // guess.
+    let map = source.mapx(|x: &_| x);
+    let filter = map.filterx(|x: &_| true);
+    //[migrate]~^ ERROR no method named `filterx`
+    //[nll]~^^ ERROR no method named `filterx`
 }
+
+fn variant2() {
+    let source = Repeat(10);
+
+    // Here, we use a function, which is not subject to the vagaries
+    // of closure signature inference. In this case, we get the error
+    // on `countx` as, I think, the test originally expected.
+    let map = source.mapx(identity);
+    let filter = map.filterx(|x: &_| true);
+    let count = filter.countx();
+    //[migrate]~^ ERROR no method named `countx`
+    //[nll]~^^ ERROR no method named `countx`
+}
+
+fn main() {}
diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr
new file mode 100644
index 00000000000..6c127b92d97
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-46989.rs:38:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs
index 2c859055458..4a09f4be156 100644
--- a/src/test/ui/hrtb/issue-46989.rs
+++ b/src/test/ui/hrtb/issue-46989.rs
@@ -28,15 +28,13 @@
 //
 // holds because 'a can be instantiated to 'empty.
 
-trait Foo {
+trait Foo {}
 
-}
-
-impl<A> Foo for fn(A) { }
+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
+    //~^ ERROR implementation of `Foo` is not general enough
 }
diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr
index 0a7382c4dd8..c85c37ff923 100644
--- a/src/test/ui/hrtb/issue-46989.stderr
+++ b/src/test/ui/hrtb/issue-46989.stderr
@@ -1,15 +1,14 @@
-error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
-  --> $DIR/issue-46989.rs:40:18
+error: implementation of `Foo` is not general enough
+  --> $DIR/issue-46989.rs:38:5
    |
-LL | fn assert_foo<T: Foo>() {}
-   |                  --- required by this bound in `assert_foo`
+LL | trait Foo {}
+   | ------------ trait `Foo` defined here
 ...
 LL |     assert_foo::<fn(&i32)>();
-   |                  ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <fn(A) as Foo>
+   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+   = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index ca9ca8a9deb..3b339c5c3d7 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -53,7 +53,15 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               -        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |               |
+   |               let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
@@ -62,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -72,14 +80,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    = help: consider adding the following bound: `'b: 'a`
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:43:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                                   ^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0310, E0621.
 For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
index 837244b0227..9bf86fa66cd 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
@@ -27,6 +27,10 @@ fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
 fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
 //~^ ERROR cannot infer an appropriate lifetime
 
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+//~^ ERROR cannot infer an appropriate lifetime
+//~| ERROR cannot infer an appropriate lifetime
+
 trait LifetimeTrait<'a> {}
 impl<'a> LifetimeTrait<'a> for &'a i32 {}
 
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index e1fa4f02b6f..ffadcaae08e 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -87,13 +87,48 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`...     ^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |                                         ^^^^^^^^^^
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ------- this data with lifetime `'a`...        ^ ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:34
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:34
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x
    |                      ^^^^^^^^^^^^
 
 error[E0623]: lifetime mismatch
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                                                 -------     ^^^^^^^^^^^^^^^^
@@ -116,7 +151,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                 this parameter and the return type are declared with different lifetimes...
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:43:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
@@ -181,7 +216,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0310, E0621, E0623, E0759.
 For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs
index 36a69cf4c22..d1093c20579 100644
--- a/src/test/ui/issues/issue-25826.rs
+++ b/src/test/ui/issues/issue-25826.rs
@@ -1,6 +1,6 @@
 fn id<T>(t: T) -> T { t }
 fn main() {
     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
-    //~^ ERROR comparing raw pointers inside constant
+    //~^ ERROR pointers cannot be reliably compared during const eval
     println!("{}", A);
 }
diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr
index 3a5a6b509ba..67d1b3ab9be 100644
--- a/src/test/ui/issues/issue-25826.stderr
+++ b/src/test/ui/issues/issue-25826.stderr
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside constant
+error: pointers cannot be reliably compared during const eval.
   --> $DIR/issue-25826.rs:3:30
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr
new file mode 100644
index 00000000000..f673fbae8b7
--- /dev/null
+++ b/src/test/ui/issues/issue-40000.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-40000.rs:6:9
+   |
+LL |     foo(bar);
+   |         ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr
index 983fdb13083..3eb3482ac91 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);
-   |         ^^^ expected concrete lifetime, found bound lifetime parameter
+   |         ^^^ one type is more general than the other
    |
-   = note: expected struct `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
-              found struct `std::boxed::Box<dyn std::ops::Fn(_)>`
+   = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)`
+              found trait object `dyn std::ops::Fn(&i32)`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs
index b259e9e269d..99cae46fd9c 100644
--- a/src/test/ui/issues/issue-43623.rs
+++ b/src/test/ui/issues/issue-43623.rs
@@ -9,11 +9,12 @@ impl<'a> Trait<'a> for Type {
 }
 
 pub fn break_me<T, F>(f: F)
-where T: for<'b> Trait<'b>,
-      F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+where
+    T: for<'b> Trait<'b>,
+    F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
     break_me::<Type, fn(_)>;
     //~^ ERROR: type mismatch in function arguments
-    //~| ERROR: type mismatch resolving
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr
index 99fb2a1f5d0..80aca482b3d 100644
--- a/src/test/ui/issues/issue-43623.stderr
+++ b/src/test/ui/issues/issue-43623.stderr
@@ -1,29 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-43623.rs:14:5
+  --> $DIR/issue-43623.rs:16:5
    |
 LL | pub fn break_me<T, F>(f: F)
    |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |          -------------------------------------- required by this bound in `break_me`
+...
+LL |     F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+   |                ------------------------------ required by this bound in `break_me`
+LL | {
 LL |     break_me::<Type, fn(_)>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |     |
-   |     expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
-   |     found signature of `fn(_) -> _`
+   |     expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
+   |     found signature of `fn(()) -> _`
 
-error[E0271]: type mismatch resolving `for<'b> <fn(_) as std::ops::FnOnce<(<Type as Trait<'b>>::Assoc,)>>::Output == ()`
-  --> $DIR/issue-43623.rs:14:5
-   |
-LL | pub fn break_me<T, F>(f: F)
-   |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |                  ------------------------------ required by this bound in `break_me`
-LL |     break_me::<Type, fn(_)>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr
index 2edc0097464..47cc64ec470 100644
--- a/src/test/ui/issues/issue-57362-2.stderr
+++ b/src/test/ui/issues/issue-57362-2.stderr
@@ -4,6 +4,8 @@ error[E0599]: no function or associated item named `make_g` found for fn pointer
 LL |     let x = <fn (&())>::make_g();
    |                         ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())`
    |
+   = note: the method `make_g` exists but the following trait bounds were not satisfied:
+           `for<'r> fn(&'r ()): X`
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `X` defines an item `make_g`, perhaps you need to implement it
   --> $DIR/issue-57362-2.rs:8:1
diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs
index e5a9caa32fa..9c2b2dc9f4d 100644
--- a/src/test/ui/issues/issue-60283.rs
+++ b/src/test/ui/issues/issue-60283.rs
@@ -7,11 +7,13 @@ impl<'a> Trait<'a> for () {
 }
 
 pub fn foo<T, F>(_: T, _: F)
-where T: for<'a> Trait<'a>,
-      F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
+where
+    T: for<'a> Trait<'a>,
+    F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
 
 fn main() {
     foo((), drop)
     //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
 }
diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr
index e74a34e247a..ad679bfa220 100644
--- a/src/test/ui/issues/issue-60283.stderr
+++ b/src/test/ui/issues/issue-60283.stderr
@@ -1,31 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-60283.rs:14:13
+  --> $DIR/issue-60283.rs:17:13
    |
 LL | pub fn foo<T, F>(_: T, _: F)
    |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |          ------------------------------------- required by this bound in `foo`
+...
+LL |     F: for<'a> FnMut(<T as Trait<'a>>::Item),
+   |                ----------------------------- required by this bound in `foo`
 ...
 LL |     foo((), drop)
    |             ^^^^
    |             |
-   |             expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
-   |             found signature of `fn(_) -> _`
-
-error[E0271]: type mismatch resolving `for<'a> <fn(_) {std::mem::drop::<_>} as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()`
-  --> $DIR/issue-60283.rs:14:5
-   |
-LL | pub fn foo<T, F>(_: T, _: F)
-   |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |                  ----------------------------- required by this bound in `foo`
-...
-LL |     foo((), drop)
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |             expected signature of `fn(<() as Trait<'a>>::Item) -> _`
+   |             found signature of `fn(()) -> _`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
index bc7b787cd65..fbf4aee0204 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
@@ -4,23 +4,19 @@
 // longer get an error, because we recognize these two types as
 // equivalent!
 //
-// Whoops -- now that we reinstituted the leak-check, we get an error
-// again.
+// check-pass
 
-fn foo(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
+fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    // The two types above are actually equivalent. With the older
+    // leak check, though, we didn't consider them as equivalent, and
+    // hence we gave errors. But now we've fixed that.
     let z = match 22 {
         0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
+        _ => y,
     };
 }
 
-fn bar(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
+fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
     let z = match 22 {
         // No error with an explicit cast:
         0 => x as for<'a> fn(&'a u8, &'a u8),
@@ -28,5 +24,4 @@ fn bar(
     };
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
new file mode 100644
index 00000000000..b95e247d2a8
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
new file mode 100644
index 00000000000..918542d471b
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
@@ -0,0 +1,24 @@
+// Test taking the LUB of two function types that are not equatable but where one is more
+// general than the other. Test the case where the more general type (`x`) is the first
+// match arm specifically.
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => x,
+        _ => y, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
new file mode 100644
index 00000000000..305e952d604
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => x,
+   | |              - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+LL | |         _ => y,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+              found fn pointer `for<'a> fn(&'a u8, &'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-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
new file mode 100644
index 00000000000..4bdd05b4f92
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
@@ -0,0 +1,33 @@
+// Test taking the LUB of two function types that are not equatable but where
+// one is more general than the other. Test the case where the more general type
+// (`x`) is the second match arm specifically.
+//
+// FIXME(#73154) Skip for compare-mode because the pure NLL checker accepts this
+// test. (Note that it still errors in old-lub-glb-hr-noteq1.rs). What happens
+// is that, due to the ordering of the match arms, we pick the correct "more
+// general" fn type, and we ignore the errors from the non-NLL type checker that
+// requires equality. The NLL type checker only requires a subtyping
+// relationship, and that holds.
+//
+// ignore-compare-mode-nll
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => y,
+        _ => x, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
new file mode 100644
index 00000000000..252e13aada0
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq2.rs:20:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => y,
+   | |              - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+LL | |         _ => x,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+              found fn pointer `for<'a, 'b> fn(&'a u8, &'b 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-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
deleted file mode 100644
index 6d5d5117469..00000000000
--- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-hr.rs:16:14
-   |
-LL |       let z = match 22 {
-   |  _____________-
-LL | |         0 => x,
-   | |              - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)`
-LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter, found concrete lifetime
-LL | |     };
-   | |_____- `match` arms have incompatible types
-   |
-   = note:    expected type `for<'r, 's> fn(&'r u8, &'s u8)`
-           found fn pointer `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.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
new file mode 100644
index 00000000000..51bf96f3233
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to 2 previous errors
+
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 63bbae59991..39d351c2355 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-object.rs
@@ -1,22 +1,17 @@
 // Test that we give a note when the old LUB/GLB algorithm would have
 // succeeded but the new code (which is stricter) gives an error.
 
-trait Foo<T, U> { }
+trait Foo<T, U> {}
 
-fn foo(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     let z = match 22 {
+        //~^ ERROR mismatched types
         0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
+        _ => y,
     };
 }
 
-fn bar(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn bar(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     // Accepted with explicit case:
     let z = match 22 {
         0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>,
@@ -24,5 +19,4 @@ fn bar(
     };
 }
 
-fn main() {
-}
+fn main() {}
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 65c797f6b19..6eabe5eaeee 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -1,17 +1,16 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-object.rs:12:14
+error[E0308]: mismatched types
+  --> $DIR/old-lub-glb-object.rs:7:13
    |
 LL |       let z = match 22 {
-   |  _____________-
+   |  _____________^
+LL | |
 LL | |         0 => x,
-   | |              - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
 LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter 'a, found concrete lifetime
 LL | |     };
-   | |_____- `match` arms have incompatible types
+   | |_____^ one type is more general than the other
    |
-   = note:   expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
-           found reference `&dyn for<'a> Foo<&'a u8, &'a u8>`
+   = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found trait object `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.nll.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
new file mode 100644
index 00000000000..6ed91b20ab8
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
@@ -0,0 +1,27 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:3:14
+   |
+LL |     a.iter().map(|_: (u32, u32)| 45);
+   |              ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:4:14
+   |
+LL |     a.iter().map(|_: &(u16, u16)| 45);
+   |              ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:5:14
+   |
+LL |     a.iter().map(|_: (u16, u16)| 45);
+   |              ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
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 521bd3695df..e278049c8cc 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,9 @@ fn main() {
 
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
-    baz(f); //~ ERROR type mismatch
-     //~| ERROR type mismatch
+    baz(f);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
 }
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 69a4b458ebf..664fa4bcaf3 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -22,28 +22,43 @@ LL |     a.iter().map(|_: (u16, u16)| 45);
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
 
-error[E0631]: type mismatch in function arguments
-  --> $DIR/closure-arg-type-mismatch.rs:10:9
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |         ^
-   |         |
-   |         expected signature of `for<'r> fn(*mut &'r u32) -> _`
-   |         found signature of `fn(*mut &'a u32) -> _`
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
new file mode 100644
index 00000000000..745a61b866e
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
index 40a4641fe71..d2b78b4b7db 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -5,6 +5,5 @@ impl<T: Fn(&())> Foo for T {}
 fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    baz(|_| ()); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
+    baz(|_| ()); //~ ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index 389b2157446..d6c17d125cf 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -1,28 +1,12 @@
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-mismatch.rs:8:5
    |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
 LL |     baz(|_| ());
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
    |
-   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+   = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
+              found type `std::ops::Fn<(&(),)>`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/closure-mismatch.rs:8:5
-   |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
-LL |     baz(|_| ());
-   |     ^^^ ------ 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]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
new file mode 100644
index 00000000000..d762f55f9d5
--- /dev/null
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+   |
+LL |     want_G(baz);
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 2dd0c9796e2..539221b5a04 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
@@ -13,11 +13,11 @@ struct S;
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -25,7 +25,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
@@ -48,5 +48,4 @@ fn supply_G() {
     want_G(baz); //~ ERROR mismatched types
 }
 
-pub fn main() {
-}
+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 27704b3e0a8..c9ce936c7d4 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
@@ -1,21 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `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);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |            ^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
-                 found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
+              found fn pointer `for<'r> fn(&'r S) -> &'r S`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
index c3e8789a903..695f5506d5e 100644
--- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 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 159d32b50b0..b83e07663fa 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,12 +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;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
index 2aadd8f4f8c..a28f7aa3e08 100644
--- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -1,14 +1,46 @@
-error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+   |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+   |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y, z);
+   |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+   |
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
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 dda6129e195..c93f2890f11 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,12 +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;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                                        ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+              found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
 
 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 fa2cc37d05b..de14d5ba82a 100644
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
@@ -5,6 +5,8 @@
 // *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.
+//
+// check-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
@@ -14,11 +16,11 @@ struct S;
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -26,7 +28,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -38,10 +40,9 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
deleted file mode 100644
index a8a7e97e6ac..00000000000
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `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.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
index 434a3e47b49..37f7fcf2e33 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
-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 01f43aeebaf..2b2dd0dbbf2 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -20,12 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
new file mode 100644
index 00000000000..848d4fef1ab
--- /dev/null
+++ b/src/test/ui/rfc1623.nll.stderr
@@ -0,0 +1,68 @@
+error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+  --> $DIR/rfc1623.rs:21:1
+   |
+LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+   |
+   = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `SomeStruct`
+   = note: required because it appears within the type `&SomeStruct`
+   = note: shared static variables must have a type that implements `Sync`
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs
index 55f5d0b94dc..aa6b1c0012c 100644
--- a/src/test/ui/rfc1623.rs
+++ b/src/test/ui/rfc1623.rs
@@ -8,23 +8,21 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
 static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
 
-
 struct SomeStruct<'x, 'y, 'z: 'x> {
     foo: &'x Foo<'z>,
     bar: &'x Bar<'z>,
-    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
 }
 
 fn id<T>(t: T) -> T {
     t
 }
 
-static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types
+static SOME_STRUCT: &SomeStruct = &SomeStruct {
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
-    //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
+    //~^ ERROR mismatched types
 };
 
 // very simple test for a 'static static with default lifetime
diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr
index ca956004ef7..2efc58ac381 100644
--- a/src/test/ui/rfc1623.stderr
+++ b/src/test/ui/rfc1623.stderr
@@ -1,46 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:22:35
-   |
-LL |   static SOME_STRUCT: &SomeStruct = SomeStruct {
-   |  ___________________________________^
-LL | |     foo: &Foo { bools: &[false, true] },
-LL | |     bar: &Bar { bools: &[true, true] },
-LL | |     f: &id,
-LL | |
-LL | |
-LL | | };
-   | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct`
-   |
-help: consider borrowing here
-   |
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL |     foo: &Foo { bools: &[false, true] },
-LL |     bar: &Bar { bools: &[true, true] },
-LL |     f: &id,
-LL |
-LL |
- ...
-
-error[E0631]: type mismatch in function arguments
-  --> $DIR/rfc1623.rs:25:8
-   |
-LL | fn id<T>(t: T) -> T {
-   | ------------------- found signature of `fn(_) -> _`
-...
-LL |     f: &id,
-   |        ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _`
-   |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-
-error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>`
-  --> $DIR/rfc1623.rs:25:8
+  --> $DIR/rfc1623.rs:24:8
    |
 LL |     f: &id,
-   |        ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |        ^^^ one type is more general than the other
    |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>`
+              found type `std::ops::FnOnce<(&Foo<'_>,)>`
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0308, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 88bd990b1e8..f2fbb0ba7d7 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -6,6 +6,11 @@ LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
    |                |     |
    |                |     this data with an anonymous lifetime `'_`...
    |                ...is captured here...
+   |
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                                                ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr
index d05e89e257f..29d1b000943 100644
--- a/src/test/ui/span/E0493.stderr
+++ b/src/test/ui/span/E0493.stderr
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/E0493.rs:17:17
    |
 LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - value is dropped here
+   |                 |
+   |                 constants cannot evaluate destructors
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr
index bc08f33f820..ed81734f6eb 100644
--- a/src/test/ui/static/static-drop-scope.stderr
+++ b/src/test/ui/static/static-drop-scope.stderr
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:9:60
    |
 LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
-   |                                                            ^^^^^^^^ statics cannot evaluate destructors
+   |                                                            ^^^^^^^^- value is dropped here
+   |                                                            |
+   |                                                            statics cannot evaluate destructors
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:9:60
@@ -18,7 +20,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:13:59
    |
 LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
-   |                                                           ^^^^^^^^ constants cannot evaluate destructors
+   |                                                           ^^^^^^^^- value is dropped here
+   |                                                           |
+   |                                                           constants cannot evaluate destructors
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:13:59
@@ -34,37 +38,50 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:17:28
    |
 LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1;
-   |                            ^^^^^^^^^^^^^ statics cannot evaluate destructors
+   |                            ^^^^^^^^^^^^^ - value is dropped here
+   |                            |
+   |                            statics cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:20:27
    |
 LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1;
-   |                           ^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                           ^^^^^^^^^^^^^ - value is dropped here
+   |                           |
+   |                           constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:23:24
    |
 LL | const fn const_drop<T>(_: T) {}
-   |                        ^ constant functions cannot evaluate destructors
+   |                        ^      - value is dropped here
+   |                        |
+   |                        constant functions cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:27:5
    |
 LL |     (x, ()).1
    |     ^^^^^^^ constant functions cannot evaluate destructors
+LL |
+LL | }
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:31:34
    |
 LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1;
-   |                                  ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                                  ^^^^^^^^^^^^^^^^^^^ - value is dropped here
+   |                                  |
+   |                                  constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:36:43
    |
 LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
-   |                                           ^^^^^^^^^^^ constants cannot evaluate destructors
+   |                                           ^^^^^^^^^^^ - value is dropped here
+   |                                           |
+   |                                           constants cannot evaluate destructors
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
new file mode 100644
index 00000000000..2407d13714a
--- /dev/null
+++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
@@ -0,0 +1,53 @@
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             -         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |             |
+   |             let's call the lifetime of this reference `'1`
+   |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:39:9
+   |
+LL |       fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |               - let's call the lifetime of this reference `'1`
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:50:9
+   |
+LL |       fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |               -- lifetime `'a` defined here
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             --               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |             |
+   |             lifetime `'a` defined here
+   |
+   = help: consider replacing `'a` with `'static`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs
new file mode 100644
index 00000000000..f78edb1c83a
--- /dev/null
+++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs
@@ -0,0 +1,68 @@
+trait Foo {}
+impl<'a, T: Foo> Foo for &'a T {}
+impl<T: Foo + ?Sized> Foo for Box<T> {}
+
+struct Iter<'a, T> {
+    current: Option<Box<dyn Foo + 'a>>,
+    remaining: T,
+}
+
+impl<'a, T> Iterator for Iter<'a, T>
+where
+    T: Iterator,
+    T::Item: Foo + 'a,
+{
+    type Item = Box<dyn Foo + 'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let result = self.current.take();
+        self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _);
+        result
+    }
+}
+
+struct Bar(Vec<Box<dyn Foo>>);
+
+impl Bar {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Baz(Vec<Box<dyn Foo>>);
+
+impl Baz {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Bat(Vec<Box<dyn Foo>>);
+
+impl Bat {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Ban(Vec<Box<dyn Foo>>);
+
+impl Ban {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
new file mode 100644
index 00000000000..1257e9b172c
--- /dev/null
+++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
@@ -0,0 +1,95 @@
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:30:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                                                          ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:41:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:38:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:52:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:49:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+   |                                                               ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:63:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                                                                 ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+   |                                                               ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr
index 96f1656bae4..3c2226574ee 100644
--- a/src/test/ui/suggestions/suggest-move-types.stderr
+++ b/src/test/ui/suggestions/suggest-move-types.stderr
@@ -125,6 +125,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
+   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
 error[E0747]: lifetime provided when a type was expected
   --> $DIR/suggest-move-types.rs:82:56
@@ -133,6 +134,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, '
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
+   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
new file mode 100644
index 00000000000..8c9cb742fac
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
index 1c2051e7eae..41e019247c9 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
@@ -14,8 +14,8 @@ trait Foo {
 struct X;
 
 impl Foo for X {
-    type Bar = impl Baz<Self, Self>; //~ ERROR type mismatch in closure arguments
-    //~^ ERROR type mismatch resolving
+    type Bar = impl Baz<Self, Self>;
+    //~^ ERROR mismatched types
 
     fn bar(&self) -> Self::Bar {
         |x| x
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index cc121ac89fb..cd637056c94 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -1,23 +1,12 @@
-error[E0631]: type mismatch in closure arguments
+error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _`
-...
-LL |         |x| x
-   |         ----- found signature of `fn(_) -> _`
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: the return type of a function must have a statically known size
+   = note: expected type `std::ops::FnOnce<(&X,)>`
+              found type `std::ops::FnOnce<(&X,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X`
-  --> $DIR/issue-57611-trait-alias.rs:17:16
-   |
-LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
-   |
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
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 a6e26614a6a..e2082d4f78e 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
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: &isize) -> isize { (*x) * (*x) }
+unsafe fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+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() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
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 b9ee9e46020..b06f745e7c1 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
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
-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:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-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}`
-
 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:18:25
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
 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:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-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}`
-
-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:26
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 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 `std::ops::FnOnce<(&isize,)>` is not implemented for `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}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 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 dd3b1afc39f..dd76c597d28 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-extern "C" fn square(x: &isize) -> isize { (*x) * (*x) }
+extern "C" fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+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() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
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 654b626cf65..8f6945cda80 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:12:21
+  --> $DIR/unboxed-closures-wrong-abi.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
-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:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-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}`
-
 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:18:25
+  --> $DIR/unboxed-closures-wrong-abi.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
 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:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-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}`
-
-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:26
+  --> $DIR/unboxed-closures-wrong-abi.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 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 `std::ops::FnOnce<(&isize,)>` is not implemented for `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}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 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 c689d792661..02e8b7b47ae 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
@@ -1,24 +1,30 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: isize) -> isize { x * x }
+unsafe fn square(x: isize) -> isize {
+    x * x
+}
 // note: argument type here is `isize`, not `&isize`
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+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() {
@@ -26,4 +32,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
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 434c8a579f6..93a645b485e 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
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-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:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-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}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-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}`
-
-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:26
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(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}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
index d9d85ee9132..963d892931a 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
@@ -1,13 +1,13 @@
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
-#![feature(const_compare_raw_pointers)]
+#![feature(const_raw_ptr_deref)]
 #![feature(const_fn)]
 
 #[stable(feature = "foo", since = "1.33.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-const fn unstable(a: *const i32, b: *const i32) -> bool {
-    a == b
-    //~^ pointer operation is unsafe
+const fn unstable(a: *const i32, b: i32) -> bool {
+    *a == b
+    //~^ dereference of raw pointer is unsafe
 }
 
 fn main() {}
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
index d8f3737c8f5..4642a7a5fc9 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
@@ -1,10 +1,10 @@
-error[E0133]: pointer operation is unsafe and requires unsafe function or block
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
   --> $DIR/unsafe-unstable-const-fn.rs:9:5
    |
-LL |     a == b
-   |     ^^^^^^ pointer operation
+LL |     *a == b
+   |     ^^ dereference of raw pointer
    |
-   = note: operations on pointers in constants
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
new file mode 100644
index 00000000000..d0c476dc6ec
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/where-for-self-2.rs:23:5
+   |
+LL |     foo(&X);
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
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 31174fd4cf1..37c6954fd52 100644
--- a/src/test/ui/where-clauses/where-for-self-2.rs
+++ b/src/test/ui/where-clauses/where-for-self-2.rs
@@ -14,9 +14,11 @@ impl Bar for &'static u32 {
 }
 
 fn foo<T>(x: &T)
-    where for<'a> &'a T: Bar
-{}
+where
+    for<'a> &'a T: Bar,
+{
+}
 
 fn main() {
-    foo(&X); //~ ERROR trait bound
+    foo(&X); //~ ERROR implementation of `Bar` is not general enough
 }
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 9976243b200..30eb78b2da4 100644
--- a/src/test/ui/where-clauses/where-for-self-2.stderr
+++ b/src/test/ui/where-clauses/where-for-self-2.stderr
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
-  --> $DIR/where-for-self-2.rs:21:5
+error: implementation of `Bar` is not general enough
+  --> $DIR/where-for-self-2.rs:23:5
    |
-LL | fn foo<T>(x: &T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Bar
-   |                          --- required by this bound in `foo`
+LL | / trait Bar {
+LL | |     fn bar(&self);
+LL | | }
+   | |_- trait `Bar` defined here
 ...
-LL |     foo(&X);
-   |     ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
+LL |       foo(&X);
+   |       ^^^ implementation of `Bar` is not general enough
    |
-   = help: the following implementations were found:
-             <&'static u32 as Bar>
+   = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+   = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index d9320e9147c..3fa637b5a69 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -444,10 +444,7 @@ fn map_lib_features(
                         level: Status::Unstable,
                         since: None,
                         has_gate_test: false,
-                        // FIXME(#57563): #57563 is now used as a common tracking issue,
-                        // although we would like to have specific tracking issues for each
-                        // `rustc_const_unstable` in the future.
-                        tracking_issue: NonZeroU32::new(57563),
+                        tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
                     };
                     mf(Ok((feature_name, feature)), file, i + 1);
                     continue;