about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-02-13 07:04:56 +0000
committerbors <bors@rust-lang.org>2022-02-13 07:04:56 +0000
commit9a60099cc43c8a07abb280be323d1ed9afc27f2c (patch)
tree443e36bb4c65e2899f2cbb0e6639a152e826b5d8
parent3fe229902ecaf1017c931df6ad24cc9d968d8f03 (diff)
parent20ea5c50135fd905ad70c38abaa2a3362cf5561a (diff)
downloadrust-9a60099cc43c8a07abb280be323d1ed9afc27f2c.tar.gz
rust-9a60099cc43c8a07abb280be323d1ed9afc27f2c.zip
Auto merge of #93956 - matthiaskrgr:rollup-zfk35hb, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #89926 (make `Instant::{duration_since, elapsed, sub}` saturating and remove workarounds)
 - #90532 (More informative error message for E0015)
 - #93810 (Improve chalk integration)
 - #93851 (More practical examples for `Option::and_then` & `Result::and_then`)
 - #93885 (bootstrap.py: Suggest disabling download-ci-llvm option if url fails to download)
 - #93886 (Stabilise inherent_ascii_escape (FCP in #77174))
 - #93930 (add link to format_args! when mention it in docs)
 - #93936 (Couple of driver cleanups)
 - #93944 (Don't relabel to a team if there is already a team label)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs25
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs115
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs96
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs434
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs143
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs2
-rw-r--r--compiler/rustc_driver/src/lib.rs289
-rw-r--r--compiler/rustc_hir/src/lang_items.rs16
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs175
-rw-r--r--compiler/rustc_interface/src/callbacks.rs15
-rw-r--r--compiler/rustc_interface/src/interface.rs4
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs8
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_span/src/lib.rs38
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs9
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs32
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs106
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs22
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/slice.rs2
-rw-r--r--library/core/src/macros/mod.rs4
-rw-r--r--library/core/src/num/mod.rs7
-rw-r--r--library/core/src/ops/try_trait.rs1
-rw-r--r--library/core/src/option.rs24
-rw-r--r--library/core/src/result.rs26
-rw-r--r--library/core/src/slice/ascii.rs17
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/std/src/sys/hermit/time.rs8
-rw-r--r--library/std/src/sys/itron/time.rs9
-rw-r--r--library/std/src/sys/sgx/time.rs8
-rw-r--r--library/std/src/sys/unix/time.rs19
-rw-r--r--library/std/src/sys/unsupported/time.rs8
-rw-r--r--library/std/src/sys/wasi/time.rs8
-rw-r--r--library/std/src/sys/windows/time.rs8
-rw-r--r--library/std/src/time.rs109
-rw-r--r--library/std/src/time/monotonic.rs116
-rw-r--r--library/std/src/time/tests.rs31
-rw-r--r--src/bootstrap/bootstrap.py28
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs1
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr6
-rw-r--r--src/test/ui/associated-type-bounds/trait-params.rs1
-rw-r--r--src/test/ui/associated-type-bounds/union-bounds.rs1
-rw-r--r--src/test/ui/associated-types/associated-types-stream.rs2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-2.rs1
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr12
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-5.rs1
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr8
-rw-r--r--src/test/ui/associated-types/issue-50301.rs1
-rw-r--r--src/test/ui/borrowck/issue-64453.rs2
-rw-r--r--src/test/ui/borrowck/issue-64453.stderr3
-rw-r--r--src/test/ui/chalkify/assert.rs6
-rw-r--r--src/test/ui/chalkify/println.rs3
-rw-r--r--src/test/ui/chalkify/trait-objects.rs3
-rw-r--r--src/test/ui/check-static-values-constraints.rs2
-rw-r--r--src/test/ui/check-static-values-constraints.stderr8
-rw-r--r--src/test/ui/const-generics/issue-93647.rs2
-rw-r--r--src/test/ui/const-generics/issue-93647.stderr5
-rw-r--r--src/test/ui/const-generics/issues/issue-90318.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-90318.stderr20
-rw-r--r--src/test/ui/const-generics/nested-type.full.stderr4
-rw-r--r--src/test/ui/const-generics/nested-type.min.stderr4
-rw-r--r--src/test/ui/const-generics/nested-type.rs2
-rw-r--r--src/test/ui/consts/const-call.rs2
-rw-r--r--src/test/ui/consts/const-call.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr9
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr9
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs4
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr8
-rw-r--r--src/test/ui/consts/const-fn-error.rs4
-rw-r--r--src/test/ui/consts/const-fn-error.stderr13
-rw-r--r--src/test/ui/consts/const-fn-not-safe-for-const.stderr4
-rw-r--r--src/test/ui/consts/const-for.rs4
-rw-r--r--src/test/ui/consts/const-for.stderr13
-rw-r--r--src/test/ui/consts/control-flow/issue-46843.rs2
-rw-r--r--src/test/ui/consts/control-flow/issue-46843.stderr4
-rw-r--r--src/test/ui/consts/intrinsic_without_const_stab.rs2
-rw-r--r--src/test/ui/consts/intrinsic_without_const_stab.stderr4
-rw-r--r--src/test/ui/consts/intrinsic_without_const_stab_fail.rs2
-rw-r--r--src/test/ui/consts/intrinsic_without_const_stab_fail.stderr4
-rw-r--r--src/test/ui/consts/issue-28113.rs2
-rw-r--r--src/test/ui/consts/issue-28113.stderr5
-rw-r--r--src/test/ui/consts/issue-32829-2.rs6
-rw-r--r--src/test/ui/consts/issue-32829-2.stderr12
-rw-r--r--src/test/ui/consts/issue-43105.rs2
-rw-r--r--src/test/ui/consts/issue-43105.stderr4
-rw-r--r--src/test/ui/consts/issue-56164.rs2
-rw-r--r--src/test/ui/consts/issue-56164.stderr5
-rw-r--r--src/test/ui/consts/issue-68542-closure-in-array-len.rs2
-rw-r--r--src/test/ui/consts/issue-68542-closure-in-array-len.stderr5
-rw-r--r--src/test/ui/consts/issue-90870.fixed6
-rw-r--r--src/test/ui/consts/issue-90870.rs6
-rw-r--r--src/test/ui/consts/issue-90870.stderr9
-rw-r--r--src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr3
-rw-r--r--src/test/ui/consts/mir_check_nonconst.rs2
-rw-r--r--src/test/ui/consts/mir_check_nonconst.stderr4
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.stderr8
-rw-r--r--src/test/ui/deriving/deriving-associated-types.rs1
-rw-r--r--src/test/ui/impl-trait/example-calendar.rs1
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.rs1
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.stderr4
-rw-r--r--src/test/ui/impl-trait/issue-55872.rs1
-rw-r--r--src/test/ui/impl-trait/issue-55872.stderr2
-rw-r--r--src/test/ui/impl-trait/issues/issue-65581.rs1
-rw-r--r--src/test/ui/issues/issue-16538.mir.stderr4
-rw-r--r--src/test/ui/issues/issue-16538.thir.stderr4
-rw-r--r--src/test/ui/issues/issue-23122-1.rs6
-rw-r--r--src/test/ui/issues/issue-23122-2.rs5
-rw-r--r--src/test/ui/issues/issue-23122-2.stderr4
-rw-r--r--src/test/ui/issues/issue-25901.rs2
-rw-r--r--src/test/ui/issues/issue-25901.stderr15
-rw-r--r--src/test/ui/issues/issue-28561.rs1
-rw-r--r--src/test/ui/issues/issue-33187.rs16
-rw-r--r--src/test/ui/issues/issue-37051.rs1
-rw-r--r--src/test/ui/issues/issue-39559-2.stderr8
-rw-r--r--src/test/ui/issues/issue-55796.nll.stderr4
-rw-r--r--src/test/ui/issues/issue-55796.rs6
-rw-r--r--src/test/ui/issues/issue-55796.stderr20
-rw-r--r--src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs1
-rw-r--r--src/test/ui/never_type/issue-52443.rs4
-rw-r--r--src/test/ui/never_type/issue-52443.stderr13
-rw-r--r--src/test/ui/nll/ty-outlives/issue-53789-2.rs59
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr16
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr21
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr4
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-1.rs (renamed from src/test/ui/specialization/deafult-associated-type-bound-1.rs)1
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-1.stderr (renamed from src/test/ui/specialization/deafult-associated-type-bound-1.stderr)6
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-2.rs (renamed from src/test/ui/specialization/deafult-associated-type-bound-2.rs)0
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-2.stderr (renamed from src/test/ui/specialization/deafult-associated-type-bound-2.stderr)6
-rw-r--r--src/test/ui/specialization/default-generic-associated-type-bound.rs (renamed from src/test/ui/specialization/deafult-generic-associated-type-bound.rs)0
-rw-r--r--src/test/ui/specialization/default-generic-associated-type-bound.stderr (renamed from src/test/ui/specialization/deafult-generic-associated-type-bound.stderr)6
-rw-r--r--src/test/ui/static/static-vec-repeat-not-constant.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53598.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53598.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57700.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57700.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60371.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60371.stderr6
-rw-r--r--triagebot.toml6
157 files changed, 1551 insertions, 1131 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7b8b5974fe7..f6d21f879ff 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,4 +1,5 @@
 use either::Either;
+use rustc_const_eval::util::{CallDesugaringKind, CallKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -26,7 +27,7 @@ use crate::{
 
 use super::{
     explain_borrow::{BorrowExplanation, LaterUseKind},
-    FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    IncludingDowncast, RegionName, RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -195,7 +196,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         .map(|n| format!("`{}`", n))
                         .unwrap_or_else(|| "value".to_owned());
                     match kind {
-                        FnSelfUseKind::FnOnceCall => {
+                        CallKind::FnCall { fn_trait_id, .. }
+                            if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+                        {
                             err.span_label(
                                 fn_call_span,
                                 &format!(
@@ -208,7 +211,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 "this value implements `FnOnce`, which causes it to be moved when called",
                             );
                         }
-                        FnSelfUseKind::Operator { self_arg } => {
+                        CallKind::Operator { self_arg, .. } => {
+                            let self_arg = self_arg.unwrap();
                             err.span_label(
                                 fn_call_span,
                                 &format!(
@@ -235,12 +239,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 );
                             }
                         }
-                        FnSelfUseKind::Normal {
-                            self_arg,
-                            implicit_into_iter,
-                            is_option_or_result,
-                        } => {
-                            if implicit_into_iter {
+                        CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+                            let self_arg = self_arg.unwrap();
+                            if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
@@ -305,8 +306,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     );
                             }
                         }
-                        // Deref::deref takes &self, which cannot cause a move
-                        FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+                        // Other desugarings takes &self, which cannot cause a move
+                        _ => unreachable!(),
                     }
                 } else {
                     err.span_label(
@@ -433,7 +434,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             if let UseSpans::FnSelfUse {
-                kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+                kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
                 ..
             } = use_spans
             {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 84acfbf941d..4400fed13b7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,10 +1,10 @@
 //! Borrow checker diagnostics.
 
+use rustc_const_eval::util::call_kind;
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItemGroup;
 use rustc_hir::GeneratorKind;
 use rustc_middle::mir::{
     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
+use rustc_span::{symbol::sym, Span};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -37,7 +37,7 @@ crate use mutability_errors::AccessKind;
 crate use outlives_suggestion::OutlivesSuggestionBuilder;
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
 crate use region_name::{RegionName, RegionNameSource};
-use rustc_span::symbol::Ident;
+crate use rustc_const_eval::util::CallKind;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
 
@@ -563,7 +563,7 @@ pub(super) enum UseSpans<'tcx> {
         fn_call_span: Span,
         /// The definition span of the method being called
         fn_span: Span,
-        kind: FnSelfUseKind<'tcx>,
+        kind: CallKind<'tcx>,
     },
     /// This access is caused by a `match` or `if let` pattern.
     PatUse(Span),
@@ -571,38 +571,15 @@ pub(super) enum UseSpans<'tcx> {
     OtherUse(Span),
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind<'tcx> {
-    /// A normal method call of the form `receiver.foo(a, b, c)`
-    Normal {
-        self_arg: Ident,
-        implicit_into_iter: bool,
-        /// Whether the self type of the method call has an `.as_ref()` method.
-        /// Used for better diagnostics.
-        is_option_or_result: bool,
-    },
-    /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
-    FnOnceCall,
-    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
-    Operator { self_arg: Ident },
-    DerefCoercion {
-        /// The `Span` of the `Target` associated type
-        /// in the `Deref` impl we are using.
-        deref_target: Span,
-        /// The type `T::Deref` we are dereferencing to
-        deref_target_ty: Ty<'tcx>,
-    },
-}
-
 impl UseSpans<'_> {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -613,9 +590,9 @@ impl UseSpans<'_> {
             UseSpans::ClosureUse { path_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -626,9 +603,9 @@ impl UseSpans<'_> {
             UseSpans::ClosureUse { capture_kind_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -904,67 +881,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 return normal_ret;
             };
 
-            let tcx = self.infcx.tcx;
-            let parent = tcx.parent(method_did);
-            let is_fn_once = parent == tcx.lang_items().fn_once_trait();
-            let is_operator = !from_hir_call
-                && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
-            let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
-            let fn_call_span = *fn_span;
-
-            let self_arg = tcx.fn_arg_names(method_did)[0];
-
-            debug!(
-                "terminator = {:?} from_hir_call={:?}",
-                self.body[location.block].terminator, from_hir_call
+            let kind = call_kind(
+                self.infcx.tcx,
+                self.param_env,
+                method_did,
+                method_substs,
+                *fn_span,
+                *from_hir_call,
+                Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
             );
 
-            // Check for a 'special' use of 'self' -
-            // an FnOnce call, an operator (e.g. `<<`), or a
-            // deref coercion.
-            let kind = if is_fn_once {
-                Some(FnSelfUseKind::FnOnceCall)
-            } else if is_operator {
-                Some(FnSelfUseKind::Operator { self_arg })
-            } else if is_deref {
-                let deref_target =
-                    tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-                        Instance::resolve(tcx, self.param_env, deref_target, method_substs)
-                            .transpose()
-                    });
-                if let Some(Ok(instance)) = deref_target {
-                    let deref_target_ty = instance.ty(tcx, self.param_env);
-                    Some(FnSelfUseKind::DerefCoercion {
-                        deref_target: tcx.def_span(instance.def_id()),
-                        deref_target_ty,
-                    })
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-
-            let kind = kind.unwrap_or_else(|| {
-                // This isn't a 'special' use of `self`
-                debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
-                let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
-                    && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
-                let parent_self_ty = parent
-                    .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
-                    .and_then(|did| match tcx.type_of(did).kind() {
-                        ty::Adt(def, ..) => Some(def.did),
-                        _ => None,
-                    });
-                let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
-                    matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
-                });
-                FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
-            });
-
             return FnSelfUse {
                 var_span: stmt.source_info.span,
-                fn_call_span,
+                fn_call_span: *fn_span,
                 fn_span: self
                     .infcx
                     .tcx
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 2934d921868..b33b779edda 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -1,3 +1,4 @@
+use rustc_const_eval::util::CallDesugaringKind;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
@@ -8,7 +9,7 @@ use rustc_mir_dataflow::move_paths::{
 use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
-use crate::diagnostics::{FnSelfUseKind, UseSpans};
+use crate::diagnostics::{CallKind, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -410,7 +411,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
         } else if let Some(UseSpans::FnSelfUse {
-            kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+            kind:
+                CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
             ..
         }) = use_spans
         {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 12a8b8c6d77..095c8f84f41 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -14,6 +14,7 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::SelectionContext;
 
 use std::mem;
@@ -293,13 +294,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     }
 
     /// Emits an error if an expression cannot be evaluated in the current context.
-    pub fn check_op(&mut self, op: impl NonConstOp) {
+    pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
         self.check_op_spanned(op, self.span);
     }
 
     /// Emits an error at the given `span` if an expression cannot be evaluated in the current
     /// context.
-    pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
+    pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
         let gate = match op.status_in_item(self.ccx) {
             Status::Allowed => return,
 
@@ -773,7 +774,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
-            TerminatorKind::Call { func, args, .. } => {
+            TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
                 let ConstCx { tcx, body, param_env, .. } = *self.ccx;
                 let caller = self.def_id().to_def_id();
 
@@ -797,20 +798,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
                     if !self.tcx.features().const_trait_impl {
-                        self.check_op(ops::FnCallNonConst(Some((callee, substs))));
+                        self.check_op(ops::FnCallNonConst {
+                            caller,
+                            callee,
+                            substs,
+                            span: *fn_span,
+                            from_hir_call: *from_hir_call,
+                        });
                         return;
                     }
 
                     let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
-                    let obligation = Obligation::new(
-                        ObligationCause::dummy(),
-                        param_env,
-                        Binder::dummy(TraitPredicate {
-                            trait_ref,
-                            constness: ty::BoundConstness::NotConst,
-                            polarity: ty::ImplPolarity::Positive,
-                        }),
-                    );
+                    let poly_trait_pred = Binder::dummy(TraitPredicate {
+                        trait_ref,
+                        constness: ty::BoundConstness::ConstIfConst,
+                        polarity: ty::ImplPolarity::Positive,
+                    });
+                    let obligation =
+                        Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
 
                     let implsrc = tcx.infer_ctxt().enter(|infcx| {
                         let mut selcx = SelectionContext::new(&infcx);
@@ -826,10 +831,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             return;
                         }
                         Ok(Some(ImplSource::UserDefined(data))) => {
-                            if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
-                                self.check_op(ops::FnCallNonConst(None));
-                                return;
-                            }
                             let callee_name = tcx.item_name(callee);
                             if let Some(&did) = tcx
                                 .associated_item_def_ids(data.impl_def_id)
@@ -841,22 +842,61 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 substs = InternalSubsts::identity_for_item(tcx, did);
                                 callee = did;
                             }
+
+                            if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
+                                self.check_op(ops::FnCallNonConst {
+                                    caller,
+                                    callee,
+                                    substs,
+                                    span: *fn_span,
+                                    from_hir_call: *from_hir_call,
+                                });
+                                return;
+                            }
                         }
                         _ if !tcx.is_const_fn_raw(callee) => {
                             // At this point, it is only legal when the caller is marked with
                             // #[default_method_body_is_const], and the callee is in the same
                             // trait.
                             let callee_trait = tcx.trait_of_item(callee);
-                            if callee_trait.is_some() {
-                                if tcx.has_attr(caller, sym::default_method_body_is_const) {
-                                    if tcx.trait_of_item(caller) == callee_trait {
-                                        nonconst_call_permission = true;
-                                    }
-                                }
+                            if callee_trait.is_some()
+                                && tcx.has_attr(caller, sym::default_method_body_is_const)
+                                && callee_trait == tcx.trait_of_item(caller)
+                                // Can only call methods when it's `<Self as TheTrait>::f`.
+                                && tcx.types.self_param == substs.type_at(0)
+                            {
+                                nonconst_call_permission = true;
                             }
 
                             if !nonconst_call_permission {
-                                self.check_op(ops::FnCallNonConst(None));
+                                let obligation = Obligation::new(
+                                    ObligationCause::dummy_with_span(*fn_span),
+                                    param_env,
+                                    tcx.mk_predicate(
+                                        poly_trait_pred.map_bound(ty::PredicateKind::Trait),
+                                    ),
+                                );
+
+                                // improve diagnostics by showing what failed. Our requirements are stricter this time
+                                // as we are going to error again anyways.
+                                tcx.infer_ctxt().enter(|infcx| {
+                                    if let Err(e) = implsrc {
+                                        infcx.report_selection_error(
+                                            obligation.clone(),
+                                            &obligation,
+                                            &e,
+                                            false,
+                                        );
+                                    }
+                                });
+
+                                self.check_op(ops::FnCallNonConst {
+                                    caller,
+                                    callee,
+                                    substs,
+                                    span: *fn_span,
+                                    from_hir_call: *from_hir_call,
+                                });
                                 return;
                             }
                         }
@@ -925,7 +965,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     }
 
                     if !nonconst_call_permission {
-                        self.check_op(ops::FnCallNonConst(None));
+                        self.check_op(ops::FnCallNonConst {
+                            caller,
+                            callee,
+                            substs,
+                            span: *fn_span,
+                            from_hir_call: *from_hir_call,
+                        });
                         return;
                     }
                 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 24c4a4915e5..519b4c02b61 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -3,14 +3,22 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
+use rustc_middle::mir;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::{mir, ty::AssocKind};
+use rustc_middle::ty::{
+    suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
+};
+use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
-use rustc_span::{symbol::Ident, Span, Symbol};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, Span, Symbol};
+use rustc_trait_selection::traits::SelectionContext;
 
 use super::ConstCx;
+use crate::util::{call_kind, CallDesugaringKind, CallKind};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
@@ -29,9 +37,9 @@ pub enum DiagnosticImportance {
 }
 
 /// An operation that is not *always* allowed in a const context.
-pub trait NonConstOp: std::fmt::Debug {
+pub trait NonConstOp<'tcx>: std::fmt::Debug {
     /// Returns an enum indicating whether this operation is allowed within the given item.
-    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
 
@@ -39,13 +47,13 @@ pub trait NonConstOp: std::fmt::Debug {
         DiagnosticImportance::Primary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
 }
 
 #[derive(Debug)]
 pub struct FloatingPointOp;
-impl NonConstOp for FloatingPointOp {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if ccx.const_kind() == hir::ConstContext::ConstFn {
             Status::Unstable(sym::const_fn_floating_point_arithmetic)
         } else {
@@ -53,7 +61,7 @@ impl NonConstOp for FloatingPointOp {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_floating_point_arithmetic,
@@ -66,77 +74,229 @@ impl NonConstOp for FloatingPointOp {
 /// A function call where the callee is a pointer.
 #[derive(Debug)]
 pub struct FnCallIndirect;
-impl NonConstOp for FnCallIndirect {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
     }
 }
 
 /// A function call where the callee is not marked as `const`.
-#[derive(Debug)]
-pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
-impl<'a> NonConstOp for FnCallNonConst<'a> {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        let mut err = struct_span_err!(
-            ccx.tcx.sess,
-            span,
-            E0015,
-            "calls in {}s are limited to constant functions, \
-             tuple structs and tuple variants",
-            ccx.const_kind(),
-        );
+#[derive(Debug, Clone, Copy)]
+pub struct FnCallNonConst<'tcx> {
+    pub caller: DefId,
+    pub callee: DefId,
+    pub substs: SubstsRef<'tcx>,
+    pub span: Span,
+    pub from_hir_call: bool,
+}
 
-        if let FnCallNonConst(Some((callee, substs))) = *self {
-            if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
-                if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
-                    ccx.tcx,
-                    Ident::with_dummy_span(sym::eq),
-                    AssocKind::Fn,
-                    trait_def_id,
-                ) {
-                    if callee == eq_item.def_id && substs.len() == 2 {
-                        match (substs[0].unpack(), substs[1].unpack()) {
-                            (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
-                                if self_ty == rhs_ty
-                                    && self_ty.is_ref()
-                                    && self_ty.peel_refs().is_primitive() =>
-                            {
-                                let mut num_refs = 0;
-                                let mut tmp_ty = self_ty;
-                                while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
-                                    num_refs += 1;
-                                    tmp_ty = inner_ty;
-                                }
-                                let deref = "*".repeat(num_refs);
-
-                                if let Ok(call_str) =
-                                    ccx.tcx.sess.source_map().span_to_snippet(span)
-                                {
-                                    if let Some(eq_idx) = call_str.find("==") {
-                                        if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
-                                            .find(|c: char| !c.is_whitespace())
-                                        {
-                                            let rhs_pos = span.lo()
-                                                + BytePos::from_usize(eq_idx + 2 + rhs_idx);
-                                            let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
-                                            err.multipart_suggestion(
-                                                "consider dereferencing here",
-                                                vec![
-                                                    (span.shrink_to_lo(), deref.clone()),
-                                                    (rhs_span, deref),
-                                                ],
-                                                Applicability::MachineApplicable,
-                                            );
-                                        }
+impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
+        let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
+        let ConstCx { tcx, param_env, .. } = *ccx;
+
+        let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
+            let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
+
+            match self_ty.kind() {
+                Param(param_ty) => {
+                    debug!(?param_ty);
+                    if let Some(generics) = caller
+                        .as_local()
+                        .map(|id| tcx.hir().local_def_id_to_hir_id(id))
+                        .map(|id| tcx.hir().get(id))
+                        .as_ref()
+                        .and_then(|node| node.generics())
+                    {
+                        let constraint = with_no_trimmed_paths(|| {
+                            format!("~const {}", trait_ref.print_only_trait_path())
+                        });
+                        suggest_constraining_type_param(
+                            tcx,
+                            generics,
+                            &mut err,
+                            &param_ty.name.as_str(),
+                            &constraint,
+                            None,
+                        );
+                    }
+                }
+                Adt(..) => {
+                    let obligation = Obligation::new(
+                        ObligationCause::dummy(),
+                        param_env,
+                        Binder::dummy(TraitPredicate {
+                            trait_ref,
+                            constness: BoundConstness::NotConst,
+                            polarity: ImplPolarity::Positive,
+                        }),
+                    );
+
+                    let implsrc = tcx.infer_ctxt().enter(|infcx| {
+                        let mut selcx = SelectionContext::new(&infcx);
+                        selcx.select(&obligation)
+                    });
+
+                    if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
+                        let span =
+                            tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
+                        err.span_note(span, "impl defined here, but it is not `const`");
+                    }
+                }
+                _ => {}
+            }
+
+            err
+        };
+
+        let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
+
+        debug!(?call_kind);
+
+        let mut err = match call_kind {
+            CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
+                macro_rules! error {
+                    ($fmt:literal) => {
+                        struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
+                    };
+                }
+
+                let err = match kind {
+                    CallDesugaringKind::ForLoopIntoIter => {
+                        error!("cannot convert `{}` into an iterator in {}s")
+                    }
+                    CallDesugaringKind::QuestionBranch => {
+                        error!("`?` cannot determine the branch of `{}` in {}s")
+                    }
+                    CallDesugaringKind::QuestionFromResidual => {
+                        error!("`?` cannot convert from residual of `{}` in {}s")
+                    }
+                    CallDesugaringKind::TryBlockFromOutput => {
+                        error!("`try` block cannot convert `{}` to the result in {}s")
+                    }
+                };
+
+                diag_trait(err, self_ty, kind.trait_def_id(tcx))
+            }
+            CallKind::FnCall { fn_trait_id, self_ty } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot call non-const closure in {}s",
+                    ccx.const_kind(),
+                );
+
+                match self_ty.kind() {
+                    FnDef(def_id, ..) => {
+                        let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
+                        if ccx.tcx.is_const_fn_raw(*def_id) {
+                            span_bug!(span, "calling const FnDef errored when it shouldn't");
+                        }
+
+                        err.span_note(span, "function defined here, but it is not `const`");
+                    }
+                    FnPtr(..) => {
+                        err.note(&format!(
+                            "function pointers need an RFC before allowed to be called in {}s",
+                            ccx.const_kind()
+                        ));
+                    }
+                    Closure(..) => {
+                        err.note(&format!(
+                            "closures need an RFC before allowed to be called in {}s",
+                            ccx.const_kind()
+                        ));
+                    }
+                    _ => {}
+                }
+
+                diag_trait(err, self_ty, fn_trait_id)
+            }
+            CallKind::Operator { trait_id, self_ty, .. } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot call non-const operator in {}s",
+                    ccx.const_kind()
+                );
+
+                if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
+                    match (substs[0].unpack(), substs[1].unpack()) {
+                        (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+                            if self_ty == rhs_ty
+                                && self_ty.is_ref()
+                                && self_ty.peel_refs().is_primitive() =>
+                        {
+                            let mut num_refs = 0;
+                            let mut tmp_ty = self_ty;
+                            while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+                                num_refs += 1;
+                                tmp_ty = inner_ty;
+                            }
+                            let deref = "*".repeat(num_refs);
+
+                            if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
+                                if let Some(eq_idx) = call_str.find("==") {
+                                    if let Some(rhs_idx) =
+                                        call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
+                                    {
+                                        let rhs_pos =
+                                            span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+                                        let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+                                        err.multipart_suggestion(
+                                            "consider dereferencing here",
+                                            vec![
+                                                (span.shrink_to_lo(), deref.clone()),
+                                                (rhs_span, deref),
+                                            ],
+                                            Applicability::MachineApplicable,
+                                        );
                                     }
                                 }
                             }
-                            _ => {}
                         }
+                        _ => {}
                     }
                 }
+
+                diag_trait(err, self_ty, trait_id)
             }
-        }
+            CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot perform deref coercion on `{}` in {}s",
+                    self_ty,
+                    ccx.const_kind()
+                );
+
+                err.note(&format!("attempting to deref into `{}`", deref_target_ty));
+
+                // Check first whether the source is accessible (issue #87060)
+                if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+                    err.span_note(deref_target, "deref defined here");
+                }
+
+                diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
+            }
+            _ => struct_span_err!(
+                ccx.tcx.sess,
+                span,
+                E0015,
+                "cannot call non-const fn `{}` in {}s",
+                ccx.tcx.def_path_str_with_substs(callee, substs),
+                ccx.const_kind(),
+            ),
+        };
+
+        err.note(&format!(
+            "calls in {}s are limited to constant functions, \
+             tuple structs and tuple variants",
+            ccx.const_kind(),
+        ));
 
         err
     }
@@ -148,8 +308,8 @@ impl<'a> NonConstOp for FnCallNonConst<'a> {
 #[derive(Debug)]
 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
 
-impl NonConstOp for FnCallUnstable {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let FnCallUnstable(def_id, feature) = *self;
 
         let mut err = ccx.tcx.sess.struct_span_err(
@@ -174,8 +334,8 @@ impl NonConstOp for FnCallUnstable {
 
 #[derive(Debug)]
 pub struct FnPtrCast;
-impl NonConstOp for FnPtrCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if ccx.const_kind() != hir::ConstContext::ConstFn {
             Status::Allowed
         } else {
@@ -183,7 +343,7 @@ impl NonConstOp for FnPtrCast {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_fn_ptr_basics,
@@ -195,8 +355,8 @@ impl NonConstOp for FnPtrCast {
 
 #[derive(Debug)]
 pub struct Generator(pub hir::GeneratorKind);
-impl NonConstOp for Generator {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for Generator {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
             Status::Unstable(sym::const_async_blocks)
         } else {
@@ -204,7 +364,7 @@ impl NonConstOp for Generator {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
             feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
@@ -216,8 +376,8 @@ impl NonConstOp for Generator {
 
 #[derive(Debug)]
 pub struct HeapAllocation;
-impl NonConstOp for HeapAllocation {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -240,8 +400,8 @@ impl NonConstOp for HeapAllocation {
 
 #[derive(Debug)]
 pub struct InlineAsm;
-impl NonConstOp for InlineAsm {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for InlineAsm {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -256,8 +416,8 @@ impl NonConstOp for InlineAsm {
 pub struct LiveDrop {
     pub dropped_at: Option<Span>,
 }
-impl NonConstOp for LiveDrop {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -276,8 +436,8 @@ impl NonConstOp for LiveDrop {
 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
 /// the final value of the constant.
 pub struct TransientCellBorrow;
-impl NonConstOp for TransientCellBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_refs_to_cell)
     }
     fn importance(&self) -> DiagnosticImportance {
@@ -285,7 +445,7 @@ impl NonConstOp for TransientCellBorrow {
         // not additionally emit a feature gate error if activating the feature gate won't work.
         DiagnosticImportance::Secondary
     }
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_refs_to_cell,
@@ -300,8 +460,8 @@ impl NonConstOp for TransientCellBorrow {
 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
 /// it in the future for static items.
 pub struct CellBorrow;
-impl NonConstOp for CellBorrow {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -337,8 +497,8 @@ impl NonConstOp for CellBorrow {
 /// static or const items.
 pub struct MutBorrow(pub hir::BorrowKind);
 
-impl NonConstOp for MutBorrow {
-    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutBorrow {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
 
@@ -348,7 +508,7 @@ impl NonConstOp for MutBorrow {
         DiagnosticImportance::Secondary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let raw = match self.0 {
             hir::BorrowKind::Raw => "raw ",
             hir::BorrowKind::Ref => "",
@@ -382,12 +542,12 @@ impl NonConstOp for MutBorrow {
 #[derive(Debug)]
 pub struct TransientMutBorrow(pub hir::BorrowKind);
 
-impl NonConstOp for TransientMutBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let raw = match self.0 {
             hir::BorrowKind::Raw => "raw ",
             hir::BorrowKind::Ref => "",
@@ -404,8 +564,8 @@ impl NonConstOp for TransientMutBorrow {
 
 #[derive(Debug)]
 pub struct MutDeref;
-impl NonConstOp for MutDeref {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutDeref {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
@@ -414,7 +574,7 @@ impl NonConstOp for MutDeref {
         DiagnosticImportance::Secondary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_mut_refs,
@@ -427,8 +587,8 @@ impl NonConstOp for MutDeref {
 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
 #[derive(Debug)]
 pub struct PanicNonStr;
-impl NonConstOp for PanicNonStr {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx.sess.struct_span_err(
             span,
             "argument to `panic!()` in a const context must have type `&str`",
@@ -441,8 +601,8 @@ impl NonConstOp for PanicNonStr {
 /// allocation base addresses that are not known at compile-time.
 #[derive(Debug)]
 pub struct RawPtrComparison;
-impl NonConstOp for RawPtrComparison {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = ccx
             .tcx
             .sess
@@ -457,12 +617,12 @@ impl NonConstOp for RawPtrComparison {
 
 #[derive(Debug)]
 pub struct RawMutPtrDeref;
-impl NonConstOp for RawMutPtrDeref {
+impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_mut_refs,
@@ -477,8 +637,8 @@ impl NonConstOp for RawMutPtrDeref {
 /// allocation base addresses that are not known at compile-time.
 #[derive(Debug)]
 pub struct RawPtrToIntCast;
-impl NonConstOp for RawPtrToIntCast {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = ccx
             .tcx
             .sess
@@ -494,8 +654,8 @@ impl NonConstOp for RawPtrToIntCast {
 /// An access to a (non-thread-local) `static`.
 #[derive(Debug)]
 pub struct StaticAccess;
-impl NonConstOp for StaticAccess {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for StaticAccess {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
             Status::Allowed
         } else {
@@ -503,7 +663,7 @@ impl NonConstOp for StaticAccess {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -528,8 +688,8 @@ impl NonConstOp for StaticAccess {
 /// An access to a thread-local `static`.
 #[derive(Debug)]
 pub struct ThreadLocalAccess;
-impl NonConstOp for ThreadLocalAccess {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -546,8 +706,8 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct MutRef(pub mir::LocalKind);
-    impl NonConstOp for MutRef {
-        fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+    impl<'tcx> NonConstOp<'tcx> for MutRef {
+        fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
             Status::Unstable(sym::const_mut_refs)
         }
 
@@ -560,11 +720,7 @@ pub mod ty {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_mut_refs,
@@ -576,7 +732,7 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct FnPtr(pub mir::LocalKind);
-    impl NonConstOp for FnPtr {
+    impl<'tcx> NonConstOp<'tcx> for FnPtr {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -586,7 +742,7 @@ pub mod ty {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -594,11 +750,7 @@ pub mod ty {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_fn_ptr_basics,
@@ -610,16 +762,12 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct ImplTrait;
-    impl NonConstOp for ImplTrait {
+    impl<'tcx> NonConstOp<'tcx> for ImplTrait {
         fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
             Status::Unstable(sym::const_impl_trait)
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_impl_trait,
@@ -631,7 +779,7 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct TraitBound(pub mir::LocalKind);
-    impl NonConstOp for TraitBound {
+    impl<'tcx> NonConstOp<'tcx> for TraitBound {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -641,7 +789,7 @@ pub mod ty {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -649,11 +797,7 @@ pub mod ty {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
@@ -674,7 +818,7 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct DynTrait(pub mir::LocalKind);
-    impl NonConstOp for DynTrait {
+    impl<'tcx> NonConstOp<'tcx> for DynTrait {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -684,7 +828,7 @@ pub mod ty {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -692,11 +836,7 @@ pub mod ty {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
@@ -718,16 +858,12 @@ pub mod ty {
     /// A trait bound with the `?const Trait` opt-out
     #[derive(Debug)]
     pub struct TraitBoundNotConst;
-    impl NonConstOp for TraitBoundNotConst {
-        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+    impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
+        fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
             Status::Unstable(sym::const_trait_bound_opt_out)
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_trait_bound_opt_out,
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
new file mode 100644
index 00000000000..11bb9508a1f
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -0,0 +1,143 @@
+//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
+//! as well as errors when attempting to call a non-const function in a const
+//! context.
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, DesugaringKind, Span};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallDesugaringKind {
+    /// for _ in x {} calls x.into_iter()
+    ForLoopIntoIter,
+    /// x? calls x.branch()
+    QuestionBranch,
+    /// x? calls type_of(x)::from_residual()
+    QuestionFromResidual,
+    /// try { ..; x } calls type_of(x)::from_output(x)
+    TryBlockFromOutput,
+}
+
+impl CallDesugaringKind {
+    pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
+        match self {
+            Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
+            Self::QuestionBranch | Self::TryBlockFromOutput => {
+                tcx.lang_items().try_trait().unwrap()
+            }
+            Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallKind<'tcx> {
+    /// A normal method call of the form `receiver.foo(a, b, c)`
+    Normal {
+        self_arg: Option<Ident>,
+        desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
+        /// Whether the self type of the method call has an `.as_ref()` method.
+        /// Used for better diagnostics.
+        is_option_or_result: bool,
+    },
+    /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
+    FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
+    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+    Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
+    DerefCoercion {
+        /// The `Span` of the `Target` associated type
+        /// in the `Deref` impl we are using.
+        deref_target: Span,
+        /// The type `T::Deref` we are dereferencing to
+        deref_target_ty: Ty<'tcx>,
+        self_ty: Ty<'tcx>,
+    },
+}
+
+pub fn call_kind<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    method_did: DefId,
+    method_substs: SubstsRef<'tcx>,
+    fn_call_span: Span,
+    from_hir_call: bool,
+    self_arg: Option<Ident>,
+) -> CallKind<'tcx> {
+    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
+        AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
+        AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+    });
+
+    let fn_call = parent
+        .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
+
+    let operator = (!from_hir_call)
+        .then(|| parent)
+        .flatten()
+        .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
+
+    let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
+
+    // Check for a 'special' use of 'self' -
+    // an FnOnce call, an operator (e.g. `<<`), or a
+    // deref coercion.
+    let kind = if let Some(&trait_id) = fn_call {
+        Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
+    } else if let Some(&trait_id) = operator {
+        Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
+    } else if is_deref {
+        let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+            Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
+        });
+        if let Some(Ok(instance)) = deref_target {
+            let deref_target_ty = instance.ty(tcx, param_env);
+            Some(CallKind::DerefCoercion {
+                deref_target: tcx.def_span(instance.def_id()),
+                deref_target_ty,
+                self_ty: method_substs.type_at(0),
+            })
+        } else {
+            None
+        }
+    } else {
+        None
+    };
+
+    kind.unwrap_or_else(|| {
+        // This isn't a 'special' use of `self`
+        debug!(?method_did, ?fn_call_span);
+        let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
+            && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
+        {
+            Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
+        } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
+            if Some(method_did) == tcx.lang_items().branch_fn() {
+                Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
+            } else if Some(method_did) == tcx.lang_items().from_residual_fn() {
+                Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
+            } else {
+                None
+            }
+        } else if Some(method_did) == tcx.lang_items().from_output_fn()
+            && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
+        {
+            Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
+        } else {
+            None
+        };
+        let parent_self_ty = tcx
+            .parent(method_did)
+            .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+            .and_then(|did| match tcx.type_of(did).kind() {
+                ty::Adt(def, ..) => Some(def.did),
+                _ => None,
+            });
+        let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+            matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+        });
+        CallKind::Normal { self_arg, desugaring, is_option_or_result }
+    })
+}
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 4a406f8bfd0..a1876bed83e 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -1,8 +1,10 @@
 pub mod aggregate;
 mod alignment;
+mod call_kind;
 pub mod collect_writes;
 mod find_self_call;
 
 pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
+pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
 pub use self::find_self_call::find_self_call;
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index ca4e7b5142e..7eeae66d709 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -263,7 +263,7 @@ fn run_compiler(
                         describe_lints(compiler.session(), &lint_store, registered_lints);
                         return;
                     }
-                    let should_stop = RustcDefaultCalls::print_crate_info(
+                    let should_stop = print_crate_info(
                         &***compiler.codegen_backend(),
                         compiler.session(),
                         None,
@@ -292,7 +292,7 @@ fn run_compiler(
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
-        let should_stop = RustcDefaultCalls::print_crate_info(
+        let should_stop = print_crate_info(
             &***compiler.codegen_backend(),
             sess,
             Some(compiler.input()),
@@ -301,13 +301,9 @@ fn run_compiler(
             compiler.temps_dir(),
         )
         .and_then(|| {
-            RustcDefaultCalls::list_metadata(
-                sess,
-                &*compiler.codegen_backend().metadata_loader(),
-                compiler.input(),
-            )
+            list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
         })
-        .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
+        .and_then(|| try_process_rlink(sess, compiler));
 
         if should_stop == Compilation::Stop {
             return sess.compile_status();
@@ -512,10 +508,6 @@ impl Compilation {
     }
 }
 
-/// CompilerCalls instance for a regular rustc build.
-#[derive(Copy, Clone)]
-pub struct RustcDefaultCalls;
-
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised = if upper_cased_code.starts_with('E') {
@@ -588,162 +580,157 @@ fn show_content_with_pager(content: &str) {
     }
 }
 
-impl RustcDefaultCalls {
-    pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
-        if sess.opts.debugging_opts.link_only {
-            if let Input::File(file) = compiler.input() {
-                // FIXME: #![crate_type] and #![crate_name] support not implemented yet
-                sess.init_crate_types(collect_crate_types(sess, &[]));
-                let outputs = compiler.build_output_filenames(sess, &[]);
-                let rlink_data = fs::read(file).unwrap_or_else(|err| {
-                    sess.fatal(&format!("failed to read rlink file: {}", err));
-                });
-                let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
-                let codegen_results: CodegenResults =
-                    rustc_serialize::Decodable::decode(&mut decoder);
-                let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
-                abort_on_err(result, sess);
-            } else {
-                sess.fatal("rlink must be a file")
-            }
-            Compilation::Stop
+pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
+    if sess.opts.debugging_opts.link_only {
+        if let Input::File(file) = compiler.input() {
+            // FIXME: #![crate_type] and #![crate_name] support not implemented yet
+            sess.init_crate_types(collect_crate_types(sess, &[]));
+            let outputs = compiler.build_output_filenames(sess, &[]);
+            let rlink_data = fs::read(file).unwrap_or_else(|err| {
+                sess.fatal(&format!("failed to read rlink file: {}", err));
+            });
+            let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
+            let codegen_results: CodegenResults = rustc_serialize::Decodable::decode(&mut decoder);
+            let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
+            abort_on_err(result, sess);
         } else {
-            Compilation::Continue
+            sess.fatal("rlink must be a file")
         }
+        Compilation::Stop
+    } else {
+        Compilation::Continue
     }
+}
 
-    pub fn list_metadata(
-        sess: &Session,
-        metadata_loader: &dyn MetadataLoader,
-        input: &Input,
-    ) -> Compilation {
-        if sess.opts.debugging_opts.ls {
-            match *input {
-                Input::File(ref ifile) => {
-                    let path = &(*ifile);
-                    let mut v = Vec::new();
-                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
-                        .unwrap();
-                    println!("{}", String::from_utf8(v).unwrap());
-                }
-                Input::Str { .. } => {
-                    early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
-                }
+pub fn list_metadata(
+    sess: &Session,
+    metadata_loader: &dyn MetadataLoader,
+    input: &Input,
+) -> Compilation {
+    if sess.opts.debugging_opts.ls {
+        match *input {
+            Input::File(ref ifile) => {
+                let path = &(*ifile);
+                let mut v = Vec::new();
+                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
+                println!("{}", String::from_utf8(v).unwrap());
+            }
+            Input::Str { .. } => {
+                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
             }
-            return Compilation::Stop;
         }
-
-        Compilation::Continue
+        return Compilation::Stop;
     }
 
-    fn print_crate_info(
-        codegen_backend: &dyn CodegenBackend,
-        sess: &Session,
-        input: Option<&Input>,
-        odir: &Option<PathBuf>,
-        ofile: &Option<PathBuf>,
-        temps_dir: &Option<PathBuf>,
-    ) -> Compilation {
-        use rustc_session::config::PrintRequest::*;
-        // NativeStaticLibs and LinkArgs are special - printed during linking
-        // (empty iterator returns true)
-        if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
-            return Compilation::Continue;
-        }
+    Compilation::Continue
+}
 
-        let attrs = match input {
-            None => None,
-            Some(input) => {
-                let result = parse_crate_attrs(sess, input);
-                match result {
-                    Ok(attrs) => Some(attrs),
-                    Err(mut parse_error) => {
-                        parse_error.emit();
-                        return Compilation::Stop;
-                    }
+fn print_crate_info(
+    codegen_backend: &dyn CodegenBackend,
+    sess: &Session,
+    input: Option<&Input>,
+    odir: &Option<PathBuf>,
+    ofile: &Option<PathBuf>,
+    temps_dir: &Option<PathBuf>,
+) -> Compilation {
+    use rustc_session::config::PrintRequest::*;
+    // NativeStaticLibs and LinkArgs are special - printed during linking
+    // (empty iterator returns true)
+    if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
+        return Compilation::Continue;
+    }
+
+    let attrs = match input {
+        None => None,
+        Some(input) => {
+            let result = parse_crate_attrs(sess, input);
+            match result {
+                Ok(attrs) => Some(attrs),
+                Err(mut parse_error) => {
+                    parse_error.emit();
+                    return Compilation::Stop;
                 }
             }
-        };
-        for req in &sess.opts.prints {
-            match *req {
-                TargetList => {
-                    let mut targets =
-                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
-                    targets.sort_unstable();
-                    println!("{}", targets.join("\n"));
-                }
-                Sysroot => println!("{}", sess.sysroot.display()),
-                TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
-                TargetSpec => println!("{}", sess.target.to_json().pretty()),
-                FileNames | CrateName => {
-                    let input = input.unwrap_or_else(|| {
-                        early_error(ErrorOutputType::default(), "no input file provided")
-                    });
-                    let attrs = attrs.as_ref().unwrap();
-                    let t_outputs = rustc_interface::util::build_output_filenames(
-                        input, odir, ofile, temps_dir, attrs, sess,
-                    );
-                    let id = rustc_session::output::find_crate_name(sess, attrs, input);
-                    if *req == PrintRequest::CrateName {
-                        println!("{}", id);
-                        continue;
-                    }
-                    let crate_types = collect_crate_types(sess, attrs);
-                    for &style in &crate_types {
-                        let fname =
-                            rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
-                        println!("{}", fname.file_name().unwrap().to_string_lossy());
-                    }
+        }
+    };
+    for req in &sess.opts.prints {
+        match *req {
+            TargetList => {
+                let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
+                targets.sort_unstable();
+                println!("{}", targets.join("\n"));
+            }
+            Sysroot => println!("{}", sess.sysroot.display()),
+            TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+            TargetSpec => println!("{}", sess.target.to_json().pretty()),
+            FileNames | CrateName => {
+                let input = input.unwrap_or_else(|| {
+                    early_error(ErrorOutputType::default(), "no input file provided")
+                });
+                let attrs = attrs.as_ref().unwrap();
+                let t_outputs = rustc_interface::util::build_output_filenames(
+                    input, odir, ofile, temps_dir, attrs, sess,
+                );
+                let id = rustc_session::output::find_crate_name(sess, attrs, input);
+                if *req == PrintRequest::CrateName {
+                    println!("{}", id);
+                    continue;
                 }
-                Cfg => {
-                    let mut cfgs = sess
-                        .parse_sess
-                        .config
-                        .iter()
-                        .filter_map(|&(name, value)| {
-                            // Note that crt-static is a specially recognized cfg
-                            // directive that's printed out here as part of
-                            // rust-lang/rust#37406, but in general the
-                            // `target_feature` cfg is gated under
-                            // rust-lang/rust#29717. For now this is just
-                            // specifically allowing the crt-static cfg and that's
-                            // it, this is intended to get into Cargo and then go
-                            // through to build scripts.
-                            if (name != sym::target_feature || value != Some(sym::crt_dash_static))
-                                && !sess.is_nightly_build()
-                                && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
-                            {
-                                return None;
-                            }
-
-                            if let Some(value) = value {
-                                Some(format!("{}=\"{}\"", name, value))
-                            } else {
-                                Some(name.to_string())
-                            }
-                        })
-                        .collect::<Vec<String>>();
-
-                    cfgs.sort();
-                    for cfg in cfgs {
-                        println!("{}", cfg);
-                    }
+                let crate_types = collect_crate_types(sess, attrs);
+                for &style in &crate_types {
+                    let fname =
+                        rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
+                    println!("{}", fname.file_name().unwrap().to_string_lossy());
                 }
-                RelocationModels
-                | CodeModels
-                | TlsModels
-                | TargetCPUs
-                | StackProtectorStrategies
-                | TargetFeatures => {
-                    codegen_backend.print(*req, sess);
+            }
+            Cfg => {
+                let mut cfgs = sess
+                    .parse_sess
+                    .config
+                    .iter()
+                    .filter_map(|&(name, value)| {
+                        // Note that crt-static is a specially recognized cfg
+                        // directive that's printed out here as part of
+                        // rust-lang/rust#37406, but in general the
+                        // `target_feature` cfg is gated under
+                        // rust-lang/rust#29717. For now this is just
+                        // specifically allowing the crt-static cfg and that's
+                        // it, this is intended to get into Cargo and then go
+                        // through to build scripts.
+                        if (name != sym::target_feature || value != Some(sym::crt_dash_static))
+                            && !sess.is_nightly_build()
+                            && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
+                        {
+                            return None;
+                        }
+
+                        if let Some(value) = value {
+                            Some(format!("{}=\"{}\"", name, value))
+                        } else {
+                            Some(name.to_string())
+                        }
+                    })
+                    .collect::<Vec<String>>();
+
+                cfgs.sort();
+                for cfg in cfgs {
+                    println!("{}", cfg);
                 }
-                // Any output here interferes with Cargo's parsing of other printed output
-                NativeStaticLibs => {}
-                LinkArgs => {}
             }
+            RelocationModels
+            | CodeModels
+            | TlsModels
+            | TargetCPUs
+            | StackProtectorStrategies
+            | TargetFeatures => {
+                codegen_backend.print(*req, sess);
+            }
+            // Any output here interferes with Cargo's parsing of other printed output
+            NativeStaticLibs => {}
+            LinkArgs => {}
         }
-        Compilation::Stop
     }
+    Compilation::Stop
 }
 
 /// Prints version information
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 603971a6a91..b299e71c9c4 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -21,9 +21,10 @@ use std::lazy::SyncLazy;
 
 pub enum LangItemGroup {
     Op,
+    Fn,
 }
 
-const NUM_GROUPS: usize = 1;
+const NUM_GROUPS: usize = 2;
 
 macro_rules! expand_group {
     () => {
@@ -98,11 +99,12 @@ macro_rules! language_item_table {
             /// Construct an empty collection of lang items and no missing ones.
             pub fn new() -> Self {
                 fn init_none(_: LangItem) -> Option<DefId> { None }
+                const EMPTY: Vec<DefId> = Vec::new();
 
                 Self {
                     items: vec![$(init_none(LangItem::$variant)),*],
                     missing: Vec::new(),
-                    groups: [vec![]; NUM_GROUPS],
+                    groups: [EMPTY; NUM_GROUPS],
                 }
             }
 
@@ -251,9 +253,9 @@ language_item_table! {
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
 
-    Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
-    FnOnce,                  sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
+    Fn(Fn),                  kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    FnMut(Fn),               sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    FnOnce(Fn),              sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
 
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
@@ -264,8 +266,8 @@ language_item_table! {
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
-    PartialEq,               sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    PartialOrd,              sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
+    PartialEq(Op),           sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    PartialOrd(Op),          sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
 
     // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
     // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9d40b3cba29..bd5892dba38 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -49,6 +49,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
     }
 
+    /// Like [Self::canonicalize_query], but preserves distinct universes. For
+    /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
+    /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
+    /// in `U2`.
+    ///
+    /// This is used for Chalk integration.
+    pub fn canonicalize_query_preserving_universes<V>(
+        &self,
+        value: V,
+        query_state: &mut OriginalQueryValues<'tcx>,
+    ) -> Canonicalized<'tcx, V>
+    where
+        V: TypeFoldable<'tcx>,
+    {
+        self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
+
+        Canonicalizer::canonicalize(
+            value,
+            self,
+            self.tcx,
+            &CanonicalizeAllFreeRegionsPreservingUniverses,
+            query_state,
+        )
+    }
+
     /// Canonicalizes a query *response* `V`. When we canonicalize a
     /// query response, we only canonicalize unbound inference
     /// variables, and we leave other free regions alone. So,
@@ -133,7 +158,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 /// maximally general query. But if we are canonicalizing a *query
 /// response*, then we don't typically replace free regions, as they
 /// must have been introduced from other parts of the system.
-trait CanonicalizeRegionMode {
+trait CanonicalizeMode {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -141,11 +166,14 @@ trait CanonicalizeRegionMode {
     ) -> ty::Region<'tcx>;
 
     fn any(&self) -> bool;
+
+    // Do we preserve universe of variables.
+    fn preserve_universes(&self) -> bool;
 }
 
 struct CanonicalizeQueryResponse;
 
-impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
+impl CanonicalizeMode for CanonicalizeQueryResponse {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -198,11 +226,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
     fn any(&self) -> bool {
         false
     }
+
+    fn preserve_universes(&self) -> bool {
+        true
+    }
 }
 
 struct CanonicalizeUserTypeAnnotation;
 
-impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
+impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -221,11 +253,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
     fn any(&self) -> bool {
         false
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
 }
 
 struct CanonicalizeAllFreeRegions;
 
-impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
+impl CanonicalizeMode for CanonicalizeAllFreeRegions {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -237,11 +273,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
     fn any(&self) -> bool {
         true
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
+}
+
+struct CanonicalizeAllFreeRegionsPreservingUniverses;
+
+impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
+    fn canonicalize_free_region<'tcx>(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        let universe = canonicalizer.infcx.universe_of_region(r);
+        canonicalizer.canonical_var_for_region(
+            CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
+            r,
+        )
+    }
+
+    fn any(&self) -> bool {
+        true
+    }
+
+    fn preserve_universes(&self) -> bool {
+        true
+    }
 }
 
 struct CanonicalizeFreeRegionsOtherThanStatic;
 
-impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
+impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -257,6 +321,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
     fn any(&self) -> bool {
         true
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
 }
 
 struct Canonicalizer<'cx, 'tcx> {
@@ -267,7 +335,7 @@ struct Canonicalizer<'cx, 'tcx> {
     // Note that indices is only used once `var_values` is big enough to be
     // heap-allocated.
     indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
-    canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
+    canonicalize_mode: &'cx dyn CanonicalizeMode,
     needs_canonical_flags: TypeFlags,
 
     binder_index: ty::DebruijnIndex,
@@ -311,7 +379,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     vid, r
                 );
                 let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
-                self.canonicalize_region_mode.canonicalize_free_region(self, r)
+                self.canonicalize_mode.canonicalize_free_region(self, r)
             }
 
             ty::ReStatic
@@ -319,7 +387,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             | ty::ReFree(_)
             | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
-            | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+            | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
         }
     }
 
@@ -337,8 +405,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
                     // result.
                     Err(mut ui) => {
-                        // FIXME: perf problem described in #55921.
-                        ui = ty::UniverseIndex::ROOT;
+                        if !self.canonicalize_mode.preserve_universes() {
+                            // FIXME: perf problem described in #55921.
+                            ui = ty::UniverseIndex::ROOT;
+                        }
                         self.canonicalize_ty_var(
                             CanonicalVarInfo {
                                 kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
@@ -422,8 +492,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     // `ConstVar(vid)` is unresolved, track its universe index in the
                     // canonicalized result
                     Err(mut ui) => {
-                        // FIXME: perf problem described in #55921.
-                        ui = ty::UniverseIndex::ROOT;
+                        if !self.canonicalize_mode.preserve_universes() {
+                            // FIXME: perf problem described in #55921.
+                            ui = ty::UniverseIndex::ROOT;
+                        }
                         return self.canonicalize_const_var(
                             CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
                             ct,
@@ -462,7 +534,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         value: V,
         infcx: &InferCtxt<'_, 'tcx>,
         tcx: TyCtxt<'tcx>,
-        canonicalize_region_mode: &dyn CanonicalizeRegionMode,
+        canonicalize_region_mode: &dyn CanonicalizeMode,
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
@@ -493,7 +565,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         let mut canonicalizer = Canonicalizer {
             infcx,
             tcx,
-            canonicalize_region_mode,
+            canonicalize_mode: canonicalize_region_mode,
             needs_canonical_flags,
             variables: SmallVec::new(),
             query_state,
@@ -504,10 +576,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
 
         // Once we have canonicalized `out_value`, it should not
         // contain anything that ties it to this inference context
-        // anymore, so it should live in the global arena.
-        debug_assert!(!out_value.needs_infer());
+        // anymore.
+        debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
 
-        let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
+        let canonical_variables =
+            tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
 
         let max_universe = canonical_variables
             .iter()
@@ -527,6 +600,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
 
         let var_values = &mut query_state.var_values;
 
+        let universe = info.universe();
+        if universe != ty::UniverseIndex::ROOT {
+            assert!(self.canonicalize_mode.preserve_universes());
+
+            // Insert universe into the universe map. To preserve the order of the
+            // universes in the value being canonicalized, we don't update the
+            // universe in `info` until we have finished canonicalizing.
+            match query_state.universe_map.binary_search(&universe) {
+                Err(idx) => query_state.universe_map.insert(idx, universe),
+                Ok(_) => {}
+            }
+        }
+
         // This code is hot. `variables` and `var_values` are usually small
         // (fewer than 8 elements ~95% of the time). They are SmallVec's to
         // avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +655,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         }
     }
 
+    /// Replaces the universe indexes used in `var_values` with their index in
+    /// `query_state.universe_map`. This minimizes the maximum universe used in
+    /// the canonicalized value.
+    fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
+        if self.query_state.universe_map.len() == 1 {
+            return self.variables;
+        }
+
+        let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
+            .query_state
+            .universe_map
+            .iter()
+            .enumerate()
+            .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
+            .collect();
+
+        self.variables
+            .iter()
+            .map(|v| CanonicalVarInfo {
+                kind: match v.kind {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                        return *v;
+                    }
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
+                        CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+                    }
+                    CanonicalVarKind::Region(u) => {
+                        CanonicalVarKind::Region(reverse_universe_map[&u])
+                    }
+                    CanonicalVarKind::Const(u, t) => {
+                        CanonicalVarKind::Const(reverse_universe_map[&u], t)
+                    }
+                    CanonicalVarKind::PlaceholderTy(placeholder) => {
+                        CanonicalVarKind::PlaceholderTy(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                    CanonicalVarKind::PlaceholderRegion(placeholder) => {
+                        CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                    CanonicalVarKind::PlaceholderConst(placeholder) => {
+                        CanonicalVarKind::PlaceholderConst(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                },
+            })
+            .collect()
+    }
+
     /// Shorthand helper that creates a canonical region variable for
     /// `r` (always in the root universe). The reason that we always
     /// put these variables into the root universe is because this
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index 3c7908fae79..a18e2d1d638 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -4,7 +4,7 @@
 //! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
 //! static which can then be set in this file at program startup.
 //!
-//! See `SPAN_DEBUG` for an example of how to set things up.
+//! See `SPAN_TRACK` for an example of how to set things up.
 //!
 //! The functions in this file should fall back to the default set in their
 //! origin crate when the `TyCtxt` is not present in TLS.
@@ -13,18 +13,6 @@ use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
 use rustc_middle::ty::tls;
 use std::fmt;
 
-/// This is a callback from `rustc_ast` as it cannot access the implicit state
-/// in `rustc_middle` otherwise.
-fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    tls::with_opt(|tcx| {
-        if let Some(tcx) = tcx {
-            rustc_span::debug_with_source_map(span, f, tcx.sess.source_map())
-        } else {
-            rustc_span::default_span_debug(span, f)
-        }
-    })
-}
-
 fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
     tls::with_opt(|tcx| {
         if let Some(tcx) = tcx {
@@ -65,7 +53,6 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
 /// Sets up the callbacks in prior crates which we want to refer to the
 /// TyCtxt in.
 pub fn setup_callbacks() {
-    rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
     rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 237aef1cf23..8bd24487b78 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -186,6 +186,8 @@ pub struct Config {
 }
 
 pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
+    crate::callbacks::setup_callbacks();
+
     let registry = &config.registry;
     let (mut sess, codegen_backend) = util::create_session(
         config.opts,
@@ -238,7 +240,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
     tracing::trace!("run_compiler");
     let stderr = config.stderr.take();
-    util::setup_callbacks_and_run_in_thread_pool_with_globals(
+    util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.debugging_opts.threads,
         &stderr,
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index eebeabbd452..dcad3036cc2 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -15,6 +15,7 @@ mod proc_macro_decls;
 mod queries;
 pub mod util;
 
+pub use callbacks::setup_callbacks;
 pub use interface::{run_compiler, Config};
 pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
 pub use queries::Queries;
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f74cadfebac..d206f2644e0 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -128,7 +128,7 @@ fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -
 }
 
 #[cfg(not(parallel_compiler))]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     _threads: usize,
     stderr: &Option<Arc<Mutex<Vec<u8>>>>,
@@ -140,8 +140,6 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
         cfg = cfg.stack_size(size);
     }
 
-    crate::callbacks::setup_callbacks();
-
     let main_handler = move || {
         rustc_span::create_session_globals_then(edition, || {
             io::set_output_capture(stderr.clone());
@@ -176,14 +174,12 @@ unsafe fn handle_deadlock() {
 }
 
 #[cfg(parallel_compiler)]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     threads: usize,
     stderr: &Option<Arc<Mutex<Vec<u8>>>>,
     f: F,
 ) -> R {
-    crate::callbacks::setup_callbacks();
-
     let mut config = rayon::ThreadPoolBuilder::new()
         .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 28217aeab13..4efe3640dfa 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -64,9 +64,9 @@ pub struct CanonicalVarValues<'tcx> {
 /// result.
 #[derive(Clone, Debug)]
 pub struct OriginalQueryValues<'tcx> {
-    /// Map from the universes that appear in the query to the
-    /// universes in the caller context. For the time being, we only
-    /// ever put ROOT values into the query, so this map is very
+    /// Map from the universes that appear in the query to the universes in the
+    /// caller context. For all queries except `evaluate_goal` (used by Chalk),
+    /// we only ever put ROOT values into the query, so this map is very
     /// simple.
     pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
 
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 823a927fd8c..3ce9f852c3d 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1013,37 +1013,25 @@ pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) ->
     f()
 }
 
-pub fn debug_with_source_map(
-    span: Span,
-    f: &mut fmt::Formatter<'_>,
-    source_map: &SourceMap,
-) -> fmt::Result {
-    write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt())
-}
-
-pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    with_session_globals(|session_globals| {
-        if let Some(source_map) = &*session_globals.source_map.borrow() {
-            debug_with_source_map(span, f, source_map)
-        } else {
-            f.debug_struct("Span")
-                .field("lo", &span.lo())
-                .field("hi", &span.hi())
-                .field("ctxt", &span.ctxt())
-                .finish()
-        }
-    })
-}
-
 impl fmt::Debug for Span {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (*SPAN_DEBUG)(*self, f)
+        with_session_globals(|session_globals| {
+            if let Some(source_map) = &*session_globals.source_map.borrow() {
+                write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
+            } else {
+                f.debug_struct("Span")
+                    .field("lo", &self.lo())
+                    .field("hi", &self.hi())
+                    .field("ctxt", &self.ctxt())
+                    .finish()
+            }
+        })
     }
 }
 
 impl fmt::Debug for SpanData {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
+        fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
     }
 }
 
@@ -2003,8 +1991,6 @@ pub struct FileLines {
     pub lines: Vec<LineInfo>,
 }
 
-pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
-    AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
 pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
 
 // _____________________________________________________________________________
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cab1d4e21c9..2e451502263 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -184,6 +184,7 @@ symbols! {
         Formatter,
         From,
         FromIterator,
+        FromResidual,
         Future,
         FxHashMap,
         FxHashSet,
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 34fc4ca8fea..93c2f202545 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -8,7 +8,7 @@ use crate::traits::{
     PredicateObligation, SelectionError, TraitEngine,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
@@ -91,7 +91,12 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
                 let environment = obligation.param_env.caller_bounds();
                 let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
                 let mut orig_values = OriginalQueryValues::default();
-                let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
+                if goal.references_error() {
+                    continue;
+                }
+
+                let canonical_goal =
+                    infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
 
                 match infcx.tcx.evaluate_goal(canonical_goal) {
                     Ok(response) => {
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 3f51442277f..0170ab223b0 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -20,11 +20,10 @@ use rustc_span::symbol::sym;
 use std::fmt;
 use std::sync::Arc;
 
-use crate::chalk::lowering::{self, LowerInto};
+use crate::chalk::lowering::LowerInto;
 
 pub struct RustIrDatabase<'tcx> {
     pub(crate) interner: RustInterner<'tcx>,
-    pub(crate) reempty_placeholder: ty::Region<'tcx>,
 }
 
 impl fmt::Debug for RustIrDatabase<'_> {
@@ -40,12 +39,9 @@ impl<'tcx> RustIrDatabase<'tcx> {
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
         let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
-        let mut regions_substitutor =
-            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
         predicates
             .iter()
             .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
-            .map(|wc| wc.fold_with(&mut regions_substitutor))
             .filter_map(|wc| LowerInto::<
                     Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
                     >::lower_into(wc, self.interner)).collect()
@@ -287,9 +283,6 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
-        let mut regions_substitutor =
-            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-        let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
@@ -335,9 +328,6 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
             let self_ty = trait_ref.self_ty();
             let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
-            let mut regions_substitutor =
-                lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-            let self_ty = self_ty.fold_with(&mut regions_substitutor);
             let lowered_ty = self_ty.lower_into(self.interner);
 
             parameters[0].assert_ty_ref(self.interner).could_match(
@@ -556,11 +546,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             Fn => lang_items.fn_trait(),
             FnMut => lang_items.fn_mut_trait(),
             FnOnce => lang_items.fn_once_trait(),
+            Generator => lang_items.gen_trait(),
             Unsize => lang_items.unsize_trait(),
             Unpin => lang_items.unpin_trait(),
             CoerceUnsized => lang_items.coerce_unsized_trait(),
             DiscriminantKind => lang_items.discriminant_kind_trait(),
-            Generator => lang_items.generator_return(),
         };
         def_id.map(chalk_ir::TraitId)
     }
@@ -684,28 +674,18 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<
         let variances = self.interner.tcx.variances_of(def_id.0);
         chalk_ir::Variances::from_iter(
             self.interner,
-            variances.iter().map(|v| match v {
-                ty::Variance::Invariant => chalk_ir::Variance::Invariant,
-                ty::Variance::Covariant => chalk_ir::Variance::Covariant,
-                ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                ty::Variance::Bivariant => unimplemented!(),
-            }),
+            variances.iter().map(|v| v.lower_into(self.interner)),
         )
     }
 
     fn adt_variance(
         &self,
-        def_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+        adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
     ) -> chalk_ir::Variances<RustInterner<'tcx>> {
-        let variances = self.interner.tcx.variances_of(def_id.0.did);
+        let variances = self.interner.tcx.variances_of(adt_id.0.did);
         chalk_ir::Variances::from_iter(
             self.interner,
-            variances.iter().map(|v| match v {
-                ty::Variance::Invariant => chalk_ir::Variance::Invariant,
-                ty::Variance::Covariant => chalk_ir::Variance::Covariant,
-                ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                ty::Variance::Bivariant => unimplemented!(),
-            }),
+            variances.iter().map(|v| v.lower_into(self.interner)),
         )
     }
 }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 67d0ba39667..6f143c1c607 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -188,12 +188,18 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
                 chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
             ),
 
+            ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+                chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal {
+                    a: a.lower_into(interner),
+                    b: b.lower_into(interner),
+                })
+            }
+
             // FIXME(chalk): other predicates
             //
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..) => {
@@ -464,9 +470,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'t
                 })
                 .intern(interner)
             }
-            ReEmpty(_) => unimplemented!(),
-            // FIXME(chalk): need to handle ReErased
-            ReErased => unimplemented!(),
+            ReEmpty(ui) => {
+                chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() })
+                    .intern(interner)
+            }
+            ReErased => chalk_ir::LifetimeData::Erased.intern(interner),
         }
     }
 }
@@ -488,12 +496,12 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t
                     name: ty::BoundRegionKind::BrAnon(p.idx as u32),
                 })
             }
-            chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
-            chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
+            chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
             chalk_ir::LifetimeData::Empty(ui) => {
-                ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
+                ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
             }
-            chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased,
+            chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased,
+            chalk_ir::LifetimeData::Phantom(void, _) => match *void {},
         };
         interner.tcx.mk_region(kind)
     }
@@ -788,6 +796,16 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity
         }
     }
 }
+impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance {
+    fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance {
+        match self {
+            ty::Variance::Covariant => chalk_ir::Variance::Covariant,
+            ty::Variance::Invariant => chalk_ir::Variance::Invariant,
+            ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
+            ty::Variance::Bivariant => unimplemented!(),
+        }
+    }
+}
 
 impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
     for ty::ProjectionPredicate<'tcx>
@@ -1016,10 +1034,6 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
-            // FIXME(chalk): currently we convert params to placeholders starting at
-            // index `0`. To support placeholders, we'll actually need to do a
-            // first pass to collect placeholders. Then we can insert params after.
-            ty::Placeholder(_) => unimplemented!(),
             ty::Param(param) => match self.list.iter().position(|r| r == &param) {
                 Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
                     universe: ty::UniverseIndex::from_usize(0),
@@ -1035,15 +1049,15 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
                     }))
                 }
             },
-
             _ => t.super_fold_with(self),
         }
     }
 
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
         match r {
-            // FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
-            // This covers any region variables in a goal, right?
+            // FIXME(chalk) - jackh726 - this currently isn't hit in any tests,
+            // since canonicalization will already change these to canonical
+            // variables (ty::ReLateBound).
             ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) {
                 Some(idx) => {
                     let br = ty::BoundRegion {
@@ -1066,6 +1080,39 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
     }
 }
 
+crate struct ReverseParamsSubstitutor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+}
+
+impl<'tcx> ReverseParamsSubstitutor<'tcx> {
+    crate fn new(
+        tcx: TyCtxt<'tcx>,
+        params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+    ) -> Self {
+        Self { tcx, params }
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => {
+                match self.params.get(&name.as_usize()) {
+                    Some(param) => self.tcx.mk_ty(ty::Param(*param)),
+                    None => t,
+                }
+            }
+
+            _ => t.super_fold_with(self),
+        }
+    }
+}
+
 /// Used to collect `Placeholder`s.
 crate struct PlaceholdersCollector {
     universe_index: ty::UniverseIndex,
@@ -1110,32 +1157,3 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
         r.super_visit_with(self)
     }
 }
-
-/// Used to substitute specific `Regions`s with placeholders.
-crate struct RegionsSubstitutor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    reempty_placeholder: ty::Region<'tcx>,
-}
-
-impl<'tcx> RegionsSubstitutor<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self {
-        RegionsSubstitutor { tcx, reempty_placeholder }
-    }
-}
-
-impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        match r {
-            ty::ReEmpty(ui) => {
-                assert_eq!(ui.as_usize(), 0);
-                self.reempty_placeholder
-            }
-
-            _ => r.super_fold_with(self),
-        }
-    }
-}
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 09bfdabf473..3c2a266dab9 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -22,9 +22,8 @@ use rustc_infer::infer::canonical::{
 use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
 
 use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
-use crate::chalk::lowering::{
-    LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
-};
+use crate::chalk::lowering::LowerInto;
+use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor};
 
 use chalk_solve::Solution;
 
@@ -42,19 +41,10 @@ crate fn evaluate_goal<'tcx>(
     let mut placeholders_collector = PlaceholdersCollector::new();
     obligation.visit_with(&mut placeholders_collector);
 
-    let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
-        universe: ty::UniverseIndex::ROOT,
-        name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
-    }));
-
     let mut params_substitutor =
         ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
     let obligation = obligation.fold_with(&mut params_substitutor);
-    // FIXME(chalk): we really should be substituting these back in the solution
-    let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
-
-    let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
-    let obligation = obligation.fold_with(&mut regions_substitutor);
+    let params: FxHashMap<usize, ParamTy> = params_substitutor.params;
 
     let max_universe = obligation.max_universe.index();
 
@@ -96,7 +86,8 @@ crate fn evaluate_goal<'tcx>(
 
     use chalk_solve::Solver;
     let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
-    let db = ChalkRustIrDatabase { interner, reempty_placeholder };
+    let db = ChalkRustIrDatabase { interner };
+    debug!(?lowered_goal);
     let solution = solver.solve(&db, &lowered_goal);
     debug!(?obligation, ?solution, "evaluate goal");
 
@@ -110,8 +101,9 @@ crate fn evaluate_goal<'tcx>(
         use rustc_middle::infer::canonical::CanonicalVarInfo;
 
         let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
+        let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
         subst.as_slice(interner).iter().for_each(|p| {
-            var_values.push(p.lower_into(interner));
+            var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
         });
         let variables: Vec<_> = binders
             .iter(interner)
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index ab9f0b9d737..ce75859f963 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -112,7 +112,6 @@
 #![feature(extend_one)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
-#![feature(inherent_ascii_escape)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(layout_for_ptr)]
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index a5c4140e313..f0397d08f95 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -108,7 +108,7 @@ pub use core::slice::ArrayChunks;
 pub use core::slice::ArrayChunksMut;
 #[unstable(feature = "array_windows", issue = "75027")]
 pub use core::slice::ArrayWindows;
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 pub use core::slice::EscapeAscii;
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 pub use core::slice::SliceIndex;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index a9e90556f6c..628b679236e 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -872,7 +872,7 @@ pub(crate) mod builtin {
         ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
     }
 
-    /// Same as `format_args`, but can be used in some const contexts.
+    /// Same as [`format_args`], but can be used in some const contexts.
     ///
     /// This macro is used by the panic macros for the `const_panic` feature.
     ///
@@ -886,7 +886,7 @@ pub(crate) mod builtin {
         ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
     }
 
-    /// Same as `format_args`, but adds a newline in the end.
+    /// Same as [`format_args`], but adds a newline in the end.
     #[unstable(
         feature = "format_args_nl",
         issue = "none",
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 864a253299f..72105888f94 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -791,7 +791,6 @@ impl u8 {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inherent_ascii_escape)]
     ///
     /// assert_eq!("0", b'0'.escape_ascii().to_string());
     /// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
@@ -804,10 +803,10 @@ impl u8 {
     /// ```
     #[must_use = "this returns the escaped byte as an iterator, \
                   without modifying the original"]
-    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
     #[inline]
-    pub fn escape_ascii(&self) -> ascii::EscapeDefault {
-        ascii::escape_default(*self)
+    pub fn escape_ascii(self) -> ascii::EscapeDefault {
+        ascii::escape_default(self)
     }
 
     pub(crate) fn is_utf8_char_boundary(self) -> bool {
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index eac426ad311..ba369e7f3aa 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -302,6 +302,7 @@ pub trait Try: FromResidual {
         enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
     ),
 )]
+#[rustc_diagnostic_item = "FromResidual"]
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index ec04692d3e0..508837f63c3 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1207,13 +1207,25 @@ impl<T> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// fn sq(x: u32) -> Option<u32> { Some(x * x) }
-    /// fn nope(_: u32) -> Option<u32> { None }
+    /// fn sq_then_to_string(x: u32) -> Option<String> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string())
+    /// }
+    ///
+    /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
+    /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
+    /// assert_eq!(None.and_then(sq_then_to_string), None);
+    /// ```
+    ///
+    /// Often used to chain fallible operations that may return [`None`].
+    ///
+    /// ```
+    /// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
+    ///
+    /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
+    /// assert_eq!(item_0_1, Some(&"A1"));
     ///
-    /// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
-    /// assert_eq!(Some(2).and_then(sq).and_then(nope), None);
-    /// assert_eq!(Some(2).and_then(nope).and_then(sq), None);
-    /// assert_eq!(None.and_then(sq).and_then(sq), None);
+    /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
+    /// assert_eq!(item_2_0, None);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 05b4fa035b1..801e3a0b3a4 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1281,16 +1281,28 @@ impl<T, E> Result<T, E> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
+    /// ```
+    /// fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
+    /// }
     ///
+    /// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
+    /// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
+    /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
     /// ```
-    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
-    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
     ///
-    /// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
-    /// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
-    /// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
-    /// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
+    /// Often used to chain fallible operations that may return [`Err`].
+    ///
+    /// ```
+    /// use std::{io::ErrorKind, path::Path};
+    ///
+    /// // Note: on Windows "/" maps to "C:\"
+    /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
+    /// assert!(root_modified_time.is_ok());
+    ///
+    /// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
+    /// assert!(should_fail.is_err());
+    /// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 080256f493f..304ba7ee554 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -68,7 +68,6 @@ impl [u8] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inherent_ascii_escape)]
     ///
     /// let s = b"0\t\r\n'\"\\\x9d";
     /// let escaped = s.escape_ascii().to_string();
@@ -76,7 +75,7 @@ impl [u8] {
     /// ```
     #[must_use = "this returns the escaped bytes as an iterator, \
                   without modifying the original"]
-    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
     pub fn escape_ascii(&self) -> EscapeAscii<'_> {
         EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
     }
@@ -93,13 +92,13 @@ impl_fn_for_zst! {
 ///
 /// This `struct` is created by the [`slice::escape_ascii`] method. See its
 /// documentation for more information.
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 #[derive(Clone)]
 pub struct EscapeAscii<'a> {
     inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
 }
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::Iterator for EscapeAscii<'a> {
     type Item = u8;
     #[inline]
@@ -131,23 +130,23 @@ impl<'a> iter::Iterator for EscapeAscii<'a> {
     }
 }
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
     fn next_back(&mut self) -> Option<u8> {
         self.inner.next_back()
     }
 }
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> fmt::Display for EscapeAscii<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.clone().try_for_each(|b| f.write_char(b as char))
     }
 }
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> fmt::Debug for EscapeAscii<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("EscapeAscii").finish_non_exhaustive()
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4e22c1d8c6d..cd38c3a7547 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -81,7 +81,7 @@ pub use index::SliceIndex;
 #[unstable(feature = "slice_range", issue = "76393")]
 pub use index::range;
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 pub use ascii::EscapeAscii;
 
 /// Calculates the direction and split point of a one-sided range.
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c02de17c1fc..27173de6307 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -115,14 +115,6 @@ impl Instant {
         Instant { t: time }
     }
 
-    pub const fn zero() -> Instant {
-        Instant { t: Timespec::zero() }
-    }
-
-    pub fn actually_monotonic() -> bool {
-        true
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.t.sub_timespec(&other.t).ok()
     }
diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs
index 6a992ad1d3c..25f13ee441a 100644
--- a/library/std/src/sys/itron/time.rs
+++ b/library/std/src/sys/itron/time.rs
@@ -14,15 +14,6 @@ impl Instant {
         }
     }
 
-    pub const fn zero() -> Instant {
-        Instant(0)
-    }
-
-    pub fn actually_monotonic() -> bool {
-        // There are ways to change the system time
-        false
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0).map(|ticks| {
             // `SYSTIM` is measured in microseconds
diff --git a/library/std/src/sys/sgx/time.rs b/library/std/src/sys/sgx/time.rs
index e2f6e6dba69..db4cf2804bf 100644
--- a/library/std/src/sys/sgx/time.rs
+++ b/library/std/src/sys/sgx/time.rs
@@ -25,14 +25,6 @@ impl Instant {
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
         Some(Instant(self.0.checked_sub(*other)?))
     }
-
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
 }
 
 impl SystemTime {
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 824283ef6c4..59ddd1aa92f 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -154,14 +154,6 @@ mod inner {
             Instant { t: unsafe { mach_absolute_time() } }
         }
 
-        pub const fn zero() -> Instant {
-            Instant { t: 0 }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            true
-        }
-
         pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
             let diff = self.t.checked_sub(other.t)?;
             let info = info();
@@ -296,17 +288,6 @@ mod inner {
             Instant { t: now(libc::CLOCK_MONOTONIC) }
         }
 
-        pub const fn zero() -> Instant {
-            Instant { t: Timespec::zero() }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
-                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
-                || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
-                || cfg!(target_os = "fuchsia")
-        }
-
         pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
             self.t.sub_timespec(&other.t).ok()
         }
diff --git a/library/std/src/sys/unsupported/time.rs b/library/std/src/sys/unsupported/time.rs
index 8aaf1777f24..6d67b538a96 100644
--- a/library/std/src/sys/unsupported/time.rs
+++ b/library/std/src/sys/unsupported/time.rs
@@ -13,14 +13,6 @@ impl Instant {
         panic!("time not implemented on this platform")
     }
 
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
-
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0)
     }
diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs
index db0ddecf0c6..088585654b9 100644
--- a/library/std/src/sys/wasi/time.rs
+++ b/library/std/src/sys/wasi/time.rs
@@ -25,14 +25,6 @@ impl Instant {
         Instant(current_time(wasi::CLOCKID_MONOTONIC))
     }
 
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
-
-    pub fn actually_monotonic() -> bool {
-        true
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0)
     }
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 91e4f765484..a04908b541c 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -41,14 +41,6 @@ impl Instant {
         perf_counter::PerformanceCounterInstant::now().into()
     }
 
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
-    pub const fn zero() -> Instant {
-        Instant { t: Duration::from_secs(0) }
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         // On windows there's a threshold below which we consider two timestamps
         // equivalent due to measurement error. For more details + doc link,
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 2d2b96c8bce..df8a726e64e 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -31,7 +31,6 @@
 
 #![stable(feature = "time", since = "1.3.0")]
 
-mod monotonic;
 #[cfg(test)]
 mod tests;
 
@@ -50,8 +49,8 @@ pub use core::time::FromFloatSecsError;
 /// A measurement of a monotonically nondecreasing clock.
 /// Opaque and useful only with [`Duration`].
 ///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
+/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously
+/// measured instant when created, and are often useful for tasks such as measuring
 /// benchmarks or timing how long an operation takes.
 ///
 /// Note, however, that instants are **not** guaranteed to be **steady**. In other
@@ -84,6 +83,8 @@ pub use core::time::FromFloatSecsError;
 /// }
 /// ```
 ///
+/// [platform bugs]: Instant#monotonicity
+///
 /// # OS-specific behaviors
 ///
 /// An `Instant` is a wrapper around system-specific types and it may behave
@@ -125,6 +126,26 @@ pub use core::time::FromFloatSecsError;
 /// > structure cannot represent the new point in time.
 ///
 /// [`add`]: Instant::add
+///
+/// ## Monotonicity
+///
+/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
+/// if available, which is the case for all [tier 1] platforms.
+/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
+/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
+/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this
+/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations
+/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order.
+///
+/// This workaround obscures programming errors where earlier and later instants are accidentally
+/// swapped. For this reason future rust versions may reintroduce panics.
+///
+/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
+/// [`duration_since`]: Instant::duration_since
+/// [`elapsed`]: Instant::elapsed
+/// [`sub`]: Instant::sub
+/// [`checked_duration_since`]: Instant::checked_duration_since
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -247,59 +268,19 @@ impl Instant {
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn now() -> Instant {
-        let os_now = time::Instant::now();
-
-        // And here we come upon a sad state of affairs. The whole point of
-        // `Instant` is that it's monotonically increasing. We've found in the
-        // wild, however, that it's not actually monotonically increasing for
-        // one reason or another. These appear to be OS and hardware level bugs,
-        // and there's not really a whole lot we can do about them. Here's a
-        // taste of what we've found:
-        //
-        // * #48514 - OpenBSD, x86_64
-        // * #49281 - linux arm64 and s390x
-        // * #51648 - windows, x86
-        // * #56560 - windows, x86_64, AWS
-        // * #56612 - windows, x86, vm (?)
-        // * #56940 - linux, arm64
-        // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
-        //   Firefox bug
-        //
-        // It seems that this just happens a lot in the wild.
-        // We're seeing panics across various platforms where consecutive calls
-        // to `Instant::now`, such as via the `elapsed` function, are panicking
-        // as they're going backwards. Placed here is a last-ditch effort to try
-        // to fix things up. We keep a global "latest now" instance which is
-        // returned instead of what the OS says if the OS goes backwards.
-        //
-        // To hopefully mitigate the impact of this, a few platforms are
-        // excluded as "these at least haven't gone backwards yet".
-        //
-        // While issues have been seen on arm64 platforms the Arm architecture
-        // requires that the counter monotonically increases and that it must
-        // provide a uniform view of system time (e.g. it must not be possible
-        // for a core to receive a message from another core with a time stamp
-        // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
-        // there have been a few 64bit SoCs that have bugs which cause time to
-        // not monoticially increase, these have been fixed in the Linux kernel
-        // and we shouldn't penalize all Arm SoCs for those who refuse to
-        // update their kernels:
-        // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
-        // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
-        // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
-        // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
-        if time::Instant::actually_monotonic() {
-            return Instant(os_now);
-        }
-
-        Instant(monotonic::monotonize(os_now))
+        Instant(time::Instant::now())
     }
 
-    /// Returns the amount of time elapsed from another instant to this one.
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
     ///
     /// # Panics
     ///
-    /// This function will panic if `earlier` is later than `self`.
+    /// Previous rust versions panicked when `earlier` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
@@ -311,16 +292,22 @@ impl Instant {
     /// sleep(Duration::new(1, 0));
     /// let new_now = Instant::now();
     /// println!("{:?}", new_now.duration_since(now));
+    /// println!("{:?}", now.duration_since(new_now)); // 0ns
     /// ```
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration_since(&self, earlier: Instant) -> Duration {
-        self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
+        self.checked_duration_since(earlier).unwrap_or_default()
     }
 
     /// Returns the amount of time elapsed from another instant to this one,
     /// or None if that instant is later than this one.
     ///
+    /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
+    /// this method can return `None`.
+    ///
+    /// [monotonicity bugs]: Instant#monotonicity
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -364,9 +351,11 @@ impl Instant {
     ///
     /// # Panics
     ///
-    /// This function may panic if the current time is earlier than this
-    /// instant, which is something that can happen if an `Instant` is
-    /// produced synthetically.
+    /// Previous rust versions panicked when self was earlier than the current time. Currently this
+    /// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
@@ -442,6 +431,16 @@ impl SubAssign<Duration> for Instant {
 impl Sub<Instant> for Instant {
     type Output = Duration;
 
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
+    ///
+    /// # Panics
+    ///
+    /// Previous rust versions panicked when `other` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     fn sub(self, other: Instant) -> Duration {
         self.duration_since(other)
     }
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
deleted file mode 100644
index 64f16245c2b..00000000000
--- a/library/std/src/time/monotonic.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-use crate::sys::time;
-
-#[inline]
-pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-    inner::monotonize(raw)
-}
-
-#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))]
-pub mod inner {
-    use crate::sync::atomic::AtomicU64;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
-
-    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
-    const UNINITIALIZED: u64 = 0b11 << 30;
-    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        monotonize_impl(&MONO, raw)
-    }
-
-    #[inline]
-    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        let secs = delta.as_secs();
-        // occupies no more than 30 bits (10^9 seconds)
-        let nanos = delta.subsec_nanos() as u64;
-
-        // This wraps around every 136 years (2^32 seconds).
-        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
-        // than 2^31 seconds as expected and everything else as a backslide which will be
-        // monotonized.
-        // This could be a problem for programs that call instants at intervals greater
-        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
-        let packed = (secs << 32) | nanos;
-        let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
-            (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
-        });
-        match updated {
-            Ok(_) => raw,
-            Err(newer) => {
-                // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
-                // passed in value and the 64bits loaded from the atomic
-                let seconds_lower = newer >> 32;
-                let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
-                if secs & 0xffff_ffff > seconds_lower {
-                    // Backslide caused the lower 32bit of the seconds part to wrap.
-                    // This must be the case because the seconds part is larger even though
-                    // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
-                    //
-                    // We assume that backslides are smaller than 2^32 seconds
-                    // which means we need to add 1 to the upper half to restore it.
-                    //
-                    // Example:
-                    // most recent observed time: 0xA1_0000_0000_0000_0000u128
-                    // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
-                    // backslide by 1s
-                    // caller time is             0xA0_ffff_ffff_0000_0000u128
-                    // -> we can fix up the upper half time by adding 1 << 32
-                    seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
-                }
-                let secs = seconds_upper | seconds_lower;
-                let nanos = newer as u32;
-                ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-            }
-        }
-    }
-}
-
-#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))]
-pub mod inner {
-    use crate::sync::atomic::AtomicU128;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    const ZERO: time::Instant = time::Instant::zero();
-    static MONO: AtomicU128 = AtomicU128::new(0);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        // Split into seconds and nanos since Duration doesn't have a
-        // constructor that takes a u128
-        let secs = delta.as_secs() as u128;
-        let nanos = delta.subsec_nanos() as u128;
-        let timestamp: u128 = secs << 64 | nanos;
-        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
-        let secs = (timestamp >> 64) as u64;
-        let nanos = timestamp as u32;
-        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-    }
-}
-
-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
-pub mod inner {
-    use crate::cmp;
-    use crate::sys::time;
-    use crate::sys_common::mutex::StaticMutex;
-
-    #[inline]
-    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
-        static LOCK: StaticMutex = StaticMutex::new();
-        static mut LAST_NOW: time::Instant = time::Instant::zero();
-        unsafe {
-            let _lock = LOCK.lock();
-            let now = cmp::max(LAST_NOW, os_now);
-            LAST_NOW = now;
-            now
-        }
-    }
-}
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 7279925a6d0..d1a69ff8697 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -90,10 +90,9 @@ fn instant_math_is_associative() {
 }
 
 #[test]
-#[should_panic]
-fn instant_duration_since_panic() {
+fn instant_duration_since_saturates() {
     let a = Instant::now();
-    let _ = (a - Duration::SECOND).duration_since(a);
+    assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO);
 }
 
 #[test]
@@ -109,6 +108,7 @@ fn instant_checked_duration_since_nopanic() {
 #[test]
 fn instant_saturating_duration_since_nopanic() {
     let a = Instant::now();
+    #[allow(deprecated, deprecated_in_future)]
     let ret = (a - Duration::SECOND).saturating_duration_since(a);
     assert_eq!(ret, Duration::ZERO);
 }
@@ -192,31 +192,6 @@ fn since_epoch() {
     assert!(a < hundred_twenty_years);
 }
 
-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
-#[test]
-fn monotonizer_wrapping_backslide() {
-    use super::monotonic::inner::{monotonize_impl, ZERO};
-    use core::sync::atomic::AtomicU64;
-
-    let reference = AtomicU64::new(0);
-
-    let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) {
-        Some(time) => time,
-        None => {
-            // platform cannot represent u32::MAX seconds so it won't have to deal with this kind
-            // of overflow either
-            return;
-        }
-    };
-
-    let monotonized = monotonize_impl(&reference, time);
-    let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap();
-    assert_eq!(
-        monotonized, expected,
-        "64bit monotonizer should handle overflows in the seconds part"
-    );
-}
-
 macro_rules! bench_instant_threaded {
     ($bench_name:ident, $thread_count:expr) => {
         #[bench]
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 86115a90294..6c1128b393f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -63,7 +63,7 @@ def support_xz():
     except tarfile.CompressionError:
         return False
 
-def get(base, url, path, checksums, verbose=False, do_verify=True):
+def get(base, url, path, checksums, verbose=False, do_verify=True, help_on_error=None):
     with tempfile.NamedTemporaryFile(delete=False) as temp_file:
         temp_path = temp_file.name
 
@@ -82,7 +82,7 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
                         print("ignoring already-download file",
                             path, "due to failed verification")
                     os.unlink(path)
-        download(temp_path, "{}/{}".format(base, url), True, verbose)
+        download(temp_path, "{}/{}".format(base, url), True, verbose, help_on_error=help_on_error)
         if do_verify and not verify(temp_path, sha256, verbose):
             raise RuntimeError("failed verification")
         if verbose:
@@ -95,17 +95,17 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
             os.unlink(temp_path)
 
 
-def download(path, url, probably_big, verbose):
+def download(path, url, probably_big, verbose, help_on_error=None):
     for _ in range(0, 4):
         try:
-            _download(path, url, probably_big, verbose, True)
+            _download(path, url, probably_big, verbose, True, help_on_error=help_on_error)
             return
         except RuntimeError:
             print("\nspurious failure, trying again")
-    _download(path, url, probably_big, verbose, False)
+    _download(path, url, probably_big, verbose, False, help_on_error=help_on_error)
 
 
-def _download(path, url, probably_big, verbose, exception):
+def _download(path, url, probably_big, verbose, exception, help_on_error=None):
     if probably_big or verbose:
         print("downloading {}".format(url))
     # see https://serverfault.com/questions/301128/how-to-download
@@ -126,7 +126,8 @@ def _download(path, url, probably_big, verbose, exception):
              "--connect-timeout", "30",  # timeout if cannot connect within 30 seconds
              "--retry", "3", "-Sf", "-o", path, url],
             verbose=verbose,
-            exception=exception)
+            exception=exception,
+            help_on_error=help_on_error)
 
 
 def verify(path, expected, verbose):
@@ -167,7 +168,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
     shutil.rmtree(os.path.join(dst, fname))
 
 
-def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
+def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error=None, **kwargs):
     """Run a child program in a new process"""
     if verbose:
         print("running: " + ' '.join(args))
@@ -178,6 +179,8 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
     code = ret.wait()
     if code != 0:
         err = "failed to run: " + ' '.join(args)
+        if help_on_error is not None:
+            err += "\n" + help_on_error
         if verbose or exception:
             raise RuntimeError(err)
         # For most failures, we definitely do want to print this error, or the user will have no
@@ -624,6 +627,14 @@ class RustBuild(object):
         filename = "rust-dev-nightly-" + self.build + tarball_suffix
         tarball = os.path.join(rustc_cache, filename)
         if not os.path.exists(tarball):
+            help_on_error = "error: failed to download llvm from ci"
+            help_on_error += "\nhelp: old builds get deleted after a certain time"
+            help_on_error += "\nhelp: if trying to compile an old commit of rustc,"
+            help_on_error += " disable `download-ci-llvm` in config.toml:"
+            help_on_error += "\n"
+            help_on_error += "\n[llvm]"
+            help_on_error += "\ndownload-ci-llvm = false"
+            help_on_error += "\n"
             get(
                 base,
                 "{}/{}".format(url, filename),
@@ -631,6 +642,7 @@ class RustBuild(object):
                 self.checksums_sha256,
                 verbose=self.verbose,
                 do_verify=False,
+                help_on_error=help_on_error,
             )
         unpack(tarball, tarball_suffix, self.llvm_root(),
                 match="rust-dev",
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 68028604fa4..c3205165040 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -688,7 +688,7 @@ fn main_args(at_args: &[String]) -> MainResult {
         Ok(opts) => opts,
         Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
     };
-    rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals(
+    rustc_interface::util::run_in_thread_pool_with_globals(
         options.edition,
         1, // this runs single-threaded, even in a parallel compiler
         &None,
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
index 0c4907fd002..d180de9be3b 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
@@ -1,6 +1,5 @@
 // NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
 // This should hopefully be fixed with Chalk.
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
index 4ecae471ec2..c23e54594ee 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                    ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
@@ -11,7 +11,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
    |             ++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:43
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
@@ -23,7 +23,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
    |             ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                                                                             ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs
index a9aa2747e52..b0703a4ee22 100644
--- a/src/test/ui/associated-type-bounds/trait-params.rs
+++ b/src/test/ui/associated-type-bounds/trait-params.rs
@@ -1,5 +1,4 @@
 // build-pass (FIXME(62277): could be check-pass?)
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
index f1aab2a6da0..97c5acf1f72 100644
--- a/src/test/ui/associated-type-bounds/union-bounds.rs
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 #![feature(untagged_unions)]
diff --git a/src/test/ui/associated-types/associated-types-stream.rs b/src/test/ui/associated-types/associated-types-stream.rs
index 220ee6af2fc..c9b302b9691 100644
--- a/src/test/ui/associated-types/associated-types-stream.rs
+++ b/src/test/ui/associated-types/associated-types-stream.rs
@@ -1,8 +1,6 @@
 // run-pass
 // Test references to the trait `Stream` in the bounds for associated
 // types defined on `Stream`. Issue #20551.
-// ignore-compare-mode-chalk
-
 
 trait Stream {
     type Car;
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
index 5193400882d..f74c5a8590d 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 trait Z<'a, T: ?Sized>
 where
     T: Z<'a, u16>,
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
index 730229b5208..354caef1e41 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
    |
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -14,13 +14,13 @@ LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
    |                                   ^^^^^ required by this bound in `Z`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
    |
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -29,13 +29,13 @@ LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
    |                                   ^^^^^ required by this bound in `Z`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:16:14
+  --> $DIR/hr-associated-type-bound-param-2.rs:15:14
    |
 LL |     type W = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
index 920aa835280..d7f3151a502 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 trait Cycle: Sized {
     type Next: Cycle<Next = Self>;
 }
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
index 63cd89316b3..4c04d12a714 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:27:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:26:14
    |
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `X`
-  --> $DIR/hr-associated-type-bound-param-5.rs:18:45
+  --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
@@ -14,13 +14,13 @@ LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
    |                                             ^^^^^ required by this bound in `X`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:32:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:31:14
    |
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `X`
-  --> $DIR/hr-associated-type-bound-param-5.rs:18:45
+  --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
diff --git a/src/test/ui/associated-types/issue-50301.rs b/src/test/ui/associated-types/issue-50301.rs
index 4fcb41485d0..47ee3e7ad70 100644
--- a/src/test/ui/associated-types/issue-50301.rs
+++ b/src/test/ui/associated-types/issue-50301.rs
@@ -1,6 +1,5 @@
 // Tests that HRTBs are correctly accepted -- https://github.com/rust-lang/rust/issues/50301
 // check-pass
-// ignore-compare-mode-chalk
 trait Trait
 where
     for<'a> &'a Self::IntoIter: IntoIterator<Item = u32>,
diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs
index 9e70a847457..33d55be5812 100644
--- a/src/test/ui/borrowck/issue-64453.rs
+++ b/src/test/ui/borrowck/issue-64453.rs
@@ -2,7 +2,7 @@ struct Project;
 struct Value;
 
 static settings_dir: String = format!("");
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot call non-const fn
 //~| ERROR is not yet stable as a const
 
 fn from_string(_: String) -> Value {
diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr
index 14e16670389..f3436fbec66 100644
--- a/src/test/ui/borrowck/issue-64453.stderr
+++ b/src/test/ui/borrowck/issue-64453.stderr
@@ -7,12 +7,13 @@ LL | static settings_dir: String = format!("");
    = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
    = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `format` in statics
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
    |                               ^^^^^^^^^^^
    |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `settings_dir`
diff --git a/src/test/ui/chalkify/assert.rs b/src/test/ui/chalkify/assert.rs
new file mode 100644
index 00000000000..f4ebf91924c
--- /dev/null
+++ b/src/test/ui/chalkify/assert.rs
@@ -0,0 +1,6 @@
+// run-pass
+// compile-flags: -Z chalk
+
+fn main() {
+    assert_eq!(1, 1);
+}
diff --git a/src/test/ui/chalkify/println.rs b/src/test/ui/chalkify/println.rs
index cf36aef8afa..0f0df29019e 100644
--- a/src/test/ui/chalkify/println.rs
+++ b/src/test/ui/chalkify/println.rs
@@ -2,6 +2,5 @@
 // compile-flags: -Z chalk
 
 fn main() {
-    // FIXME(chalk): Require `RegionOutlives`/`TypeOutlives`/`Subtype` support
-    //println!("hello");
+    println!("hello");
 }
diff --git a/src/test/ui/chalkify/trait-objects.rs b/src/test/ui/chalkify/trait-objects.rs
index 13d9e6a6578..d56abc42bf5 100644
--- a/src/test/ui/chalkify/trait-objects.rs
+++ b/src/test/ui/chalkify/trait-objects.rs
@@ -5,8 +5,7 @@ use std::fmt::Display;
 
 fn main() {
     let d: &dyn Display = &mut 3;
-    // FIXME(chalk) should be able to call d.to_string() as well, but doing so
-    // requires Chalk to be able to prove trait object well-formed goals.
+    d.to_string();
     (&d).to_string();
     let f: &dyn Fn(i32) -> _ = &|x| x + x;
     f(2);
diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs
index 3d1b5a08227..eb4ecd8baca 100644
--- a/src/test/ui/check-static-values-constraints.rs
+++ b/src/test/ui/check-static-values-constraints.rs
@@ -87,7 +87,7 @@ static mut STATIC13: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
 static mut STATIC14: SafeStruct = SafeStruct {
     field1: SafeEnum::Variant1,
     field2: SafeEnum::Variant4("str".to_string())
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot call non-const fn
 };
 
 static STATIC15: &'static [Box<MyOwned>] = &[
diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr
index eb640c88e02..b28cf0d6bd0 100644
--- a/src/test/ui/check-static-values-constraints.stderr
+++ b/src/test/ui/check-static-values-constraints.stderr
@@ -15,11 +15,13 @@ error[E0010]: allocations are not allowed in statics
 LL | static STATIC11: Box<MyOwned> = box MyOwned;
    |                                 ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/check-static-values-constraints.rs:89:32
+error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics
+  --> $DIR/check-static-values-constraints.rs:89:38
    |
 LL |     field2: SafeEnum::Variant4("str".to_string())
-   |                                ^^^^^^^^^^^^^^^^^
+   |                                      ^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:94:5
diff --git a/src/test/ui/const-generics/issue-93647.rs b/src/test/ui/const-generics/issue-93647.rs
index 6a8fe64d187..c1a6bf6e34d 100644
--- a/src/test/ui/const-generics/issue-93647.rs
+++ b/src/test/ui/const-generics/issue-93647.rs
@@ -1,6 +1,6 @@
 struct X<const N: usize = {
     (||1usize)()
-    //~^ ERROR calls in constants are limited to
+    //~^ ERROR cannot call
 }>;
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issue-93647.stderr b/src/test/ui/const-generics/issue-93647.stderr
index 0fe54e7de41..e2048ecd60f 100644
--- a/src/test/ui/const-generics/issue-93647.stderr
+++ b/src/test/ui/const-generics/issue-93647.stderr
@@ -1,8 +1,11 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-93647.rs:2:5
    |
 LL |     (||1usize)()
    |     ^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs
index 0c640a5ef71..bebd0c6ac12 100644
--- a/src/test/ui/const-generics/issues/issue-90318.rs
+++ b/src/test/ui/const-generics/issues/issue-90318.rs
@@ -13,7 +13,7 @@ fn consume<T: 'static>(_val: T)
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
     //~^ ERROR: overly complex generic constant
-    //~| ERROR: calls in constants are limited to constant functions
+    //~| ERROR: cannot call non-const operator in constants
 {
 }
 
@@ -21,7 +21,7 @@ fn test<T: 'static>()
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
     //~^ ERROR: overly complex generic constant
-    //~| ERROR: calls in constants are limited to constant functions
+    //~| ERROR: cannot call non-const operator in constants
 {
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr
index 2b8afe2ef09..c8690ecd0da 100644
--- a/src/test/ui/const-generics/issues/issue-90318.stderr
+++ b/src/test/ui/const-generics/issues/issue-90318.stderr
@@ -9,11 +9,19 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:14:10
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   |
+LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+   |                       ^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: overly complex generic constant
   --> $DIR/issue-90318.rs:22:8
@@ -26,11 +34,19 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:22:10
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   |
+LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+   |                       ^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr
index 9d7ca36545c..52f1c588258 100644
--- a/src/test/ui/const-generics/nested-type.full.stderr
+++ b/src/test/ui/const-generics/nested-type.full.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
   --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index 4f32284ecb1..0e3c988ae4d 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -14,11 +14,13 @@ LL | | }]>;
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
   --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 039f996de96..5240f5c3b0b 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -13,7 +13,7 @@ struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
     }
 
     Foo::<17>::value()
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }]>;
 
 fn main() {}
diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs
index db642988971..28e89559fe5 100644
--- a/src/test/ui/consts/const-call.rs
+++ b/src/test/ui/consts/const-call.rs
@@ -4,5 +4,5 @@ fn f(x: usize) -> usize {
 
 fn main() {
     let _ = [0; f(2)];
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }
diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr
index 9761348bab8..e46bcad0e1d 100644
--- a/src/test/ui/consts/const-call.stderr
+++ b/src/test/ui/consts/const-call.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `f` in constants
   --> $DIR/const-call.rs:6:17
    |
 LL |     let _ = [0; f(2)];
    |                 ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr
new file mode 100644
index 00000000000..2a4b6f3b76f
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr
@@ -0,0 +1,9 @@
+error[E0284]: type annotations needed: cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
+  --> $DIR/ub-nonnull.rs:19:30
+   |
+LL |     let out_of_bounds_ptr = &ptr[255];
+   |                              ^^^^^^^^ cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr
new file mode 100644
index 00000000000..39352ca848a
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/ub-wide-ptr.rs:90:67
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   |                                                                   ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
index ee07dfae47c..eccda49db3e 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
@@ -7,7 +7,7 @@ extern "C" {
 const extern "C" fn bar() {
     unsafe {
         regular_in_block();
-        //~^ ERROR: calls in constant functions
+        //~^ ERROR: cannot call non-const fn
     }
 }
 
@@ -16,7 +16,7 @@ extern "C" fn regular() {}
 const extern "C" fn foo() {
     unsafe {
         regular();
-        //~^ ERROR: calls in constant functions
+        //~^ ERROR: cannot call non-const fn
     }
 }
 
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
index 348387ff5f8..5acf22e4bc6 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
@@ -1,14 +1,18 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `regular_in_block` in constant functions
   --> $DIR/const-extern-fn-call-extern-fn.rs:9:9
    |
 LL |         regular_in_block();
    |         ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `regular` in constant functions
   --> $DIR/const-extern-fn-call-extern-fn.rs:18:9
    |
 LL |         regular();
    |         ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs
index 065944ea7ea..abe68c17a0d 100644
--- a/src/test/ui/consts/const-fn-error.rs
+++ b/src/test/ui/consts/const-fn-error.rs
@@ -4,8 +4,8 @@ const fn f(x: usize) -> usize {
     let mut sum = 0;
     for i in 0..x {
         //~^ ERROR mutable references
-        //~| ERROR calls in constant functions
-        //~| ERROR calls in constant functions
+        //~| ERROR cannot convert
+        //~| ERROR cannot call non-const fn
         //~| ERROR `for` is not allowed in a `const fn`
         sum += i;
     }
diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr
index e4b62f20a33..4d53cfc35e1 100644
--- a/src/test/ui/consts/const-fn-error.stderr
+++ b/src/test/ui/consts/const-fn-error.stderr
@@ -13,11 +13,18 @@ LL | |     }
    = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
    = help: add `#![feature(const_for)]` to the crate attributes to enable
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `std::ops::Range<usize>` into an iterator in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/const-fn-error.rs:5:14
@@ -28,11 +35,13 @@ LL |     for i in 0..x {
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr
index df793d7dd7e..4c7effc0d15 100644
--- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr
+++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `random` in constant functions
   --> $DIR/const-fn-not-safe-for-const.rs:14:5
    |
 LL |     random()
    |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0013]: constant functions cannot refer to statics
   --> $DIR/const-fn-not-safe-for-const.rs:20:5
diff --git a/src/test/ui/consts/const-for.rs b/src/test/ui/consts/const-for.rs
index 5fc1ee0e369..58bcb5f74cc 100644
--- a/src/test/ui/consts/const-for.rs
+++ b/src/test/ui/consts/const-for.rs
@@ -3,8 +3,8 @@
 
 const _: () = {
     for _ in 0..5 {}
-    //~^ error: calls in constants are limited to
-    //~| error: calls in constants are limited to
+    //~^ error: cannot convert
+    //~| error: cannot call non-const fn
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr
index a35c04b3570..b0dc43eb8e8 100644
--- a/src/test/ui/consts/const-for.stderr
+++ b/src/test/ui/consts/const-for.stderr
@@ -1,14 +1,23 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
   --> $DIR/const-for.rs:5:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for.rs:5:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/control-flow/issue-46843.rs b/src/test/ui/consts/control-flow/issue-46843.rs
index edf62f23266..ddddc8505c6 100644
--- a/src/test/ui/consts/control-flow/issue-46843.rs
+++ b/src/test/ui/consts/control-flow/issue-46843.rs
@@ -8,7 +8,7 @@ fn non_const() -> Thing {
 }
 
 pub const Q: i32 = match non_const() {
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
     Thing::This => 1,
     Thing::That => 0
 };
diff --git a/src/test/ui/consts/control-flow/issue-46843.stderr b/src/test/ui/consts/control-flow/issue-46843.stderr
index ea9ea25f9e1..66227f61e35 100644
--- a/src/test/ui/consts/control-flow/issue-46843.stderr
+++ b/src/test/ui/consts/control-flow/issue-46843.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `non_const` in constants
   --> $DIR/issue-46843.rs:10:26
    |
 LL | pub const Q: i32 = match non_const() {
    |                          ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs
index 810158a2957..d5f694986fc 100644
--- a/src/test/ui/consts/intrinsic_without_const_stab.rs
+++ b/src/test/ui/consts/intrinsic_without_const_stab.rs
@@ -11,7 +11,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     }
 
     unsafe { copy(src, dst, count) }
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr
index 5a42823a605..b32b6398ece 100644
--- a/src/test/ui/consts/intrinsic_without_const_stab.stderr
+++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
   --> $DIR/intrinsic_without_const_stab.rs:13:14
    |
 LL |     unsafe { copy(src, dst, count) }
    |              ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
index bf2c44169d4..8b37268b0b2 100644
--- a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
@@ -9,7 +9,7 @@ extern "rust-intrinsic" {
 #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
 #[inline]
 pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
-    unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited
+    unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
index d4a2989e785..fcbb3724567 100644
--- a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
   --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
    |
 LL |     unsafe { copy(src, dst, count) }
    |              ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-28113.rs b/src/test/ui/consts/issue-28113.rs
index e5bd7aafe41..f8131c9f3b7 100644
--- a/src/test/ui/consts/issue-28113.rs
+++ b/src/test/ui/consts/issue-28113.rs
@@ -2,7 +2,7 @@
 
 const X: u8 =
     || -> u8 { 5 }()
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const closure
 ;
 
 fn main() {}
diff --git a/src/test/ui/consts/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr
index 3d274d777b0..7ad1f752eb0 100644
--- a/src/test/ui/consts/issue-28113.stderr
+++ b/src/test/ui/consts/issue-28113.stderr
@@ -1,8 +1,11 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-28113.rs:4:5
    |
 LL |     || -> u8 { 5 }()
    |     ^^^^^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-32829-2.rs b/src/test/ui/consts/issue-32829-2.rs
index e0fcf278330..d70b5a8c4e1 100644
--- a/src/test/ui/consts/issue-32829-2.rs
+++ b/src/test/ui/consts/issue-32829-2.rs
@@ -8,7 +8,7 @@ const bad : u32 = {
 const bad_two : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
@@ -30,7 +30,7 @@ static bad_four : u32 = {
 static bad_five : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
@@ -52,7 +52,7 @@ static mut bad_seven : u32 = {
 static mut bad_eight : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
diff --git a/src/test/ui/consts/issue-32829-2.stderr b/src/test/ui/consts/issue-32829-2.stderr
index 1d265875c5c..b94bdc0e3df 100644
--- a/src/test/ui/consts/issue-32829-2.stderr
+++ b/src/test/ui/consts/issue-32829-2.stderr
@@ -1,20 +1,26 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in constants
   --> $DIR/issue-32829-2.rs:10:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in statics
   --> $DIR/issue-32829-2.rs:32:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in statics
   --> $DIR/issue-32829-2.rs:54:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/consts/issue-43105.rs b/src/test/ui/consts/issue-43105.rs
index cc6a4850853..cac12b90970 100644
--- a/src/test/ui/consts/issue-43105.rs
+++ b/src/test/ui/consts/issue-43105.rs
@@ -1,7 +1,7 @@
 fn xyz() -> u8 { 42 }
 
 const NUM: u8 = xyz();
-//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants
+//~^ ERROR cannot call non-const fn
 
 fn main() {
     match 1 {
diff --git a/src/test/ui/consts/issue-43105.stderr b/src/test/ui/consts/issue-43105.stderr
index e508cbdd1dd..2d1174af71c 100644
--- a/src/test/ui/consts/issue-43105.stderr
+++ b/src/test/ui/consts/issue-43105.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `xyz` in constants
   --> $DIR/issue-43105.rs:3:17
    |
 LL | const NUM: u8 = xyz();
    |                 ^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: could not evaluate constant pattern
   --> $DIR/issue-43105.rs:8:9
diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs
index 90ea217698d..9c673d20b2a 100644
--- a/src/test/ui/consts/issue-56164.rs
+++ b/src/test/ui/consts/issue-56164.rs
@@ -1,7 +1,7 @@
 #![feature(const_fn_fn_ptr_basics)]
 
 const fn foo() { (||{})() }
-//~^ ERROR calls in constant functions
+//~^ ERROR cannot call non-const closure
 
 const fn bad(input: fn()) {
     input()
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
index 500af0a4006..62a7c7db6b8 100644
--- a/src/test/ui/consts/issue-56164.stderr
+++ b/src/test/ui/consts/issue-56164.stderr
@@ -1,8 +1,11 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/issue-56164.rs:3:18
    |
 LL | const fn foo() { (||{})() }
    |                  ^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constant functions
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: function pointers are not allowed in const fn
   --> $DIR/issue-56164.rs:7:5
diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.rs b/src/test/ui/consts/issue-68542-closure-in-array-len.rs
index d77fd9aa831..37958e7919d 100644
--- a/src/test/ui/consts/issue-68542-closure-in-array-len.rs
+++ b/src/test/ui/consts/issue-68542-closure-in-array-len.rs
@@ -3,7 +3,7 @@
 // in the length part of an array.
 
 struct Bug {
-    a: [(); (|| { 0 })()] //~ ERROR calls in constants are limited to
+    a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr
index 74d70e18a24..74fbbc680f7 100644
--- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr
+++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr
@@ -1,8 +1,11 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-68542-closure-in-array-len.rs:6:13
    |
 LL |     a: [(); (|| { 0 })()]
    |             ^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-90870.fixed b/src/test/ui/consts/issue-90870.fixed
index e767effcdd0..0d28e06e532 100644
--- a/src/test/ui/consts/issue-90870.fixed
+++ b/src/test/ui/consts/issue-90870.fixed
@@ -6,20 +6,20 @@
 
 const fn f(a: &u8, b: &u8) -> bool {
     *a == *b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     ****a == ****b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
     while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
         if *l == *r {
-        //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+        //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
             a = at;
             b = bt;
diff --git a/src/test/ui/consts/issue-90870.rs b/src/test/ui/consts/issue-90870.rs
index 35b3c8242aa..c6bfffd2c5c 100644
--- a/src/test/ui/consts/issue-90870.rs
+++ b/src/test/ui/consts/issue-90870.rs
@@ -6,20 +6,20 @@
 
 const fn f(a: &u8, b: &u8) -> bool {
     a == b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     a == b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
     while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
         if l == r {
-        //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+        //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
             a = at;
             b = bt;
diff --git a/src/test/ui/consts/issue-90870.stderr b/src/test/ui/consts/issue-90870.stderr
index 0e33e6ebe5a..478445cfb39 100644
--- a/src/test/ui/consts/issue-90870.stderr
+++ b/src/test/ui/consts/issue-90870.stderr
@@ -1,31 +1,34 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:8:5
    |
 LL |     a == b
    |     ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |     *a == *b
    |     +     +
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:14:5
    |
 LL |     a == b
    |     ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |     ****a == ****b
    |     ++++     ++++
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:21:12
    |
 LL |         if l == r {
    |            ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |         if *l == *r {
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
index 4e1b7bf119c..258997597ea 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
@@ -1,7 +1,7 @@
 const fn foo(a: i32) -> Vec<i32> {
     vec![1, 2, 3]
     //~^ ERROR allocations are not allowed
-    //~| ERROR calls in constant functions
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
index fee43864e20..74234108911 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
@@ -6,12 +6,13 @@ LL |     vec![1, 2, 3]
    |
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constant functions
   --> $DIR/bad_const_fn_body_ice.rs:2:5
    |
 LL |     vec![1, 2, 3]
    |     ^^^^^^^^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/mir_check_nonconst.rs b/src/test/ui/consts/mir_check_nonconst.rs
index b8ec0c3c449..b6f34b922fa 100644
--- a/src/test/ui/consts/mir_check_nonconst.rs
+++ b/src/test/ui/consts/mir_check_nonconst.rs
@@ -6,6 +6,6 @@ fn bar() -> Foo {
 }
 
 static foo: Foo = bar();
-//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
+//~^ ERROR cannot call non-const fn
 
 fn main() {}
diff --git a/src/test/ui/consts/mir_check_nonconst.stderr b/src/test/ui/consts/mir_check_nonconst.stderr
index 30f68ba4372..2bac995eebf 100644
--- a/src/test/ui/consts/mir_check_nonconst.stderr
+++ b/src/test/ui/consts/mir_check_nonconst.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `bar` in statics
   --> $DIR/mir_check_nonconst.rs:8:19
    |
 LL | static foo: Foo = bar();
    |                   ^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
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 928605356a1..4ef25bd1334 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,8 +1,14 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/unstable-const-fn-in-libcore.rs:24:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL |     const fn unwrap_or_else<F: FnOnce() -> T + ~const std::ops::FnOnce<()>>(self, f: F) -> T {
+   |                                              +++++++++++++++++++++++++++++
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:53
diff --git a/src/test/ui/deriving/deriving-associated-types.rs b/src/test/ui/deriving/deriving-associated-types.rs
index 13735ff2c5a..4b1cbe80c50 100644
--- a/src/test/ui/deriving/deriving-associated-types.rs
+++ b/src/test/ui/deriving/deriving-associated-types.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 pub trait DeclaredTrait {
     type Type;
 }
diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs
index 45dcb74a6e0..da45f0d133d 100644
--- a/src/test/ui/impl-trait/example-calendar.rs
+++ b/src/test/ui/impl-trait/example-calendar.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 
 #![feature(fn_traits,
            step_trait,
diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs
index a519397806e..17a6a857874 100644
--- a/src/test/ui/impl-trait/issue-55872-2.rs
+++ b/src/test/ui/impl-trait/issue-55872-2.rs
@@ -1,5 +1,4 @@
 // edition:2018
-// ignore-compare-mode-chalk
 
 #![feature(type_alias_impl_trait)]
 
diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr
index 97545ba3d11..b76b564dfb1 100644
--- a/src/test/ui/impl-trait/issue-55872-2.stderr
+++ b/src/test/ui/impl-trait/issue-55872-2.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
-  --> $DIR/issue-55872-2.rs:14:20
+  --> $DIR/issue-55872-2.rs:13:20
    |
 LL |     fn foo<T>() -> Self::E {
    |                    ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
 
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-2.rs:14:28
+  --> $DIR/issue-55872-2.rs:13:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs
index bbd94025417..183728b0f7f 100644
--- a/src/test/ui/impl-trait/issue-55872.rs
+++ b/src/test/ui/impl-trait/issue-55872.rs
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 pub trait Bar {
diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr
index 60654ec3461..39d870dc003 100644
--- a/src/test/ui/impl-trait/issue-55872.stderr
+++ b/src/test/ui/impl-trait/issue-55872.stderr
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872.rs:13:28
+  --> $DIR/issue-55872.rs:12:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs
index af65b79d3e8..b947fc1d239 100644
--- a/src/test/ui/impl-trait/issues/issue-65581.rs
+++ b/src/test/ui/impl-trait/issues/issue-65581.rs
@@ -1,4 +1,5 @@
 // check-pass
+// ignore-compare-mode-chalk
 
 #![allow(dead_code)]
 
diff --git a/src/test/ui/issues/issue-16538.mir.stderr b/src/test/ui/issues/issue-16538.mir.stderr
index 5a276f27886..60a2bf1e2d6 100644
--- a/src/test/ui/issues/issue-16538.mir.stderr
+++ b/src/test/ui/issues/issue-16538.mir.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Y::foo` in statics
   --> $DIR/issue-16538.rs:15:23
    |
 LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
   --> $DIR/issue-16538.rs:15:30
diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr
index 8365a1dbf6e..2ba9dfa2bc5 100644
--- a/src/test/ui/issues/issue-16538.thir.stderr
+++ b/src/test/ui/issues/issue-16538.thir.stderr
@@ -14,11 +14,13 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Y::foo` in statics
   --> $DIR/issue-16538.rs:15:23
    |
 LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-23122-1.rs b/src/test/ui/issues/issue-23122-1.rs
index efa4e614be5..7fe0900ed5f 100644
--- a/src/test/ui/issues/issue-23122-1.rs
+++ b/src/test/ui/issues/issue-23122-1.rs
@@ -1,10 +1,10 @@
-// ignore-compare-mode-chalk
-
 trait Next {
     type Next: Next;
 }
 
-struct GetNext<T: Next> { t: T }
+struct GetNext<T: Next> {
+    t: T,
+}
 
 impl<T: Next> Next for GetNext<T> {
     type Next = <GetNext<T> as Next>::Next;
diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs
index 7866b931ec4..95e1f60d8b0 100644
--- a/src/test/ui/issues/issue-23122-2.rs
+++ b/src/test/ui/issues/issue-23122-2.rs
@@ -1,9 +1,10 @@
-// ignore-compare-mode-chalk
 trait Next {
     type Next: Next;
 }
 
-struct GetNext<T: Next> { t: T }
+struct GetNext<T: Next> {
+    t: T,
+}
 
 impl<T: Next> Next for GetNext<T> {
     type Next = <GetNext<T::Next> as Next>::Next;
diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr
index b345e901787..7519e632d54 100644
--- a/src/test/ui/issues/issue-23122-2.stderr
+++ b/src/test/ui/issues/issue-23122-2.stderr
@@ -1,12 +1,12 @@
 error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
-  --> $DIR/issue-23122-2.rs:9:17
+  --> $DIR/issue-23122-2.rs:10:17
    |
 LL |     type Next = <GetNext<T::Next> as Next>::Next;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`)
 note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
-  --> $DIR/issue-23122-2.rs:8:15
+  --> $DIR/issue-23122-2.rs:9:15
    |
 LL | impl<T: Next> Next for GetNext<T> {
    |               ^^^^     ^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-25901.rs b/src/test/ui/issues/issue-25901.rs
index a139ad0d3e3..ba12e1ad021 100644
--- a/src/test/ui/issues/issue-25901.rs
+++ b/src/test/ui/issues/issue-25901.rs
@@ -2,7 +2,7 @@ struct A;
 struct B;
 
 static S: &'static B = &A;
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot perform deref coercion on `A` in statics
 
 use std::ops::Deref;
 
diff --git a/src/test/ui/issues/issue-25901.stderr b/src/test/ui/issues/issue-25901.stderr
index d6eb3760cdf..5c35250bc3f 100644
--- a/src/test/ui/issues/issue-25901.stderr
+++ b/src/test/ui/issues/issue-25901.stderr
@@ -1,8 +1,21 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot perform deref coercion on `A` in statics
   --> $DIR/issue-25901.rs:4:24
    |
 LL | static S: &'static B = &A;
    |                        ^^
+   |
+   = note: attempting to deref into `B`
+note: deref defined here
+  --> $DIR/issue-25901.rs:10:5
+   |
+LL |     type Target = B;
+   |     ^^^^^^^^^^^^^^^^
+note: impl defined here, but it is not `const`
+  --> $DIR/issue-25901.rs:9:1
+   |
+LL | impl Deref for A {
+   | ^^^^^^^^^^^^^^^^
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-28561.rs b/src/test/ui/issues/issue-28561.rs
index 184f5cb26c5..1241fb0b1f8 100644
--- a/src/test/ui/issues/issue-28561.rs
+++ b/src/test/ui/issues/issue-28561.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-compare-mode-chalk
 #[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 struct Array<T> {
     f00: [T; 00],
diff --git a/src/test/ui/issues/issue-33187.rs b/src/test/ui/issues/issue-33187.rs
index f6b56610ec7..8db9e005885 100644
--- a/src/test/ui/issues/issue-33187.rs
+++ b/src/test/ui/issues/issue-33187.rs
@@ -1,10 +1,15 @@
 // run-pass
-// ignore-compare-mode-chalk
+
 struct Foo<A: Repr>(<A as Repr>::Data);
 
-impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy { }
-impl<A> Clone for Foo<A> where <A as Repr>::Data: Clone {
-    fn clone(&self) -> Self { Foo(self.0.clone()) }
+impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy {}
+impl<A> Clone for Foo<A>
+where
+    <A as Repr>::Data: Clone,
+{
+    fn clone(&self) -> Self {
+        Foo(self.0.clone())
+    }
 }
 
 trait Repr {
@@ -15,5 +20,4 @@ impl<A> Repr for A {
     type Data = u32;
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-37051.rs b/src/test/ui/issues/issue-37051.rs
index e0c47197eaa..9cae6cf5e76 100644
--- a/src/test/ui/issues/issue-37051.rs
+++ b/src/test/ui/issues/issue-37051.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_defaults)]
 
diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr
index 3d765daa7cd..ea27e7bd250 100644
--- a/src/test/ui/issues/issue-39559-2.stderr
+++ b/src/test/ui/issues/issue-39559-2.stderr
@@ -1,14 +1,18 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:14:24
    |
 LL |     let array: [usize; Dim3::dim()]
    |                        ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:16:15
    |
 LL |         = [0; Dim3::dim()];
    |               ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr
index c1a3084f30e..5809a56cd4b 100644
--- a/src/test/ui/issues/issue-55796.nll.stderr
+++ b/src/test/ui/issues/issue-55796.nll.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
@@ -8,7 +8,7 @@ LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
diff --git a/src/test/ui/issues/issue-55796.rs b/src/test/ui/issues/issue-55796.rs
index 1086669ee74..d802ce3b6cf 100644
--- a/src/test/ui/issues/issue-55796.rs
+++ b/src/test/ui/issues/issue-55796.rs
@@ -1,5 +1,3 @@
-// ignore-compare-mode-chalk
-
 pub trait EdgeTrait<N> {
     fn target(&self) -> N;
 }
@@ -16,12 +14,12 @@ pub trait Graph<'a> {
 
     fn out_neighbors(&'a self, u: &Self::Node) -> Box<dyn Iterator<Item = Self::Node>> {
         Box::new(self.out_edges(u).map(|e| e.target()))
-//~^ ERROR cannot infer
+        //~^ ERROR cannot infer
     }
 
     fn in_neighbors(&'a self, u: &Self::Node) -> Box<dyn Iterator<Item = Self::Node>> {
         Box::new(self.in_edges(u).map(|e| e.target()))
-//~^ ERROR cannot infer
+        //~^ ERROR cannot infer
     }
 }
 
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index 304339657f0..569a13f45bc 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -1,22 +1,22 @@
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-55796.rs:7:17
+  --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:18:40: 18:54]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:18:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,24 +24,24 @@ LL |         Box::new(self.out_edges(u).map(|e| e.target()))
               found `Box<dyn Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-55796.rs:7:17
+  --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:23:39: 23:53]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:23:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
index 44ea9f12d38..36e9932602f 100644
--- a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
+++ b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
@@ -1,6 +1,5 @@
 // build-pass
 // ignore-tidy-filelength
-// ignore-compare-mode-chalk
 #![crate_type = "rlib"]
 
 fn banana(v: &str) -> u32 {
diff --git a/src/test/ui/never_type/issue-52443.rs b/src/test/ui/never_type/issue-52443.rs
index 4519833b864..cebcca944af 100644
--- a/src/test/ui/never_type/issue-52443.rs
+++ b/src/test/ui/never_type/issue-52443.rs
@@ -8,7 +8,7 @@ fn main() {
 
     [(); { for _ in 0usize.. {}; 0}];
     //~^ ERROR `for` is not allowed in a `const`
-    //~| ERROR calls in constants are limited to constant functions
+    //~| ERROR cannot convert
     //~| ERROR mutable references are not allowed in constants
-    //~| ERROR calls in constants are limited to constant functions
+    //~| ERROR cannot call non-const fn
 }
diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr
index 216b56f7059..8c1755205f0 100644
--- a/src/test/ui/never_type/issue-52443.stderr
+++ b/src/test/ui/never_type/issue-52443.stderr
@@ -38,11 +38,18 @@ LL |     [(); loop { break }];
    |                 expected `usize`, found `()`
    |                 help: give it a value of the expected type: `break 42`
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `RangeFrom<usize>` into an iterator in constants
   --> $DIR/issue-52443.rs:9:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constants
   --> $DIR/issue-52443.rs:9:21
@@ -53,11 +60,13 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
   --> $DIR/issue-52443.rs:9:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
index d15e4024607..5109a0e4a68 100644
--- a/src/test/ui/nll/ty-outlives/issue-53789-2.rs
+++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
@@ -1,16 +1,14 @@
 // Regression test for #53789.
 //
 // check-pass
-// ignore-compare-mode-chalk
 
+use std::cmp::Ord;
 use std::collections::BTreeMap;
 use std::ops::Range;
-use std::cmp::Ord;
 
 macro_rules! valuetree {
     () => {
-        type ValueTree =
-            <Self::Strategy as $crate::Strategy>::Value;
+        type ValueTree = <Self::Strategy as $crate::Strategy>::Value;
     };
 }
 
@@ -41,7 +39,9 @@ macro_rules! product_type {
 macro_rules! default {
     ($type: ty, $val: expr) => {
         impl Default for $type {
-            fn default() -> Self { $val.into() }
+            fn default() -> Self {
+                $val.into()
+            }
         }
     };
 }
@@ -90,21 +90,17 @@ trait ValueTree {
 }
 
 trait Strategy {
-    type Value : ValueTree;
+    type Value: ValueTree;
 }
 
 #[derive(Clone)]
-struct VecStrategy<T : Strategy> {
+struct VecStrategy<T: Strategy> {
     element: T,
     size: Range<usize>,
 }
 
-fn vec<T : Strategy>(element: T, size: Range<usize>)
-                     -> VecStrategy<T> {
-    VecStrategy {
-        element: element,
-        size: size,
-    }
+fn vec<T: Strategy>(element: T, size: Range<usize>) -> VecStrategy<T> {
+    VecStrategy { element: element, size: size }
 }
 
 type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
@@ -124,7 +120,6 @@ type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
 struct SizeBounds(Range<usize>);
 default!(SizeBounds, 0..100);
 
-
 impl From<Range<usize>> for SizeBounds {
     fn from(high: Range<usize>) -> Self {
         unimplemented!()
@@ -137,24 +132,26 @@ impl From<SizeBounds> for Range<usize> {
     }
 }
 
-
-fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters)
-                                  -> StrategyType<'a, A> {
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
     unimplemented!()
 }
 
-impl<K: ValueTree, V: ValueTree> Strategy for (K, V) where
-    <K as ValueTree>::Value: Ord {
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V)
+where
+    <K as ValueTree>::Value: Ord,
+{
     type Value = TupleValueTree<(K, V)>;
 }
 
-impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> where
-    <K as ValueTree>::Value: Ord {
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)>
+where
+    <K as ValueTree>::Value: Ord,
+{
     type Value = BTreeMapValueTree<K, V>;
 }
 
 #[derive(Clone)]
-struct VecValueTree<T : ValueTree> {
+struct VecValueTree<T: ValueTree> {
     elements: Vec<T>,
 }
 
@@ -185,8 +182,8 @@ impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
 where
     A: Arbitrary<'static> + Ord,
     B: Arbitrary<'static>,
-StrategyFor<A>: 'static,
-StrategyFor<B>: 'static,
+    StrategyFor<A>: 'static,
+    StrategyFor<B>: 'static,
 {
     valuetree!();
     type Parameters = RangedParams2<A::Parameters, B::Parameters>;
@@ -208,10 +205,14 @@ mapfn! {
     }
 }
 
-fn btree_map<K : Strategy + 'static, V : Strategy + 'static>
-    (key: K, value: V, size: Range<usize>)
-     -> BTreeMapStrategy<K, V>
-where ValueFor<K> : Ord {
+fn btree_map<K: Strategy + 'static, V: Strategy + 'static>(
+    key: K,
+    value: V,
+    size: Range<usize>,
+) -> BTreeMapStrategy<K, V>
+where
+    ValueFor<K>: Ord,
+{
     unimplemented!()
 }
 
@@ -245,4 +246,4 @@ mod statics {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
index 33e839fd120..24b9235bb9a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
@@ -22,7 +22,8 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {
 
 pub const fn add_u32(a: u32, b: u32) -> u32 {
     a.plus(b)
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
index 5a73c4debb4..1fc9db27761 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/call-const-trait-method-fail.rs:24:5
+error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
+  --> $DIR/call-const-trait-method-fail.rs:24:7
    |
 LL |     a.plus(b)
-   |     ^^^^^^^^^
+   |       ^^^^^^^ the trait `~const Plus` is not implemented for `u32`
+   |
+note: the trait `Plus` is implemented for `u32`, but that implementation is not `const`
+  --> $DIR/call-const-trait-method-fail.rs:24:7
+   |
+LL |     a.plus(b)
+   |       ^^^^^^^
+
+error[E0015]: cannot call non-const fn `<u32 as Plus>::plus` in constant functions
+  --> $DIR/call-const-trait-method-fail.rs:24:7
+   |
+LL |     a.plus(b)
+   |       ^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
index e96249ff2fd..e81e0d1e571 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
@@ -3,7 +3,8 @@
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR can't compare
+    //~| ERROR cannot call non-const
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
index 818c5828696..3963f64ad32 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
@@ -1,9 +1,28 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0277]: can't compare `T` with `T` in const contexts
+  --> $DIR/call-generic-method-fail.rs:5:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^ no implementation for `T == T`
+   |
+note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
   --> $DIR/call-generic-method-fail.rs:5:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
 
-error: aborting due to previous error
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-fail.rs:5:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                       ++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
index 3a707416352..b3e3dd62be8 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
@@ -9,7 +9,7 @@ fn non_const() {}
 
 impl const T for S {
     fn foo() { non_const() }
-    //~^ ERROR calls in constant functions
+    //~^ ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
index aaec67161a6..9e49785c589 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `non_const` in constant functions
   --> $DIR/const-check-fns-in-const-impl.rs:11:16
    |
 LL |     fn foo() { non_const() }
    |                ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
index 7a0db9c98ea..3e87787a091 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
@@ -23,7 +23,8 @@ impl const ConstDefaultFn for ConstImpl {
 
 const fn test() {
     NonConstImpl.a();
-    //~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
     ConstImpl.a();
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
index 63e4095af29..948830d6def 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-default-method-bodies.rs:25:5
+error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+  --> $DIR/const-default-method-bodies.rs:25:18
    |
 LL |     NonConstImpl.a();
-   |     ^^^^^^^^^^^^^^^^
+   |                  ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
+   |
+note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
+  --> $DIR/const-default-method-bodies.rs:25:18
+   |
+LL |     NonConstImpl.a();
+   |                  ^^^
+
+error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
+  --> $DIR/const-default-method-bodies.rs:25:18
+   |
+LL |     NonConstImpl.a();
+   |                  ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr
index 3f553a8ee70..3ca9abb139b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:15:5
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+  --> $DIR/cross-crate.rs:15:14
    |
 LL |     NonConst.func();
-   |     ^^^^^^^^^^^^^^^
+   |              ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+   |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+  --> $DIR/cross-crate.rs:15:14
+   |
+LL |     NonConst.func();
+   |              ^^^^^^
+
+error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:15:14
+   |
+LL |     NonConst.func();
+   |              ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs
index 4bd3359947d..fa049ab86ff 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs
@@ -12,10 +12,10 @@ fn non_const_context() {
 }
 
 const fn const_context() {
-    NonConst.func();
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    NonConst.func(); //~ ERROR: cannot call non-const fn
+    //[gated]~^ ERROR: the trait bound
     Const.func();
-    //[stock]~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    //[stock]~^ ERROR: cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
index 9908f47a7b2..ea75ad0aeaf 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
@@ -1,14 +1,18 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:15:5
+error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:15:14
    |
 LL |     NonConst.func();
-   |     ^^^^^^^^^^^^^^^
+   |              ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:17:5
+error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:17:11
    |
 LL |     Const.func();
-   |     ^^^^^^^^^^^^
+   |           ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
index cccb856c2f6..4d087b5180b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
@@ -8,7 +8,8 @@ pub trait Tr {
     #[default_method_body_is_const]
     fn b(&self) {
         ().a()
-        //~^ ERROR calls in constant functions are limited
+        //~^ ERROR the trait bound
+        //~| ERROR cannot call
     }
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index 91f4d2fd4b0..db4d61f88ab 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
    |
 LL |         ().a()
-   |         ^^^^^^
+   |            ^^^ the trait `~const Tr` is not implemented for `()`
+   |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+   |
+LL |         ().a()
+   |            ^^^
+
+error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+   |
+LL |         ().a()
+   |            ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
index 157005bba7b..cbe3fe0ce5f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
@@ -7,7 +7,8 @@ pub trait A {
 
 pub const fn foo<T: A>() -> bool {
     T::assoc()
-    //~^ ERROR calls in constant functions are limited
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
index 931baac5389..931c0b3658f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0277]: the trait bound `T: ~const A` is not satisfied
+  --> $DIR/issue-88155.rs:9:5
+   |
+LL |     T::assoc()
+   |     ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
+   |
+note: the trait `A` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/issue-88155.rs:9:5
+   |
+LL |     T::assoc()
+   |     ^^^^^^^^^^
+
+error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
   --> $DIR/issue-88155.rs:9:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs
index c6975da7121..2f54c09e31c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs
@@ -11,7 +11,7 @@ fn non_const_context() -> Vec<usize> {
 
 const fn const_context() -> Vec<usize> {
     Default::default()
-    //[stock]~^ ERROR calls in constant functions are limited
+    //[stock]~^ ERROR cannot call non-const fn
 }
 
 fn main() {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
index 55a0daaaec7..0b450a94742 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Vec<usize> as Default>::default` in constant functions
   --> $DIR/std-impl-gate.rs:13:5
    |
 LL |     Default::default()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/default-associated-type-bound-1.rs
index 6eb2aa980d1..c043114b565 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-1.rs
+++ b/src/test/ui/specialization/default-associated-type-bound-1.rs
@@ -1,6 +1,5 @@
 // Check that we check that default associated types satisfy the required
 // bounds on them.
-// ignore-compare-mode-chalk
 
 #![feature(specialization)]
 //~^ WARNING `specialization` is incomplete
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr
index 9e400f87024..6680a29f942 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
+++ b/src/test/ui/specialization/default-associated-type-bound-1.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-associated-type-bound-1.rs:5:12
+  --> $DIR/default-associated-type-bound-1.rs:4:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -9,13 +9,13 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/deafult-associated-type-bound-1.rs:19:22
+  --> $DIR/default-associated-type-bound-1.rs:18:22
    |
 LL |     default type U = str;
    |                      ^^^ the trait `Clone` is not implemented for `str`
    |
 note: required by a bound in `X::U`
-  --> $DIR/deafult-associated-type-bound-1.rs:9:13
+  --> $DIR/default-associated-type-bound-1.rs:8:13
    |
 LL |     type U: Clone;
    |             ^^^^^ required by this bound in `X::U`
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/default-associated-type-bound-2.rs
index 0a21b1f0910..0a21b1f0910 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-2.rs
+++ b/src/test/ui/specialization/default-associated-type-bound-2.rs
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/default-associated-type-bound-2.stderr
index 47ea69d40bb..0fd1f65b0a2 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
+++ b/src/test/ui/specialization/default-associated-type-bound-2.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-associated-type-bound-2.rs:2:12
+  --> $DIR/default-associated-type-bound-2.rs:2:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -9,14 +9,14 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: can't compare `&'static B` with `B`
-  --> $DIR/deafult-associated-type-bound-2.rs:16:22
+  --> $DIR/default-associated-type-bound-2.rs:16:22
    |
 LL |     default type U = &'static B;
    |                      ^^^^^^^^^^ no implementation for `&'static B == B`
    |
    = help: the trait `PartialEq<B>` is not implemented for `&'static B`
 note: required by a bound in `X::U`
-  --> $DIR/deafult-associated-type-bound-2.rs:6:13
+  --> $DIR/default-associated-type-bound-2.rs:6:13
    |
 LL |     type U: PartialEq<T>;
    |             ^^^^^^^^^^^^ required by this bound in `X::U`
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/default-generic-associated-type-bound.rs
index 0f5714e996a..0f5714e996a 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
+++ b/src/test/ui/specialization/default-generic-associated-type-bound.rs
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/default-generic-associated-type-bound.stderr
index da5fe97cf1b..58c6667c8c7 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
+++ b/src/test/ui/specialization/default-generic-associated-type-bound.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-generic-associated-type-bound.rs:3:12
+  --> $DIR/default-generic-associated-type-bound.rs:3:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -9,14 +9,14 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: can't compare `T` with `T`
-  --> $DIR/deafult-generic-associated-type-bound.rs:18:26
+  --> $DIR/default-generic-associated-type-bound.rs:18:26
    |
 LL |     default type U<'a> = &'a T;
    |                          ^^^^^ no implementation for `T == T`
    |
    = note: required because of the requirements on the impl of `PartialEq` for `&'a T`
 note: required by a bound in `X::U`
-  --> $DIR/deafult-generic-associated-type-bound.rs:8:17
+  --> $DIR/default-generic-associated-type-bound.rs:8:17
    |
 LL |     type U<'a>: PartialEq<&'a Self> where Self: 'a;
    |                 ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U`
diff --git a/src/test/ui/static/static-vec-repeat-not-constant.stderr b/src/test/ui/static/static-vec-repeat-not-constant.stderr
index ef98aa546eb..84fc638a973 100644
--- a/src/test/ui/static/static-vec-repeat-not-constant.stderr
+++ b/src/test/ui/static/static-vec-repeat-not-constant.stderr
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `foo` in statics
   --> $DIR/static-vec-repeat-not-constant.rs:3:25
    |
 LL | static a: [isize; 2] = [foo(); 2];
    |                         ^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.rs b/src/test/ui/type-alias-impl-trait/issue-53598.rs
index 37b330ba4b8..f936dc42f13 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.rs
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.stderr b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
index 4c8144a2359..9971c7e0e20 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-53598.rs:20:42
+  --> $DIR/issue-53598.rs:19:42
    |
 LL |       fn foo<T: Debug>(_: T) -> Self::Item {
    |  __________________________________________^
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.rs b/src/test/ui/type-alias-impl-trait/issue-57700.rs
index f1db4d3291b..13a6b7c2f7c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.rs
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(arbitrary_self_types)]
 #![feature(type_alias_impl_trait)]
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.stderr b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
index c701e3e74ef..b2e3f46f1f5 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
@@ -1,5 +1,5 @@
 error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-57700.rs:16:58
+  --> $DIR/issue-57700.rs:15:58
    |
 LL |       fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
    |  __________________________________________________________^
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs
index 9d2ba849c86..badf35484f3 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs
@@ -1,5 +1,3 @@
-// ignore-compare-mode-chalk
-
 trait Bug {
     type Item: Bug;
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
index 62ab7eb4560..dc8a381aece 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/issue-60371.rs:10:17
+  --> $DIR/issue-60371.rs:8:17
    |
 LL |     type Item = impl Bug;
    |                 ^^^^^^^^
@@ -8,7 +8,7 @@ LL |     type Item = impl Bug;
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `(): Bug` is not satisfied
-  --> $DIR/issue-60371.rs:12:40
+  --> $DIR/issue-60371.rs:10:40
    |
 LL |     const FUN: fn() -> Self::Item = || ();
    |                                        ^ the trait `Bug` is not implemented for `()`
@@ -17,7 +17,7 @@ LL |     const FUN: fn() -> Self::Item = || ();
              <&() as Bug>
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-60371.rs:12:37
+  --> $DIR/issue-60371.rs:10:37
    |
 LL | impl Bug for &() {
    |              - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
diff --git a/triagebot.toml b/triagebot.toml
index b484c25ea51..276587e7f13 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -113,6 +113,9 @@ trigger_files = [
     "src/tools/rustdoc-js",
     "src/tools/rustdoc-themes",
 ]
+exclude_labels = [
+    "T-*",
+]
 
 [autolabel."T-compiler"]
 trigger_files = [
@@ -122,6 +125,9 @@ trigger_files = [
     # Tests
     "src/test/ui",
 ]
+exclude_labels = [
+    "T-*",
+]
 
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts