diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 095c3c03c307b..e6560771c0ee7 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -93,12 +93,12 @@ static NIGHTLY_TOOLS: &[(&str, &str)] = &[
 ];
 
 fn print_error(tool: &str, submodule: &str) {
-    eprintln!("");
+    eprintln!();
     eprintln!("We detected that this PR updated '{}', but its tests failed.", tool);
-    eprintln!("");
+    eprintln!();
     eprintln!("If you do intend to update '{}', please check the error messages above and", tool);
     eprintln!("commit another update.");
-    eprintln!("");
+    eprintln!();
     eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
     eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
     eprintln!("proper steps.");
diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs
index 03c9164fb9095..8e170d970bc57 100644
--- a/src/liballoc/collections/binary_heap.rs
+++ b/src/liballoc/collections/binary_heap.rs
@@ -665,6 +665,34 @@ impl<T: Ord> BinaryHeap<T> {
     pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
         DrainSorted { inner: self }
     }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns
+    /// `false`. The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(binary_heap_retain)]
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
+    ///
+    /// heap.retain(|x| x % 2 == 0); // only keep even numbers
+    ///
+    /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
+    /// ```
+    #[unstable(feature = "binary_heap_retain", issue = "71503")]
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        self.data.retain(f);
+        self.rebuild();
+    }
 }
 
 impl<T> BinaryHeap<T> {
diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs
index 057afd41824e7..62084ccf53c59 100644
--- a/src/liballoc/tests/binary_heap.rs
+++ b/src/liballoc/tests/binary_heap.rs
@@ -372,6 +372,14 @@ fn assert_covariance() {
     }
 }
 
+#[test]
+fn test_retain() {
+    let mut a = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
+    a.retain(|x| x % 2 == 0);
+
+    assert_eq!(a.into_sorted_vec(), [-10, 2, 4])
+}
+
 // old binaryheap failed this test
 //
 // Integrity means that all elements are present after a comparison panics,
diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs
index ad6feaeebc67f..78d49558262e3 100644
--- a/src/liballoc/tests/lib.rs
+++ b/src/liballoc/tests/lib.rs
@@ -14,6 +14,7 @@
 #![feature(binary_heap_drain_sorted)]
 #![feature(vec_remove_item)]
 #![feature(split_inclusive)]
+#![feature(binary_heap_retain)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index dbfcbca3ffcbf..575f51d0a7d56 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -77,7 +77,11 @@ impl<'a> PanicInfo<'a> {
     /// use std::panic;
     ///
     /// panic::set_hook(Box::new(|panic_info| {
-    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
+    ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
+    ///         println!("panic occurred: {:?}", s);
+    ///     } else {
+    ///         println!("panic occurred");
+    ///     }
     /// }));
     ///
     /// panic!("Normal panic");
@@ -112,8 +116,10 @@ impl<'a> PanicInfo<'a> {
     ///
     /// panic::set_hook(Box::new(|panic_info| {
     ///     if let Some(location) = panic_info.location() {
-    ///         println!("panic occurred in file '{}' at line {}", location.file(),
-    ///             location.line());
+    ///         println!("panic occurred in file '{}' at line {}",
+    ///             location.file(),
+    ///             location.line(),
+    ///         );
     ///     } else {
     ///         println!("panic occurred but can't get location information...");
     ///     }
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index ab5a844e58f7a..c2b2e7ce59f37 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -98,7 +98,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                         }
                     }
 
-                    diagnostic.map(|d| {
+                    if let Some(d) = diagnostic {
                         struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
                             .span_label(attr.span, "invalid argument")
                             .span_suggestions(
@@ -110,7 +110,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                                 Applicability::MachineApplicable,
                             )
                             .emit();
-                    });
+                    };
                 }
             }
         }
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index 2618c758ca5da..972e75d201b90 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -1172,10 +1172,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             // ignore derives so they remain unused
             let (attr, after_derive) = self.classify_nonitem(&mut expr);
 
-            if attr.is_some() {
+            if let Some(ref attr_value) = attr {
                 // Collect the invoc regardless of whether or not attributes are permitted here
                 // expansion will eat the attribute so it won't error later.
-                attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+                self.cfg.maybe_emit_expr_attr_err(attr_value);
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
@@ -1322,8 +1322,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             // Ignore derives so they remain unused.
             let (attr, after_derive) = self.classify_nonitem(&mut expr);
 
-            if attr.is_some() {
-                attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+            if let Some(ref attr_value) = attr {
+                self.cfg.maybe_emit_expr_attr_err(attr_value);
 
                 return self
                     .collect_attr(
diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs
index 033c2973af6ee..30cddac6aac91 100644
--- a/src/librustc_hir/definitions.rs
+++ b/src/librustc_hir/definitions.rs
@@ -246,7 +246,7 @@ impl DefPath {
 
         let mut opt_delimiter = None;
         for component in &self.data {
-            opt_delimiter.map(|d| s.push(d));
+            s.extend(opt_delimiter);
             opt_delimiter = Some('-');
             if component.disambiguator == 0 {
                 write!(s, "{}", component.data.as_symbol()).unwrap();
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index dd1d08a75ae19..8b53019106537 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -755,7 +755,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             },
             ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
                 err.span_label(then, "expected because of this");
-                outer.map(|sp| err.span_label(sp, "`if` and `else` have incompatible types"));
+                if let Some(sp) = outer {
+                    err.span_label(sp, "`if` and `else` have incompatible types");
+                }
                 if let Some(sp) = semicolon {
                     err.span_suggestion_short(
                         sp,
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index bb6e5700ccad4..53f52038ed022 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -17,23 +17,27 @@ use std::borrow::Cow;
 struct FindHirNodeVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
     target: GenericArg<'tcx>,
+    target_span: Span,
     found_node_ty: Option<Ty<'tcx>>,
     found_local_pattern: Option<&'tcx Pat<'tcx>>,
     found_arg_pattern: Option<&'tcx Pat<'tcx>>,
     found_closure: Option<&'tcx Expr<'tcx>>,
     found_method_call: Option<&'tcx Expr<'tcx>>,
+    found_exact_method_call: Option<&'tcx Expr<'tcx>>,
 }
 
 impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
+    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
         Self {
             infcx,
             target,
+            target_span,
             found_node_ty: None,
             found_local_pattern: None,
             found_arg_pattern: None,
             found_closure: None,
             found_method_call: None,
+            found_exact_method_call: None,
         }
     }
 
@@ -103,6 +107,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
+            if call_span == self.target_span
+                && Some(self.target)
+                    == self.infcx.in_progress_tables.and_then(|tables| {
+                        tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
+                    })
+            {
+                self.found_exact_method_call = Some(&expr);
+                return;
+            }
+        }
         if self.node_ty_contains_target(expr.hir_id).is_some() {
             match expr.kind {
                 ExprKind::Closure(..) => self.found_closure = Some(&expr),
@@ -234,7 +249,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
         let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
 
-        let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
+        let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
         let ty_to_string = |ty: Ty<'tcx>| -> String {
             let mut s = String::new();
             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@@ -287,14 +302,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
         };
 
-        let ty_msg = match local_visitor.found_node_ty {
-            Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
+        let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
+            (_, Some(_)) => String::new(),
+            (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => {
                 let fn_sig = substs.as_closure().sig();
                 let args = closure_args(&fn_sig);
                 let ret = fn_sig.output().skip_binder().to_string();
                 format!(" for the closure `fn({}) -> {}`", args, ret)
             }
-            Some(ty) if is_named_and_not_impl_trait(ty) => {
+            (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
                 let ty = ty_to_string(ty);
                 format!(" for `{}`", ty)
             }
@@ -370,7 +386,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             _ => "a type".to_string(),
         };
 
-        if let Some(pattern) = local_visitor.found_arg_pattern {
+        if let Some(e) = local_visitor.found_exact_method_call {
+            if let ExprKind::MethodCall(segment, ..) = &e.kind {
+                // Suggest specifying type params or point out the return type of the call:
+                //
+                // error[E0282]: type annotations needed
+                //   --> $DIR/type-annotations-needed-expr.rs:2:39
+                //    |
+                // LL |     let _ = x.into_iter().sum() as f64;
+                //    |                           ^^^
+                //    |                           |
+                //    |                           cannot infer type for `S`
+                //    |                           help: consider specifying the type argument in
+                //    |                           the method call: `sum::<S>`
+                //    |
+                //    = note: type must be known at this point
+                //
+                // or
+                //
+                // error[E0282]: type annotations needed
+                //   --> $DIR/issue-65611.rs:59:20
+                //    |
+                // LL |     let x = buffer.last().unwrap().0.clone();
+                //    |             -------^^^^--
+                //    |             |      |
+                //    |             |      cannot infer type for `T`
+                //    |             this method call resolves to `std::option::Option<&T>`
+                //    |
+                //    = note: type must be known at this point
+                self.annotate_method_call(segment, e, &mut err);
+            }
+        } else if let Some(pattern) = local_visitor.found_arg_pattern {
             // We don't want to show the default label for closures.
             //
             // So, before clearing, the output would look something like this:
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index fe8fbd50627d3..e7a863c63ccaa 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -101,9 +101,15 @@ fn dump_crates(cstore: &CStore) {
         info!("  hash: {}", data.hash());
         info!("  reqd: {:?}", data.dep_kind());
         let CrateSource { dylib, rlib, rmeta } = data.source();
-        dylib.as_ref().map(|dl| info!("  dylib: {}", dl.0.display()));
-        rlib.as_ref().map(|rl| info!("   rlib: {}", rl.0.display()));
-        rmeta.as_ref().map(|rl| info!("   rmeta: {}", rl.0.display()));
+        if let Some(dylib) = dylib {
+            info!("  dylib: {}", dylib.0.display());
+        }
+        if let Some(rlib) = rlib {
+            info!("   rlib: {}", rlib.0.display());
+        }
+        if let Some(rmeta) = rmeta {
+            info!("   rmeta: {}", rmeta.0.display());
+        }
     });
 }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index f9f32247c9487..b87429199ec3a 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -3,7 +3,6 @@
 use rustc_errors::struct_span_err;
 use rustc_hir::lang_items;
 use rustc_hir::{def_id::DefId, HirId};
-use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -28,70 +27,100 @@ use crate::dataflow::{self, Analysis};
 // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
 // through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
 // kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-pub type IndirectlyMutableResults<'mir, 'tcx> =
+type IndirectlyMutableResults<'mir, 'tcx> =
     dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
 
-struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> {
-    cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
-    in_any_value_of_ty: BitSet<Local>,
-}
-
-impl<Q: Qualif> QualifCursor<'a, 'mir, 'tcx, Q> {
-    pub fn new(q: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
-        let cursor = FlowSensitiveAnalysis::new(q, ccx)
-            .into_engine(ccx.tcx, ccx.body, ccx.def_id)
-            .iterate_to_fixpoint()
-            .into_results_cursor(ccx.body);
-
-        let mut in_any_value_of_ty = BitSet::new_empty(ccx.body.local_decls.len());
-        for (local, decl) in ccx.body.local_decls.iter_enumerated() {
-            if Q::in_any_value_of_ty(ccx, decl.ty) {
-                in_any_value_of_ty.insert(local);
-            }
-        }
+type QualifResults<'mir, 'tcx, Q> =
+    dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
 
-        QualifCursor { cursor, in_any_value_of_ty }
-    }
-}
-
-pub struct Qualifs<'a, 'mir, 'tcx> {
-    has_mut_interior: QualifCursor<'a, 'mir, 'tcx, HasMutInterior>,
-    needs_drop: QualifCursor<'a, 'mir, 'tcx, NeedsDrop>,
-    indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>,
+#[derive(Default)]
+pub struct Qualifs<'mir, 'tcx> {
+    has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
+    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+    indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
 }
 
-impl Qualifs<'a, 'mir, 'tcx> {
-    fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool {
-        self.indirectly_mutable.seek_before(location);
-        self.indirectly_mutable.get().contains(local)
+impl Qualifs<'mir, 'tcx> {
+    fn indirectly_mutable(
+        &mut self,
+        ccx: &'mir ConstCx<'mir, 'tcx>,
+        local: Local,
+        location: Location,
+    ) -> bool {
+        let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
+            let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
+
+            // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
+            // allowed in a const.
+            //
+            // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
+            // without breaking stable code?
+            MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
+                .unsound_ignore_borrow_on_drop()
+                .into_engine(tcx, &body, def_id)
+                .iterate_to_fixpoint()
+                .into_results_cursor(&body)
+        });
+
+        indirectly_mutable.seek_before(location);
+        indirectly_mutable.get().contains(local)
     }
 
     /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary
-    fn needs_drop(&mut self, local: Local, location: Location) -> bool {
-        if !self.needs_drop.in_any_value_of_ty.contains(local) {
+    fn needs_drop(
+        &mut self,
+        ccx: &'mir ConstCx<'mir, 'tcx>,
+        local: Local,
+        location: Location,
+    ) -> bool {
+        let ty = ccx.body.local_decls[local].ty;
+        if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
             return false;
         }
 
-        self.needs_drop.cursor.seek_before(location);
-        self.needs_drop.cursor.get().contains(local) || self.indirectly_mutable(local, location)
+        let needs_drop = self.needs_drop.get_or_insert_with(|| {
+            let ConstCx { tcx, body, def_id, .. } = *ccx;
+
+            FlowSensitiveAnalysis::new(NeedsDrop, ccx)
+                .into_engine(tcx, &body, def_id)
+                .iterate_to_fixpoint()
+                .into_results_cursor(&body)
+        });
+
+        needs_drop.seek_before(location);
+        needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
     }
 
     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary.
-    fn has_mut_interior(&mut self, local: Local, location: Location) -> bool {
-        if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
+    fn has_mut_interior(
+        &mut self,
+        ccx: &'mir ConstCx<'mir, 'tcx>,
+        local: Local,
+        location: Location,
+    ) -> bool {
+        let ty = ccx.body.local_decls[local].ty;
+        if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
             return false;
         }
 
-        self.has_mut_interior.cursor.seek_before(location);
-        self.has_mut_interior.cursor.get().contains(local)
-            || self.indirectly_mutable(local, location)
+        let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
+            let ConstCx { tcx, body, def_id, .. } = *ccx;
+
+            FlowSensitiveAnalysis::new(HasMutInterior, ccx)
+                .into_engine(tcx, &body, def_id)
+                .iterate_to_fixpoint()
+                .into_results_cursor(&body)
+        });
+
+        has_mut_interior.seek_before(location);
+        has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
     }
 
-    fn in_return_place(&mut self, ccx: &ConstCx<'_, 'tcx>) -> ConstQualifs {
+    fn in_return_place(&mut self, ccx: &'mir ConstCx<'mir, 'tcx>) -> ConstQualifs {
         // Find the `Return` terminator if one exists.
         //
         // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@@ -114,21 +143,21 @@ impl Qualifs<'a, 'mir, 'tcx> {
         let return_loc = ccx.body.terminator_loc(return_block);
 
         ConstQualifs {
-            needs_drop: self.needs_drop(RETURN_PLACE, return_loc),
-            has_mut_interior: self.has_mut_interior(RETURN_PLACE, return_loc),
+            needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
+            has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
         }
     }
 }
 
-pub struct Validator<'a, 'mir, 'tcx> {
-    ccx: &'a ConstCx<'mir, 'tcx>,
-    qualifs: Qualifs<'a, 'mir, 'tcx>,
+pub struct Validator<'mir, 'tcx> {
+    ccx: &'mir ConstCx<'mir, 'tcx>,
+    qualifs: Qualifs<'mir, 'tcx>,
 
     /// The span of the current statement.
     span: Span,
 }
 
-impl Deref for Validator<'_, 'mir, 'tcx> {
+impl Deref for Validator<'mir, 'tcx> {
     type Target = ConstCx<'mir, 'tcx>;
 
     fn deref(&self) -> &Self::Target {
@@ -136,27 +165,9 @@ impl Deref for Validator<'_, 'mir, 'tcx> {
     }
 }
 
-impl Validator<'a, 'mir, 'tcx> {
-    pub fn new(ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
-        let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
-
-        let needs_drop = QualifCursor::new(NeedsDrop, ccx);
-        let has_mut_interior = QualifCursor::new(HasMutInterior, ccx);
-
-        // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
-        // allowed in a const.
-        //
-        // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
-        // without breaking stable code?
-        let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
-            .unsound_ignore_borrow_on_drop()
-            .into_engine(tcx, body, def_id)
-            .iterate_to_fixpoint()
-            .into_results_cursor(body);
-
-        let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable };
-
-        Validator { span: ccx.body.span, ccx, qualifs }
+impl Validator<'mir, 'tcx> {
+    pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
+        Validator { span: ccx.body.span, ccx, qualifs: Default::default() }
     }
 
     pub fn check_body(&mut self) {
@@ -205,7 +216,7 @@ impl Validator<'a, 'mir, 'tcx> {
     where
         O: NonConstOp,
     {
-        trace!("check_op: op={:?}", op);
+        debug!("check_op: op={:?}", op);
 
         if op.is_allowed_in_item(self) {
             return;
@@ -239,7 +250,7 @@ impl Validator<'a, 'mir, 'tcx> {
     }
 }
 
-impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
+impl Visitor<'tcx> for Validator<'mir, 'tcx> {
     fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
         trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
 
@@ -345,7 +356,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
             | Rvalue::AddressOf(Mutability::Not, ref place) => {
                 let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
                     &self.ccx,
-                    &mut |local| self.qualifs.has_mut_interior(local, location),
+                    &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
                     place.as_ref(),
                 );
 
@@ -386,15 +397,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
         }
     }
 
-    fn visit_local(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
-        trace!(
-            "visit_local: place_local={:?} context={:?} location={:?}",
-            place_local,
-            context,
-            location,
-        );
-    }
-
     fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
         self.super_operand(op, location);
         if let Operand::Constant(c) = op {
@@ -571,7 +573,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 let needs_drop = if let Some(local) = dropped_place.as_local() {
                     // Use the span where the local was declared as the span of the drop error.
                     err_span = self.body.local_decls[local].source_info.span;
-                    self.qualifs.needs_drop(local, location)
+                    self.qualifs.needs_drop(self.ccx, local, location)
                 } else {
                     true
                 };
diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs
index 10ffc81f179d1..b9d61458a839b 100644
--- a/src/librustc_mir_build/build/matches/mod.rs
+++ b/src/librustc_mir_build/build/matches/mod.rs
@@ -1388,7 +1388,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         // Insert a Shallow borrow of any places that is switched on.
-        fake_borrows.as_mut().map(|fb| fb.insert(match_place));
+        if let Some(fb) = fake_borrows {
+            fb.insert(match_place);
+        }
 
         // perform the test, branching to one of N blocks. For each of
         // those N possible outcomes, create a (initially empty)
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index b987813e38d98..9264fc8a73518 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -1206,8 +1206,8 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
     *sess.reached_eof.borrow_mut() |=
         unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none());
     for unmatched in unclosed_delims.drain(..) {
-        make_unclosed_delims_error(unmatched, sess).map(|mut e| {
+        if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) {
             e.emit();
-        });
+        }
     }
 }
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 23a605bef0cd3..09b3d44020d81 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -68,7 +68,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 self.with_context(LabeledBlock, |v| v.visit_block(&b));
             }
             hir::ExprKind::Break(label, ref opt_expr) => {
-                opt_expr.as_ref().map(|e| self.visit_expr(e));
+                if let Some(e) = opt_expr {
+                    self.visit_expr(e);
+                }
 
                 if self.require_label_in_labeled_block(e.span, &label, "break") {
                     // If we emitted an error about an unlabeled break in a labeled
diff --git a/src/librustc_query_system/query/job.rs b/src/librustc_query_system/query/job.rs
index de6dc81d8687a..5150b278a7722 100644
--- a/src/librustc_query_system/query/job.rs
+++ b/src/librustc_query_system/query/job.rs
@@ -133,7 +133,11 @@ impl<CTX: QueryContext> QueryJob<CTX> {
     /// as there are no concurrent jobs which could be waiting on us
     pub fn signal_complete(self) {
         #[cfg(parallel_compiler)]
-        self.latch.map(|latch| latch.set());
+        {
+            if let Some(latch) = self.latch {
+                latch.set();
+            }
+        }
     }
 }
 
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 67713b5636965..f369e827a402b 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -1996,7 +1996,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     this.visit_expr(cond);
                     this.visit_block(then);
                 });
-                opt_else.as_ref().map(|expr| self.visit_expr(expr));
+                if let Some(expr) = opt_else {
+                    self.visit_expr(expr);
+                }
             }
 
             ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e94d7d6a85fb4..77aa7230aa893 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -499,7 +499,9 @@ impl<'a> ModuleData<'a> {
         F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>),
     {
         for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
-            name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding));
+            if let Some(binding) = name_resolution.borrow().binding {
+                f(resolver, key.ident, key.ns, binding);
+            }
         }
     }
 
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 8f3097ad4233e..d904046331723 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -979,20 +979,21 @@ impl Target {
         macro_rules! key {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).map(|o| o.as_string()
-                                    .map(|s| base.options.$key_name = s.to_string()));
+                if let Some(s) = obj.find(&name).and_then(Json::as_string) {
+                    base.options.$key_name = s.to_string();
+                }
             } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..])
-                    .map(|o| o.as_boolean()
-                         .map(|s| base.options.$key_name = s));
+                if let Some(s) = obj.find(&name).and_then(Json::as_boolean) {
+                    base.options.$key_name = s;
+                }
             } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..])
-                    .map(|o| o.as_u64()
-                         .map(|s| base.options.$key_name = Some(s)));
+                if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
+                    base.options.$key_name = Some(s);
+                }
             } );
             ($key_name:ident, MergeFunctions) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
@@ -1034,19 +1035,19 @@ impl Target {
             } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).map(|o| o.as_array()
-                    .map(|v| base.options.$key_name = v.iter()
-                        .map(|a| a.as_string().unwrap().to_string()).collect()
-                        )
-                    );
+                if let Some(v) = obj.find(&name).and_then(Json::as_array) {
+                    base.options.$key_name = v.iter()
+                        .map(|a| a.as_string().unwrap().to_string())
+                        .collect();
+                }
             } );
             ($key_name:ident, opt_list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).map(|o| o.as_array()
-                    .map(|v| base.options.$key_name = Some(v.iter()
-                        .map(|a| a.as_string().unwrap().to_string()).collect())
-                        )
-                    );
+                if let Some(v) = obj.find(&name).and_then(Json::as_array) {
+                    base.options.$key_name = Some(v.iter()
+                        .map(|a| a.as_string().unwrap().to_string())
+                        .collect());
+                }
             } );
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 706dca999fa32..c7d749815febb 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -213,7 +213,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             None,
         );
 
-        assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span));
+        if let Some(b) = assoc_bindings.first() {
+            Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+        }
 
         substs
     }
@@ -1095,7 +1097,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ) -> ty::TraitRef<'tcx> {
         let (substs, assoc_bindings, _) =
             self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
-        assoc_bindings.first().map(|b| AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span));
+        if let Some(b) = assoc_bindings.first() {
+            AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span);
+        }
         ty::TraitRef::new(trait_def_id, substs)
     }
 
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 7db376b20aaa8..c75283e419a6d 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -36,7 +36,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // Requires that the two types unify, and prints an error message if
     // they don't.
     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-        self.demand_suptype_diag(sp, expected, actual).map(|mut e| e.emit());
+        if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
+            e.emit();
+        }
     }
 
     pub fn demand_suptype_diag(
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 51e3bc4cae406..b7e86c0791f63 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4492,15 +4492,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => Err(ErrorReported),
             };
             if item_name.name != kw::Invalid {
-                self.report_method_error(
+                if let Some(mut e) = self.report_method_error(
                     span,
                     ty,
                     item_name,
                     SelfSource::QPath(qself),
                     error,
                     None,
-                )
-                .map(|mut e| e.emit());
+                ) {
+                    e.emit();
+                }
             }
             result
         });
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index b53ae6acdebbb..8e109efbcb576 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -104,7 +104,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         actual: Ty<'tcx>,
         ti: TopInfo<'tcx>,
     ) {
-        self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map(|mut err| err.emit());
+        if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
+            err.emit();
+        }
     }
 }
 
@@ -449,12 +451,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Subtyping doesn't matter here, as the value is some kind of scalar.
         let demand_eqtype = |x, y| {
             if let Some((_, x_ty, x_span)) = x {
-                self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| {
+                if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
                     if let Some((_, y_ty, y_span)) = y {
                         self.endpoint_has_type(&mut err, y_span, y_ty);
                     }
                     err.emit();
-                });
+                };
             }
         };
         demand_eqtype(lhs, rhs);
@@ -852,8 +854,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check the tuple struct pattern against the expected type.
         let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti);
-        let had_err = diag.is_some();
-        diag.map(|mut err| err.emit());
+        let had_err = if let Some(mut err) = diag {
+            err.emit();
+            true
+        } else {
+            false
+        };
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len()
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 56714a4fa6793..c5bf151bc1e11 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -165,12 +165,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                         hir::ExprKind::Binary(..) => {
                             if !op.node.is_by_value() {
                                 let mut adjustments = tables.adjustments_mut();
-                                adjustments.get_mut(lhs.hir_id).map(|a| a.pop());
-                                adjustments.get_mut(rhs.hir_id).map(|a| a.pop());
+                                if let Some(a) = adjustments.get_mut(lhs.hir_id) {
+                                    a.pop();
+                                }
+                                if let Some(a) = adjustments.get_mut(rhs.hir_id) {
+                                    a.pop();
+                                }
                             }
                         }
                         hir::ExprKind::AssignOp(..) => {
-                            tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop());
+                            if let Some(a) = tables.adjustments_mut().get_mut(lhs.hir_id) {
+                                a.pop();
+                            }
                         }
                         _ => {}
                     }
@@ -215,7 +221,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     tables.type_dependent_defs_mut().remove(e.hir_id);
                     tables.node_substs_mut().remove(e.hir_id);
 
-                    tables.adjustments_mut().get_mut(base.hir_id).map(|a| {
+                    if let Some(a) = tables.adjustments_mut().get_mut(base.hir_id) {
                         // Discard the need for a mutable borrow
 
                         // Extra adjustment made when indexing causes a drop
@@ -229,7 +235,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                             // So the borrow discard actually happens here
                             a.pop();
                         }
-                    });
+                    }
                 }
             }
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4d03bb21cb3ec..63ab0ef5f1728 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1599,7 +1599,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 inline::record_extern_fqn(cx, did, TypeKind::Trait);
 
                 let mut param_names = vec![];
-                reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b)));
+                if let Some(b) = reg.clean(cx) {
+                    param_names.push(GenericBound::Outlives(b));
+                }
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
                     let path =
@@ -1662,10 +1664,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                             tr
                         } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
                             // these should turn up at the end
-                            pred.skip_binder()
-                                .1
-                                .clean(cx)
-                                .map(|r| regions.push(GenericBound::Outlives(r)));
+                            if let Some(r) = pred.skip_binder().1.clean(cx) {
+                                regions.push(GenericBound::Outlives(r));
+                            }
                             return None;
                         } else {
                             return None;
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index 034fb27300027..3754029577475 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -94,7 +94,7 @@ impl TocBuilder {
         loop {
             match self.chain.pop() {
                 Some(mut next) => {
-                    this.map(|e| next.children.entries.push(e));
+                    next.children.entries.extend(this);
                     if next.level < level {
                         // this is the parent we want, so return it to
                         // its rightful place.
@@ -105,7 +105,7 @@ impl TocBuilder {
                     }
                 }
                 None => {
-                    this.map(|e| self.top_level.entries.push(e));
+                    self.top_level.entries.extend(this);
                     return;
                 }
             }
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index 314424631fcbf..6fbb0139b0eca 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -685,12 +685,12 @@ mod impl_keyword {}
 /// ## Literal Examples:
 ///
 ///    * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3.
-///    * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and includeing 3.
+///    * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and including 3.
 ///
 /// (Read more about [range patterns])
 ///
 /// [`Iterator`]: ../book/ch13-04-performance.html
-/// [`range patterns`]: ../reference/patterns.html?highlight=range#range-patterns
+/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
 /// [`for`]: keyword.for.html
 mod in_keyword {}
 
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index c4e929624d7a4..fd9d61e99c2cd 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -91,7 +91,7 @@ impl<T> Packet<T> {
     //
     // This can only be called at channel-creation time
     pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) {
-        token.map(|token| {
+        if let Some(token) = token {
             assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
             assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
             self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
@@ -118,7 +118,7 @@ impl<T> Packet<T> {
             unsafe {
                 *self.steals.get() = -1;
             }
-        });
+        }
 
         // When the shared packet is constructed, we grabbed this lock. The
         // purpose of this lock is to ensure that abort_selection() doesn't
diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs
index 3e2050799ccb4..79123903e92a5 100644
--- a/src/libstd/sync/mpsc/sync.rs
+++ b/src/libstd/sync/mpsc/sync.rs
@@ -343,8 +343,12 @@ impl<T> Packet<T> {
         mem::drop(guard);
 
         // only outside of the lock do we wake up the pending threads
-        pending_sender1.map(|t| t.signal());
-        pending_sender2.map(|t| t.signal());
+        if let Some(token) = pending_sender1 {
+            token.signal();
+        }
+        if let Some(token) = pending_sender2 {
+            token.signal();
+        }
     }
 
     // Prepares this shared packet for a channel clone, essentially just bumping
@@ -410,7 +414,9 @@ impl<T> Packet<T> {
         while let Some(token) = queue.dequeue() {
             token.signal();
         }
-        waiter.map(|t| t.signal());
+        if let Some(token) = waiter {
+            token.signal();
+        }
     }
 }
 
diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr
index 8fd67b19d6a5a..ee621a8cb1473 100644
--- a/src/test/ui/issues/issue-17252.stderr
+++ b/src/test/ui/issues/issue-17252.stderr
@@ -1,11 +1,22 @@
-error[E0391]: cycle detected when const checking `FOO`
-  --> $DIR/issue-17252.rs:1:20
+error[E0391]: cycle detected when normalizing `FOO`
+   |
+note: ...which requires const-evaluating + checking `FOO`...
+  --> $DIR/issue-17252.rs:1:1
+   |
+LL | const FOO: usize = FOO;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `FOO`...
+  --> $DIR/issue-17252.rs:1:1
    |
 LL | const FOO: usize = FOO;
-   |                    ^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating `FOO`...
+  --> $DIR/issue-17252.rs:1:1
    |
-   = note: ...which again requires const checking `FOO`, completing the cycle
-note: cycle used when const checking `main::{{constant}}#0`
+LL | const FOO: usize = FOO;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires normalizing `FOO`, completing the cycle
+note: cycle used when const-evaluating `main::{{constant}}#0`
   --> $DIR/issue-17252.rs:4:18
    |
 LL |     let _x: [u8; FOO]; // caused stack overflow prior to fix
diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr
index f2457774326dd..b6c85b9e22749 100644
--- a/src/test/ui/issues/issue-23302-1.stderr
+++ b/src/test/ui/issues/issue-23302-1.stderr
@@ -1,15 +1,26 @@
-error[E0391]: cycle detected when const checking `X::A::{{constant}}#0`
+error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0`
   --> $DIR/issue-23302-1.rs:4:9
    |
 LL |     A = X::A as isize,
    |         ^^^^^^^^^^^^^
    |
-   = note: ...which again requires const checking `X::A::{{constant}}#0`, completing the cycle
-note: cycle used when processing `X::A::{{constant}}#0`
+note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`...
   --> $DIR/issue-23302-1.rs:4:9
    |
 LL |     A = X::A as isize,
    |         ^^^^^^^^^^^^^
+note: ...which requires const-evaluating `X::A::{{constant}}#0`...
+  --> $DIR/issue-23302-1.rs:4:9
+   |
+LL |     A = X::A as isize,
+   |         ^^^^^^^^^^^^^
+   = note: ...which requires normalizing `X::A as isize`...
+   = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/issue-23302-1.rs:3:1
+   |
+LL | enum X {
+   | ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr
index c121c17b904ea..d014922fe2069 100644
--- a/src/test/ui/issues/issue-23302-2.stderr
+++ b/src/test/ui/issues/issue-23302-2.stderr
@@ -1,15 +1,26 @@
-error[E0391]: cycle detected when const checking `Y::A::{{constant}}#0`
+error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0`
   --> $DIR/issue-23302-2.rs:4:9
    |
 LL |     A = Y::B as isize,
    |         ^^^^^^^^^^^^^
    |
-   = note: ...which again requires const checking `Y::A::{{constant}}#0`, completing the cycle
-note: cycle used when processing `Y::A::{{constant}}#0`
+note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`...
   --> $DIR/issue-23302-2.rs:4:9
    |
 LL |     A = Y::B as isize,
    |         ^^^^^^^^^^^^^
+note: ...which requires const-evaluating `Y::A::{{constant}}#0`...
+  --> $DIR/issue-23302-2.rs:4:9
+   |
+LL |     A = Y::B as isize,
+   |         ^^^^^^^^^^^^^
+   = note: ...which requires normalizing `Y::B as isize`...
+   = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/issue-23302-2.rs:3:1
+   |
+LL | enum Y {
+   | ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr
index 0229469f04140..b30b1214271a0 100644
--- a/src/test/ui/issues/issue-23302-3.stderr
+++ b/src/test/ui/issues/issue-23302-3.stderr
@@ -1,20 +1,38 @@
-error[E0391]: cycle detected when const checking `A`
-  --> $DIR/issue-23302-3.rs:1:16
+error[E0391]: cycle detected when const-evaluating + checking `A`
+  --> $DIR/issue-23302-3.rs:1:1
    |
 LL | const A: i32 = B;
-   |                ^
+   | ^^^^^^^^^^^^^^^^^
    |
-note: ...which requires const checking `B`...
-  --> $DIR/issue-23302-3.rs:3:16
+note: ...which requires const-evaluating + checking `A`...
+  --> $DIR/issue-23302-3.rs:1:1
    |
-LL | const B: i32 = A;
-   |                ^
-   = note: ...which again requires const checking `A`, completing the cycle
-note: cycle used when processing `A`
+LL | const A: i32 = B;
+   | ^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating `A`...
   --> $DIR/issue-23302-3.rs:1:1
    |
 LL | const A: i32 = B;
    | ^^^^^^^^^^^^^^^^^
+   = note: ...which requires normalizing `B`...
+note: ...which requires const-evaluating + checking `B`...
+  --> $DIR/issue-23302-3.rs:3:1
+   |
+LL | const B: i32 = A;
+   | ^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `B`...
+  --> $DIR/issue-23302-3.rs:3:1
+   |
+LL | const B: i32 = A;
+   | ^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating `B`...
+  --> $DIR/issue-23302-3.rs:3:1
+   |
+LL | const B: i32 = A;
+   | ^^^^^^^^^^^^^^^^^
+   = note: ...which requires normalizing `A`...
+   = note: ...which again requires const-evaluating + checking `A`, completing the cycle
+   = note: cycle used when running analysis passes on this crate
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr
index 3866243914b89..7c2da9dce6e9d 100644
--- a/src/test/ui/issues/issue-36163.stderr
+++ b/src/test/ui/issues/issue-36163.stderr
@@ -1,20 +1,48 @@
-error[E0391]: cycle detected when const checking `Foo::B::{{constant}}#0`
+error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0`
   --> $DIR/issue-36163.rs:4:9
    |
 LL |     B = A,
    |         ^
    |
-note: ...which requires const checking `A`...
-  --> $DIR/issue-36163.rs:1:18
+note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`...
+  --> $DIR/issue-36163.rs:4:9
    |
-LL | const A: isize = Foo::B as isize;
-   |                  ^^^^^^^^^^^^^^^
-   = note: ...which again requires const checking `Foo::B::{{constant}}#0`, completing the cycle
-note: cycle used when processing `Foo::B::{{constant}}#0`
+LL |     B = A,
+   |         ^
+note: ...which requires const-evaluating `Foo::B::{{constant}}#0`...
   --> $DIR/issue-36163.rs:4:9
    |
 LL |     B = A,
    |         ^
+   = note: ...which requires normalizing `A`...
+note: ...which requires const-evaluating + checking `A`...
+  --> $DIR/issue-36163.rs:1:1
+   |
+LL | const A: isize = Foo::B as isize;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `A`...
+  --> $DIR/issue-36163.rs:1:1
+   |
+LL | const A: isize = Foo::B as isize;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating `A`...
+  --> $DIR/issue-36163.rs:1:1
+   |
+LL | const A: isize = Foo::B as isize;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires normalizing `A`...
+   = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/issue-36163.rs:1:1
+   |
+LL | / const A: isize = Foo::B as isize;
+LL | |
+LL | | enum Foo {
+LL | |     B = A,
+LL | | }
+LL | |
+LL | | fn main() {}
+   | |____________^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-69455.rs b/src/test/ui/issues/issue-69455.rs
new file mode 100644
index 0000000000000..017654554be16
--- /dev/null
+++ b/src/test/ui/issues/issue-69455.rs
@@ -0,0 +1,30 @@
+// Regression test for #69455: projection predicate was not satisfied.
+// Compiler should indicate the correct location of the
+// unsatisfied projection predicate
+
+pub trait Test<Rhs = Self> {
+    type Output;
+
+    fn test(self, rhs: Rhs) -> Self::Output;
+}
+
+impl Test<u32> for u64 {
+    type Output = u64;
+
+    fn test(self, other: u32) -> u64 {
+        self + (other as u64)
+    }
+}
+
+impl Test<u64> for u64 {
+    type Output = u64;
+
+    fn test(self, other: u64) -> u64 {
+        (self + other) as u64
+    }
+}
+
+fn main() {
+    let xs: Vec<u64> = vec![1, 2, 3];
+    println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284]
+}
diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr
new file mode 100644
index 0000000000000..4caa1aca9fd21
--- /dev/null
+++ b/src/test/ui/issues/issue-69455.stderr
@@ -0,0 +1,17 @@
+error[E0284]: type annotations needed
+  --> $DIR/issue-69455.rs:29:26
+   |
+LL |     type Output;
+   |     ------------ `<Self as Test<Rhs>>::Output` defined here
+...
+LL |     println!("{}", 23u64.test(xs.iter().sum()));
+   |                    ------^^^^-----------------
+   |                    |     |
+   |                    |     cannot infer type for type `u64`
+   |                    this method call resolves to `<Self as Test<Rhs>>::Output`
+   |
+   = note: cannot satisfy `<u64 as Test<_>>::Output == _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.