Auto merge of #81103 - zackmdavis:comma_trail, r=davidtwco

don't suggest erroneous trailing comma after `..`

In #76612, suggestions were added for missing fields in patterns. However, the suggestions are being inserted just at the end
of the last field in the pattern—before any trailing comma after the last field. This resulted in the "if you don't care about missing fields" suggestion to recommend code with a trailing comma after the field ellipsis (`..,`), which is actually not legal ("`..` must be at the end and cannot have a trailing comma")!

Incidentally, the doc-comment on `error_unmentioned_fields` was using `you_cant_use_this_field` as an example field name (presumably copy-paste inherited from the description of Issue #76077), but the present author found this confusing, because unmentioned fields aren't necessarily unusable.

The suggested code in the diff this commit introduces to `destructuring-assignment/struct_destructure_fail.stderr` doesn't work, but it didn't work beforehand, either (because of the "found reserved identifier `_`" thing), so you can't really call it a regression; it could be fixed in a separate PR.

Resolves #78511.

r? `@davidtwco` or `@estebank`
diff --git a/Cargo.lock b/Cargo.lock
index 5e5a48a..c2c06a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4400,7 +4400,7 @@
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.31"
+version = "1.4.32"
 dependencies = [
  "annotate-snippets 0.6.1",
  "anyhow",
diff --git a/README.md b/README.md
index 07c0960..6ab11e7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,4 @@
-<a href = "https://www.rust-lang.org/">
-<img width = "90%" height = "auto" src = "https://img.shields.io/badge/Rust-Programming%20Language-black?style=flat&logo=rust" alt = "The Rust Programming Language">
-</a>
+# The Rust Programming Language
 
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 6a54cb4..4dcbe48 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -526,7 +526,7 @@
     fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
         let mut tokens = tokens.into_trees().peekable();
         let mut result = Vec::new();
-        while let Some(..) = tokens.peek() {
+        while tokens.peek().is_some() {
             let item = NestedMetaItem::from_tokens(&mut tokens)?;
             result.push(item);
             match tokens.next() {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index be5b247..8946ac4 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -824,7 +824,7 @@
                     }
                     ty => unreachable!("bswap {}", ty),
                 }
-            };
+            }
             let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T));
             ret.write_cvalue(fx, res);
         };
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 6c2a871..544ef38 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -214,11 +214,7 @@
 }
 
 pub fn target_cpu(sess: &Session) -> &str {
-    let name = match sess.opts.cg.target_cpu {
-        Some(ref s) => &**s,
-        None => &*sess.target.cpu,
-    };
-
+    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
     handle_native(name)
 }
 
@@ -254,8 +250,6 @@
 }
 
 pub fn tune_cpu(sess: &Session) -> Option<&str> {
-    match sess.opts.debugging_opts.tune_cpu {
-        Some(ref s) => Some(handle_native(&**s)),
-        None => None,
-    }
+    let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
+    Some(handle_native(name))
 }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f47d2ad..2ce5fe5 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -29,7 +29,6 @@
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, EntryFnType};
-use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
 use rustc_target::abi::{Align, LayoutOf, VariantIdx};
 
@@ -817,32 +816,6 @@
         }
         tcx.sess.opts.optimize
     };
-
-    providers.dllimport_foreign_items = |tcx, krate| {
-        let module_map = tcx.foreign_modules(krate);
-
-        let dllimports = tcx
-            .native_libraries(krate)
-            .iter()
-            .filter(|lib| {
-                if !matches!(lib.kind, NativeLibKind::Dylib | NativeLibKind::Unspecified) {
-                    return false;
-                }
-                let cfg = match lib.cfg {
-                    Some(ref cfg) => cfg,
-                    None => return true,
-                };
-                attr::cfg_matches(cfg, &tcx.sess.parse_sess, None)
-            })
-            .filter_map(|lib| lib.foreign_module)
-            .map(|id| &module_map[&id])
-            .flat_map(|module| module.foreign_items.iter().cloned())
-            .collect();
-        dllimports
-    };
-
-    providers.is_dllimport_foreign_item =
-        |tcx, def_id| tcx.dllimport_foreign_items(def_id.krate).contains(&def_id);
 }
 
 fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index e532a84..7f9e416 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -30,6 +30,7 @@
         Steal { value: RwLock::new(Some(value)) }
     }
 
+    #[track_caller]
     pub fn borrow(&self) -> MappedReadGuard<'_, T> {
         ReadGuard::map(self.value.borrow(), |opt| match *opt {
             None => panic!("attempted to read from stolen value"),
@@ -37,10 +38,11 @@
         })
     }
 
+    #[track_caller]
     pub fn steal(&self) -> T {
         let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");
         let value = value_ref.take();
-        value.expect("attempt to read from stolen value")
+        value.expect("attempt to steal from stolen value")
     }
 }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md
index fd96987..effa597 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0373.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0373.md
@@ -50,3 +50,24 @@
 
 Now that the closure has its own copy of the data, there's no need to worry
 about safety.
+
+This error may also be encountered while using `async` blocks:
+
+```compile_fail,E0373,edition2018
+use std::future::Future;
+
+async fn f() {
+    let v = vec![1, 2, 3i32];
+    spawn(async { //~ ERROR E0373
+        println!("{:?}", v)
+    });
+}
+
+fn spawn<F: Future + Send + 'static>(future: F) {
+    unimplemented!()
+}
+```
+
+Similarly to closures, `async` blocks are not executed immediately and may
+capture closed-over data by reference. For more information, see
+https://rust-lang.github.io/async-book/03_async_await/01_chapter.html.
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 8373304..e8c711c 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -56,36 +56,11 @@
     };
 }
 
-/// Instead of e.g. `vec![a, b, c]` in a pattern context, suggest `[a, b, c]`.
-fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Parser<'_>) {
-    let mut suggestion = None;
-    if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) {
-        if let Some(bang) = code.find('!') {
-            suggestion = Some(code[bang + 1..].to_string());
-        }
-    }
-    if let Some(suggestion) = suggestion {
-        e.span_suggestion(
-            site_span,
-            "use a slice pattern here instead",
-            suggestion,
-            Applicability::MachineApplicable,
-        );
-    } else {
-        e.span_label(site_span, "use a slice pattern here instead");
-    }
-    e.help(
-        "for more information, see https://doc.rust-lang.org/edition-guide/\
-        rust-2018/slice-patterns.html",
-    );
-}
-
 fn emit_frag_parse_err(
     mut e: DiagnosticBuilder<'_>,
     parser: &Parser<'_>,
     orig_parser: &mut Parser<'_>,
     site_span: Span,
-    macro_ident: Ident,
     arm_span: Span,
     kind: AstFragmentKind,
 ) {
@@ -113,9 +88,6 @@
         e.span_label(site_span, "in this macro invocation");
     }
     match kind {
-        AstFragmentKind::Pat if macro_ident.name == sym::vec => {
-            suggest_slice_pat(&mut e, site_span, parser);
-        }
         // Try a statement if an expression is wanted but failed and suggest adding `;` to call.
         AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) {
             Err(mut err) => err.cancel(),
@@ -143,7 +115,7 @@
         let fragment = match parse_ast_fragment(parser, kind) {
             Ok(f) => f,
             Err(err) => {
-                emit_frag_parse_err(err, parser, snapshot, site_span, macro_ident, arm_span, kind);
+                emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind);
                 return kind.dummy(site_span);
             }
         };
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 3b54ffb..b9d1597 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -629,6 +629,8 @@
     /// Allows references to types with interior mutability within constants
     (active, const_refs_to_cell, "1.51.0", Some(80384), None),
 
+    /// Allows using `pointer` and `reference` in intra-doc links
+    (active, intra_doc_pointers, "1.51.0", Some(80896), None),
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 4ede9d6..a81eb74 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -5,6 +5,7 @@
 use rustc_ast::NodeId;
 use rustc_macros::HashStable_Generic;
 use rustc_span::hygiene::MacroKind;
+use rustc_span::Symbol;
 
 use std::array::IntoIter;
 use std::fmt::Debug;
@@ -34,7 +35,7 @@
 #[derive(HashStable_Generic)]
 pub enum NonMacroAttrKind {
     /// Single-segment attribute defined by the language (`#[inline]`)
-    Builtin,
+    Builtin(Symbol),
     /// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`).
     Tool,
     /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
@@ -371,7 +372,7 @@
 impl NonMacroAttrKind {
     pub fn descr(self) -> &'static str {
         match self {
-            NonMacroAttrKind::Builtin => "built-in attribute",
+            NonMacroAttrKind::Builtin(..) => "built-in attribute",
             NonMacroAttrKind::Tool => "tool attribute",
             NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => {
                 "derive helper attribute"
@@ -393,7 +394,7 @@
             NonMacroAttrKind::Tool
             | NonMacroAttrKind::DeriveHelper
             | NonMacroAttrKind::DeriveHelperCompat => true,
-            NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
+            NonMacroAttrKind::Builtin(..) | NonMacroAttrKind::Registered => false,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 71ce50f..4357eb3 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -530,10 +530,10 @@
 
             let atom = match k1.unpack() {
                 GenericArgKind::Lifetime(r1) => {
-                    ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+                    ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
                 }
                 GenericArgKind::Type(t1) => {
-                    ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t1, r2))
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
                 }
                 GenericArgKind::Const(..) => {
                     // Consts cannot outlive one another, so we don't expect to
@@ -541,8 +541,7 @@
                     span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
                 }
             };
-            let predicate =
-                predicate.rebind(atom).potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
+            let predicate = predicate.rebind(atom).to_predicate(self.tcx);
 
             Obligation::new(cause.clone(), param_env, predicate)
         })
@@ -664,7 +663,7 @@
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
-            predicate: ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(sup, sub))
+            predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
                 .to_predicate(self.infcx.tcx),
             recursion_depth: 0,
         });
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index e38eebe..b344086 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -358,7 +358,7 @@
             self.obligations.push(Obligation::new(
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::PredicateAtom::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
+                ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
             ));
         }
 
@@ -451,9 +451,9 @@
         b: &'tcx ty::Const<'tcx>,
     ) {
         let predicate = if a_is_expected {
-            ty::PredicateAtom::ConstEquate(a, b)
+            ty::PredicateKind::ConstEquate(a, b)
         } else {
-            ty::PredicateAtom::ConstEquate(b, a)
+            ty::PredicateKind::ConstEquate(b, a)
         };
         self.obligations.push(Obligation::new(
             self.trace.cause.clone(),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index fee6f87..c39daea 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1706,8 +1706,8 @@
 
             for (predicate, _) in bounds {
                 let predicate = predicate.subst(self.tcx, substs);
-                if let ty::PredicateAtom::Projection(projection_predicate) =
-                    predicate.skip_binders()
+                if let ty::PredicateKind::Projection(projection_predicate) =
+                    predicate.kind().skip_binder()
                 {
                     if projection_predicate.projection_ty.item_def_id == item_def_id {
                         // We don't account for multiple `Future::Output = Ty` contraints.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index aaab89a..bd43d3c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -429,6 +429,7 @@
         body_id: Option<hir::BodyId>,
         span: Span,
         arg: GenericArg<'tcx>,
+        impl_candidates: Vec<ty::TraitRef<'tcx>>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx> {
         let arg = self.resolve_vars_if_possible(arg);
@@ -653,7 +654,44 @@
             };
             err.span_label(pattern.span, msg);
         } else if let Some(e) = local_visitor.found_method_call {
-            if let ExprKind::MethodCall(segment, ..) = &e.kind {
+            if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
+                // Suggest impl candidates:
+                //
+                // error[E0283]: type annotations needed
+                //   --> $DIR/E0283.rs:35:24
+                //    |
+                // LL |     let bar = foo_impl.into() * 1u32;
+                //    |               ---------^^^^--
+                //    |               |        |
+                //    |               |        cannot infer type for type parameter `T` declared on the trait `Into`
+                //    |               this method call resolves to `T`
+                //    |               help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
+                //    |
+                //    = note: cannot satisfy `Impl: Into<_>`
+                if !impl_candidates.is_empty() && e.span.contains(span) {
+                    if let Some(expr) = exprs.first() {
+                        if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
+                            if let [path_segment] = &path.segments[..] {
+                                let candidate_len = impl_candidates.len();
+                                let suggestions = impl_candidates.iter().map(|candidate| {
+                                    format!(
+                                        "{}::{}({})",
+                                        candidate, segment.ident, path_segment.ident
+                                    )
+                                });
+                                err.span_suggestions(
+                                    e.span,
+                                    &format!(
+                                        "use the fully qualified path for the potential candidate{}",
+                                        pluralize!(candidate_len),
+                                    ),
+                                    suggestions,
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    };
+                }
                 // Suggest specifying type params or point out the return type of the call:
                 //
                 // error[E0282]: type annotations needed
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index de98ccc..07c75d5 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -6,7 +6,6 @@
 
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty;
-use rustc_middle::ty::fold::TypeFoldable;
 
 pub fn explicit_outlives_bounds<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
@@ -15,20 +14,20 @@
     param_env
         .caller_bounds()
         .into_iter()
-        .map(ty::Predicate::skip_binders)
-        .filter(|atom| !atom.has_escaping_bound_vars())
-        .filter_map(move |atom| match atom {
-            ty::PredicateAtom::Projection(..)
-            | ty::PredicateAtom::Trait(..)
-            | ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::WellFormed(..)
-            | ty::PredicateAtom::ObjectSafe(..)
-            | ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::TypeOutlives(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..)
-            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-            ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
+        .map(ty::Predicate::kind)
+        .filter_map(ty::Binder::no_bound_vars)
+        .filter_map(move |kind| match kind {
+            ty::PredicateKind::Projection(..)
+            | ty::PredicateKind::Trait(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::TypeOutlives(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+            ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                 Some(OutlivesBound::RegionSubRegion(r_b, r_a))
             }
         })
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index a676c5e..6687198 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -100,7 +100,7 @@
                 self.fields.obligations.push(Obligation::new(
                     self.fields.trace.cause.clone(),
                     self.fields.param_env,
-                    ty::PredicateAtom::Subtype(ty::SubtypePredicate {
+                    ty::PredicateKind::Subtype(ty::SubtypePredicate {
                         a_is_expected: self.a_is_expected,
                         a,
                         b,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 8273c2d..13cf1e10 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -9,13 +9,8 @@
     tcx: TyCtxt<'tcx>,
     pred: ty::Predicate<'tcx>,
 ) -> ty::Predicate<'tcx> {
-    match *pred.kind() {
-        ty::PredicateKind::ForAll(binder) => {
-            let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
-            tcx.reuse_or_mk_predicate(pred, new)
-        }
-        ty::PredicateKind::Atom(_) => pred,
-    }
+    let new = tcx.anonymize_late_bound_regions(pred.kind());
+    tcx.reuse_or_mk_predicate(pred, new)
 }
 
 struct PredicateSet<'tcx> {
@@ -126,9 +121,9 @@
     fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
         let tcx = self.visited.tcx;
 
-        let bound_predicate = obligation.predicate.bound_atom();
+        let bound_predicate = obligation.predicate.kind();
         match bound_predicate.skip_binder() {
-            ty::PredicateAtom::Trait(data, _) => {
+            ty::PredicateKind::Trait(data, _) => {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
@@ -150,36 +145,36 @@
 
                 self.stack.extend(obligations);
             }
-            ty::PredicateAtom::WellFormed(..) => {
+            ty::PredicateKind::WellFormed(..) => {
                 // Currently, we do not elaborate WF predicates,
                 // although we easily could.
             }
-            ty::PredicateAtom::ObjectSafe(..) => {
+            ty::PredicateKind::ObjectSafe(..) => {
                 // Currently, we do not elaborate object-safe
                 // predicates.
             }
-            ty::PredicateAtom::Subtype(..) => {
+            ty::PredicateKind::Subtype(..) => {
                 // Currently, we do not "elaborate" predicates like `X <: Y`,
                 // though conceivably we might.
             }
-            ty::PredicateAtom::Projection(..) => {
+            ty::PredicateKind::Projection(..) => {
                 // Nothing to elaborate in a projection predicate.
             }
-            ty::PredicateAtom::ClosureKind(..) => {
+            ty::PredicateKind::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
-            ty::PredicateAtom::ConstEvaluatable(..) => {
+            ty::PredicateKind::ConstEvaluatable(..) => {
                 // Currently, we do not elaborate const-evaluatable
                 // predicates.
             }
-            ty::PredicateAtom::ConstEquate(..) => {
+            ty::PredicateKind::ConstEquate(..) => {
                 // Currently, we do not elaborate const-equate
                 // predicates.
             }
-            ty::PredicateAtom::RegionOutlives(..) => {
+            ty::PredicateKind::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
             }
-            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
+            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
                 // We know that `T: 'a` for some type `T`. We can
                 // often elaborate this. For example, if we know that
                 // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
@@ -209,7 +204,7 @@
                                 if r.is_late_bound() {
                                     None
                                 } else {
-                                    Some(ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
+                                    Some(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
                                         r, r_min,
                                     )))
                                 }
@@ -217,7 +212,7 @@
 
                             Component::Param(p) => {
                                 let ty = tcx.mk_ty_param(p.index, p.name);
-                                Some(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(
+                                Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
                                     ty, r_min,
                                 )))
                             }
@@ -242,7 +237,7 @@
                         }),
                 );
             }
-            ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+            ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 // Nothing to elaborate
             }
         }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 4e393df..8cdb33e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1550,13 +1550,13 @@
 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::fold::TypeFoldable;
-        use rustc_middle::ty::PredicateAtom::*;
+        use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
             let def_id = cx.tcx.hir().local_def_id(item.hir_id);
             let predicates = cx.tcx.predicates_of(def_id);
             for &(predicate, span) in predicates.predicates {
-                let predicate_kind_name = match predicate.skip_binders() {
+                let predicate_kind_name = match predicate.kind().skip_binder() {
                     Trait(..) => "Trait",
                     TypeOutlives(..) |
                     RegionOutlives(..) => "Lifetime",
@@ -1936,8 +1936,8 @@
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(pred, _)| match pred.skip_binders() {
-                ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
+            .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+                ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
                     ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
                     _ => None,
                 },
@@ -1952,8 +1952,8 @@
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(pred, _)| match pred.skip_binders() {
-                ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+            .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
                     a.is_param(index).then_some(b)
                 }
                 _ => None,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 0f40324..3971a30 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -354,10 +354,23 @@
             lint_name.to_string()
         };
         // If the lint was scoped with `tool::` check if the tool lint exists
-        if tool_name.is_some() {
+        if let Some(tool_name) = tool_name {
             match self.by_name.get(&complete_name) {
                 None => match self.lint_groups.get(&*complete_name) {
-                    None => return CheckLintNameResult::Tool(Err((None, String::new()))),
+                    // If the lint isn't registered, there are two possibilities:
+                    None => {
+                        // 1. The tool is currently running, so this lint really doesn't exist.
+                        // FIXME: should this handle tools that never register a lint, like rustfmt?
+                        tracing::debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
+                        let tool_prefix = format!("{}::", tool_name);
+                        return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
+                            self.no_lint_suggestion(&complete_name)
+                        } else {
+                            // 2. The tool isn't currently running, so no lints will be registered.
+                            // To avoid giving a false positive, ignore all unknown lints.
+                            CheckLintNameResult::Tool(Err((None, String::new())))
+                        };
+                    }
                     Some(LintGroup { lint_ids, .. }) => {
                         return CheckLintNameResult::Tool(Ok(&lint_ids));
                     }
@@ -398,6 +411,21 @@
         }
     }
 
+    fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> {
+        let name_lower = lint_name.to_lowercase();
+        let symbols =
+            self.get_lints().iter().map(|l| Symbol::intern(&l.name_lower())).collect::<Vec<_>>();
+
+        if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() {
+            // First check if the lint name is (partly) in upper case instead of lower case...
+            CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower)))
+        } else {
+            // ...if not, search for lints with a similar name
+            let suggestion = find_best_match_for_name(&symbols, Symbol::intern(&name_lower), None);
+            CheckLintNameResult::NoLint(suggestion)
+        }
+    }
+
     fn check_tool_name_for_backwards_compat(
         &self,
         lint_name: &str,
@@ -407,18 +435,7 @@
         match self.by_name.get(&complete_name) {
             None => match self.lint_groups.get(&*complete_name) {
                 // Now we are sure, that this lint exists nowhere
-                None => {
-                    let symbols =
-                        self.by_name.keys().map(|name| Symbol::intern(&name)).collect::<Vec<_>>();
-
-                    let suggestion = find_best_match_for_name(
-                        &symbols,
-                        Symbol::intern(&lint_name.to_lowercase()),
-                        None,
-                    );
-
-                    CheckLintNameResult::NoLint(suggestion)
-                }
+                None => self.no_lint_suggestion(lint_name),
                 Some(LintGroup { lint_ids, depr, .. }) => {
                     // Reaching this would be weird, but let's cover this case anyway
                     if let Some(LintAlias { name, silent }) = depr {
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 37bdc87..fc8f844 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -381,6 +381,11 @@
                             src,
                             Some(li.span().into()),
                             |lint| {
+                                let name = if let Some(tool_name) = tool_name {
+                                    format!("{}::{}", tool_name, name)
+                                } else {
+                                    name.to_string()
+                                };
                                 let mut db = lint.build(&format!("unknown lint: `{}`", name));
                                 if let Some(suggestion) = suggestion {
                                     db.span_suggestion(
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index d4f7903..b031c11 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -45,12 +45,12 @@
 
 impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        use rustc_middle::ty::PredicateAtom::*;
+        use rustc_middle::ty::PredicateKind::*;
 
         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
         let predicates = cx.tcx.explicit_predicates_of(def_id);
         for &(predicate, span) in predicates.predicates {
-            let trait_predicate = match predicate.skip_binders() {
+            let trait_predicate = match predicate.kind().skip_binder() {
                 Trait(trait_predicate, _constness) => trait_predicate,
                 _ => continue,
             };
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index bc7363a..c1a3eec 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -202,8 +202,8 @@
                     let mut has_emitted = false;
                     for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
-                        if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
-                            predicate.skip_binders()
+                        if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) =
+                            predicate.kind().skip_binder()
                         {
                             let def_id = poly_trait_predicate.trait_ref.def_id;
                             let descr_pre =
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e963279..20052ad 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4,7 +4,7 @@
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
 
-use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
+use crate::{declare_lint, declare_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 
@@ -2825,8 +2825,29 @@
     };
 }
 
-declare_tool_lint! {
-    pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
+declare_lint! {
+    /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
+    ///
+    /// ### Example
+    ///
+    /// ```compile_fail
+    /// #![feature(staged_api)]
+    ///
+    /// #[derive(Clone)]
+    /// #[stable(feature = "x", since = "1")]
+    /// struct S {}
+    ///
+    /// #[unstable(feature = "y", issue = "none")]
+    /// impl Copy for S {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `staged_api` does not currently support using a stability attribute on `impl` blocks.
+    /// `impl`s are always stable if both the type and trait are stable, and always unstable otherwise.
+    pub INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
     Deny,
     "detects `#[unstable]` on stable trait implementations for stable types"
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 58931bc..5e26742 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -46,7 +46,7 @@
 
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
-    predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+    predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
 
     interpret_allocs: FxIndexSet<interpret::AllocId>,
 
@@ -328,7 +328,7 @@
         &mut self.type_shorthands
     }
 
-    fn predicate_shorthands(&mut self) -> &mut FxHashMap<rustc_middle::ty::Predicate<'tcx>, usize> {
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
         &mut self.predicate_shorthands
     }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9770e67..00ee7b8 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1281,11 +1281,6 @@
     }
 
     Other {
-        query dllimport_foreign_items(_: CrateNum)
-            -> FxHashSet<DefId> {
-            storage(ArenaCacheSelector<'tcx>)
-            desc { "dllimport_foreign_items" }
-        }
         query is_dllimport_foreign_item(def_id: DefId) -> bool {
             desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
         }
@@ -1316,7 +1311,7 @@
             desc { "looking up a named region" }
         }
         query is_late_bound_map(_: LocalDefId) ->
-            Option<&'tcx FxHashSet<ItemLocalId>> {
+            Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
             desc { "testing if a region is late bound" }
         }
         query object_lifetime_defaults_map(_: LocalDefId)
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index b47d9c5..d737d1e 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -22,15 +22,16 @@
     /// Various types that are represented as ints and handled mostly
     /// in the same way, merged for easier matching.
     Int(IntTy),
-    /// Floating-Point types
+    /// Floating-point types.
     Float,
-    /// Function Pointers
+    /// Function pointers.
     FnPtr,
-    /// Raw pointers
+    /// Raw pointers.
     Ptr(ty::TypeAndMut<'tcx>),
 }
 
-/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
+/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
+/// (or librustc_typeck/check/cast.rs).
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum CastKind {
     CoercionCast,
@@ -48,7 +49,7 @@
 
 impl<'tcx> CastTy<'tcx> {
     /// Returns `Some` for integral/pointer casts.
-    /// casts like unsizing casts will return `None`
+    /// Casts like unsizing casts will return `None`.
     pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
         match *t.kind() {
             ty::Bool => Some(CastTy::Int(IntTy::Bool)),
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 9d37150..0dad5df 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -18,7 +18,6 @@
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
-use std::convert::{TryFrom, TryInto};
 use std::hash::Hash;
 use std::intrinsics;
 use std::marker::DiscriminantKind;
@@ -43,10 +42,12 @@
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate<'tcx> {
+impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> {
     type Variant = ty::PredicateKind<'tcx>;
+
+    #[inline]
     fn variant(&self) -> &Self::Variant {
-        self.kind()
+        self
     }
 }
 
@@ -55,7 +56,7 @@
 
     fn position(&self) -> usize;
     fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize>;
-    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize>;
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize>;
     fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>;
 }
 
@@ -79,7 +80,8 @@
     E: TyEncoder<'tcx>,
     M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
     T: EncodableWithShorthand<'tcx, E>,
-    <T::Variant as DiscriminantKind>::Discriminant: Ord + TryFrom<usize>,
+    // The discriminant and shorthand must have the same size.
+    T::Variant: DiscriminantKind<Discriminant = isize>,
 {
     let existing_shorthand = cache(encoder).get(value).copied();
     if let Some(shorthand) = existing_shorthand {
@@ -95,7 +97,7 @@
     // The shorthand encoding uses the same usize as the
     // discriminant, with an offset so they can't conflict.
     let discriminant = intrinsics::discriminant_value(variant);
-    assert!(discriminant < SHORTHAND_OFFSET.try_into().ok().unwrap());
+    assert!(SHORTHAND_OFFSET > discriminant as usize);
 
     let shorthand = start + SHORTHAND_OFFSET;
 
@@ -118,9 +120,15 @@
     }
 }
 
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<ty::PredicateKind<'tcx>> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands)
+    }
+}
+
 impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        encode_with_shorthand(e, self, TyEncoder::predicate_shorthands)
+        self.kind().encode(e)
     }
 }
 
@@ -218,18 +226,24 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
-    fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<ty::PredicateKind<'tcx>> {
+    fn decode(decoder: &mut D) -> Result<ty::Binder<ty::PredicateKind<'tcx>>, D::Error> {
         // Handle shorthands first, if we have an usize > 0x80.
-        let predicate_kind = if decoder.positioned_at_shorthand() {
+        Ok(ty::Binder::bind(if decoder.positioned_at_shorthand() {
             let pos = decoder.read_usize()?;
             assert!(pos >= SHORTHAND_OFFSET);
             let shorthand = pos - SHORTHAND_OFFSET;
 
-            decoder.with_position(shorthand, ty::PredicateKind::decode)
+            decoder.with_position(shorthand, ty::PredicateKind::decode)?
         } else {
-            ty::PredicateKind::decode(decoder)
-        }?;
+            ty::PredicateKind::decode(decoder)?
+        }))
+    }
+}
+
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
+    fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
+        let predicate_kind = Decodable::decode(decoder)?;
         let predicate = decoder.tcx().mk_predicate(predicate_kind);
         Ok(predicate)
     }
@@ -457,3 +471,28 @@
         }
     }
 }
+
+macro_rules! impl_binder_encode_decode {
+    ($($t:ty),+ $(,)?) => {
+        $(
+            impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<$t> {
+                fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+                    self.as_ref().skip_binder().encode(e)
+                }
+            }
+            impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<$t> {
+                fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+                    Ok(ty::Binder::bind(Decodable::decode(decoder)?))
+                }
+            }
+        )*
+    }
+}
+
+impl_binder_encode_decode! {
+    &'tcx ty::List<Ty<'tcx>>,
+    ty::FnSig<'tcx>,
+    ty::ExistentialPredicate<'tcx>,
+    ty::TraitRef<'tcx>,
+    Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a355242..1cbf761 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -3,6 +3,7 @@
 use crate::arena::Arena;
 use crate::dep_graph::DepGraph;
 use crate::hir::exports::ExportMap;
+use crate::hir::place::Place as HirPlace;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
@@ -17,9 +18,9 @@
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
 use crate::ty::TyKind::*;
 use crate::ty::{
-    self, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, DefIdTree,
-    ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntVar,
-    IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
+    self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
+    DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
+    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
     ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
     TyVid, TypeAndMut, Visibility,
 };
@@ -133,7 +134,7 @@
     }
 
     #[inline(never)]
-    fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
+    fn intern_predicate(&self, kind: Binder<PredicateKind<'tcx>>) -> &'tcx PredicateInner<'tcx> {
         self.predicate
             .intern(kind, |kind| {
                 let flags = super::flags::FlagComputation::for_predicate(kind);
@@ -379,7 +380,7 @@
 
     /// Records the reasons that we picked the kind of each closure;
     /// not all closures are present in the map.
-    closure_kind_origins: ItemLocalMap<(Span, Symbol)>,
+    closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
 
     /// For each fn, records the "liberated" types of its arguments
     /// and return type. Liberated means that all bound regions
@@ -642,11 +643,13 @@
         self.upvar_capture_map[&upvar_id]
     }
 
-    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, Symbol)> {
+    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
         LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
     }
 
-    pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<'_, (Span, Symbol)> {
+    pub fn closure_kind_origins_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
     }
 
@@ -1948,8 +1951,8 @@
     }
 }
 
-impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+impl<'tcx> Borrow<Binder<PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a Binder<PredicateKind<'tcx>> {
         &self.0.kind
     }
 }
@@ -1987,12 +1990,6 @@
     }
 }
 
-impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateKind<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
-        &self.0
-    }
-}
-
 macro_rules! direct_interners {
     ($($name:ident: $method:ident($ty:ty),)+) => {
         $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
@@ -2091,8 +2088,8 @@
     }
 
     #[inline]
-    pub fn mk_predicate(self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
-        let inner = self.interners.intern_predicate(kind);
+    pub fn mk_predicate(self, binder: Binder<PredicateKind<'tcx>>) -> Predicate<'tcx> {
+        let inner = self.interners.intern_predicate(binder);
         Predicate { inner }
     }
 
@@ -2100,9 +2097,9 @@
     pub fn reuse_or_mk_predicate(
         self,
         pred: Predicate<'tcx>,
-        kind: PredicateKind<'tcx>,
+        binder: Binder<PredicateKind<'tcx>>,
     ) -> Predicate<'tcx> {
-        if *pred.kind() != kind { self.mk_predicate(kind) } else { pred }
+        if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
@@ -2578,7 +2575,8 @@
     }
 
     pub fn is_late_bound(self, id: HirId) -> bool {
-        self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id))
+        self.is_late_bound_map(id.owner)
+            .map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id))
     }
 
     pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 4de3d15..6ecd1eb 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -22,9 +22,9 @@
         result
     }
 
-    pub fn for_predicate(kind: ty::PredicateKind<'_>) -> FlagComputation {
+    pub fn for_predicate(binder: ty::Binder<ty::PredicateKind<'_>>) -> FlagComputation {
         let mut result = FlagComputation::new();
-        result.add_predicate_kind(kind);
+        result.add_predicate(binder);
         result
     }
 
@@ -204,53 +204,46 @@
         }
     }
 
-    fn add_predicate_kind(&mut self, kind: ty::PredicateKind<'_>) {
-        match kind {
-            ty::PredicateKind::ForAll(binder) => {
-                self.bound_computation(binder, |computation, atom| {
-                    computation.add_predicate_atom(atom)
-                });
-            }
-            ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom),
-        }
+    fn add_predicate(&mut self, binder: ty::Binder<ty::PredicateKind<'_>>) {
+        self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
     }
 
-    fn add_predicate_atom(&mut self, atom: ty::PredicateAtom<'_>) {
+    fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
         match atom {
-            ty::PredicateAtom::Trait(trait_pred, _constness) => {
+            ty::PredicateKind::Trait(trait_pred, _constness) => {
                 self.add_substs(trait_pred.trait_ref.substs);
             }
-            ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+            ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
                 self.add_region(a);
                 self.add_region(b);
             }
-            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) => {
+            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, region)) => {
                 self.add_ty(ty);
                 self.add_region(region);
             }
-            ty::PredicateAtom::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
+            ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
                 self.add_ty(a);
                 self.add_ty(b);
             }
-            ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 self.add_projection_ty(projection_ty);
                 self.add_ty(ty);
             }
-            ty::PredicateAtom::WellFormed(arg) => {
+            ty::PredicateKind::WellFormed(arg) => {
                 self.add_substs(slice::from_ref(&arg));
             }
-            ty::PredicateAtom::ObjectSafe(_def_id) => {}
-            ty::PredicateAtom::ClosureKind(_def_id, substs, _kind) => {
+            ty::PredicateKind::ObjectSafe(_def_id) => {}
+            ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
                 self.add_substs(substs);
             }
-            ty::PredicateAtom::ConstEvaluatable(_def_id, substs) => {
+            ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
                 self.add_substs(substs);
             }
-            ty::PredicateAtom::ConstEquate(expected, found) => {
+            ty::PredicateKind::ConstEquate(expected, found) => {
                 self.add_const(expected);
                 self.add_const(found);
             }
-            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 self.add_ty(ty);
             }
         }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1399fc7..c6970df 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -17,7 +17,9 @@
 pub use self::Variance::*;
 
 use crate::hir::exports::ExportMap;
-use crate::hir::place::Place as HirPlace;
+use crate::hir::place::{
+    Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
+};
 use crate::ich::StableHashingContext;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
@@ -734,6 +736,43 @@
     pub info: CaptureInfo<'tcx>,
 }
 
+pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
+    let name = match place.base {
+        HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
+        _ => bug!("Capture_information should only contain upvars"),
+    };
+    let mut curr_string = name;
+
+    for (i, proj) in place.projections.iter().enumerate() {
+        match proj.kind {
+            HirProjectionKind::Deref => {
+                curr_string = format!("*{}", curr_string);
+            }
+            HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
+                ty::Adt(def, ..) => {
+                    curr_string = format!(
+                        "{}.{}",
+                        curr_string,
+                        def.variants[variant].fields[idx as usize].ident.name.as_str()
+                    );
+                }
+                ty::Tuple(_) => {
+                    curr_string = format!("{}.{}", curr_string, idx);
+                }
+                _ => {
+                    bug!(
+                        "Field projection applied to a type other than Adt or Tuple: {:?}.",
+                        place.ty_before_projection(i).kind()
+                    )
+                }
+            },
+            proj => bug!("{:?} unexpected because it isn't captured", proj),
+        }
+    }
+
+    curr_string.to_string()
+}
+
 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
@@ -1030,14 +1069,14 @@
 
 #[derive(Debug)]
 crate struct PredicateInner<'tcx> {
-    kind: PredicateKind<'tcx>,
+    kind: Binder<PredicateKind<'tcx>>,
     flags: TypeFlags,
     /// See the comment for the corresponding field of [TyS].
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateInner<'_>, 48);
+static_assert_size!(PredicateInner<'_>, 40);
 
 #[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
@@ -1060,59 +1099,9 @@
 impl<'tcx> Eq for Predicate<'tcx> {}
 
 impl<'tcx> Predicate<'tcx> {
-    #[inline(always)]
-    pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
-        &self.inner.kind
-    }
-
-    /// Returns the inner `PredicateAtom`.
-    ///
-    /// The returned atom may contain unbound variables bound to binders skipped in this method.
-    /// It is safe to reapply binders to the given atom.
-    ///
-    /// Note that this method panics in case this predicate has unbound variables.
-    pub fn skip_binders(self) -> PredicateAtom<'tcx> {
-        match self.kind() {
-            &PredicateKind::ForAll(binder) => binder.skip_binder(),
-            &PredicateKind::Atom(atom) => {
-                debug_assert!(!atom.has_escaping_bound_vars());
-                atom
-            }
-        }
-    }
-
-    /// Returns the inner `PredicateAtom`.
-    ///
-    /// Note that this method does not check if the predicate has unbound variables.
-    ///
-    /// Rebinding the returned atom can causes the previously bound variables
-    /// to end up at the wrong binding level.
-    pub fn skip_binders_unchecked(self) -> PredicateAtom<'tcx> {
-        match self.kind() {
-            &PredicateKind::ForAll(binder) => binder.skip_binder(),
-            &PredicateKind::Atom(atom) => atom,
-        }
-    }
-
-    /// Converts this to a `Binder<PredicateAtom<'tcx>>`. If the value was an
-    /// `Atom`, then it is not allowed to contain escaping bound vars.
-    pub fn bound_atom(self) -> Binder<PredicateAtom<'tcx>> {
-        match self.kind() {
-            &PredicateKind::ForAll(binder) => binder,
-            &PredicateKind::Atom(atom) => {
-                debug_assert!(!atom.has_escaping_bound_vars());
-                Binder::dummy(atom)
-            }
-        }
-    }
-
-    /// Allows using a `Binder<PredicateAtom<'tcx>>` even if the given predicate previously
-    /// contained unbound variables by shifting these variables outwards.
-    pub fn bound_atom_with_opt_escaping(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> {
-        match self.kind() {
-            &PredicateKind::ForAll(binder) => binder,
-            &PredicateKind::Atom(atom) => Binder::wrap_nonbinding(tcx, atom),
-        }
+    /// Gets the inner `Binder<PredicateKind<'tcx>>`.
+    pub fn kind(self) -> Binder<PredicateKind<'tcx>> {
+        self.inner.kind
     }
 }
 
@@ -1134,14 +1123,6 @@
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum PredicateKind<'tcx> {
-    /// `for<'a>: ...`
-    ForAll(Binder<PredicateAtom<'tcx>>),
-    Atom(PredicateAtom<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
-pub enum PredicateAtom<'tcx> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
@@ -1187,21 +1168,6 @@
     TypeWellFormedFromEnv(Ty<'tcx>),
 }
 
-impl<'tcx> Binder<PredicateAtom<'tcx>> {
-    /// Wraps `self` with the given qualifier if this predicate has any unbound variables.
-    pub fn potentially_quantified(
-        self,
-        tcx: TyCtxt<'tcx>,
-        qualifier: impl FnOnce(Binder<PredicateAtom<'tcx>>) -> PredicateKind<'tcx>,
-    ) -> Predicate<'tcx> {
-        match self.no_bound_vars() {
-            Some(atom) => PredicateKind::Atom(atom),
-            None => qualifier(self),
-        }
-        .to_predicate(tcx)
-    }
-}
-
 /// The crate outlives map is computed during typeck and contains the
 /// outlives of every item in the local crate. You should not use it
 /// directly, because to do so will make your pass dependent on the
@@ -1287,13 +1253,9 @@
         // from the substitution and the value being substituted into, and
         // this trick achieves that).
         let substs = trait_ref.skip_binder().substs;
-        let pred = self.skip_binders();
+        let pred = self.kind().skip_binder();
         let new = pred.subst(tcx, substs);
-        if new != pred {
-            ty::Binder::bind(new).potentially_quantified(tcx, PredicateKind::ForAll)
-        } else {
-            self
-        }
+        tcx.reuse_or_mk_predicate(self, ty::Binder::bind(new))
     }
 }
 
@@ -1414,24 +1376,23 @@
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>;
 }
 
-impl ToPredicate<'tcx> for PredicateKind<'tcx> {
+impl ToPredicate<'tcx> for Binder<PredicateKind<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         tcx.mk_predicate(self)
     }
 }
 
-impl ToPredicate<'tcx> for PredicateAtom<'tcx> {
+impl ToPredicate<'tcx> for PredicateKind<'tcx> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        debug_assert!(!self.has_escaping_bound_vars(), "escaping bound vars for {:?}", self);
-        tcx.mk_predicate(PredicateKind::Atom(self))
+        tcx.mk_predicate(Binder::dummy(self))
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateAtom::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
+        PredicateKind::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
             .to_predicate(tcx)
     }
 }
@@ -1448,66 +1409,62 @@
 
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.value
-            .map_bound(|value| PredicateAtom::Trait(value, self.constness))
-            .potentially_quantified(tcx, PredicateKind::ForAll)
+        self.value.map_bound(|value| PredicateKind::Trait(value, self.constness)).to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(PredicateAtom::RegionOutlives)
-            .potentially_quantified(tcx, PredicateKind::ForAll)
+        self.map_bound(PredicateKind::RegionOutlives).to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(PredicateAtom::TypeOutlives)
-            .potentially_quantified(tcx, PredicateKind::ForAll)
+        self.map_bound(PredicateKind::TypeOutlives).to_predicate(tcx)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(PredicateAtom::Projection).potentially_quantified(tcx, PredicateKind::ForAll)
+        self.map_bound(PredicateKind::Projection).to_predicate(tcx)
     }
 }
 
 impl<'tcx> Predicate<'tcx> {
     pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
-        let predicate = self.bound_atom();
+        let predicate = self.kind();
         match predicate.skip_binder() {
-            PredicateAtom::Trait(t, constness) => {
+            PredicateKind::Trait(t, constness) => {
                 Some(ConstnessAnd { constness, value: predicate.rebind(t.trait_ref) })
             }
-            PredicateAtom::Projection(..)
-            | PredicateAtom::Subtype(..)
-            | PredicateAtom::RegionOutlives(..)
-            | PredicateAtom::WellFormed(..)
-            | PredicateAtom::ObjectSafe(..)
-            | PredicateAtom::ClosureKind(..)
-            | PredicateAtom::TypeOutlives(..)
-            | PredicateAtom::ConstEvaluatable(..)
-            | PredicateAtom::ConstEquate(..)
-            | PredicateAtom::TypeWellFormedFromEnv(..) => None,
+            PredicateKind::Projection(..)
+            | PredicateKind::Subtype(..)
+            | PredicateKind::RegionOutlives(..)
+            | PredicateKind::WellFormed(..)
+            | PredicateKind::ObjectSafe(..)
+            | PredicateKind::ClosureKind(..)
+            | PredicateKind::TypeOutlives(..)
+            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::ConstEquate(..)
+            | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
 
     pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
-        let predicate = self.bound_atom();
+        let predicate = self.kind();
         match predicate.skip_binder() {
-            PredicateAtom::TypeOutlives(data) => Some(predicate.rebind(data)),
-            PredicateAtom::Trait(..)
-            | PredicateAtom::Projection(..)
-            | PredicateAtom::Subtype(..)
-            | PredicateAtom::RegionOutlives(..)
-            | PredicateAtom::WellFormed(..)
-            | PredicateAtom::ObjectSafe(..)
-            | PredicateAtom::ClosureKind(..)
-            | PredicateAtom::ConstEvaluatable(..)
-            | PredicateAtom::ConstEquate(..)
-            | PredicateAtom::TypeWellFormedFromEnv(..) => None,
+            PredicateKind::TypeOutlives(data) => Some(predicate.rebind(data)),
+            PredicateKind::Trait(..)
+            | PredicateKind::Projection(..)
+            | PredicateKind::Subtype(..)
+            | PredicateKind::RegionOutlives(..)
+            | PredicateKind::WellFormed(..)
+            | PredicateKind::ObjectSafe(..)
+            | PredicateKind::ClosureKind(..)
+            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::ConstEquate(..)
+            | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8935727..8911de4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -623,12 +623,8 @@
                     p!("impl");
                     for (predicate, _) in bounds {
                         let predicate = predicate.subst(self.tcx(), substs);
-                        // Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
-                        // may contain unbound variables. We therefore do this manually.
-                        //
-                        // FIXME(lcnr): Find out why exactly this is the case :)
-                        let bound_predicate = predicate.bound_atom_with_opt_escaping(self.tcx());
-                        if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+                        let bound_predicate = predicate.kind();
+                        if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
                             let trait_ref = bound_predicate.rebind(pred.trait_ref);
                             // Don't print +Sized, but rather +?Sized if absent.
                             if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
@@ -2068,40 +2064,38 @@
     }
 
     ty::Predicate<'tcx> {
-        match self.kind() {
-            &ty::PredicateKind::Atom(atom) => p!(print(atom)),
-            ty::PredicateKind::ForAll(binder) => p!(print(binder)),
-        }
+        let binder = self.kind();
+        p!(print(binder))
     }
 
-    ty::PredicateAtom<'tcx> {
+    ty::PredicateKind<'tcx> {
         match *self {
-            ty::PredicateAtom::Trait(ref data, constness) => {
+            ty::PredicateKind::Trait(ref data, constness) => {
                 if let hir::Constness::Const = constness {
                     p!("const ");
                 }
                 p!(print(data))
             }
-            ty::PredicateAtom::Subtype(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::RegionOutlives(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::TypeOutlives(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::Projection(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::WellFormed(arg) => p!(print(arg), " well-formed"),
-            ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+            ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
+            ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
+            ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
+            ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
             }
-            ty::PredicateAtom::ClosureKind(closure_def_id, _closure_substs, kind) => {
+            ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => {
                 p!("the closure `",
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind))
             }
-            ty::PredicateAtom::ConstEvaluatable(def, substs) => {
+            ty::PredicateKind::ConstEvaluatable(def, substs) => {
                 p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
             }
-            ty::PredicateAtom::ConstEquate(c1, c2) => {
+            ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!("the constant `", print(c1), "` equals `", print(c2), "`")
             }
-            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 p!("the type `", print(ty), "` is found in the environment")
             }
         }
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index 6003509..cfe4700 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -989,7 +989,7 @@
     tcx: TyCtxt<'tcx>,
     encoder: &'a mut E,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
-    predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+    predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
     interpret_allocs: FxIndexSet<interpret::AllocId>,
     source_map: CachingSourceMapView<'tcx>,
     file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
@@ -1103,7 +1103,7 @@
     fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
         &mut self.type_shorthands
     }
-    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize> {
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
         &mut self.predicate_shorthands
     }
     fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7a1ca6a..44c173e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -231,37 +231,28 @@
 impl fmt::Debug for ty::PredicateKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ty::PredicateKind::ForAll(binder) => write!(f, "ForAll({:?})", binder),
-            ty::PredicateKind::Atom(atom) => write!(f, "{:?}", atom),
-        }
-    }
-}
-
-impl fmt::Debug for ty::PredicateAtom<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::PredicateAtom::Trait(ref a, constness) => {
+            ty::PredicateKind::Trait(ref a, constness) => {
                 if let hir::Constness::Const = constness {
                     write!(f, "const ")?;
                 }
                 a.fmt(f)
             }
-            ty::PredicateAtom::Subtype(ref pair) => pair.fmt(f),
-            ty::PredicateAtom::RegionOutlives(ref pair) => pair.fmt(f),
-            ty::PredicateAtom::TypeOutlives(ref pair) => pair.fmt(f),
-            ty::PredicateAtom::Projection(ref pair) => pair.fmt(f),
-            ty::PredicateAtom::WellFormed(data) => write!(f, "WellFormed({:?})", data),
-            ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+            ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+            ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
+            ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
+            ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
+            ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data),
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 write!(f, "ObjectSafe({:?})", trait_def_id)
             }
-            ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                 write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
             }
-            ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
-            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
         }
@@ -485,46 +476,36 @@
     type Lifted = ty::PredicateKind<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match self {
-            ty::PredicateKind::ForAll(binder) => tcx.lift(binder).map(ty::PredicateKind::ForAll),
-            ty::PredicateKind::Atom(atom) => tcx.lift(atom).map(ty::PredicateKind::Atom),
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> {
-    type Lifted = ty::PredicateAtom<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::PredicateAtom::Trait(data, constness) => {
-                tcx.lift(data).map(|data| ty::PredicateAtom::Trait(data, constness))
+            ty::PredicateKind::Trait(data, constness) => {
+                tcx.lift(data).map(|data| ty::PredicateKind::Trait(data, constness))
             }
-            ty::PredicateAtom::Subtype(data) => tcx.lift(data).map(ty::PredicateAtom::Subtype),
-            ty::PredicateAtom::RegionOutlives(data) => {
-                tcx.lift(data).map(ty::PredicateAtom::RegionOutlives)
+            ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
+            ty::PredicateKind::RegionOutlives(data) => {
+                tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
             }
-            ty::PredicateAtom::TypeOutlives(data) => {
-                tcx.lift(data).map(ty::PredicateAtom::TypeOutlives)
+            ty::PredicateKind::TypeOutlives(data) => {
+                tcx.lift(data).map(ty::PredicateKind::TypeOutlives)
             }
-            ty::PredicateAtom::Projection(data) => {
-                tcx.lift(data).map(ty::PredicateAtom::Projection)
+            ty::PredicateKind::Projection(data) => {
+                tcx.lift(data).map(ty::PredicateKind::Projection)
             }
-            ty::PredicateAtom::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateAtom::WellFormed),
-            ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+            ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed),
+            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 tcx.lift(closure_substs).map(|closure_substs| {
-                    ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind)
+                    ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
                 })
             }
-            ty::PredicateAtom::ObjectSafe(trait_def_id) => {
-                Some(ty::PredicateAtom::ObjectSafe(trait_def_id))
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                Some(ty::PredicateKind::ObjectSafe(trait_def_id))
             }
-            ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
-                tcx.lift(substs).map(|substs| ty::PredicateAtom::ConstEvaluatable(def_id, substs))
+            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+                tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
             }
-            ty::PredicateAtom::ConstEquate(c1, c2) => {
-                tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
+            ty::PredicateKind::ConstEquate(c1, c2) => {
+                tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
             }
-            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
-                tcx.lift(ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
+            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+                tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
             }
         }
     }
@@ -1036,12 +1017,12 @@
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        let new = ty::PredicateKind::super_fold_with(self.inner.kind, folder);
+        let new = self.inner.kind.fold_with(folder);
         folder.tcx().reuse_or_mk_predicate(self, new)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
+        self.inner.kind.visit_with(visitor)
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d43c513..e53977b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -955,7 +955,9 @@
 /// erase, or otherwise "discharge" these bound vars, we change the
 /// type from `Binder<T>` to just `T` (see
 /// e.g., `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+///
+/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 pub struct Binder<T>(T);
 
 impl<T> Binder<T> {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index db02ee6..8f41bfa 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -141,6 +141,7 @@
             self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
 
             let mut is_loop_move = false;
+            let mut in_pattern = false;
 
             for move_site in &move_site_vec {
                 let move_out = self.move_data.moves[(*move_site).moi];
@@ -256,6 +257,7 @@
                         "ref ".to_string(),
                         Applicability::MachineApplicable,
                     );
+                    in_pattern = true;
                 }
 
                 if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
@@ -302,7 +304,8 @@
             let place = &self.move_data.move_paths[mpi].place;
             let ty = place.ty(self.body, self.infcx.tcx).ty;
 
-            if is_loop_move {
+            // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
+            if is_loop_move & !in_pattern {
                 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
                     // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
                     err.span_suggestion_verbose(
@@ -1318,21 +1321,30 @@
             Applicability::MachineApplicable,
         );
 
-        let msg = match category {
+        match category {
             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
-                format!("{} is returned here", kind)
+                let msg = format!("{} is returned here", kind);
+                err.span_note(constraint_span, &msg);
             }
             ConstraintCategory::CallArgument => {
                 fr_name.highlight_region_name(&mut err);
-                format!("function requires argument type to outlive `{}`", fr_name)
+                if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
+                    err.note(
+                        "async blocks are not executed immediately and must either take a \
+                    reference or ownership of outside variables they use",
+                    );
+                } else {
+                    let msg = format!("function requires argument type to outlive `{}`", fr_name);
+                    err.span_note(constraint_span, &msg);
+                }
             }
             _ => bug!(
                 "report_escaping_closure_capture called with unexpected constraint \
                  category: `{:?}`",
                 category
             ),
-        };
-        err.span_note(constraint_span, &msg);
+        }
+
         err
     }
 
@@ -1604,20 +1616,17 @@
 
     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
         let tcx = self.infcx.tcx;
-        match place.projection {
-            [] => StorageDeadOrDrop::LocalStorageDead,
-            [proj_base @ .., elem] => {
+        match place.last_projection() {
+            None => StorageDeadOrDrop::LocalStorageDead,
+            Some((place_base, elem)) => {
                 // FIXME(spastorino) make this iterate
-                let base_access = self.classify_drop_access_kind(PlaceRef {
-                    local: place.local,
-                    projection: proj_base,
-                });
+                let base_access = self.classify_drop_access_kind(place_base);
                 match elem {
                     ProjectionElem::Deref => match base_access {
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(place.local, proj_base, self.body, tcx).ty.is_box(),
+                                place_base.ty(self.body, tcx).ty.is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1625,7 +1634,7 @@
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty;
+                        let base_ty = place_base.ty(self.body, tcx).ty;
                         match base_ty.kind() {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
@@ -1640,7 +1649,6 @@
                             _ => base_access,
                         }
                     }
-
                     ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
                     | ProjectionElem::Index(_) => base_access,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 4ebc1cd..6d98bf5 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -103,7 +103,7 @@
                         let did = did.expect_local();
                         let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
 
-                        if let Some((span, name)) =
+                        if let Some((span, hir_place)) =
                             self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
                         {
                             diag.span_note(
@@ -111,7 +111,7 @@
                                 &format!(
                                     "closure cannot be invoked more than once because it moves the \
                                     variable `{}` out of its environment",
-                                    name,
+                                    ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
                                 ),
                             );
                             return;
@@ -127,7 +127,7 @@
                 let did = did.expect_local();
                 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
 
-                if let Some((span, name)) =
+                if let Some((span, hir_place)) =
                     self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
                 {
                     diag.span_note(
@@ -135,7 +135,7 @@
                         &format!(
                             "closure cannot be moved more than once as it is not `Copy` due to \
                              moving the variable `{}` out of its environment",
-                            name
+                            ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
                         ),
                     );
                 }
@@ -338,8 +338,7 @@
                     self.describe_field(PlaceRef { local, projection: proj_base }, field)
                 }
                 ProjectionElem::Downcast(_, variant_index) => {
-                    let base_ty =
-                        Place::ty_from(place.local, place.projection, self.body, self.infcx.tcx).ty;
+                    let base_ty = place.ty(self.body, self.infcx.tcx).ty;
                     self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
@@ -473,7 +472,7 @@
 
         // If we didn't find an overloaded deref or index, then assume it's a
         // built in deref and check the type of the base.
-        let base_ty = Place::ty_from(deref_base.local, deref_base.projection, self.body, tcx).ty;
+        let base_ty = deref_base.ty(self.body, tcx).ty;
         if base_ty.is_unsafe_ptr() {
             BorrowedContentSource::DerefRawPointer
         } else if base_ty.is_mutable_ptr() {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
index 78da43c..ab83fc8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -590,8 +590,8 @@
 
                     let mut found = false;
                     for (bound, _) in bounds {
-                        if let ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_, r)) =
-                            bound.skip_binders()
+                        if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
+                            bound.kind().skip_binder()
                         {
                             let r = r.subst(self.infcx.tcx, substs);
                             if let ty::RegionKind::ReStatic = r {
diff --git a/compiler/rustc_mir/src/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs
index 9347295..fa3ae23 100644
--- a/compiler/rustc_mir/src/borrow_check/path_utils.rs
+++ b/compiler/rustc_mir/src/borrow_check/path_utils.rs
@@ -147,27 +147,25 @@
     place_ref: PlaceRef<'tcx>,
     body: &Body<'tcx>,
 ) -> Option<Field> {
-    let mut place_projection = place_ref.projection;
+    let mut place_ref = place_ref;
     let mut by_ref = false;
 
-    if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
-        place_projection = proj_base;
+    if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() {
+        place_ref = place_base;
         by_ref = true;
     }
 
-    match place_projection {
-        [base @ .., ProjectionElem::Field(field, _ty)] => {
-            let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;
-
+    match place_ref.last_projection() {
+        Some((place_base, ProjectionElem::Field(field, _ty))) => {
+            let base_ty = place_base.ty(body, tcx).ty;
             if (base_ty.is_closure() || base_ty.is_generator())
                 && (!by_ref || upvars[field.index()].by_ref)
             {
-                Some(*field)
+                Some(field)
             } else {
                 None
             }
         }
-
         _ => None,
     }
 }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index b7d22fa..157959b 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -39,10 +39,8 @@
             user_provided_sig = None;
         } else {
             let typeck_results = self.tcx().typeck(mir_def_id);
-            user_provided_sig = match typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id())
-            {
-                None => None,
-                Some(user_provided_poly_sig) => {
+            user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
+                |user_provided_poly_sig| {
                     // Instantiate the canonicalized variables from
                     // user-provided signature (e.g., the `_` in the code
                     // above) with fresh variables.
@@ -54,18 +52,16 @@
                     // Replace the bound items in the fn sig with fresh
                     // variables, so that they represent the view from
                     // "inside" the closure.
-                    Some(
-                        self.infcx
-                            .replace_bound_vars_with_fresh_vars(
-                                body.span,
-                                LateBoundRegionConversionTime::FnCall,
-                                poly_sig,
-                            )
-                            .0,
-                    )
-                }
-            }
-        };
+                    self.infcx
+                        .replace_bound_vars_with_fresh_vars(
+                            body.span,
+                            LateBoundRegionConversionTime::FnCall,
+                            poly_sig,
+                        )
+                        .0
+                },
+            );
+        }
 
         debug!(
             "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 5aad752..fb9820e 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -1014,7 +1014,7 @@
                     }
 
                     self.prove_predicate(
-                        ty::PredicateAtom::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
+                        ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
                         Locations::All(span),
                         ConstraintCategory::TypeAnnotation,
                     );
@@ -1266,7 +1266,7 @@
                     obligations.obligations.push(traits::Obligation::new(
                         ObligationCause::dummy(),
                         param_env,
-                        ty::PredicateAtom::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
+                        ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
                     ));
                     obligations.add(
                         infcx
@@ -1611,7 +1611,7 @@
                 self.check_call_dest(body, term, &sig, destination, term_location);
 
                 self.prove_predicates(
-                    sig.inputs_and_output.iter().map(|ty| ty::PredicateAtom::WellFormed(ty.into())),
+                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
@@ -2694,7 +2694,7 @@
         category: ConstraintCategory,
     ) {
         self.prove_predicates(
-            Some(ty::PredicateAtom::Trait(
+            Some(ty::PredicateKind::Trait(
                 ty::TraitPredicate { trait_ref },
                 hir::Constness::NotConst,
             )),
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
index c1a0d98..02d951b 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
@@ -788,13 +788,13 @@
     fn_def_id: DefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
-        for late_bound in late_bounds.iter() {
-            let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound };
+    if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
+        for &late_bound in late_bounds.iter() {
+            let hir_id = HirId { owner, local_id: late_bound };
             let name = tcx.hir().name(hir_id);
             let region_def_id = tcx.hir().local_def_id(hir_id);
             let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: fn_def_id,
+                scope: owner.to_def_id(),
                 bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
             }));
             f(liberated_region);
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
index ab7fada..ee78ff0 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
@@ -518,14 +518,10 @@
 
         // Check if we are assigning into a field of a union, if so, lookup the place
         // of the union so it is marked as initialized again.
-        if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
-            if let ty::Adt(def, _) =
-                Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx)
-                    .ty
-                    .kind()
-            {
+        if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
+            if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
                 if def.is_union() {
-                    place = PlaceRef { local: place.local, projection: proj_base }
+                    place = place_base;
                 }
             }
         }
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index aa58356..b740dfa 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -165,7 +165,7 @@
     let mut body =
         new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
 
-    if let Some(..) = ty {
+    if ty.is_some() {
         // The first argument (index 0), but add 1 for the return value.
         let dropee_ptr = Place::from(Local::new(1 + 0));
         if tcx.sess.opts.debugging_opts.mir_emit_retag {
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 9e90a75..99ffb0e 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -72,7 +72,7 @@
 
 /// A function call where the callee is not marked as `const`.
 #[derive(Debug)]
-pub struct FnCallNonConst(pub DefId);
+pub struct FnCallNonConst;
 impl NonConstOp for FnCallNonConst {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index c66d3ed..0ce1980 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -174,14 +174,10 @@
 
         Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
             // Special-case reborrows to be more like a copy of the reference.
-            if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx).ty;
+            if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
+                let base_ty = place_base.ty(cx.body, cx.tcx).ty;
                 if let ty::Ref(..) = base_ty.kind() {
-                    return in_place::<Q, _>(
-                        cx,
-                        in_local,
-                        PlaceRef { local: place.local, projection: proj_base },
-                    );
+                    return in_place::<Q, _>(cx, in_local, place_base);
                 }
             }
 
@@ -209,9 +205,9 @@
     Q: Qualif,
     F: FnMut(Local) -> bool,
 {
-    let mut projection = place.projection;
-    while let &[ref proj_base @ .., proj_elem] = projection {
-        match proj_elem {
+    let mut place = place;
+    while let Some((place_base, elem)) = place.last_projection() {
+        match elem {
             ProjectionElem::Index(index) if in_local(index) => return true,
 
             ProjectionElem::Deref
@@ -222,16 +218,16 @@
             | ProjectionElem::Index(_) => {}
         }
 
-        let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx);
-        let proj_ty = base_ty.projection_ty(cx.tcx, proj_elem).ty;
+        let base_ty = place_base.ty(cx.body, cx.tcx);
+        let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty;
         if !Q::in_any_value_of_ty(cx, proj_ty) {
             return false;
         }
 
-        projection = proj_base;
+        place = place_base;
     }
 
-    assert!(projection.is_empty());
+    assert!(place.projection.is_empty());
     in_local(place.local)
 }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index d1c07d1..08d969b 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -411,24 +411,24 @@
         loop {
             let predicates = tcx.predicates_of(current);
             for (predicate, _) in predicates.predicates {
-                match predicate.skip_binders() {
-                    ty::PredicateAtom::RegionOutlives(_)
-                    | ty::PredicateAtom::TypeOutlives(_)
-                    | ty::PredicateAtom::WellFormed(_)
-                    | ty::PredicateAtom::Projection(_)
-                    | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..)
-                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
-                    ty::PredicateAtom::ObjectSafe(_) => {
+                match predicate.kind().skip_binder() {
+                    ty::PredicateKind::RegionOutlives(_)
+                    | ty::PredicateKind::TypeOutlives(_)
+                    | ty::PredicateKind::WellFormed(_)
+                    | ty::PredicateKind::Projection(_)
+                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+                    ty::PredicateKind::ObjectSafe(_) => {
                         bug!("object safe predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateAtom::ClosureKind(..) => {
+                    ty::PredicateKind::ClosureKind(..) => {
                         bug!("closure kind predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateAtom::Subtype(_) => {
+                    ty::PredicateKind::Subtype(_) => {
                         bug!("subtype predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateAtom::Trait(pred, constness) => {
+                    ty::PredicateKind::Trait(pred, constness) => {
                         if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                             continue;
                         }
@@ -789,10 +789,10 @@
         }
     }
 
+    #[instrument(skip(self))]
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         use rustc_target::spec::abi::Abi::RustIntrinsic;
 
-        trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
@@ -816,8 +816,9 @@
 
                 // Attempting to call a trait method?
                 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(callee));
+                        self.check_op(ops::FnCallNonConst);
                         return;
                     }
 
@@ -871,25 +872,26 @@
                     return;
                 }
 
+                let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+
                 // HACK: This is to "unstabilize" the `transmute` intrinsic
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.fn_sig(callee).abi() == RustIntrinsic
-                    && tcx.item_name(callee) == sym::transmute
-                {
+                if is_intrinsic && tcx.item_name(callee) == sym::transmute {
                     self.check_op(ops::Transmute);
                     return;
                 }
 
                 if !tcx.is_const_fn_raw(callee) {
-                    self.check_op(ops::FnCallNonConst(callee));
+                    self.check_op(ops::FnCallNonConst);
                     return;
                 }
 
                 // If the `const fn` we are trying to call is not const-stable, ensure that we have
                 // the proper feature gate enabled.
                 if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+                    trace!(?gate, "calling unstable const fn");
                     if self.span.allows_unstable(gate) {
                         return;
                     }
@@ -904,12 +906,14 @@
                     // If this crate is not using stability attributes, or the caller is not claiming to be a
                     // stable `const fn`, that is all that is required.
                     if !self.ccx.is_const_stable_const_fn() {
+                        trace!("crate not using stability attributes or caller not stably const");
                         return;
                     }
 
                     // Otherwise, we are something const-stable calling a const-unstable fn.
 
                     if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
+                        trace!("rustc_allow_const_fn_unstable gate active");
                         return;
                     }
 
@@ -923,10 +927,16 @@
                 let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
                     && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
                 if callee_is_unstable_unmarked {
-                    if self.ccx.is_const_stable_const_fn() {
+                    trace!("callee_is_unstable_unmarked");
+                    // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
+                    // `extern` funtions, and these have no way to get marked `const`. So instead we
+                    // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
+                    if self.ccx.is_const_stable_const_fn() || is_intrinsic {
                         self.check_op(ops::FnCallUnstable(callee, None));
+                        return;
                     }
                 }
+                trace!("permitting call");
             }
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
@@ -1007,27 +1017,26 @@
     body: &Body<'tcx>,
     place: Place<'tcx>,
 ) -> Option<&'a [PlaceElem<'tcx>]> {
-    place.projection.split_last().and_then(|(outermost, inner)| {
-        if outermost != &ProjectionElem::Deref {
-            return None;
+    match place.as_ref().last_projection() {
+        Some((place_base, ProjectionElem::Deref)) => {
+            // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
+            // that points to the allocation for the static. Don't treat these as reborrows.
+            if body.local_decls[place_base.local].is_ref_to_static() {
+                None
+            } else {
+                // Ensure the type being derefed is a reference and not a raw pointer.
+                //
+                // This is sufficient to prevent an access to a `static mut` from being marked as a
+                // reborrow, even if the check above were to disappear.
+                let inner_ty = place_base.ty(body, tcx).ty;
+                match inner_ty.kind() {
+                    ty::Ref(..) => Some(place_base.projection),
+                    _ => None,
+                }
+            }
         }
-
-        // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
-        // that points to the allocation for the static. Don't treat these as reborrows.
-        if body.local_decls[place.local].is_ref_to_static() {
-            return None;
-        }
-
-        // Ensure the type being derefed is a reference and not a raw pointer.
-        //
-        // This is sufficient to prevent an access to a `static mut` from being marked as a
-        // reborrow, even if the check above were to disappear.
-        let inner_ty = Place::ty_from(place.local, inner, body, tcx).ty;
-        match inner_ty.kind() {
-            ty::Ref(..) => Some(inner),
-            _ => None,
-        }
-    })
+        _ => None,
+    }
 }
 
 fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index e64955c..bac47d0 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -223,13 +223,6 @@
         // Check for raw pointer `Deref`.
         for (base, proj) in place.iter_projections() {
             if proj == ProjectionElem::Deref {
-                let source_info = self.source_info; // Backup source_info so we can restore it later.
-                if base.projection.is_empty() && decl.internal {
-                    // Internal locals are used in the `move_val_init` desugaring.
-                    // We want to check unsafety against the source info of the
-                    // desugaring, rather than the source info of the RHS.
-                    self.source_info = self.body.local_decls[place.local].source_info;
-                }
                 let base_ty = base.ty(self.body, self.tcx).ty;
                 if base_ty.is_unsafe_ptr() {
                     self.require_unsafe(
@@ -237,7 +230,6 @@
                         UnsafetyViolationDetails::DerefOfRawPointer,
                     )
                 }
-                self.source_info = source_info; // Restore backed-up source_info.
             }
         }
 
@@ -407,17 +399,13 @@
         place: Place<'tcx>,
         is_mut_use: bool,
     ) {
-        let mut cursor = place.projection.as_ref();
-        while let &[ref proj_base @ .., elem] = cursor {
-            cursor = proj_base;
-
+        for (place_base, elem) in place.iter_projections().rev() {
             match elem {
                 // Modifications behind a dereference don't affect the value of
                 // the pointer.
                 ProjectionElem::Deref => return,
                 ProjectionElem::Field(..) => {
-                    let ty =
-                        Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty;
+                    let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
                     if let ty::Adt(def, _) = ty.kind() {
                         if self.tcx.layout_scalar_valid_range(def.did)
                             != (Bound::Unbounded, Bound::Unbounded)
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index a311e26..354d213 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -139,7 +139,7 @@
             Default::default(),
             body.arg_count,
             Default::default(),
-            tcx.def_span(def_id),
+            body.span,
             body.generator_kind,
         );
 
diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs
index 7c8c349..8d02ac6 100644
--- a/compiler/rustc_mir/src/transform/function_item_references.rs
+++ b/compiler/rustc_mir/src/transform/function_item_references.rs
@@ -5,7 +5,7 @@
 use rustc_middle::ty::{
     self,
     subst::{GenericArgKind, Subst, SubstsRef},
-    PredicateAtom, Ty, TyCtxt, TyS,
+    PredicateKind, Ty, TyCtxt, TyS,
 };
 use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::{symbol::sym, Span};
@@ -105,7 +105,7 @@
         let param_env = self.tcx.param_env(def_id);
         let bounds = param_env.caller_bounds();
         for bound in bounds {
-            if let Some(bound_ty) = self.is_pointer_trait(&bound.skip_binders()) {
+            if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) {
                 // Get the argument types as they appear in the function signature.
                 let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
                 for (arg_num, arg_def) in arg_defs.iter().enumerate() {
@@ -131,8 +131,8 @@
     }
 
     /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
-    fn is_pointer_trait(&self, bound: &PredicateAtom<'tcx>) -> Option<Ty<'tcx>> {
-        if let ty::PredicateAtom::Trait(predicate, _) = bound {
+    fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
+        if let ty::PredicateKind::Trait(predicate, _) = bound {
             if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) {
                 Some(predicate.trait_ref.self_ty())
             } else {
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index 990ca31..b0c7037 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -277,11 +277,9 @@
 impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         if let Rvalue::Ref(_, _, place) = rvalue {
-            if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
-                place.as_ref()
-            {
+            if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
                 // The dereferenced place must have type `&_`.
-                let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty;
+                let ty = place_base.ty(self.body, self.tcx).ty;
                 if let ty::Ref(_, _, Mutability::Not) = ty.kind() {
                     self.optimizations.and_stars.insert(location);
                 }
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index ea92e23..cac5abb 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -445,43 +445,50 @@
     }
 
     fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
-        match place {
-            PlaceRef { local, projection: [] } => self.validate_local(local),
-            PlaceRef { local, projection: [proj_base @ .., elem] } => {
+        match place.last_projection() {
+            None => self.validate_local(place.local),
+            Some((place_base, elem)) => {
                 // Validate topmost projection, then recurse.
-                match *elem {
+                match elem {
                     ProjectionElem::Deref => {
                         let mut promotable = false;
-                        // This is a special treatment for cases like *&STATIC where STATIC is a
-                        // global static variable.
-                        // This pattern is generated only when global static variables are directly
-                        // accessed and is qualified for promotion safely.
-                        if let TempState::Defined { location, .. } = self.temps[local] {
-                            let def_stmt =
-                                self.body[location.block].statements.get(location.statement_index);
-                            if let Some(Statement {
-                                kind:
-                                    StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(c)))),
-                                ..
-                            }) = def_stmt
+                        // The `is_empty` predicate is introduced to exclude the case
+                        // where the projection operations are [ .field, * ].
+                        // The reason is because promotion will be illegal if field
+                        // accesses precede the dereferencing.
+                        // Discussion can be found at
+                        // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
+                        // There may be opportunity for generalization, but this needs to be
+                        // accounted for.
+                        if place_base.projection.is_empty() {
+                            // This is a special treatment for cases like *&STATIC where STATIC is a
+                            // global static variable.
+                            // This pattern is generated only when global static variables are directly
+                            // accessed and is qualified for promotion safely.
+                            if let TempState::Defined { location, .. } =
+                                self.temps[place_base.local]
                             {
-                                if let Some(did) = c.check_static_ptr(self.tcx) {
-                                    // Evaluating a promoted may not read statics except if it got
-                                    // promoted from a static (this is a CTFE check). So we
-                                    // can only promote static accesses inside statics.
-                                    if let Some(hir::ConstContext::Static(..)) = self.const_kind {
-                                        // The `is_empty` predicate is introduced to exclude the case
-                                        // where the projection operations are [ .field, * ].
-                                        // The reason is because promotion will be illegal if field
-                                        // accesses precede the dereferencing.
-                                        // Discussion can be found at
-                                        // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
-                                        // There may be opportunity for generalization, but this needs to be
-                                        // accounted for.
-                                        if proj_base.is_empty()
-                                            && !self.tcx.is_thread_local_static(did)
+                                let def_stmt = self.body[location.block]
+                                    .statements
+                                    .get(location.statement_index);
+                                if let Some(Statement {
+                                    kind:
+                                        StatementKind::Assign(box (
+                                            _,
+                                            Rvalue::Use(Operand::Constant(c)),
+                                        )),
+                                    ..
+                                }) = def_stmt
+                                {
+                                    if let Some(did) = c.check_static_ptr(self.tcx) {
+                                        // Evaluating a promoted may not read statics except if it got
+                                        // promoted from a static (this is a CTFE check). So we
+                                        // can only promote static accesses inside statics.
+                                        if let Some(hir::ConstContext::Static(..)) = self.const_kind
                                         {
-                                            promotable = true;
+                                            if !self.tcx.is_thread_local_static(did) {
+                                                promotable = true;
+                                            }
                                         }
                                     }
                                 }
@@ -502,8 +509,7 @@
                     }
 
                     ProjectionElem::Field(..) => {
-                        let base_ty =
-                            Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+                        let base_ty = place_base.ty(self.body, self.tcx).ty;
                         if let Some(def) = base_ty.ty_adt_def() {
                             // No promotion of union field accesses.
                             if def.is_union() {
@@ -513,7 +519,7 @@
                     }
                 }
 
-                self.validate_place(PlaceRef { local: place.local, projection: proj_base })
+                self.validate_place(place_base)
             }
         }
     }
@@ -660,13 +666,11 @@
             Rvalue::AddressOf(_, place) => {
                 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
                 // no problem, only using it is.
-                if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                    let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+                if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection()
+                {
+                    let base_ty = place_base.ty(self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind() {
-                        return self.validate_place(PlaceRef {
-                            local: place.local,
-                            projection: proj_base,
-                        });
+                        return self.validate_place(place_base);
                     }
                 }
                 return Err(Unpromotable);
@@ -675,12 +679,12 @@
             Rvalue::Ref(_, kind, place) => {
                 // Special-case reborrows to be more like a copy of the reference.
                 let mut place_simplified = place.as_ref();
-                if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection {
-                    let base_ty =
-                        Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty;
+                if let Some((place_base, ProjectionElem::Deref)) =
+                    place_simplified.last_projection()
+                {
+                    let base_ty = place_base.ty(self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind() {
-                        place_simplified =
-                            PlaceRef { local: place_simplified.local, projection: proj_base };
+                        place_simplified = place_base;
                     }
                 }
 
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index b7c9a3a..289231e 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -61,7 +61,7 @@
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
+        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
         simplify_cfg(body);
     }
 }
diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs
index a0728a6..f567c9c 100644
--- a/compiler/rustc_mir/src/util/alignment.rs
+++ b/compiler/rustc_mir/src/util/alignment.rs
@@ -38,15 +38,12 @@
 where
     L: HasLocalDecls<'tcx>,
 {
-    let mut cursor = place.projection.as_ref();
-    while let &[ref proj_base @ .., elem] = cursor {
-        cursor = proj_base;
-
+    for (place_base, elem) in place.iter_projections().rev() {
         match elem {
             // encountered a Deref, which is ABI-aligned
             ProjectionElem::Deref => break,
             ProjectionElem::Field(..) => {
-                let ty = Place::ty_from(place.local, proj_base, local_decls, tcx).ty;
+                let ty = place_base.ty(local_decls, tcx).ty;
                 match ty.kind() {
                     ty::Adt(def, _) if def.repr.packed() => return true,
                     _ => {}
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 9777a97..639f2bb 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -10,9 +10,7 @@
 use rustc_hir as hir;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
-use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
+use rustc_middle::ty::{CanonicalUserTypeAnnotation};
 
 use std::slice;
 
@@ -219,79 +217,41 @@
                     },
                 )
             }
-            ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
-                let intrinsic = match *ty.kind() {
-                    ty::FnDef(def_id, _) => {
-                        let f = ty.fn_sig(this.hir.tcx());
-                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
-                            Some(this.hir.tcx().item_name(def_id))
-                        } else {
-                            None
-                        }
-                    }
-                    _ => None,
-                };
+            ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
                 let fun = unpack!(block = this.as_local_operand(block, fun));
-                if let Some(sym::move_val_init) = intrinsic {
-                    // `move_val_init` has "magic" semantics - the second argument is
-                    // always evaluated "directly" into the first one.
+                let args: Vec<_> = args
+                    .into_iter()
+                    .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
+                    .collect();
 
-                    let mut args = args.into_iter();
-                    let ptr = args.next().expect("0 arguments to `move_val_init`");
-                    let val = args.next().expect("1 argument to `move_val_init`");
-                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
+                let success = this.cfg.start_new_block();
 
-                    let ptr = this.hir.mirror(ptr);
-                    let ptr_ty = ptr.ty;
-                    // Create an *internal* temp for the pointer, so that unsafety
-                    // checking won't complain about the raw pointer assignment.
-                    let ptr_temp = this
-                        .local_decls
-                        .push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
-                    let ptr_temp = Place::from(ptr_temp);
-                    // No need for a scope, ptr_temp doesn't need drop
-                    let block = unpack!(this.into(ptr_temp, None, block, ptr));
-                    // Maybe we should provide a scope here so that
-                    // `move_val_init` wouldn't leak on panic even with an
-                    // arbitrary `val` expression, but `schedule_drop`,
-                    // borrowck and drop elaboration all prevent us from
-                    // dropping `ptr_temp.deref()`.
-                    this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val)
-                } else {
-                    let args: Vec<_> = args
-                        .into_iter()
-                        .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
-                        .collect();
+                this.record_operands_moved(&args);
 
-                    let success = this.cfg.start_new_block();
+                debug!("into_expr: fn_span={:?}", fn_span);
 
-                    this.record_operands_moved(&args);
-
-                    debug!("into_expr: fn_span={:?}", fn_span);
-
-                    this.cfg.terminate(
-                        block,
-                        source_info,
-                        TerminatorKind::Call {
-                            func: fun,
-                            args,
-                            cleanup: None,
-                            // FIXME(varkor): replace this with an uninhabitedness-based check.
-                            // This requires getting access to the current module to call
-                            // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
-                            destination: if expr.ty.is_never() {
-                                None
-                            } else {
-                                Some((destination, success))
-                            },
-                            from_hir_call,
-                            fn_span,
+                this.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Call {
+                        func: fun,
+                        args,
+                        cleanup: None,
+                        // FIXME(varkor): replace this with an uninhabitedness-based check.
+                        // This requires getting access to the current module to call
+                        // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
+                        destination: if expr.ty.is_never() {
+                            None
+                        } else {
+                            Some((destination, success))
                         },
-                    );
-                    this.diverge_from(block);
-                    schedule_drop(this);
-                    success.unit()
-                }
+                        from_hir_call,
+                        fn_span,
+                    },
+                );
+                this.diverge_from(block);
+                schedule_drop(this);
+                success.unit()
             }
             ExprKind::Use { source } => this.into(destination, scope, block, source),
             ExprKind::Borrow { arg, borrow_kind } => {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index f7b16bd..f150f7a 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -736,7 +736,7 @@
 
     fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
         let mut eat_ws = false;
-        let mut s = snippet.chars().enumerate().peekable();
+        let mut s = snippet.char_indices().peekable();
         let mut skips = vec![];
         while let Some((pos, c)) = s.next() {
             match (c, s.peek()) {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4a3d6ec..b70cec2 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -55,6 +55,21 @@
     }
 }
 
+/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
+/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
+/// all `extern` imports declared in it should be const-stable! However, trait methods
+/// inherit const stability attributes from their parent and do not have their own.
+enum InheritConstStability {
+    Yes,
+    No,
+}
+
+impl InheritConstStability {
+    fn yes(&self) -> bool {
+        matches!(self, InheritConstStability::Yes)
+    }
+}
+
 // A private tree-walker for producing an Index.
 struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -75,6 +90,7 @@
         item_sp: Span,
         kind: AnnotationKind,
         inherit_deprecation: InheritDeprecation,
+        inherit_const_stability: InheritConstStability,
         visit_children: F,
     ) where
         F: FnOnce(&mut Self),
@@ -140,6 +156,8 @@
             const_stab
         });
 
+        // `impl const Trait for Type` items forward their const stability to their
+        // immediate children.
         if const_stab.is_none() {
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
@@ -228,7 +246,7 @@
         self.recurse_with_stability_attrs(
             depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
             stab,
-            const_stab,
+            if inherit_const_stability.yes() { const_stab } else { None },
             visit_children,
         );
     }
@@ -325,6 +343,7 @@
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
         let orig_in_trait_impl = self.in_trait_impl;
         let mut kind = AnnotationKind::Required;
+        let mut const_stab_inherit = InheritConstStability::No;
         match i.kind {
             // Inherent impls and foreign modules serve only as containers for other items,
             // they don't have their own stability. They still can be annotated as unstable
@@ -338,6 +357,7 @@
             hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
                 self.in_trait_impl = true;
                 kind = AnnotationKind::DeprecationProhibited;
+                const_stab_inherit = InheritConstStability::Yes;
             }
             hir::ItemKind::Struct(ref sd, _) => {
                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
@@ -347,6 +367,7 @@
                         i.span,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
+                        InheritConstStability::No,
                         |_| {},
                     )
                 }
@@ -354,9 +375,15 @@
             _ => {}
         }
 
-        self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| {
-            intravisit::walk_item(v, i)
-        });
+        self.annotate(
+            i.hir_id,
+            &i.attrs,
+            i.span,
+            kind,
+            InheritDeprecation::Yes,
+            const_stab_inherit,
+            |v| intravisit::walk_item(v, i),
+        );
         self.in_trait_impl = orig_in_trait_impl;
     }
 
@@ -367,6 +394,7 @@
             ti.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_trait_item(v, ti);
             },
@@ -376,9 +404,17 @@
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let kind =
             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
-        self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| {
-            intravisit::walk_impl_item(v, ii);
-        });
+        self.annotate(
+            ii.hir_id,
+            &ii.attrs,
+            ii.span,
+            kind,
+            InheritDeprecation::Yes,
+            InheritConstStability::No,
+            |v| {
+                intravisit::walk_impl_item(v, ii);
+            },
+        );
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
@@ -388,6 +424,7 @@
             var.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
                     v.annotate(
@@ -396,6 +433,7 @@
                         var.span,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
+                        InheritConstStability::No,
                         |_| {},
                     );
                 }
@@ -412,6 +450,7 @@
             s.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_struct_field(v, s);
             },
@@ -425,6 +464,7 @@
             i.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_foreign_item(v, i);
             },
@@ -438,6 +478,7 @@
             md.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |_| {},
         );
     }
@@ -451,9 +492,17 @@
             _ => AnnotationKind::Prohibited,
         };
 
-        self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| {
-            intravisit::walk_generic_param(v, p);
-        });
+        self.annotate(
+            p.hir_id,
+            &p.attrs,
+            p.span,
+            kind,
+            InheritDeprecation::No,
+            InheritConstStability::No,
+            |v| {
+                intravisit::walk_generic_param(v, p);
+            },
+        );
     }
 }
 
@@ -618,6 +667,7 @@
             krate.item.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| intravisit::walk_crate(v, krate),
         );
     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index fb007c4..66206ca 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -100,19 +100,19 @@
     }
 
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
-        match predicate.skip_binders() {
-            ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
+        match predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
                 self.visit_trait(trait_ref)
             }
-            ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 ty.visit_with(self)?;
                 self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
             }
-            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
+            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
                 ty.visit_with(self)
             }
-            ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE,
-            ty::PredicateAtom::ConstEvaluatable(..)
+            ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
+            ty::PredicateKind::ConstEvaluatable(..)
                 if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
             {
                 // FIXME(const_evaluatable_checked): If the constant used here depends on a
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index e96fc18..4ab14c1 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -115,7 +115,7 @@
         self.get_module(parent_id)
     }
 
-    crate fn get_module(&mut self, def_id: DefId) -> Module<'a> {
+    pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
         // If this is a local module, it will be in `module_map`, no need to recalculate it.
         if let Some(def_id) = def_id.as_local() {
             return self.module_map[&def_id];
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4f8047a..69fb687 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -683,7 +683,7 @@
                     ));
                 }
                 Scope::BuiltinAttrs => {
-                    let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty));
                     if filter_fn(res) {
                         suggestions.extend(
                             BUILTIN_ATTRIBUTES
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 9de35a8..97e556f 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -14,7 +14,6 @@
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
-use rustc_ast::{unwrap_or, walk_list};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::DiagnosticId;
@@ -1911,7 +1910,7 @@
                 // it needs to be added to the trait map.
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
-                    let traits = self.get_traits_containing_item(item_name, ns);
+                    let traits = self.traits_in_scope(item_name, ns);
                     self.r.trait_map.insert(id, traits);
                 }
 
@@ -2371,12 +2370,12 @@
                 // field, we need to add any trait methods we find that match
                 // the field name so that we can do some nice error reporting
                 // later on in typeck.
-                let traits = self.get_traits_containing_item(ident, ValueNS);
+                let traits = self.traits_in_scope(ident, ValueNS);
                 self.r.trait_map.insert(expr.id, traits);
             }
             ExprKind::MethodCall(ref segment, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
-                let traits = self.get_traits_containing_item(segment.ident, ValueNS);
+                let traits = self.traits_in_scope(segment.ident, ValueNS);
                 self.r.trait_map.insert(expr.id, traits);
             }
             _ => {
@@ -2385,64 +2384,13 @@
         }
     }
 
-    fn get_traits_containing_item(
-        &mut self,
-        mut ident: Ident,
-        ns: Namespace,
-    ) -> Vec<TraitCandidate> {
-        debug!("(getting traits containing item) looking for '{}'", ident.name);
-
-        let mut found_traits = Vec::new();
-        // Look for the current trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            if self
-                .r
-                .resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    &self.parent_scope,
-                    false,
-                    module.span,
-                )
-                .is_ok()
-            {
-                let def_id = module.def_id().unwrap();
-                found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
-            }
-        }
-
-        ident.span = ident.span.normalize_to_macros_2_0();
-        let mut search_module = self.parent_scope.module;
-        loop {
-            self.r.get_traits_in_module_containing_item(
-                ident,
-                ns,
-                search_module,
-                &mut found_traits,
-                &self.parent_scope,
-            );
-            let mut span_data = ident.span.data();
-            search_module = unwrap_or!(
-                self.r.hygienic_lexical_parent(search_module, &mut span_data.ctxt),
-                break
-            );
-            ident.span = span_data.span();
-        }
-
-        if let Some(prelude) = self.r.prelude {
-            if !search_module.no_implicit_prelude {
-                self.r.get_traits_in_module_containing_item(
-                    ident,
-                    ns,
-                    prelude,
-                    &mut found_traits,
-                    &self.parent_scope,
-                );
-            }
-        }
-
-        found_traits
+    fn traits_in_scope(&mut self, ident: Ident, ns: Namespace) -> Vec<TraitCandidate> {
+        self.r.traits_in_scope(
+            self.current_trait_ref.as_ref().map(|(module, _)| *module),
+            &self.parent_scope,
+            ident.span.ctxt(),
+            Some((ident.name, ns)),
+        )
     }
 }
 
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index aab5c3c..64cc113 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -11,7 +11,8 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefIdMap, LOCAL_CRATE};
+use rustc_hir::hir_id::ItemLocalId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
 use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
@@ -20,6 +21,7 @@
 use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -284,7 +286,7 @@
         resolve_lifetimes,
 
         named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id),
-        is_late_bound_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id),
+        is_late_bound_map,
         object_lifetime_defaults_map: |tcx, id| {
             tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id)
         },
@@ -320,6 +322,32 @@
     rl
 }
 
+fn is_late_bound_map<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
+    match tcx.def_kind(def_id) {
+        DefKind::AnonConst => {
+            let mut def_id = tcx
+                .parent(def_id.to_def_id())
+                .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            // We search for the next outer anon const or fn here
+            // while skipping closures.
+            //
+            // Note that for `AnonConst` we still just recurse until we
+            // find a function body, but who cares :shrug:
+            while tcx.is_closure(def_id) {
+                def_id = tcx
+                    .parent(def_id)
+                    .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            }
+
+            tcx.is_late_bound_map(def_id.expect_local())
+        }
+        _ => tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&def_id).map(|lt| (def_id, lt)),
+    }
+}
+
 fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
     let krate = tcx.hir().krate();
     let mut map = NamedRegionMap {
@@ -1370,12 +1398,10 @@
     fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> {
         generics.params.iter().enumerate().find_map(|(i, param)| {
             if param.name.ident() == name {
-                let mut in_band = false;
-                if let hir::GenericParamKind::Lifetime { kind } = param.kind {
-                    if let hir::LifetimeParamKind::InBand = kind {
-                        in_band = true;
-                    }
-                }
+                let in_band = matches!(
+                    param.kind,
+                    hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand }
+                );
                 if in_band {
                     Some(param.span)
                 } else if generics.params.len() == 1 {
@@ -1405,12 +1431,11 @@
         lifetime: &hir::Lifetime,
     ) {
         let name = lifetime.name.ident();
-        let mut remove_decl = None;
-        if let Some(parent_def_id) = self.tcx.parent(def_id) {
-            if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) {
-                remove_decl = self.lifetime_deletion_span(name, generics);
-            }
-        }
+        let remove_decl = self
+            .tcx
+            .parent(def_id)
+            .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
+            .and_then(|generics| self.lifetime_deletion_span(name, generics));
 
         let mut remove_use = None;
         let mut elide_use = None;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index c5b8f7d..af53416 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -44,9 +44,9 @@
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
+use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, ResolverOutputs};
-use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
@@ -1477,52 +1477,79 @@
         self.crate_loader.postprocess(krate);
     }
 
-    fn get_traits_in_module_containing_item(
+    pub fn traits_in_scope(
         &mut self,
-        ident: Ident,
-        ns: Namespace,
-        module: Module<'a>,
-        found_traits: &mut Vec<TraitCandidate>,
+        current_trait: Option<Module<'a>>,
         parent_scope: &ParentScope<'a>,
+        ctxt: SyntaxContext,
+        assoc_item: Option<(Symbol, Namespace)>,
+    ) -> Vec<TraitCandidate> {
+        let mut found_traits = Vec::new();
+
+        if let Some(module) = current_trait {
+            if self.trait_may_have_item(Some(module), assoc_item) {
+                let def_id = module.def_id().unwrap();
+                found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
+            }
+        }
+
+        self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
+            match scope {
+                Scope::Module(module) => {
+                    this.traits_in_module(module, assoc_item, &mut found_traits);
+                }
+                Scope::StdLibPrelude => {
+                    if let Some(module) = this.prelude {
+                        this.traits_in_module(module, assoc_item, &mut found_traits);
+                    }
+                }
+                Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
+                _ => unreachable!(),
+            }
+            None::<()>
+        });
+
+        found_traits
+    }
+
+    fn traits_in_module(
+        &mut self,
+        module: Module<'a>,
+        assoc_item: Option<(Symbol, Namespace)>,
+        found_traits: &mut Vec<TraitCandidate>,
     ) {
-        assert!(ns == TypeNS || ns == ValueNS);
         module.ensure_traits(self);
         let traits = module.traits.borrow();
-
-        for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
-            // Traits have pseudo-modules that can be used to search for the given ident.
-            if let Some(module) = binding.module() {
-                let mut ident = ident;
-                if ident.span.glob_adjust(module.expansion, binding.span).is_none() {
-                    continue;
-                }
-                if self
-                    .resolve_ident_in_module_unadjusted(
-                        ModuleOrUniformRoot::Module(module),
-                        ident,
-                        ns,
-                        parent_scope,
-                        false,
-                        module.span,
-                    )
-                    .is_ok()
-                {
-                    let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                    let trait_def_id = module.def_id().unwrap();
-                    found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-                }
-            } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
-                // For now, just treat all trait aliases as possible candidates, since we don't
-                // know if the ident is somewhere in the transitive bounds.
-                let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                let trait_def_id = binding.res().def_id();
-                found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-            } else {
-                bug!("candidate is not trait or trait alias?")
+        for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() {
+            if self.trait_may_have_item(trait_binding.module(), assoc_item) {
+                let def_id = trait_binding.res().def_id();
+                let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name);
+                found_traits.push(TraitCandidate { def_id, import_ids });
             }
         }
     }
 
+    // List of traits in scope is pruned on best effort basis. We reject traits not having an
+    // associated item with the given name and namespace (if specified). This is a conservative
+    // optimization, proper hygienic type-based resolution of associated items is done in typeck.
+    // We don't reject trait aliases (`trait_module == None`) because we don't have access to their
+    // associated items.
+    fn trait_may_have_item(
+        &mut self,
+        trait_module: Option<Module<'a>>,
+        assoc_item: Option<(Symbol, Namespace)>,
+    ) -> bool {
+        match (trait_module, assoc_item) {
+            (Some(trait_module), Some((name, ns))) => {
+                self.resolutions(trait_module).borrow().iter().any(|resolution| {
+                    let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution;
+                    assoc_ns == ns && assoc_ident.name == name
+                })
+            }
+            _ => true,
+        }
+    }
+
     fn find_transitive_imports(
         &mut self,
         mut kind: &NameBindingKind<'_>,
@@ -3227,34 +3254,6 @@
         })
     }
 
-    /// This is equivalent to `get_traits_in_module_containing_item`, but without filtering by the associated item.
-    ///
-    /// This is used by rustdoc for intra-doc links.
-    pub fn traits_in_scope(&mut self, module_id: DefId) -> Vec<TraitCandidate> {
-        let module = self.get_module(module_id);
-        module.ensure_traits(self);
-        let traits = module.traits.borrow();
-        let to_candidate =
-            |this: &mut Self, &(trait_name, binding): &(Ident, &NameBinding<'_>)| TraitCandidate {
-                def_id: binding.res().def_id(),
-                import_ids: this.find_transitive_imports(&binding.kind, trait_name),
-            };
-
-        let mut candidates: Vec<_> =
-            traits.as_ref().unwrap().iter().map(|x| to_candidate(self, x)).collect();
-
-        if let Some(prelude) = self.prelude {
-            if !module.no_implicit_prelude {
-                prelude.ensure_traits(self);
-                candidates.extend(
-                    prelude.traits.borrow().as_ref().unwrap().iter().map(|x| to_candidate(self, x)),
-                );
-            }
-        }
-
-        candidates
-    }
-
     /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
     /// isn't something that can be returned because it can't be made to live that long,
     /// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 5c74094..5d6120c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -757,7 +757,11 @@
                     }
                     Scope::BuiltinAttrs => {
                         if is_builtin_attr_name(ident.name) {
-                            ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas)
+                            ok(
+                                Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)),
+                                DUMMY_SP,
+                                this.arenas,
+                            )
                         } else {
                             Err(Determinacy::Determined)
                         }
@@ -810,13 +814,15 @@
                             // Found another solution, if the first one was "weak", report an error.
                             let (res, innermost_res) = (binding.res(), innermost_binding.res());
                             if res != innermost_res {
-                                let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
+                                let is_builtin = |res| {
+                                    matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
+                                };
                                 let derive_helper_compat =
                                     Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
 
                                 let ambiguity_error_kind = if is_import {
                                     Some(AmbiguityKind::Import)
-                                } else if innermost_res == builtin || res == builtin {
+                                } else if is_builtin(innermost_res) || is_builtin(res) {
                                     Some(AmbiguityKind::BuiltinAttr)
                                 } else if innermost_res == derive_helper_compat
                                     || res == derive_helper_compat
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b6cf584..7b90e5b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -622,6 +622,7 @@
         intel,
         into_iter,
         into_result,
+        intra_doc_pointers,
         intrinsics,
         irrefutable_let_patterns,
         isa_attribute,
@@ -716,7 +717,6 @@
         more_struct_aliases,
         movbe_target_feature,
         move_ref_pattern,
-        move_val_init,
         mul,
         mul_assign,
         mul_with_overflow,
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index f5bc90e..25ba489 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1153,7 +1153,7 @@
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
 
         for predicate in &bounds {
-            if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
+            if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
                 if projection.ty.references_error() {
                     // No point on adding these obligations since there's a type error involved.
                     return ty_var;
@@ -1251,18 +1251,18 @@
     traits::elaborate_predicates(tcx, predicates)
         .filter_map(|obligation| {
             debug!("required_region_bounds(obligation={:?})", obligation);
-            match obligation.predicate.skip_binders() {
-                ty::PredicateAtom::Projection(..)
-                | ty::PredicateAtom::Trait(..)
-                | ty::PredicateAtom::Subtype(..)
-                | ty::PredicateAtom::WellFormed(..)
-                | ty::PredicateAtom::ObjectSafe(..)
-                | ty::PredicateAtom::ClosureKind(..)
-                | ty::PredicateAtom::RegionOutlives(..)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..)
-                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-                ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
+            match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
                     // erased_self_ty : 'a` (we interpret a
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index f8fe141..6593c10 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -414,9 +414,9 @@
         let mut should_add_new = true;
         user_computed_preds.retain(|&old_pred| {
             if let (
-                ty::PredicateAtom::Trait(new_trait, _),
-                ty::PredicateAtom::Trait(old_trait, _),
-            ) = (new_pred.skip_binders(), old_pred.skip_binders())
+                ty::PredicateKind::Trait(new_trait, _),
+                ty::PredicateKind::Trait(old_trait, _),
+            ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder())
             {
                 if new_trait.def_id() == old_trait.def_id() {
                     let new_substs = new_trait.trait_ref.substs;
@@ -633,16 +633,16 @@
             // We check this by calling is_of_param on the relevant types
             // from the various possible predicates
 
-            let bound_predicate = predicate.bound_atom();
+            let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
-                ty::PredicateAtom::Trait(p, _) => {
+                ty::PredicateKind::Trait(p, _) => {
                     // Add this to `predicates` so that we end up calling `select`
                     // with it. If this predicate ends up being unimplemented,
                     // then `evaluate_predicates` will handle adding it the `ParamEnv`
                     // if possible.
                     predicates.push_back(bound_predicate.rebind(p));
                 }
-                ty::PredicateAtom::Projection(p) => {
+                ty::PredicateKind::Projection(p) => {
                     let p = bound_predicate.rebind(p);
                     debug!(
                         "evaluate_nested_obligations: examining projection predicate {:?}",
@@ -772,13 +772,13 @@
                         }
                     }
                 }
-                ty::PredicateAtom::RegionOutlives(binder) => {
+                ty::PredicateKind::RegionOutlives(binder) => {
                     let binder = bound_predicate.rebind(binder);
                     if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
                         return false;
                     }
                 }
-                ty::PredicateAtom::TypeOutlives(binder) => {
+                ty::PredicateKind::TypeOutlives(binder) => {
                     let binder = bound_predicate.rebind(binder);
                     match (
                         binder.no_bound_vars(),
@@ -801,7 +801,7 @@
                         _ => {}
                     };
                 }
-                ty::PredicateAtom::ConstEquate(c1, c2) => {
+                ty::PredicateKind::ConstEquate(c1, c2) => {
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
                             match select.infcx().const_eval_resolve(
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 370ad57..ad229e0 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -41,8 +41,8 @@
             // We are looking at a generic abstract constant.
             Some(ct) => {
                 for pred in param_env.caller_bounds() {
-                    match pred.skip_binders() {
-                        ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
+                    match pred.kind().skip_binder() {
+                        ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
                             debug!(
                                 "is_const_evaluatable: caller_bound={:?}, {:?}",
                                 b_def, b_substs
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 795cf2e..a42a05c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -256,9 +256,9 @@
                     return;
                 }
 
-                let bound_predicate = obligation.predicate.bound_atom();
+                let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateAtom::Trait(trait_predicate, _) => {
+                    ty::PredicateKind::Trait(trait_predicate, _) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
@@ -517,14 +517,14 @@
                         err
                     }
 
-                    ty::PredicateAtom::Subtype(predicate) => {
+                    ty::PredicateKind::Subtype(predicate) => {
                         // Errors for Subtype predicates show up as
                         // `FulfillmentErrorCode::CodeSubtypeError`,
                         // not selection error.
                         span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
                     }
 
-                    ty::PredicateAtom::RegionOutlives(predicate) => {
+                    ty::PredicateKind::RegionOutlives(predicate) => {
                         let predicate = bound_predicate.rebind(predicate);
                         let predicate = self.resolve_vars_if_possible(predicate);
                         let err = self
@@ -541,7 +541,7 @@
                         )
                     }
 
-                    ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => {
+                    ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => {
                         let predicate = self.resolve_vars_if_possible(obligation.predicate);
                         struct_span_err!(
                             self.tcx.sess,
@@ -552,12 +552,12 @@
                         )
                     }
 
-                    ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+                    ty::PredicateKind::ObjectSafe(trait_def_id) => {
                         let violations = self.tcx.object_safety_violations(trait_def_id);
                         report_object_safety_error(self.tcx, span, trait_def_id, violations)
                     }
 
-                    ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+                    ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                         let found_kind = self.closure_kind(closure_substs).unwrap();
                         let closure_span =
                             self.tcx.sess.source_map().guess_head_span(
@@ -589,23 +589,23 @@
                         if let Some(typeck_results) = self.in_progress_typeck_results {
                             let typeck_results = typeck_results.borrow();
                             match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
-                                (ty::ClosureKind::FnOnce, Some((span, name))) => {
+                                (ty::ClosureKind::FnOnce, Some((span, place))) => {
                                     err.span_label(
                                         *span,
                                         format!(
                                             "closure is `FnOnce` because it moves the \
                                          variable `{}` out of its environment",
-                                            name
+                                            ty::place_to_string_for_capture(tcx, place)
                                         ),
                                     );
                                 }
-                                (ty::ClosureKind::FnMut, Some((span, name))) => {
+                                (ty::ClosureKind::FnMut, Some((span, place))) => {
                                     err.span_label(
                                         *span,
                                         format!(
                                             "closure is `FnMut` because it mutates the \
                                          variable `{}` here",
-                                            name
+                                            ty::place_to_string_for_capture(tcx, place)
                                         ),
                                     );
                                 }
@@ -617,7 +617,7 @@
                         return;
                     }
 
-                    ty::PredicateAtom::WellFormed(ty) => {
+                    ty::PredicateKind::WellFormed(ty) => {
                         if !self.tcx.sess.opts.debugging_opts.chalk {
                             // WF predicates cannot themselves make
                             // errors. They can only block due to
@@ -635,7 +635,7 @@
                         }
                     }
 
-                    ty::PredicateAtom::ConstEvaluatable(..) => {
+                    ty::PredicateKind::ConstEvaluatable(..) => {
                         // Errors for `ConstEvaluatable` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
                         // not `Unimplemented`.
@@ -646,7 +646,7 @@
                         )
                     }
 
-                    ty::PredicateAtom::ConstEquate(..) => {
+                    ty::PredicateKind::ConstEquate(..) => {
                         // Errors for `ConstEquate` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
                         // not `Unimplemented`.
@@ -657,7 +657,7 @@
                         )
                     }
 
-                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!(
+                    ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
                         span,
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
                     ),
@@ -1069,9 +1069,9 @@
         }
 
         // FIXME: It should be possible to deal with `ForAll` in a cleaner way.
-        let bound_error = error.bound_atom();
-        let (cond, error) = match (cond.skip_binders(), bound_error.skip_binder()) {
-            (ty::PredicateAtom::Trait(..), ty::PredicateAtom::Trait(error, _)) => {
+        let bound_error = error.kind();
+        let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
+            (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error, _)) => {
                 (cond, bound_error.rebind(error))
             }
             _ => {
@@ -1081,8 +1081,8 @@
         };
 
         for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
-            let bound_predicate = obligation.predicate.bound_atom();
-            if let ty::PredicateAtom::Trait(implication, _) = bound_predicate.skip_binder() {
+            let bound_predicate = obligation.predicate.kind();
+            if let ty::PredicateKind::Trait(implication, _) = bound_predicate.skip_binder() {
                 let error = error.to_poly_trait_ref();
                 let implication = bound_predicate.rebind(implication.trait_ref);
                 // FIXME: I'm just not taking associated types at all here.
@@ -1162,8 +1162,8 @@
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
-            let bound_predicate = predicate.bound_atom();
-            if let ty::PredicateAtom::Projection(data) = bound_predicate.skip_binder() {
+            let bound_predicate = predicate.kind();
+            if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
                 let mut selcx = SelectionContext::new(self);
                 let (data, _) = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
@@ -1452,9 +1452,9 @@
             return;
         }
 
-        let bound_predicate = predicate.bound_atom();
+        let bound_predicate = predicate.kind();
         let mut err = match bound_predicate.skip_binder() {
-            ty::PredicateAtom::Trait(data, _) => {
+            ty::PredicateKind::Trait(data, _) => {
                 let trait_ref = bound_predicate.rebind(data.trait_ref);
                 debug!("trait_ref {:?}", trait_ref);
 
@@ -1498,11 +1498,18 @@
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
-                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
+                    self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+                        .emit();
                     return;
                 }
-                let mut err =
-                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
+                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                let mut err = self.emit_inference_failure_err(
+                    body_id,
+                    span,
+                    subst,
+                    impl_candidates,
+                    ErrorCode::E0283,
+                );
                 err.note(&format!("cannot satisfy `{}`", predicate));
                 if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@@ -1559,17 +1566,17 @@
                 err
             }
 
-            ty::PredicateAtom::WellFormed(arg) => {
+            ty::PredicateKind::WellFormed(arg) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if arg.references_error() || self.tcx.sess.has_errors() {
                     return;
                 }
 
-                self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
+                self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
             }
 
-            ty::PredicateAtom::Subtype(data) => {
+            ty::PredicateKind::Subtype(data) => {
                 if data.references_error() || self.tcx.sess.has_errors() {
                     // no need to overload user in such cases
                     return;
@@ -1577,9 +1584,9 @@
                 let SubtypePredicate { a_is_expected: _, a, b } = data;
                 // both must be type variables, or the other would've been instantiated
                 assert!(a.is_ty_var() && b.is_ty_var());
-                self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
+                self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
             }
-            ty::PredicateAtom::Projection(data) => {
+            ty::PredicateKind::Projection(data) => {
                 let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
                 let self_ty = trait_ref.skip_binder().self_ty();
                 let ty = data.ty;
@@ -1592,6 +1599,7 @@
                         body_id,
                         span,
                         self_ty.into(),
+                        vec![],
                         ErrorCode::E0284,
                     );
                     err.note(&format!("cannot satisfy `{}`", predicate));
@@ -1709,9 +1717,10 @@
         obligation: &PredicateObligation<'tcx>,
     ) {
         let (pred, item_def_id, span) =
-            match (obligation.predicate.skip_binders(), obligation.cause.code.peel_derives()) {
+            match (obligation.predicate.kind().skip_binder(), obligation.cause.code.peel_derives())
+            {
                 (
-                    ty::PredicateAtom::Trait(pred, _),
+                    ty::PredicateKind::Trait(pred, _),
                     &ObligationCauseCode::BindingObligation(item_def_id, span),
                 ) => (pred, item_def_id, span),
                 _ => return,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 565b8d3..1830aaa 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1292,8 +1292,8 @@
         // the type. The last generator (`outer_generator` below) has information about where the
         // bound was introduced. At least one generator should be present for this diagnostic to be
         // modified.
-        let (mut trait_ref, mut target_ty) = match obligation.predicate.skip_binders() {
-            ty::PredicateAtom::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())),
+        let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())),
             _ => (None, None),
         };
         let mut generator = None;
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a04f816..d4ced20 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -345,12 +345,13 @@
 
         let infcx = self.selcx.infcx();
 
-        match *obligation.predicate.kind() {
-            ty::PredicateKind::ForAll(binder) => match binder.skip_binder() {
+        let binder = obligation.predicate.kind();
+        match binder.no_bound_vars() {
+            None => match binder.skip_binder() {
                 // Evaluation will discard candidates using the leak check.
                 // This means we need to pass it the bound version of our
                 // predicate.
-                ty::PredicateAtom::Trait(trait_ref, _constness) => {
+                ty::PredicateKind::Trait(trait_ref, _constness) => {
                     let trait_obligation = obligation.with(binder.rebind(trait_ref));
 
                     self.process_trait_obligation(
@@ -359,7 +360,7 @@
                         &mut pending_obligation.stalled_on,
                     )
                 }
-                ty::PredicateAtom::Projection(data) => {
+                ty::PredicateKind::Projection(data) => {
                     let project_obligation = obligation.with(binder.rebind(data));
 
                     self.process_projection_obligation(
@@ -367,25 +368,25 @@
                         &mut pending_obligation.stalled_on,
                     )
                 }
-                ty::PredicateAtom::RegionOutlives(_)
-                | ty::PredicateAtom::TypeOutlives(_)
-                | ty::PredicateAtom::WellFormed(_)
-                | ty::PredicateAtom::ObjectSafe(_)
-                | ty::PredicateAtom::ClosureKind(..)
-                | ty::PredicateAtom::Subtype(_)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..) => {
+                ty::PredicateKind::RegionOutlives(_)
+                | ty::PredicateKind::TypeOutlives(_)
+                | ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::ObjectSafe(_)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Subtype(_)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => {
                     let pred = infcx.replace_bound_vars_with_placeholders(binder);
                     ProcessResult::Changed(mk_pending(vec![
                         obligation.with(pred.to_predicate(self.selcx.tcx())),
                     ]))
                 }
-                ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
             },
-            ty::PredicateKind::Atom(atom) => match atom {
-                ty::PredicateAtom::Trait(data, _) => {
+            Some(pred) => match pred {
+                ty::PredicateKind::Trait(data, _) => {
                     let trait_obligation = obligation.with(Binder::dummy(data));
 
                     self.process_trait_obligation(
@@ -395,14 +396,14 @@
                     )
                 }
 
-                ty::PredicateAtom::RegionOutlives(data) => {
+                ty::PredicateKind::RegionOutlives(data) => {
                     match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
                         Ok(()) => ProcessResult::Changed(vec![]),
                         Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
                     }
                 }
 
-                ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
                     if self.register_region_obligations {
                         self.selcx.infcx().register_region_obligation_with_cause(
                             t_a,
@@ -413,7 +414,7 @@
                     ProcessResult::Changed(vec![])
                 }
 
-                ty::PredicateAtom::Projection(ref data) => {
+                ty::PredicateKind::Projection(ref data) => {
                     let project_obligation = obligation.with(Binder::dummy(*data));
 
                     self.process_projection_obligation(
@@ -422,7 +423,7 @@
                     )
                 }
 
-                ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+                ty::PredicateKind::ObjectSafe(trait_def_id) => {
                     if !self.selcx.tcx().is_object_safe(trait_def_id) {
                         ProcessResult::Error(CodeSelectionError(Unimplemented))
                     } else {
@@ -430,7 +431,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+                ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
                     match self.selcx.infcx().closure_kind(closure_substs) {
                         Some(closure_kind) => {
                             if closure_kind.extends(kind) {
@@ -443,7 +444,7 @@
                     }
                 }
 
-                ty::PredicateAtom::WellFormed(arg) => {
+                ty::PredicateKind::WellFormed(arg) => {
                     match wf::obligations(
                         self.selcx.infcx(),
                         obligation.param_env,
@@ -461,7 +462,7 @@
                     }
                 }
 
-                ty::PredicateAtom::Subtype(subtype) => {
+                ty::PredicateKind::Subtype(subtype) => {
                     match self.selcx.infcx().subtype_predicate(
                         &obligation.cause,
                         obligation.param_env,
@@ -487,7 +488,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+                ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.selcx.infcx(),
                         def_id,
@@ -507,7 +508,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ConstEquate(c1, c2) => {
+                ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "equating consts");
                     if self.selcx.tcx().features().const_evaluatable_checked {
                         // FIXME: we probably should only try to unify abstract constants
@@ -593,7 +594,7 @@
                         }
                     }
                 }
-                ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
             },
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 9c894e9..dbc40a2 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -324,7 +324,7 @@
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
         .drain_filter(|predicate| {
-            matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..))
+            matches!(predicate.kind().skip_binder(), ty::PredicateKind::TypeOutlives(..))
         })
         .collect();
 
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 8b6e30f..a972361 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -273,12 +273,12 @@
 ) -> Option<Span> {
     let self_ty = tcx.types.self_param;
     let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
-    match predicate.skip_binders() {
-        ty::PredicateAtom::Trait(ref data, _) => {
+    match predicate.kind().skip_binder() {
+        ty::PredicateKind::Trait(ref data, _) => {
             // In the case of a trait predicate, we can skip the "self" type.
             if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
         }
-        ty::PredicateAtom::Projection(ref data) => {
+        ty::PredicateKind::Projection(ref data) => {
             // And similarly for projections. This should be redundant with
             // the previous check because any projection should have a
             // matching `Trait` predicate with the same inputs, but we do
@@ -300,15 +300,15 @@
                 None
             }
         }
-        ty::PredicateAtom::WellFormed(..)
-        | ty::PredicateAtom::ObjectSafe(..)
-        | ty::PredicateAtom::TypeOutlives(..)
-        | ty::PredicateAtom::RegionOutlives(..)
-        | ty::PredicateAtom::ClosureKind(..)
-        | ty::PredicateAtom::Subtype(..)
-        | ty::PredicateAtom::ConstEvaluatable(..)
-        | ty::PredicateAtom::ConstEquate(..)
-        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+        ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::TypeOutlives(..)
+        | ty::PredicateKind::RegionOutlives(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
 
@@ -328,20 +328,20 @@
     let predicates = tcx.predicates_of(def_id);
     let predicates = predicates.instantiate_identity(tcx).predicates;
     elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
-        match obligation.predicate.skip_binders() {
-            ty::PredicateAtom::Trait(ref trait_pred, _) => {
+        match obligation.predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(ref trait_pred, _) => {
                 trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
             }
-            ty::PredicateAtom::Projection(..)
-            | ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::RegionOutlives(..)
-            | ty::PredicateAtom::WellFormed(..)
-            | ty::PredicateAtom::ObjectSafe(..)
-            | ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::TypeOutlives(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..)
-            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false,
+            ty::PredicateKind::Projection(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::RegionOutlives(..)
+            | ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::TypeOutlives(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
     })
 }
@@ -843,7 +843,7 @@
         }
 
         fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
+            if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() {
                 // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
                 // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
                 // take a `ty::Const` instead.
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index fa05264..75ff931 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -625,7 +625,7 @@
         .obligations
         .iter()
         .filter(|obligation| {
-            let bound_predicate = obligation.predicate.bound_atom();
+            let bound_predicate = obligation.predicate.kind();
             match bound_predicate.skip_binder() {
                 // We found a `T: Foo<X = U>` predicate, let's check
                 // if `U` references any unresolved type
@@ -636,7 +636,7 @@
                 // indirect obligations (e.g., we project to `?0`,
                 // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
                 // ?0>`).
-                ty::PredicateAtom::Projection(data) => {
+                ty::PredicateKind::Projection(data) => {
                     infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some()
                 }
 
@@ -917,8 +917,8 @@
     let infcx = selcx.infcx();
     for predicate in env_predicates {
         debug!(?predicate);
-        let bound_predicate = predicate.bound_atom();
-        if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
+        let bound_predicate = predicate.kind();
+        if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
             let data = bound_predicate.rebind(data);
             let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 93ddcb6..de538c6 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -15,7 +15,7 @@
         // `&T`, accounts for about 60% percentage of the predicates
         // we have to prove. No need to canonicalize and all that for
         // such cases.
-        if let ty::PredicateAtom::Trait(trait_ref, _) = key.value.predicate.skip_binders() {
+        if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate.kind().skip_binder() {
             if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
                 if trait_ref.def_id() == sized_def_id {
                     if trait_ref.self_ty().is_trivially_sized(tcx) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 030c291..3015188 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -432,7 +432,7 @@
             .predicates
             .into_iter()
         {
-            if let ty::PredicateAtom::Trait(..) = super_trait.skip_binders() {
+            if let ty::PredicateKind::Trait(..) = super_trait.kind().skip_binder() {
                 let normalized_super_trait = normalize_with_depth_to(
                     self,
                     obligation.param_env,
@@ -641,7 +641,7 @@
             obligations.push(Obligation::new(
                 obligation.cause.clone(),
                 obligation.param_env,
-                ty::PredicateAtom::ClosureKind(closure_def_id, substs, kind)
+                ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
                     .to_predicate(self.tcx()),
             ));
         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 8ca540f..614a551 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -454,16 +454,16 @@
         }
 
         let result = ensure_sufficient_stack(|| {
-            let bound_predicate = obligation.predicate.bound_atom();
+            let bound_predicate = obligation.predicate.kind();
             match bound_predicate.skip_binder() {
-                ty::PredicateAtom::Trait(t, _) => {
+                ty::PredicateKind::Trait(t, _) => {
                     let t = bound_predicate.rebind(t);
                     debug_assert!(!t.has_escaping_bound_vars());
                     let obligation = obligation.with(t);
                     self.evaluate_trait_predicate_recursively(previous_stack, obligation)
                 }
 
-                ty::PredicateAtom::Subtype(p) => {
+                ty::PredicateKind::Subtype(p) => {
                     let p = bound_predicate.rebind(p);
                     // Does this code ever run?
                     match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
@@ -479,7 +479,7 @@
                     }
                 }
 
-                ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
+                ty::PredicateKind::WellFormed(arg) => match wf::obligations(
                     self.infcx,
                     obligation.param_env,
                     obligation.cause.body_id,
@@ -494,12 +494,12 @@
                     None => Ok(EvaluatedToAmbig),
                 },
 
-                ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
+                ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => {
                     // We do not consider region relationships when evaluating trait matches.
                     Ok(EvaluatedToOkModuloRegions)
                 }
 
-                ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+                ty::PredicateKind::ObjectSafe(trait_def_id) => {
                     if self.tcx().is_object_safe(trait_def_id) {
                         Ok(EvaluatedToOk)
                     } else {
@@ -507,7 +507,7 @@
                     }
                 }
 
-                ty::PredicateAtom::Projection(data) => {
+                ty::PredicateKind::Projection(data) => {
                     let data = bound_predicate.rebind(data);
                     let project_obligation = obligation.with(data);
                     match project::poly_project_and_unify_type(self, &project_obligation) {
@@ -528,7 +528,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+                ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
                     match self.infcx.closure_kind(closure_substs) {
                         Some(closure_kind) => {
                             if closure_kind.extends(kind) {
@@ -541,7 +541,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+                ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.infcx,
                         def_id,
@@ -555,7 +555,7 @@
                     }
                 }
 
-                ty::PredicateAtom::ConstEquate(c1, c2) => {
+                ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
@@ -598,7 +598,7 @@
                         }
                     }
                 }
-                ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
             }
@@ -845,8 +845,8 @@
     }
 
     fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
-        let result = match predicate.skip_binders() {
-            ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
+        let result = match predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
             _ => false,
         };
         debug!(?predicate, ?result, "coinductive_predicate");
@@ -1174,8 +1174,8 @@
             .iter()
             .enumerate()
             .filter_map(|(idx, bound)| {
-                let bound_predicate = bound.bound_atom();
-                if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+                let bound_predicate = bound.kind();
+                if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
                     let bound = bound_predicate.rebind(pred.trait_ref);
                     if self.infcx.probe(|_| {
                         match self.match_normalize_trait_ref(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index ef87071..e6ef9b1 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -106,28 +106,28 @@
     };
 
     // It's ok to skip the binder here because wf code is prepared for it
-    match predicate.skip_binders() {
-        ty::PredicateAtom::Trait(t, _) => {
+    match predicate.kind().skip_binder() {
+        ty::PredicateKind::Trait(t, _) => {
             wf.compute_trait_ref(&t.trait_ref, Elaborate::None);
         }
-        ty::PredicateAtom::RegionOutlives(..) => {}
-        ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+        ty::PredicateKind::RegionOutlives(..) => {}
+        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
             wf.compute(ty.into());
         }
-        ty::PredicateAtom::Projection(t) => {
+        ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
             wf.compute(t.ty.into());
         }
-        ty::PredicateAtom::WellFormed(arg) => {
+        ty::PredicateKind::WellFormed(arg) => {
             wf.compute(arg);
         }
-        ty::PredicateAtom::ObjectSafe(_) => {}
-        ty::PredicateAtom::ClosureKind(..) => {}
-        ty::PredicateAtom::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+        ty::PredicateKind::ObjectSafe(_) => {}
+        ty::PredicateKind::ClosureKind(..) => {}
+        ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
             wf.compute(a.into());
             wf.compute(b.into());
         }
-        ty::PredicateAtom::ConstEvaluatable(def, substs) => {
+        ty::PredicateKind::ConstEvaluatable(def, substs) => {
             let obligations = wf.nominal_obligations(def.did, substs);
             wf.out.extend(obligations);
 
@@ -135,11 +135,11 @@
                 wf.compute(arg);
             }
         }
-        ty::PredicateAtom::ConstEquate(c1, c2) => {
+        ty::PredicateKind::ConstEquate(c1, c2) => {
             wf.compute(c1.into());
             wf.compute(c2.into());
         }
-        ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+        ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
     }
@@ -209,8 +209,8 @@
         };
 
     // It is fine to skip the binder as we don't care about regions here.
-    match pred.skip_binders() {
-        ty::PredicateAtom::Projection(proj) => {
+    match pred.kind().skip_binder() {
+        ty::PredicateKind::Projection(proj) => {
             // The obligation comes not from the current `impl` nor the `trait` being implemented,
             // but rather from a "second order" obligation, where an associated type has a
             // projection coming from another associated type. See
@@ -225,7 +225,7 @@
                 }
             }
         }
-        ty::PredicateAtom::Trait(pred, _) => {
+        ty::PredicateKind::Trait(pred, _) => {
             // An associated item obligation born out of the `trait` failed to be met. An example
             // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
             debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
@@ -343,7 +343,7 @@
                         new_cause,
                         depth,
                         param_env,
-                        ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
+                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
                     )
                 }),
         );
@@ -393,7 +393,7 @@
                         cause.clone(),
                         depth,
                         param_env,
-                        ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
+                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
                     )
                 }),
         );
@@ -436,7 +436,7 @@
                             let obligations = self.nominal_obligations(def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs)
+                            let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
                                 .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::with_depth(
@@ -460,7 +460,7 @@
                                     cause,
                                     self.recursion_depth,
                                     self.param_env,
-                                    ty::PredicateAtom::WellFormed(resolved_constant.into())
+                                    ty::PredicateKind::WellFormed(resolved_constant.into())
                                         .to_predicate(self.tcx()),
                                 ));
                             }
@@ -547,7 +547,7 @@
                             cause,
                             depth,
                             param_env,
-                            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r))
+                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r))
                                 .to_predicate(self.tcx()),
                         ));
                     }
@@ -637,7 +637,7 @@
                                 cause.clone(),
                                 depth,
                                 param_env,
-                                ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx),
+                                ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
                             )
                         }));
                     }
@@ -664,7 +664,7 @@
                             cause,
                             self.recursion_depth,
                             param_env,
-                            ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()),
+                            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
                         ));
                     } else {
                         // Yes, resolved, proceed with the result.
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 8aa68e5..48d4705 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -81,39 +81,36 @@
         interner: &RustInterner<'tcx>,
     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
         let clauses = self.environment.into_iter().map(|predicate| {
-            let (predicate, binders, _named_regions) = collect_bound_vars(
-                interner,
-                interner.tcx,
-                predicate.bound_atom_with_opt_escaping(interner.tcx),
-            );
+            let (predicate, binders, _named_regions) =
+                collect_bound_vars(interner, interner.tcx, predicate.kind());
             let consequence = match predicate {
-                ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+                ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                     chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
                 }
-                ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
+                ty::PredicateKind::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
                     chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
                 ),
-                ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                ty::PredicateKind::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
                         a: predicate.0.lower_into(interner),
                         b: predicate.1.lower_into(interner),
                     }),
                 ),
-                ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                ty::PredicateKind::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
                         ty: predicate.0.lower_into(interner),
                         lifetime: predicate.1.lower_into(interner),
                     }),
                 ),
-                ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
+                ty::PredicateKind::Projection(predicate) => chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
                 ),
-                ty::PredicateAtom::WellFormed(..)
-                | ty::PredicateAtom::ObjectSafe(..)
-                | ty::PredicateAtom::ClosureKind(..)
-                | ty::PredicateAtom::Subtype(..)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+                ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
             };
             let value = chalk_ir::ProgramClauseImplication {
                 consequence,
@@ -136,19 +133,16 @@
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
-        let (predicate, binders, _named_regions) = collect_bound_vars(
-            interner,
-            interner.tcx,
-            self.bound_atom_with_opt_escaping(interner.tcx),
-        );
+        let (predicate, binders, _named_regions) =
+            collect_bound_vars(interner, interner.tcx, self.kind());
 
         let value = match predicate {
-            ty::PredicateAtom::Trait(predicate, _) => {
+            ty::PredicateKind::Trait(predicate, _) => {
                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
                 ))
             }
-            ty::PredicateAtom::RegionOutlives(predicate) => {
+            ty::PredicateKind::RegionOutlives(predicate) => {
                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
                         a: predicate.0.lower_into(interner),
@@ -156,7 +150,7 @@
                     }),
                 ))
             }
-            ty::PredicateAtom::TypeOutlives(predicate) => {
+            ty::PredicateKind::TypeOutlives(predicate) => {
                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
                         ty: predicate.0.lower_into(interner),
@@ -164,12 +158,12 @@
                     }),
                 ))
             }
-            ty::PredicateAtom::Projection(predicate) => {
+            ty::PredicateKind::Projection(predicate) => {
                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
                     chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
                 ))
             }
-            ty::PredicateAtom::WellFormed(arg) => match arg.unpack() {
+            ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
                 GenericArgKind::Type(ty) => match ty.kind() {
                     // FIXME(chalk): In Chalk, a placeholder is WellFormed if it
                     // `FromEnv`. However, when we "lower" Params, we don't update
@@ -189,7 +183,7 @@
                 GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
             },
 
-            ty::PredicateAtom::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
+            ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
                 chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
             ),
 
@@ -197,13 +191,13 @@
             //
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
-            ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..) => {
+            ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
             }
-            ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
+            ty::PredicateKind::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
                 chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))),
             ),
         };
@@ -573,38 +567,35 @@
         self,
         interner: &RustInterner<'tcx>,
     ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        let (predicate, binders, _named_regions) = collect_bound_vars(
-            interner,
-            interner.tcx,
-            self.bound_atom_with_opt_escaping(interner.tcx),
-        );
+        let (predicate, binders, _named_regions) =
+            collect_bound_vars(interner, interner.tcx, self.kind());
         let value = match predicate {
-            ty::PredicateAtom::Trait(predicate, _) => {
+            ty::PredicateKind::Trait(predicate, _) => {
                 Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)))
             }
-            ty::PredicateAtom::RegionOutlives(predicate) => {
+            ty::PredicateKind::RegionOutlives(predicate) => {
                 Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
                     a: predicate.0.lower_into(interner),
                     b: predicate.1.lower_into(interner),
                 }))
             }
-            ty::PredicateAtom::TypeOutlives(predicate) => {
+            ty::PredicateKind::TypeOutlives(predicate) => {
                 Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
                     ty: predicate.0.lower_into(interner),
                     lifetime: predicate.1.lower_into(interner),
                 }))
             }
-            ty::PredicateAtom::Projection(predicate) => {
+            ty::PredicateKind::Projection(predicate) => {
                 Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)))
             }
-            ty::PredicateAtom::WellFormed(_ty) => None,
+            ty::PredicateKind::WellFormed(_ty) => None,
 
-            ty::PredicateAtom::ObjectSafe(..)
-            | ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..)
-            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+            ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
         };
@@ -707,32 +698,29 @@
         self,
         interner: &RustInterner<'tcx>,
     ) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> {
-        let (predicate, binders, _named_regions) = collect_bound_vars(
-            interner,
-            interner.tcx,
-            self.bound_atom_with_opt_escaping(interner.tcx),
-        );
+        let (predicate, binders, _named_regions) =
+            collect_bound_vars(interner, interner.tcx, self.kind());
         match predicate {
-            ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new(
+            ty::PredicateKind::Trait(predicate, _) => Some(chalk_ir::Binders::new(
                 binders,
                 chalk_solve::rust_ir::InlineBound::TraitBound(
                     predicate.trait_ref.lower_into(interner),
                 ),
             )),
-            ty::PredicateAtom::Projection(predicate) => Some(chalk_ir::Binders::new(
+            ty::PredicateKind::Projection(predicate) => Some(chalk_ir::Binders::new(
                 binders,
                 chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)),
             )),
-            ty::PredicateAtom::TypeOutlives(_predicate) => None,
-            ty::PredicateAtom::WellFormed(_ty) => None,
+            ty::PredicateKind::TypeOutlives(_predicate) => None,
+            ty::PredicateKind::WellFormed(_ty) => None,
 
-            ty::PredicateAtom::RegionOutlives(..)
-            | ty::PredicateAtom::ObjectSafe(..)
-            | ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..)
-            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+            ty::PredicateKind::RegionOutlives(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
         }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 97017fb..90ba902 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -94,27 +94,27 @@
         // region relationships.
         implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
             assert!(!obligation.has_escaping_bound_vars());
-            match obligation.predicate.kind() {
-                &ty::PredicateKind::ForAll(..) => vec![],
-                &ty::PredicateKind::Atom(atom) => match atom {
-                    ty::PredicateAtom::Trait(..)
-                    | ty::PredicateAtom::Subtype(..)
-                    | ty::PredicateAtom::Projection(..)
-                    | ty::PredicateAtom::ClosureKind(..)
-                    | ty::PredicateAtom::ObjectSafe(..)
-                    | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..)
-                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
-                    ty::PredicateAtom::WellFormed(arg) => {
+            match obligation.predicate.kind().no_bound_vars() {
+                None => vec![],
+                Some(pred) => match pred {
+                    ty::PredicateKind::Trait(..)
+                    | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::Projection(..)
+                    | ty::PredicateKind::ClosureKind(..)
+                    | ty::PredicateKind::ObjectSafe(..)
+                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
+                    ty::PredicateKind::WellFormed(arg) => {
                         wf_args.push(arg);
                         vec![]
                     }
 
-                    ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
+                    ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                         vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
                     }
 
-                    ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
                         let ty_a = infcx.resolve_vars_if_possible(ty_a);
                         let mut components = smallvec![];
                         tcx.push_outlives_components(ty_a, &mut components);
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 4841e42..1213e55 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -46,16 +46,16 @@
 }
 
 fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
-    match p.skip_binders() {
-        ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::TypeOutlives(..) => false,
-        ty::PredicateAtom::Trait(..)
-        | ty::PredicateAtom::Projection(..)
-        | ty::PredicateAtom::WellFormed(..)
-        | ty::PredicateAtom::ObjectSafe(..)
-        | ty::PredicateAtom::ClosureKind(..)
-        | ty::PredicateAtom::Subtype(..)
-        | ty::PredicateAtom::ConstEvaluatable(..)
-        | ty::PredicateAtom::ConstEquate(..)
-        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true,
+    match p.kind().skip_binder() {
+        ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
+        ty::PredicateKind::Trait(..)
+        | ty::PredicateKind::Projection(..)
+        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
     }
 }
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 0addde5..6304f69 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -140,7 +140,7 @@
             self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
 
             self.prove_predicate(
-                ty::PredicateAtom::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+                ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
             );
         }
 
@@ -155,7 +155,7 @@
         // them?  This would only be relevant if some input
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
-        self.prove_predicate(ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()));
+        self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
         Ok(())
     }
 }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index b28cc76..bd1d9cc 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -5,7 +5,7 @@
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{
-    self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+    self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
 };
 use rustc_session::CrateDisambiguator;
 use rustc_span::symbol::Symbol;
@@ -378,8 +378,8 @@
     let input_clauses = inputs.into_iter().filter_map(|arg| {
         match arg.unpack() {
             GenericArgKind::Type(ty) => {
-                let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
-                Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
+                let binder = Binder::dummy(PredicateKind::TypeWellFormedFromEnv(ty));
+                Some(tcx.mk_predicate(binder))
             }
 
             // FIXME(eddyb) no WF conditions from lifetimes?
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 9a2f69d..059f9b4 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1177,9 +1177,9 @@
                     obligation.predicate
                 );
 
-                let bound_predicate = obligation.predicate.bound_atom();
+                let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateAtom::Trait(pred, _) => {
+                    ty::PredicateKind::Trait(pred, _) => {
                         let pred = bound_predicate.rebind(pred);
                         associated_types.entry(span).or_default().extend(
                             tcx.associated_items(pred.def_id())
@@ -1188,7 +1188,7 @@
                                 .map(|item| item.def_id),
                         );
                     }
-                    ty::PredicateAtom::Projection(pred) => {
+                    ty::PredicateKind::Projection(pred) => {
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 322ec96..30e0e3e 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -544,9 +544,9 @@
                     self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span);
                 let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
                 for o in impl_trait_ret_ty.obligations {
-                    match o.predicate.skip_binders_unchecked() {
-                        ty::PredicateAtom::Trait(t, constness) => {
-                            let pred = ty::PredicateAtom::Trait(
+                    match o.predicate.kind().skip_binder() {
+                        ty::PredicateKind::Trait(t, constness) => {
+                            let pred = ty::PredicateKind::Trait(
                                 ty::TraitPredicate {
                                     trait_ref: ty::TraitRef {
                                         def_id: t.def_id(),
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 7470c1a..f34aaec 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -192,9 +192,9 @@
                     obligation.predicate
                 );
 
-                let bound_predicate = obligation.predicate.bound_atom();
-                if let ty::PredicateAtom::Projection(proj_predicate) =
-                    obligation.predicate.skip_binders()
+                let bound_predicate = obligation.predicate.kind();
+                if let ty::PredicateKind::Projection(proj_predicate) =
+                    obligation.predicate.kind().skip_binder()
                 {
                     // Given a Projection predicate, we can potentially infer
                     // the complete signature.
@@ -622,8 +622,8 @@
         // where R is the return type we are expecting. This type `T`
         // will be our output.
         let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
-            let bound_predicate = obligation.predicate.bound_atom();
-            if let ty::PredicateAtom::Projection(proj_predicate) = bound_predicate.skip_binder() {
+            let bound_predicate = obligation.predicate.kind();
+            if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
                 self.deduce_future_output_from_projection(
                     obligation.cause.span,
                     bound_predicate.rebind(proj_predicate),
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 0d21c56..34ad8ec 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -583,9 +583,9 @@
         while !queue.is_empty() {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
-            let bound_predicate = obligation.predicate.bound_atom();
+            let bound_predicate = obligation.predicate.kind();
             let trait_pred = match bound_predicate.skip_binder() {
-                ty::PredicateAtom::Trait(trait_pred, _)
+                ty::PredicateKind::Trait(trait_pred, _)
                     if traits.contains(&trait_pred.def_id()) =>
                 {
                     if unsize_did == trait_pred.def_id() {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 0036edd..d37d6bc 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -365,12 +365,10 @@
         let item_kind = assoc_item_kind_str(impl_m);
         let def_span = tcx.sess.source_map().guess_head_span(span);
         let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
-        let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
+        let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
             let def_sp = tcx.sess.source_map().guess_head_span(sp);
-            Some(tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span))
-        } else {
-            None
-        };
+            tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
+        });
 
         tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
             span,
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index be19919..4c3c4fd 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -226,13 +226,13 @@
         // could be extended easily also to the other `Predicate`.
         let predicate_matches_closure = |p: Predicate<'tcx>| {
             let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
-            let predicate = predicate.bound_atom();
-            let p = p.bound_atom();
+            let predicate = predicate.kind();
+            let p = p.kind();
             match (predicate.skip_binder(), p.skip_binder()) {
-                (ty::PredicateAtom::Trait(a, _), ty::PredicateAtom::Trait(b, _)) => {
+                (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
-                (ty::PredicateAtom::Projection(a), ty::PredicateAtom::Projection(b)) => {
+                (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
                 _ => predicate == p,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 47799c9..c491ba3 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -542,7 +542,7 @@
         self.register_predicate(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
+            ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
         ));
     }
 
@@ -764,21 +764,21 @@
             .pending_obligations()
             .into_iter()
             .filter_map(move |obligation| {
-                let bound_predicate = obligation.predicate.bound_atom();
+                let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateAtom::Projection(data) => {
+                    ty::PredicateKind::Projection(data) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
                     }
-                    ty::PredicateAtom::Trait(data, _) => {
+                    ty::PredicateKind::Trait(data, _) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
-                    ty::PredicateAtom::Subtype(..) => None,
-                    ty::PredicateAtom::RegionOutlives(..) => None,
-                    ty::PredicateAtom::TypeOutlives(..) => None,
-                    ty::PredicateAtom::WellFormed(..) => None,
-                    ty::PredicateAtom::ObjectSafe(..) => None,
-                    ty::PredicateAtom::ConstEvaluatable(..) => None,
-                    ty::PredicateAtom::ConstEquate(..) => None,
+                    ty::PredicateKind::Subtype(..) => None,
+                    ty::PredicateKind::RegionOutlives(..) => None,
+                    ty::PredicateKind::TypeOutlives(..) => None,
+                    ty::PredicateKind::WellFormed(..) => None,
+                    ty::PredicateKind::ObjectSafe(..) => None,
+                    ty::PredicateKind::ConstEvaluatable(..) => None,
+                    ty::PredicateKind::ConstEquate(..) => None,
                     // N.B., this predicate is created by breaking down a
                     // `ClosureType: FnFoo()` predicate, where
                     // `ClosureType` represents some `Closure`. It can't
@@ -787,8 +787,8 @@
                     // this closure yet; this is exactly why the other
                     // code is looking for a self type of a unresolved
                     // inference variable.
-                    ty::PredicateAtom::ClosureKind(..) => None,
-                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+                    ty::PredicateKind::ClosureKind(..) => None,
+                    ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 }
             })
             .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
@@ -1479,7 +1479,7 @@
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
+                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282)
                     .note("type must be known at this point")
                     .emit();
             }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 6177e39..6df9e3a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -923,8 +923,8 @@
                 continue;
             }
 
-            if let ty::PredicateAtom::Trait(predicate, _) =
-                error.obligation.predicate.skip_binders()
+            if let ty::PredicateKind::Trait(predicate, _) =
+                error.obligation.predicate.kind().skip_binder()
             {
                 // Collect the argument position for all arguments that could have caused this
                 // `FulfillmentError`.
@@ -974,8 +974,8 @@
             if let hir::ExprKind::Path(qpath) = &path.kind {
                 if let hir::QPath::Resolved(_, path) = &qpath {
                     for error in errors {
-                        if let ty::PredicateAtom::Trait(predicate, _) =
-                            error.obligation.predicate.skip_binders()
+                        if let ty::PredicateKind::Trait(predicate, _) =
+                            error.obligation.predicate.kind().skip_binder()
                         {
                             // If any of the type arguments in this path segment caused the
                             // `FullfillmentError`, point at its span (#61860).
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index f635e0b..6d09043 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -194,8 +194,8 @@
             parent: None,
             predicates: tcx.arena.alloc_from_iter(
                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
-                    match predicate.skip_binders() {
-                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
+                    match predicate.kind().skip_binder() {
+                        ty::PredicateKind::Trait(data, _) if data.self_ty().is_param(index) => {
                             // HACK(eddyb) should get the original `Span`.
                             let span = tcx.def_span(def_id);
                             Some((predicate, span))
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index e4e6cf7..e99db7a 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -157,7 +157,6 @@
             }
             sym::forget => (1, vec![param(0)], tcx.mk_unit()),
             sym::transmute => (2, vec![param(0)], param(1)),
-            sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
             sym::prefetch_read_data
             | sym::prefetch_write_data
             | sym::prefetch_read_instruction
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index e604419..97c9620 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -31,6 +31,7 @@
     }
 }
 
+#[derive(Debug)]
 pub struct ConfirmResult<'tcx> {
     pub callee: MethodCallee<'tcx>,
     pub illegal_sized_bound: Option<Span>,
@@ -478,8 +479,8 @@
 
         traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
             // We don't care about regions here.
-            .filter_map(|obligation| match obligation.predicate.skip_binders() {
-                ty::PredicateAtom::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
+            .filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
                     let span = predicates
                         .predicates
                         .iter()
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 8e13b37..9a3d1e4 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -102,6 +102,7 @@
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Determines whether the type `self_ty` supports a method name `method_name` or not.
+    #[instrument(level = "debug", skip(self))]
     pub fn method_exists(
         &self,
         method_name: Ident,
@@ -129,6 +130,7 @@
     }
 
     /// Adds a suggestion to call the given method to the provided diagnostic.
+    #[instrument(level = "debug", skip(self, err, call_expr))]
     crate fn suggest_method_call(
         &self,
         err: &mut DiagnosticBuilder<'a>,
@@ -177,6 +179,7 @@
     /// * `span`:                  the span for the method call
     /// * `call_expr`:             the complete method call: (`foo.bar::<T1,...Tn>(...)`)
     /// * `self_expr`:             the self expression (`foo`)
+    #[instrument(level = "debug", skip(self, call_expr, self_expr))]
     pub fn lookup_method(
         &self,
         self_ty: Ty<'tcx>,
@@ -204,6 +207,7 @@
 
         let result =
             self.confirm_method(span, self_expr, call_expr, self_ty, pick.clone(), segment);
+        debug!("result = {:?}", result);
 
         if let Some(span) = result.illegal_sized_bound {
             let mut needs_mut = false;
@@ -256,6 +260,7 @@
         Ok(result.callee)
     }
 
+    #[instrument(level = "debug", skip(self, call_expr))]
     pub fn lookup_probe(
         &self,
         span: Span,
@@ -286,6 +291,7 @@
     // FIXME(#18741): it seems likely that we can consolidate some of this
     // code with the other method-lookup code. In particular, the second half
     // of this method is basically the same as confirmation.
+    #[instrument(level = "debug", skip(self, span, opt_input_types))]
     pub fn lookup_method_in_trait(
         &self,
         span: Span,
@@ -399,7 +405,7 @@
         obligations.push(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateAtom::WellFormed(method_ty.into()).to_predicate(tcx),
+            ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
         ));
 
         let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
@@ -409,6 +415,7 @@
         Some(InferOk { obligations, value: callee })
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub fn resolve_ufcs(
         &self,
         span: Span,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index d4631c4..8335239 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -48,7 +48,7 @@
 
 /// Boolean flag used to indicate if this search is for a suggestion
 /// or not. If true, we can allow ambiguity and so forth.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 pub struct IsSuggestion(pub bool);
 
 struct ProbeContext<'a, 'tcx> {
@@ -219,6 +219,7 @@
     /// would result in an error (basically, the same criteria we
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
+    #[instrument(level = "debug", skip(self, scope_expr_id))]
     pub fn probe_for_return_type(
         &self,
         span: Span,
@@ -264,6 +265,7 @@
             .collect()
     }
 
+    #[instrument(level = "debug", skip(self, scope_expr_id))]
     pub fn probe_for_name(
         &self,
         span: Span,
@@ -770,7 +772,7 @@
         // will be reported by `object_safety.rs` if the method refers to the
         // `Self` type anywhere other than the receiver. Here, we use a
         // substitution that replaces `Self` with the object type itself. Hence,
-        // a `&self` method will wind up with an argument type like `&Trait`.
+        // a `&self` method will wind up with an argument type like `&dyn Trait`.
         let trait_ref = principal.with_self_ty(self.tcx, self_ty);
         self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
             let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
@@ -795,9 +797,9 @@
         debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
 
         let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
-            let bound_predicate = predicate.bound_atom();
+            let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
-                ty::PredicateAtom::Trait(trait_predicate, _) => {
+                ty::PredicateKind::Trait(trait_predicate, _) => {
                     match *trait_predicate.trait_ref.self_ty().kind() {
                         ty::Param(p) if p == param_ty => {
                             Some(bound_predicate.rebind(trait_predicate.trait_ref))
@@ -805,16 +807,16 @@
                         _ => None,
                     }
                 }
-                ty::PredicateAtom::Subtype(..)
-                | ty::PredicateAtom::Projection(..)
-                | ty::PredicateAtom::RegionOutlives(..)
-                | ty::PredicateAtom::WellFormed(..)
-                | ty::PredicateAtom::ObjectSafe(..)
-                | ty::PredicateAtom::ClosureKind(..)
-                | ty::PredicateAtom::TypeOutlives(..)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..)
-                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+                ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index e6bfa5e..c553fda 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -582,8 +582,8 @@
                     let mut collect_type_param_suggestions =
                         |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
                             // We don't care about regions here, so it's fine to skip the binder here.
-                            if let (ty::Param(_), ty::PredicateAtom::Trait(p, _)) =
-                                (self_ty.kind(), parent_pred.skip_binders())
+                            if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
+                                (self_ty.kind(), parent_pred.kind().skip_binder())
                             {
                                 if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
                                     let node = def.did.as_local().map(|def_id| {
@@ -637,9 +637,9 @@
                         }
                     };
                     let mut format_pred = |pred: ty::Predicate<'tcx>| {
-                        let bound_predicate = pred.bound_atom();
+                        let bound_predicate = pred.kind();
                         match bound_predicate.skip_binder() {
-                            ty::PredicateAtom::Projection(pred) => {
+                            ty::PredicateKind::Projection(pred) => {
                                 let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
                                 let trait_ref =
@@ -658,7 +658,7 @@
                                 bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
                                 Some((obligation, trait_ref.self_ty()))
                             }
-                            ty::PredicateAtom::Trait(poly_trait_ref, _) => {
+                            ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.trait_ref;
                                 let self_ty = p.self_ty();
                                 let path = p.print_only_trait_path();
@@ -992,11 +992,11 @@
                 // implementing a trait would be legal but is rejected
                 // here).
                 unsatisfied_predicates.iter().all(|(p, _)| {
-                    match p.skip_binders() {
+                    match p.kind().skip_binder() {
                         // Hide traits if they are present in predicates as they can be fixed without
                         // having to implement them.
-                        ty::PredicateAtom::Trait(t, _) => t.def_id() == info.def_id,
-                        ty::PredicateAtom::Projection(p) => {
+                        ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
+                        ty::PredicateKind::Projection(p) => {
                             p.projection_ty.item_def_id == info.def_id
                         }
                         _ => false,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 8177b36..52276ed 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -864,9 +864,9 @@
     let mut projections = vec![];
     for (predicate, _) in predicates.predicates {
         debug!("predicate {:?}", predicate);
-        let bound_predicate = predicate.bound_atom();
+        let bound_predicate = predicate.kind();
         match bound_predicate.skip_binder() {
-            ty::PredicateAtom::Trait(trait_predicate, _) => {
+            ty::PredicateKind::Trait(trait_predicate, _) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
                 if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -875,7 +875,7 @@
                     entry.push(trait_predicate.def_id());
                 }
             }
-            ty::PredicateAtom::Projection(projection_pred) => {
+            ty::PredicateKind::Projection(projection_pred) => {
                 projections.push(bound_predicate.rebind(projection_pred));
             }
             _ => {}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index e8cbefd..feda35d 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -176,7 +176,17 @@
             self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
 
             // If we have an origin, store it.
-            if let Some(origin) = delegate.current_origin {
+            if let Some(origin) = delegate.current_origin.clone() {
+                let origin = if self.tcx.features().capture_disjoint_fields {
+                    origin
+                } else {
+                    // FIXME(project-rfc-2229#26): Once rust-lang#80092 is merged, we should restrict the
+                    // precision of origin as well. Otherwise, this will cause issues when project-rfc-2229#26
+                    // is fixed as we might see Index projections in the origin, which we can't print because
+                    // we don't store enough information.
+                    (origin.0, Place { projections: vec![], ..origin.1 })
+                };
+
                 self.typeck_results
                     .borrow_mut()
                     .closure_kind_origins_mut()
@@ -563,7 +573,7 @@
 
     // If we modified `current_closure_kind`, this field contains a `Some()` with the
     // variable access that caused us to do so.
-    current_origin: Option<(Span, Symbol)>,
+    current_origin: Option<(Span, Place<'tcx>)>,
 
     /// For each Place that is captured by the closure, we track the minimal kind of
     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -628,7 +638,7 @@
             upvar_id.closure_expr_id,
             ty::ClosureKind::FnOnce,
             usage_span,
-            var_name(tcx, upvar_id.var_path.hir_id),
+            place_with_id.place.clone(),
         );
 
         let capture_info = ty::CaptureInfo {
@@ -720,7 +730,7 @@
                 upvar_id.closure_expr_id,
                 ty::ClosureKind::FnMut,
                 tcx.hir().span(diag_expr_id),
-                var_name(tcx, upvar_id.var_path.hir_id),
+                place_with_id.place.clone(),
             );
         }
     }
@@ -765,11 +775,11 @@
         closure_id: LocalDefId,
         new_kind: ty::ClosureKind,
         upvar_span: Span,
-        var_name: Symbol,
+        place: Place<'tcx>,
     ) {
         debug!(
-            "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})",
-            closure_id, new_kind, upvar_span, var_name
+            "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, place={:?})",
+            closure_id, new_kind, upvar_span, place
         );
 
         // Is this the closure whose kind is currently being inferred?
@@ -797,7 +807,7 @@
             | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                 // new kind is stronger than the old kind
                 self.current_closure_kind = new_kind;
-                self.current_origin = Some((upvar_span, var_name));
+                self.current_origin = Some((upvar_span, place));
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 2c720ce..c90db47 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -532,7 +532,7 @@
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::PredicateAtom::ConstEvaluatable(
+                    ty::PredicateKind::ConstEvaluatable(
                         ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
                         discr_substs,
                     )
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 7c9cfe6..9e6bf5c 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -384,9 +384,11 @@
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&id, &origin) in fcx_typeck_results.closure_kind_origins().iter() {
-            let hir_id = hir::HirId { owner: common_hir_owner, local_id: id };
-            self.typeck_results.closure_kind_origins_mut().insert(hir_id, origin);
+        for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() {
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id };
+            let place_span = origin.0;
+            let place = self.resolve(origin.1.clone(), &place_span);
+            self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place));
         }
     }
 
@@ -692,6 +694,7 @@
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
                     t.into(),
+                    vec![],
                     E0282,
                 )
                 .emit();
@@ -705,6 +708,7 @@
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
                     c.into(),
+                    vec![],
                     E0282,
                 )
                 .emit();
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index a667732..d589989 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -562,8 +562,8 @@
     let extra_predicates = extend.into_iter().chain(
         icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
             .into_iter()
-            .filter(|(predicate, _)| match predicate.skip_binders() {
-                ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index),
+            .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
                 _ => false,
             }),
     );
@@ -1027,7 +1027,7 @@
     // which will, in turn, reach indirect supertraits.
     for &(pred, span) in superbounds {
         debug!("superbound: {:?}", pred);
-        if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() {
+        if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
             tcx.at(span).super_predicates_of(bound.def_id());
         }
     }
@@ -1946,13 +1946,10 @@
                     } else {
                         let span = bound_pred.bounded_ty.span;
                         let re_root_empty = tcx.lifetimes.re_root_empty;
-                        let predicate = ty::Binder::bind(ty::PredicateAtom::TypeOutlives(
+                        let predicate = ty::Binder::bind(ty::PredicateKind::TypeOutlives(
                             ty::OutlivesPredicate(ty, re_root_empty),
                         ));
-                        predicates.insert((
-                            predicate.potentially_quantified(tcx, ty::PredicateKind::ForAll),
-                            span,
-                        ));
+                        predicates.insert((predicate.to_predicate(tcx), span));
                     }
                 }
 
@@ -1993,10 +1990,10 @@
                         hir::GenericBound::Outlives(lifetime) => {
                             let region = AstConv::ast_region_to_region(&icx, lifetime, None);
                             predicates.insert((
-                                ty::Binder::bind(ty::PredicateAtom::TypeOutlives(
+                                ty::Binder::bind(ty::PredicateKind::TypeOutlives(
                                     ty::OutlivesPredicate(ty, region),
                                 ))
-                                .potentially_quantified(tcx, ty::PredicateKind::ForAll),
+                                .to_predicate(tcx),
                                 lifetime.span,
                             ));
                         }
@@ -2013,7 +2010,7 @@
                         }
                         _ => bug!(),
                     };
-                    let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+                    let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
                         .to_predicate(icx.tcx);
 
                     (pred, span)
@@ -2078,7 +2075,7 @@
             if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
+                    ty::PredicateKind::ConstEvaluatable(def, substs).to_predicate(self.tcx),
                     span,
                 ));
             }
@@ -2097,7 +2094,7 @@
                 fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
                         self.preds.insert((
-                            ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
+                            ty::PredicateKind::ConstEvaluatable(def, substs).to_predicate(self.tcx),
                             self.span,
                         ));
                     }
@@ -2183,12 +2180,12 @@
             .predicates
             .iter()
             .copied()
-            .filter(|(pred, _)| match pred.skip_binders() {
-                ty::PredicateAtom::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
-                ty::PredicateAtom::Projection(proj) => {
+            .filter(|(pred, _)| match pred.kind().skip_binder() {
+                ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
+                ty::PredicateKind::Projection(proj) => {
                     !is_assoc_item_ty(proj.projection_ty.self_ty())
                 }
-                ty::PredicateAtom::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+                ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
                 _ => true,
             })
             .collect();
@@ -2217,7 +2214,8 @@
     let (ty_def_id, item_def_id) = key;
     let mut projection_ty = None;
     for (predicate, _) in tcx.predicates_of(ty_def_id).predicates {
-        if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
+        if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder()
+        {
             if item_def_id == projection_predicate.projection_ty.item_def_id {
                 projection_ty = Some(projection_predicate.projection_ty);
                 break;
@@ -2264,7 +2262,7 @@
         }
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
-            let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
+            let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
                 .to_predicate(astconv.tcx());
             vec![(pred, lifetime.span)]
         }
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index e596dd1..537a583 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -36,13 +36,14 @@
     let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
 
-    let bounds_from_parent =
-        trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.skip_binders() {
-            ty::PredicateAtom::Trait(tr, _) => tr.self_ty() == item_ty,
-            ty::PredicateAtom::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
-            ty::PredicateAtom::TypeOutlives(outlives) => outlives.0 == item_ty,
+    let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
+        match pred.kind().skip_binder() {
+            ty::PredicateKind::Trait(tr, _) => tr.self_ty() == item_ty,
+            ty::PredicateKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
+            ty::PredicateKind::TypeOutlives(outlives) => outlives.0 == item_ty,
             _ => false,
-        });
+        }
+    });
 
     let all_bounds = tcx
         .arena
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index e389fd4..95670b9 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -183,7 +183,8 @@
         for j in i..predicates.len() {
             // Note that we don't have to care about binders here,
             // as the impl trait ref never contains any late-bound regions.
-            if let ty::PredicateAtom::Projection(projection) = predicates[j].0.skip_binders() {
+            if let ty::PredicateKind::Projection(projection) = predicates[j].0.kind().skip_binder()
+            {
                 // Special case: watch out for some kind of sneaky attempt
                 // to project out an associated type defined by this very
                 // trait.
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 5db9ff9..505d9a5 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -198,7 +198,7 @@
     // the functions in `cgp` add the constrained parameters to a list of
     // unconstrained parameters.
     for (predicate, _) in impl_generic_predicates.predicates.iter() {
-        if let ty::PredicateAtom::Projection(proj) = predicate.skip_binders() {
+        if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
             let projection_ty = proj.projection_ty;
             let projected_ty = proj.ty;
 
@@ -360,13 +360,13 @@
 
 fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
     debug!("can_specialize_on(predicate = {:?})", predicate);
-    match predicate.skip_binders() {
+    match predicate.kind().skip_binder() {
         // Global predicates are either always true or always false, so we
         // are fine to specialize on.
         _ if predicate.is_global() => (),
         // We allow specializing on explicitly marked traits with no associated
         // items.
-        ty::PredicateAtom::Trait(pred, hir::Constness::NotConst) => {
+        ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
             if !matches!(
                 trait_predicate_kind(tcx, predicate),
                 Some(TraitSpecializationKind::Marker)
@@ -393,20 +393,20 @@
     tcx: TyCtxt<'tcx>,
     predicate: ty::Predicate<'tcx>,
 ) -> Option<TraitSpecializationKind> {
-    match predicate.skip_binders() {
-        ty::PredicateAtom::Trait(pred, hir::Constness::NotConst) => {
+    match predicate.kind().skip_binder() {
+        ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
             Some(tcx.trait_def(pred.def_id()).specialization_kind)
         }
-        ty::PredicateAtom::Trait(_, hir::Constness::Const)
-        | ty::PredicateAtom::RegionOutlives(_)
-        | ty::PredicateAtom::TypeOutlives(_)
-        | ty::PredicateAtom::Projection(_)
-        | ty::PredicateAtom::WellFormed(_)
-        | ty::PredicateAtom::Subtype(_)
-        | ty::PredicateAtom::ObjectSafe(_)
-        | ty::PredicateAtom::ClosureKind(..)
-        | ty::PredicateAtom::ConstEvaluatable(..)
-        | ty::PredicateAtom::ConstEquate(..)
-        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+        ty::PredicateKind::Trait(_, hir::Constness::Const)
+        | ty::PredicateKind::RegionOutlives(_)
+        | ty::PredicateKind::TypeOutlives(_)
+        | ty::PredicateKind::Projection(_)
+        | ty::PredicateKind::WellFormed(_)
+        | ty::PredicateKind::Subtype(_)
+        | ty::PredicateKind::ObjectSafe(_)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index ae336cc..6e5be87 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -29,8 +29,8 @@
 
             // process predicates and convert to `RequiredPredicates` entry, see below
             for &(predicate, span) in predicates.predicates {
-                match predicate.skip_binders() {
-                    ty::PredicateAtom::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => {
+                match predicate.kind().skip_binder() {
+                    ty::PredicateKind::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => {
                         insert_outlives_predicate(
                             tcx,
                             (*ty).into(),
@@ -40,7 +40,7 @@
                         )
                     }
 
-                    ty::PredicateAtom::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => {
+                    ty::PredicateKind::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => {
                         insert_outlives_predicate(
                             tcx,
                             (*reg1).into(),
@@ -50,15 +50,15 @@
                         )
                     }
 
-                    ty::PredicateAtom::Trait(..)
-                    | ty::PredicateAtom::Projection(..)
-                    | ty::PredicateAtom::WellFormed(..)
-                    | ty::PredicateAtom::ObjectSafe(..)
-                    | ty::PredicateAtom::ClosureKind(..)
-                    | ty::PredicateAtom::Subtype(..)
-                    | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..)
-                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (),
+                    ty::PredicateKind::Trait(..)
+                    | ty::PredicateKind::Projection(..)
+                    | ty::PredicateKind::WellFormed(..)
+                    | ty::PredicateKind::ObjectSafe(..)
+                    | ty::PredicateKind::ClosureKind(..)
+                    | ty::PredicateKind::Subtype(..)
+                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
                 }
             }
 
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs
index b1f7933..e94b845 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -30,13 +30,9 @@
                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
                         .iter()
-                        .map(|(out_pred, _)| match out_pred.kind() {
-                            ty::PredicateKind::Atom(ty::PredicateAtom::RegionOutlives(p)) => {
-                                p.to_string()
-                            }
-                            ty::PredicateKind::Atom(ty::PredicateAtom::TypeOutlives(p)) => {
-                                p.to_string()
-                            }
+                        .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
+                            ty::PredicateKind::RegionOutlives(p) => p.to_string(),
+                            ty::PredicateKind::TypeOutlives(p) => p.to_string(),
                             err => bug!("unexpected predicate {:?}", err),
                         })
                         .collect();
@@ -89,12 +85,12 @@
                 |(ty::OutlivesPredicate(kind1, region2), &span)| {
                     match kind1.unpack() {
                         GenericArgKind::Type(ty1) => Some((
-                            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
+                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
                                 .to_predicate(tcx),
                             span,
                         )),
                         GenericArgKind::Lifetime(region1) => Some((
-                            ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
+                            ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
                                 region1, region2,
                             ))
                             .to_predicate(tcx),
diff --git a/config.toml.example b/config.toml.example
index 9e08ce9..55b20ad 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -35,9 +35,11 @@
 # Unless you're developing for a target where Rust CI doesn't build a compiler
 # toolchain or changing LLVM locally, you probably want to set this to true.
 #
-# It's currently false by default due to being newly added; please file bugs if
-# enabling this did not work for you on x86_64-unknown-linux-gnu.
-# Other target triples are currently not supported; see #77084.
+# This is false by default so that distributions don't unexpectedly download
+# LLVM from the internet.
+#
+# All tier 1 targets are currently supported; set this to `"if-supported"` if
+# you are not sure whether you're on a tier 1 target.
 #
 # We also currently only support this when building LLVM for the build triple.
 #
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 4dfdbe0..3c515af 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -161,7 +161,10 @@
 /// It is a logic error for an item to be modified in such a way that the
 /// item's ordering relative to any other item, as determined by the `Ord`
 /// trait, changes while it is in the heap. This is normally only possible
-/// through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The
+/// behavior resulting from such a logic error is not specified, but will
+/// not result in undefined behavior. This could include panics, incorrect
+/// results, aborts, memory leaks, and non-termination.
 ///
 /// # Examples
 ///
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 944e0e6..ecc2873 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -10,7 +10,7 @@
 
 use super::borrow::DormantMutRef;
 use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
-use super::search::{self, SearchResult::*};
+use super::search::SearchResult::*;
 use super::unwrap_unchecked;
 
 mod entry;
@@ -51,6 +51,9 @@
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
 /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will not result in
+/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
+/// non-termination.
 ///
 /// [`Cell`]: core::cell::Cell
 /// [`RefCell`]: core::cell::RefCell
@@ -227,7 +230,7 @@
 
     fn get(&self, key: &Q) -> Option<&K> {
         let root_node = self.root.as_ref()?.reborrow();
-        match search::search_tree(root_node, key) {
+        match root_node.search_tree(key) {
             Found(handle) => Some(handle.into_kv().0),
             GoDown(_) => None,
         }
@@ -236,7 +239,7 @@
     fn take(&mut self, key: &Q) -> Option<K> {
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = map.root.as_mut()?.borrow_mut();
-        match search::search_tree(root_node, key) {
+        match root_node.search_tree(key) {
             Found(handle) => {
                 Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0)
             }
@@ -247,7 +250,7 @@
     fn replace(&mut self, key: K) -> Option<K> {
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
-        match search::search_tree::<marker::Mut<'_>, K, (), K>(root_node, &key) {
+        match root_node.search_tree::<K>(&key) {
             Found(mut kv) => Some(mem::replace(kv.key_mut(), key)),
             GoDown(handle) => {
                 VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(());
@@ -523,7 +526,7 @@
         Q: Ord,
     {
         let root_node = self.root.as_ref()?.reborrow();
-        match search::search_tree(root_node, key) {
+        match root_node.search_tree(key) {
             Found(handle) => Some(handle.into_kv().1),
             GoDown(_) => None,
         }
@@ -551,7 +554,7 @@
         Q: Ord,
     {
         let root_node = self.root.as_ref()?.reborrow();
-        match search::search_tree(root_node, k) {
+        match root_node.search_tree(k) {
             Found(handle) => Some(handle.into_kv()),
             GoDown(_) => None,
         }
@@ -759,7 +762,7 @@
         Q: Ord,
     {
         let root_node = self.root.as_mut()?.borrow_mut();
-        match search::search_tree(root_node, key) {
+        match root_node.search_tree(key) {
             Found(handle) => Some(handle.into_val_mut()),
             GoDown(_) => None,
         }
@@ -855,7 +858,7 @@
     {
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = map.root.as_mut()?.borrow_mut();
-        match search::search_tree(root_node, key) {
+        match root_node.search_tree(key) {
             Found(handle) => {
                 Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry())
             }
@@ -1048,7 +1051,7 @@
         // FIXME(@porglezomp) Avoid allocating if we don't insert
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
-        match search::search_tree(root_node, &key) {
+        match root_node.search_tree(&key) {
             Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }),
             GoDown(handle) => {
                 Vacant(VacantEntry { key, handle, dormant_map, _marker: PhantomData })
diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs
index cce8b21..45a8e01 100644
--- a/library/alloc/src/collections/btree/navigate.rs
+++ b/library/alloc/src/collections/btree/navigate.rs
@@ -5,7 +5,7 @@
 use core::ptr;
 
 use super::node::{marker, ForceResult::*, Handle, NodeRef};
-use super::search::{self, SearchResult};
+use super::search::SearchResult;
 use super::unwrap_unchecked;
 
 /// Finds the leaf edges delimiting a specified range in or underneath a node.
@@ -42,14 +42,14 @@
 
     loop {
         let front = match (min_found, range.start_bound()) {
-            (false, Included(key)) => match search::search_node(min_node, key) {
+            (false, Included(key)) => match min_node.search_node(key) {
                 SearchResult::Found(kv) => {
                     min_found = true;
                     kv.left_edge()
                 }
                 SearchResult::GoDown(edge) => edge,
             },
-            (false, Excluded(key)) => match search::search_node(min_node, key) {
+            (false, Excluded(key)) => match min_node.search_node(key) {
                 SearchResult::Found(kv) => {
                     min_found = true;
                     kv.right_edge()
@@ -62,14 +62,14 @@
         };
 
         let back = match (max_found, range.end_bound()) {
-            (false, Included(key)) => match search::search_node(max_node, key) {
+            (false, Included(key)) => match max_node.search_node(key) {
                 SearchResult::Found(kv) => {
                     max_found = true;
                     kv.right_edge()
                 }
                 SearchResult::GoDown(edge) => edge,
             },
-            (false, Excluded(key)) => match search::search_node(max_node, key) {
+            (false, Excluded(key)) => match max_node.search_node(key) {
                 SearchResult::Found(kv) => {
                     max_found = true;
                     kv.left_edge()
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index e7d66a9..097e3e6 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -142,8 +142,17 @@
 }
 
 impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
+    fn new_internal(child: Root<K, V>) -> Self {
+        let mut new_node = Box::new(unsafe { InternalNode::new() });
+        new_node.edges[0].write(child.node);
+        NodeRef::from_new_internal(new_node, child.height + 1)
+    }
+
     fn from_new_internal(internal: Box<InternalNode<K, V>>, height: usize) -> Self {
-        NodeRef { height, node: NonNull::from(Box::leak(internal)).cast(), _marker: PhantomData }
+        let node = NonNull::from(Box::leak(internal)).cast();
+        let mut this = NodeRef { height, node, _marker: PhantomData };
+        this.borrow_mut().correct_all_childrens_parent_links();
+        this
     }
 }
 
@@ -167,11 +176,7 @@
     /// make that new node the root node, and return it. This increases the height by 1
     /// and is the opposite of `pop_internal_level`.
     pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
-        let mut new_node = Box::new(unsafe { InternalNode::new() });
-        new_node.edges[0].write(self.node);
-        let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1);
-        new_root.borrow_mut().first_edge().correct_parent_link();
-        *self = new_root.forget_type();
+        super::mem::take_mut(self, |old_root| NodeRef::new_internal(old_root).forget_type());
 
         // `self.borrow_mut()`, except that we just forgot we're internal now:
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
@@ -179,7 +184,7 @@
 
     /// Removes the internal root node, using its first child as the new root node.
     /// As it is intended only to be called when the root node has only one child,
-    /// no cleanup is done on any of the other children.
+    /// no cleanup is done on any of the keys, values and other children.
     /// This decreases the height by 1 and is the opposite of `push_internal_level`.
     ///
     /// Requires exclusive access to the `Root` object but not to the root node;
@@ -220,7 +225,7 @@
 ///    - When this is `Owned`, the `NodeRef` acts roughly like `Box<Node>`,
 ///      but does not have a destructor, and must be cleaned up manually.
 ///   Since any `NodeRef` allows navigating through the tree, `BorrowType`
-///   effectively applies to the entire tree, not just the node itself.
+///   effectively applies to the entire tree, not just to the node itself.
 /// - `K` and `V`: These are the types of keys and values stored in the nodes.
 /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is
 ///   `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the
@@ -420,7 +425,7 @@
 
 impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
     /// Similar to `ascend`, gets a reference to a node's parent node, but also
-    /// deallocate the current node in the process. This is unsafe because the
+    /// deallocates the current node in the process. This is unsafe because the
     /// current node will still be accessible despite being deallocated.
     pub unsafe fn deallocate_and_ascend(
         self,
@@ -656,7 +661,10 @@
     /// Removes a key-value pair from the end of the node and returns the pair.
     /// Also removes the edge that was to the right of that pair and, if the node
     /// is internal, returns the orphaned subtree that this edge owned.
-    fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
+    ///
+    /// # Safety
+    /// The node must not be empty.
+    unsafe fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
         debug_assert!(self.len() > 0);
 
         let idx = self.len() - 1;
@@ -1193,9 +1201,7 @@
             );
 
             let height = self.node.height;
-            let mut right = NodeRef::from_new_internal(new_node, height);
-
-            right.borrow_mut().correct_childrens_parent_links(0..new_len + 1);
+            let right = NodeRef::from_new_internal(new_node, height);
 
             SplitResult { left: self.node, kv, right }
         }
@@ -1276,25 +1282,25 @@
         self.right_child
     }
 
-    /// Returns `true` if it is valid to call `.merge()` in the balancing context,
-    /// i.e., whether there is enough room in a node to hold the combination of
-    /// both adjacent child nodes, along with the key-value pair in the parent.
+    /// Returns whether merging is possible, i.e., whether there is enough room
+    /// in a node to combine the central KV with both adjacent child nodes.
     pub fn can_merge(&self) -> bool {
         self.left_child.len() + 1 + self.right_child.len() <= CAPACITY
     }
 }
 
 impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
-    /// Merges the parent's key-value pair and both adjacent child nodes into
-    /// the left node and returns an edge handle in that expanded left node.
-    /// If `track_edge_idx` is given some value, the returned edge corresponds
-    /// to where the edge in that child node ended up,
-    ///
-    /// Panics unless we `.can_merge()`.
-    pub fn merge(
+    /// Performs a merge and lets a closure decide what to return.
+    fn do_merge<
+        F: FnOnce(
+            NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
+            NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
+        ) -> R,
+        R,
+    >(
         self,
-        track_edge_idx: Option<LeftOrRight<usize>>,
-    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
+        result: F,
+    ) -> R {
         let Handle { node: mut parent_node, idx: parent_idx, _marker } = self.parent;
         let old_parent_len = parent_node.len();
         let mut left_node = self.left_child;
@@ -1304,11 +1310,6 @@
         let new_left_len = old_left_len + 1 + right_len;
 
         assert!(new_left_len <= CAPACITY);
-        assert!(match track_edge_idx {
-            None => true,
-            Some(LeftOrRight::Left(idx)) => idx <= old_left_len,
-            Some(LeftOrRight::Right(idx)) => idx <= right_len,
-        });
 
         unsafe {
             *left_node.len_mut() = new_left_len as u16;
@@ -1347,14 +1348,47 @@
             } else {
                 Global.deallocate(right_node.node.cast(), Layout::new::<LeafNode<K, V>>());
             }
-
-            let new_idx = match track_edge_idx {
-                None => 0,
-                Some(LeftOrRight::Left(idx)) => idx,
-                Some(LeftOrRight::Right(idx)) => old_left_len + 1 + idx,
-            };
-            Handle::new_edge(left_node, new_idx)
         }
+        result(parent_node, left_node)
+    }
+
+    /// Merges the parent's key-value pair and both adjacent child nodes into
+    /// the left child node and returns the shrunk parent node.
+    ///
+    /// Panics unless we `.can_merge()`.
+    pub fn merge_tracking_parent(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
+        self.do_merge(|parent, _child| parent)
+    }
+
+    /// Merges the parent's key-value pair and both adjacent child nodes into
+    /// the left child node and returns that child node.
+    ///
+    /// Panics unless we `.can_merge()`.
+    pub fn merge_tracking_child(self) -> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
+        self.do_merge(|_parent, child| child)
+    }
+
+    /// Merges the parent's key-value pair and both adjacent child nodes into
+    /// the left child node and returns the edge handle in that child node
+    /// where the tracked child edge ended up,
+    ///
+    /// Panics unless we `.can_merge()`.
+    pub fn merge_tracking_child_edge(
+        self,
+        track_edge_idx: LeftOrRight<usize>,
+    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::Edge> {
+        let old_left_len = self.left_child.len();
+        let right_len = self.right_child.len();
+        assert!(match track_edge_idx {
+            LeftOrRight::Left(idx) => idx <= old_left_len,
+            LeftOrRight::Right(idx) => idx <= right_len,
+        });
+        let child = self.merge_tracking_child();
+        let new_idx = match track_edge_idx {
+            LeftOrRight::Left(idx) => idx,
+            LeftOrRight::Right(idx) => old_left_len + 1 + idx,
+        };
+        unsafe { Handle::new_edge(child, new_idx) }
     }
 
     /// Removes a key-value pair from the left child and places it in the key-value storage
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index 7fe8ff7..48ce9f2 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -79,10 +79,8 @@
 #[test]
 fn test_partial_cmp_eq() {
     let mut root1 = NodeRef::new_leaf();
-    let mut leaf1 = root1.borrow_mut();
-    leaf1.push(1, ());
-    let mut root1 = root1.forget_type();
-    root1.push_internal_level();
+    root1.borrow_mut().push(1, ());
+    let mut root1 = NodeRef::new_internal(root1.forget_type()).forget_type();
     let root2 = Root::new();
     root1.reborrow().assert_back_pointers();
     root2.reborrow().assert_back_pointers();
diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs
index 7aeb39c..04683e0 100644
--- a/library/alloc/src/collections/btree/remove.rs
+++ b/library/alloc/src/collections/btree/remove.rs
@@ -33,7 +33,7 @@
                 Ok(Left(left_parent_kv)) => {
                     debug_assert!(left_parent_kv.right_child_len() == MIN_LEN - 1);
                     if left_parent_kv.can_merge() {
-                        left_parent_kv.merge(Some(Right(idx)))
+                        left_parent_kv.merge_tracking_child_edge(Right(idx))
                     } else {
                         debug_assert!(left_parent_kv.left_child_len() > MIN_LEN);
                         left_parent_kv.steal_left(idx)
@@ -42,7 +42,7 @@
                 Ok(Right(right_parent_kv)) => {
                     debug_assert!(right_parent_kv.left_child_len() == MIN_LEN - 1);
                     if right_parent_kv.can_merge() {
-                        right_parent_kv.merge(Some(Left(idx)))
+                        right_parent_kv.merge_tracking_child_edge(Left(idx))
                     } else {
                         debug_assert!(right_parent_kv.right_child_len() > MIN_LEN);
                         right_parent_kv.steal_right(idx)
@@ -124,9 +124,8 @@
             Ok(Left(left_parent_kv)) => {
                 debug_assert_eq!(left_parent_kv.right_child_len(), MIN_LEN - 1);
                 if left_parent_kv.can_merge() {
-                    let pos = left_parent_kv.merge(None);
-                    let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) };
-                    Some(parent_edge.into_node())
+                    let parent = left_parent_kv.merge_tracking_parent();
+                    Some(parent)
                 } else {
                     debug_assert!(left_parent_kv.left_child_len() > MIN_LEN);
                     left_parent_kv.steal_left(0);
@@ -136,9 +135,8 @@
             Ok(Right(right_parent_kv)) => {
                 debug_assert_eq!(right_parent_kv.left_child_len(), MIN_LEN - 1);
                 if right_parent_kv.can_merge() {
-                    let pos = right_parent_kv.merge(None);
-                    let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) };
-                    Some(parent_edge.into_node())
+                    let parent = right_parent_kv.merge_tracking_parent();
+                    Some(parent)
                 } else {
                     debug_assert!(right_parent_kv.right_child_len() > MIN_LEN);
                     right_parent_kv.steal_right(0);
diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs
index ed7f95f..f62eae3 100644
--- a/library/alloc/src/collections/btree/search.rs
+++ b/library/alloc/src/collections/btree/search.rs
@@ -10,80 +10,79 @@
     GoDown(Handle<NodeRef<BorrowType, K, V, GoDownType>, marker::Edge>),
 }
 
-/// Looks up a given key in a (sub)tree headed by the given node, recursively.
-/// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
-/// returns a `GoDown` with the handle of the possible leaf edge where the key
-/// belongs.
-///
-/// The result is meaningful only if the tree is ordered by key, like the tree
-/// in a `BTreeMap` is.
-pub fn search_tree<BorrowType, K, V, Q: ?Sized>(
-    mut node: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
-    key: &Q,
-) -> SearchResult<BorrowType, K, V, marker::LeafOrInternal, marker::Leaf>
-where
-    Q: Ord,
-    K: Borrow<Q>,
-{
-    loop {
-        match search_node(node, key) {
-            Found(handle) => return Found(handle),
-            GoDown(handle) => match handle.force() {
-                Leaf(leaf) => return GoDown(leaf),
-                Internal(internal) => {
-                    node = internal.descend();
-                    continue;
-                }
-            },
+pub enum IndexResult {
+    KV(usize),
+    Edge(usize),
+}
+
+impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
+    /// Looks up a given key in a (sub)tree headed by the node, recursively.
+    /// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
+    /// returns a `GoDown` with the handle of the leaf edge where the key belongs.
+    ///
+    /// The result is meaningful only if the tree is ordered by key, like the tree
+    /// in a `BTreeMap` is.
+    pub fn search_tree<Q: ?Sized>(
+        mut self,
+        key: &Q,
+    ) -> SearchResult<BorrowType, K, V, marker::LeafOrInternal, marker::Leaf>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        loop {
+            self = match self.search_node(key) {
+                Found(handle) => return Found(handle),
+                GoDown(handle) => match handle.force() {
+                    Leaf(leaf) => return GoDown(leaf),
+                    Internal(internal) => internal.descend(),
+                },
+            }
         }
     }
 }
 
-/// Looks up a given key in a given node, without recursion.
-/// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
-/// returns a `GoDown` with the handle of the edge where the key might be found
-/// (if the node is internal) or where the key can be inserted.
-///
-/// The result is meaningful only if the tree is ordered by key, like the tree
-/// in a `BTreeMap` is.
-pub fn search_node<BorrowType, K, V, Type, Q: ?Sized>(
-    node: NodeRef<BorrowType, K, V, Type>,
-    key: &Q,
-) -> SearchResult<BorrowType, K, V, Type, Type>
-where
-    Q: Ord,
-    K: Borrow<Q>,
-{
-    match search_linear(&node, key) {
-        (idx, true) => Found(unsafe { Handle::new_kv(node, idx) }),
-        (idx, false) => GoDown(unsafe { Handle::new_edge(node, idx) }),
-    }
-}
-
-/// Returns either the KV index in the node at which the key (or an equivalent)
-/// exists and `true`, or the edge index where the key belongs and `false`.
-///
-/// The result is meaningful only if the tree is ordered by key, like the tree
-/// in a `BTreeMap` is.
-fn search_linear<BorrowType, K, V, Type, Q: ?Sized>(
-    node: &NodeRef<BorrowType, K, V, Type>,
-    key: &Q,
-) -> (usize, bool)
-where
-    Q: Ord,
-    K: Borrow<Q>,
-{
-    // This function is defined over all borrow types (immutable, mutable, owned).
-    // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return
-    // is an index -- not a reference.
-    let len = node.len();
-    for i in 0..len {
-        let k = unsafe { node.reborrow().key_at(i) };
-        match key.cmp(k.borrow()) {
-            Ordering::Greater => {}
-            Ordering::Equal => return (i, true),
-            Ordering::Less => return (i, false),
+impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
+    /// Looks up a given key in the node, without recursion.
+    /// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
+    /// returns a `GoDown` with the handle of the edge where the key might be found
+    /// (if the node is internal) or where the key can be inserted.
+    ///
+    /// The result is meaningful only if the tree is ordered by key, like the tree
+    /// in a `BTreeMap` is.
+    pub fn search_node<Q: ?Sized>(self, key: &Q) -> SearchResult<BorrowType, K, V, Type, Type>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        match self.find_index(key) {
+            IndexResult::KV(idx) => Found(unsafe { Handle::new_kv(self, idx) }),
+            IndexResult::Edge(idx) => GoDown(unsafe { Handle::new_edge(self, idx) }),
         }
     }
-    (len, false)
+
+    /// Returns either the KV index in the node at which the key (or an equivalent)
+    /// exists, or the edge index where the key belongs.
+    ///
+    /// The result is meaningful only if the tree is ordered by key, like the tree
+    /// in a `BTreeMap` is.
+    fn find_index<Q: ?Sized>(&self, key: &Q) -> IndexResult
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        // This function is defined over all borrow types (immutable, mutable, owned).
+        // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return
+        // is an index -- not a reference.
+        let len = self.len();
+        for i in 0..len {
+            let k = unsafe { self.reborrow().key_at(i) };
+            match key.cmp(k.borrow()) {
+                Ordering::Greater => {}
+                Ordering::Equal => return IndexResult::KV(i),
+                Ordering::Less => return IndexResult::Edge(i),
+            }
+        }
+        IndexResult::Edge(len)
+    }
 }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index c72e305..c2a96dd 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -22,6 +22,9 @@
 /// It is a logic error for an item to be modified in such a way that the item's ordering relative
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will not result in
+/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
+/// non-termination.
 ///
 /// [`Ord`]: core::cmp::Ord
 /// [`Cell`]: core::cell::Cell
diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs
index 4561c8e..62c5e3a 100644
--- a/library/alloc/src/collections/btree/split.rs
+++ b/library/alloc/src/collections/btree/split.rs
@@ -1,6 +1,6 @@
 use super::map::MIN_LEN;
 use super::node::{ForceResult::*, Root};
-use super::search::{search_node, SearchResult::*};
+use super::search::SearchResult::*;
 use core::borrow::Borrow;
 
 impl<K, V> Root<K, V> {
@@ -21,7 +21,7 @@
             let mut right_node = right_root.borrow_mut();
 
             loop {
-                let mut split_edge = match search_node(left_node, key) {
+                let mut split_edge = match left_node.search_node(key) {
                     // key is going to the right tree
                     Found(kv) => kv.left_edge(),
                     GoDown(edge) => edge,
@@ -66,7 +66,7 @@
                 let mut last_kv = node.last_kv().consider_for_balancing();
 
                 if last_kv.can_merge() {
-                    cur_node = last_kv.merge(None).into_node();
+                    cur_node = last_kv.merge_tracking_child();
                 } else {
                     let right_len = last_kv.right_child_len();
                     // `MIN_LEN + 1` to avoid readjust if merge happens on the next level.
@@ -93,7 +93,7 @@
                 let mut first_kv = node.first_kv().consider_for_balancing();
 
                 if first_kv.can_merge() {
-                    cur_node = first_kv.merge(None).into_node();
+                    cur_node = first_kv.merge_tracking_child();
                 } else {
                     let left_len = first_kv.left_child_len();
                     // `MIN_LEN + 1` to avoid readjust if merge happens on the next level.
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cfad111..14a10aa 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -120,6 +120,7 @@
 #![feature(receiver_trait)]
 #![cfg_attr(bootstrap, feature(min_const_generics))]
 #![feature(min_specialization)]
+#![feature(set_ptr_value)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
 #![feature(staged_api)]
@@ -139,6 +140,7 @@
 #![feature(type_alias_impl_trait)]
 #![feature(associated_type_bounds)]
 #![feature(slice_group_by)]
+#![feature(decl_macro)]
 // Allow testing this library
 
 #[cfg(test)]
@@ -192,4 +194,11 @@
 #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
 pub mod __export {
     pub use core::format_args;
+
+    /// Force AST node to an expression to improve diagnostics in pattern position.
+    #[rustc_macro_transparency = "semitransparent"]
+    #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
+    pub macro force_expr($e:expr) {
+        $e
+    }
 }
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 7d4eff6..3a46763 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -37,16 +37,16 @@
 #[cfg(not(test))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable(box_syntax)]
+#[allow_internal_unstable(box_syntax, liballoc_internals)]
 macro_rules! vec {
     () => (
-        $crate::vec::Vec::new()
+        $crate::__export::force_expr!($crate::vec::Vec::new())
     );
     ($elem:expr; $n:expr) => (
-        $crate::vec::from_elem($elem, $n)
+        $crate::__export::force_expr!($crate::vec::from_elem($elem, $n))
     );
     ($($x:expr),+ $(,)?) => (
-        <[_]>::into_vec(box [$($x),+])
+        $crate::__export::force_expr!(<[_]>::into_vec(box [$($x),+]))
     );
 }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 0973a6e..ee03f15 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -353,6 +353,26 @@
     /// to upgrade the weak reference before this function returns will result
     /// in a `None` value. However, the weak reference may be cloned freely and
     /// stored for use at a later time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(arc_new_cyclic)]
+    /// #![allow(dead_code)]
+    /// use std::rc::{Rc, Weak};
+    ///
+    /// struct Gadget {
+    ///     self_weak: Weak<Self>,
+    ///     // ... more fields
+    /// }
+    /// impl Gadget {
+    ///     pub fn new() -> Rc<Self> {
+    ///         Rc::new_cyclic(|self_weak| {
+    ///             Gadget { self_weak: self_weak.clone(), /* ... */ }
+    ///         })
+    ///     }
+    /// }
+    /// ```
     #[unstable(feature = "arc_new_cyclic", issue = "75861")]
     pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
         // Construct the inner in the "uninitialized" state with a single
@@ -829,8 +849,8 @@
         let offset = unsafe { data_offset(ptr) };
 
         // Reverse the offset to find the original RcBox.
-        let fake_ptr = ptr as *mut RcBox<T>;
-        let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) };
+        let rc_ptr =
+            unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) };
 
         unsafe { Self::from_ptr(rc_ptr) }
     }
@@ -850,7 +870,7 @@
     pub fn downgrade(this: &Self) -> Weak<T> {
         this.inner().inc_weak();
         // Make sure we do not create a dangling Weak
-        debug_assert!(!is_dangling(this.ptr));
+        debug_assert!(!is_dangling(this.ptr.as_ptr()));
         Weak { ptr: this.ptr }
     }
 
@@ -1164,7 +1184,7 @@
             Self::allocate_for_layout(
                 Layout::for_value(&*ptr),
                 |layout| Global.allocate(layout),
-                |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
+                |mem| (ptr as *mut RcBox<T>).set_ptr_value(mem),
             )
         }
     }
@@ -1203,20 +1223,7 @@
             )
         }
     }
-}
 
-/// Sets the data pointer of a `?Sized` raw pointer.
-///
-/// For a slice/trait object, this sets the `data` field and leaves the rest
-/// unchanged. For a sized raw pointer, this simply sets the pointer.
-unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
-    unsafe {
-        ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
-    }
-    ptr
-}
-
-impl<T> Rc<[T]> {
     /// Copy elements from slice into newly allocated Rc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`
@@ -1860,8 +1867,8 @@
     }
 }
 
-pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
-    let address = ptr.as_ptr() as *mut () as usize;
+pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
+    let address = ptr as *mut () as usize;
     address == usize::MAX
 }
 
@@ -1872,7 +1879,7 @@
     strong: &'a Cell<usize>,
 }
 
-impl<T> Weak<T> {
+impl<T: ?Sized> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1902,15 +1909,15 @@
     pub fn as_ptr(&self) -> *const T {
         let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
 
-        // SAFETY: we must offset the pointer manually, and said pointer may be
-        // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
-        // because we know that a pointer to unsized T was derived from a real
-        // unsized T, as dangling weaks are only created for sized T. wrapping_offset
-        // is used so that we can use the same code path for the non-dangling
-        // unsized case and the potentially dangling sized case.
-        unsafe {
-            let offset = data_offset(ptr as *mut T);
-            set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
+        if is_dangling(ptr) {
+            // If the pointer is dangling, we return the sentinel directly. This cannot be
+            // a valid payload address, as the payload is at least as aligned as RcBox (usize).
+            ptr as *const T
+        } else {
+            // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
+            // The payload may be dropped at this point, and we have to maintain provenance,
+            // so use raw pointer manipulation.
+            unsafe { &raw const (*ptr).value }
         }
     }
 
@@ -1992,22 +1999,24 @@
     /// [`new`]: Weak::new
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
         // See Weak::as_ptr for context on how the input pointer is derived.
-        let offset = unsafe { data_offset(ptr) };
 
-        // Reverse the offset to find the original RcBox.
-        // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized).
-        let ptr = unsafe {
-            set_data_ptr(ptr as *mut RcBox<T>, (ptr as *mut u8).wrapping_offset(-offset))
+        let ptr = if is_dangling(ptr as *mut T) {
+            // This is a dangling Weak.
+            ptr as *mut RcBox<T>
+        } else {
+            // Otherwise, we're guaranteed the pointer came from a nondangling Weak.
+            // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
+            let offset = unsafe { data_offset(ptr) };
+            // Thus, we reverse the offset to get the whole RcBox.
+            // SAFETY: the pointer originated from a Weak, so this offset is safe.
+            unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) }
         };
 
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
         Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
     }
-}
 
-impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
     /// dropping of the inner value if successful.
     ///
@@ -2070,7 +2079,7 @@
     /// (i.e., when this `Weak` was created by `Weak::new`).
     #[inline]
     fn inner(&self) -> Option<WeakInner<'_>> {
-        if is_dangling(self.ptr) {
+        if is_dangling(self.ptr.as_ptr()) {
             None
         } else {
             // We are careful to *not* create a reference covering the "data" field, as
@@ -2325,21 +2334,19 @@
 #[stable(feature = "pin", since = "1.33.0")]
 impl<T: ?Sized> Unpin for Rc<T> {}
 
-/// Get the offset within an `RcBox` for
-/// a payload of type described by a pointer.
+/// Get the offset within an `RcBox` for the payload behind a pointer.
 ///
 /// # Safety
 ///
-/// This has the same safety requirements as `align_of_val_raw`. In effect:
-///
-/// - This function is safe for any argument if `T` is sized, and
-/// - if `T` is unsized, the pointer must have appropriate pointer metadata
-///   acquired from the real instance that you are getting this offset for.
+/// The pointer must point to (and have valid metadata for) a previously
+/// valid instance of T, but the T is allowed to be dropped.
 unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
-    // Align the unsized value to the end of the `RcBox`.
-    // Because it is ?Sized, it will always be the last field in memory.
-    // Note: This is a detail of the current implementation of the compiler,
-    // and is not a guaranteed language detail. Do not rely on it outside of std.
+    // Align the unsized value to the end of the RcBox.
+    // Because RcBox is repr(C), it will always be the last field in memory.
+    // SAFETY: since the only unsized types possible are slices, trait objects,
+    // and extern types, the input safety requirement is currently enough to
+    // satisfy the requirements of align_of_val_raw; this is an implementation
+    // detail of the language that may not be relied upon outside of std.
     unsafe { data_offset_align(align_of_val_raw(ptr)) }
 }
 
diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
index 2d183a8..843a9b0 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloc/src/rc/tests.rs
@@ -209,6 +209,30 @@
 }
 
 #[test]
+fn test_into_from_weak_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let arc: Rc<str> = Rc::from("foo");
+    let weak: Weak<str> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert!(weak.ptr_eq(&weak2));
+
+    let arc: Rc<dyn Display> = Rc::new(123);
+    let weak: Weak<dyn Display> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert!(weak.ptr_eq(&weak2));
+}
+
+#[test]
 fn get_mut() {
     let mut x = Rc::new(3);
     *Rc::get_mut(&mut x).unwrap() = 4;
@@ -295,6 +319,23 @@
 }
 
 #[test]
+fn test_maybe_thin_unsized() {
+    // If/when custom thin DSTs exist, this test should be updated to use one
+    use std::ffi::{CStr, CString};
+
+    let x: Rc<CStr> = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
+    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    let y: Weak<CStr> = Rc::downgrade(&x);
+    drop(x);
+
+    // At this point, the weak points to a dropped DST
+    assert!(y.upgrade().is_none());
+    // But we still need to be able to get the alloc layout to drop.
+    // CStr has no drop glue, but custom DSTs might, and need to work.
+    drop(y);
+}
+
+#[test]
 fn test_from_owned() {
     let foo = 123;
     let foo_rc = Rc::from(foo);
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 05bfecc..c0d684f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -846,8 +846,7 @@
             let offset = data_offset(ptr);
 
             // Reverse the offset to find the original ArcInner.
-            let fake_ptr = ptr as *mut ArcInner<T>;
-            let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+            let arc_ptr = (ptr as *mut ArcInner<T>).set_ptr_value((ptr as *mut u8).offset(-offset));
 
             Self::from_ptr(arc_ptr)
         }
@@ -888,7 +887,7 @@
             match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
                 Ok(_) => {
                     // Make sure we do not create a dangling Weak
-                    debug_assert!(!is_dangling(this.ptr));
+                    debug_assert!(!is_dangling(this.ptr.as_ptr()));
                     return Weak { ptr: this.ptr };
                 }
                 Err(old) => cur = old,
@@ -1131,7 +1130,7 @@
             Self::allocate_for_layout(
                 Layout::for_value(&*ptr),
                 |layout| Global.allocate(layout),
-                |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>,
+                |mem| (ptr as *mut ArcInner<T>).set_ptr_value(mem) as *mut ArcInner<T>,
             )
         }
     }
@@ -1170,20 +1169,7 @@
             )
         }
     }
-}
 
-/// Sets the data pointer of a `?Sized` raw pointer.
-///
-/// For a slice/trait object, this sets the `data` field and leaves the rest
-/// unchanged. For a sized raw pointer, this simply sets the pointer.
-unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
-    unsafe {
-        ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
-    }
-    ptr
-}
-
-impl<T> Arc<[T]> {
     /// Copy elements from slice into newly allocated Arc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`.
@@ -1653,7 +1639,7 @@
     strong: &'a atomic::AtomicUsize,
 }
 
-impl<T> Weak<T> {
+impl<T: ?Sized> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1683,15 +1669,15 @@
     pub fn as_ptr(&self) -> *const T {
         let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
 
-        // SAFETY: we must offset the pointer manually, and said pointer may be
-        // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
-        // because we know that a pointer to unsized T was derived from a real
-        // unsized T, as dangling weaks are only created for sized T. wrapping_offset
-        // is used so that we can use the same code path for the non-dangling
-        // unsized case and the potentially dangling sized case.
-        unsafe {
-            let offset = data_offset(ptr as *mut T);
-            set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
+        if is_dangling(ptr) {
+            // If the pointer is dangling, we return the sentinel directly. This cannot be
+            // a valid payload address, as the payload is at least as aligned as ArcInner (usize).
+            ptr as *const T
+        } else {
+            // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
+            // The payload may be dropped at this point, and we have to maintain provenance,
+            // so use raw pointer manipulation.
+            unsafe { &raw mut (*ptr).data }
         }
     }
 
@@ -1773,18 +1759,22 @@
     /// [`forget`]: std::mem::forget
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
         // See Weak::as_ptr for context on how the input pointer is derived.
-        let offset = unsafe { data_offset(ptr) };
 
-        // Reverse the offset to find the original ArcInner.
-        // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized)
-        let ptr = unsafe {
-            set_data_ptr(ptr as *mut ArcInner<T>, (ptr as *mut u8).wrapping_offset(-offset))
+        let ptr = if is_dangling(ptr as *mut T) {
+            // This is a dangling Weak.
+            ptr as *mut ArcInner<T>
+        } else {
+            // Otherwise, we're guaranteed the pointer came from a nondangling Weak.
+            // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
+            let offset = unsafe { data_offset(ptr) };
+            // Thus, we reverse the offset to get the whole RcBox.
+            // SAFETY: the pointer originated from a Weak, so this offset is safe.
+            unsafe { (ptr as *mut ArcInner<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) }
         };
 
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
-        unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
+        Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
     }
 }
 
@@ -1889,7 +1879,7 @@
     /// (i.e., when this `Weak` was created by `Weak::new`).
     #[inline]
     fn inner(&self) -> Option<WeakInner<'_>> {
-        if is_dangling(self.ptr) {
+        if is_dangling(self.ptr.as_ptr()) {
             None
         } else {
             // We are careful to *not* create a reference covering the "data" field, as
@@ -2469,21 +2459,19 @@
 #[stable(feature = "pin", since = "1.33.0")]
 impl<T: ?Sized> Unpin for Arc<T> {}
 
-/// Get the offset within an `ArcInner` for
-/// a payload of type described by a pointer.
+/// Get the offset within an `ArcInner` for the payload behind a pointer.
 ///
 /// # Safety
 ///
-/// This has the same safety requirements as `align_of_val_raw`. In effect:
-///
-/// - This function is safe for any argument if `T` is sized, and
-/// - if `T` is unsized, the pointer must have appropriate pointer metadata
-///   acquired from the real instance that you are getting this offset for.
+/// The pointer must point to (and have valid metadata for) a previously
+/// valid instance of T, but the T is allowed to be dropped.
 unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
-    // Align the unsized value to the end of the `ArcInner`.
-    // Because it is `?Sized`, it will always be the last field in memory.
-    // Note: This is a detail of the current implementation of the compiler,
-    // and is not a guaranteed language detail. Do not rely on it outside of std.
+    // Align the unsized value to the end of the ArcInner.
+    // Because RcBox is repr(C), it will always be the last field in memory.
+    // SAFETY: since the only unsized types possible are slices, trait objects,
+    // and extern types, the input safety requirement is currently enough to
+    // satisfy the requirements of align_of_val_raw; this is an implementation
+    // detail of the language that may not be relied upon outside of std.
     unsafe { data_offset_align(align_of_val_raw(ptr)) }
 }
 
diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs
index 5067af1..4ccb32f 100644
--- a/library/alloc/src/sync/tests.rs
+++ b/library/alloc/src/sync/tests.rs
@@ -159,6 +159,30 @@
 }
 
 #[test]
+fn test_into_from_weak_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let arc: Arc<str> = Arc::from("foo");
+    let weak: Weak<str> = Arc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert!(weak.ptr_eq(&weak2));
+
+    let arc: Arc<dyn Display> = Arc::new(123);
+    let weak: Weak<dyn Display> = Arc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert!(weak.ptr_eq(&weak2));
+}
+
+#[test]
 fn test_cowarc_clone_make_mut() {
     let mut cow0 = Arc::new(75);
     let mut cow1 = cow0.clone();
@@ -330,6 +354,23 @@
 }
 
 #[test]
+fn test_maybe_thin_unsized() {
+    // If/when custom thin DSTs exist, this test should be updated to use one
+    use std::ffi::{CStr, CString};
+
+    let x: Arc<CStr> = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
+    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    let y: Weak<CStr> = Arc::downgrade(&x);
+    drop(x);
+
+    // At this point, the weak points to a dropped DST
+    assert!(y.upgrade().is_none());
+    // But we still need to be able to get the alloc layout to drop.
+    // CStr has no drop glue, but custom DSTs might, and need to work.
+    drop(y);
+}
+
+#[test]
 fn test_from_owned() {
     let foo = 123;
     let foo_arc = Arc::from(foo);
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index fcab3fd..6969049 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -33,7 +33,8 @@
     }
 }
 
-#[allow(rustc::ineffective_unstable_trait_impl)]
+#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
+#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
 #[unstable(feature = "wake_trait", issue = "69912")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
     fn from(waker: Arc<W>) -> Waker {
@@ -43,7 +44,8 @@
     }
 }
 
-#[allow(rustc::ineffective_unstable_trait_impl)]
+#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
+#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
 #[unstable(feature = "wake_trait", issue = "69912")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
     fn from(waker: Arc<W>) -> RawWaker {
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index c5ab7a3..fa0fbaa 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1261,6 +1261,40 @@
         Ref { value: f(orig.value), borrow: orig.borrow }
     }
 
+    /// Makes a new `Ref` for an optional component of the borrowed data. The
+    /// original guard is returned as an `Err(..)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RefCell` is already immutably borrowed, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `Ref::filter_map(...)`. A method would interfere with methods of the same
+    /// name on the contents of a `RefCell` used through `Deref`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cell_filter_map)]
+    ///
+    /// use std::cell::{RefCell, Ref};
+    ///
+    /// let c = RefCell::new(vec![1, 2, 3]);
+    /// let b1: Ref<Vec<u32>> = c.borrow();
+    /// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
+    /// assert_eq!(*b2.unwrap(), 2);
+    /// ```
+    #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
+    #[inline]
+    pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
+    where
+        F: FnOnce(&T) -> Option<&U>,
+    {
+        match f(orig.value) {
+            Some(value) => Ok(Ref { value, borrow: orig.borrow }),
+            None => Err(orig),
+        }
+    }
+
     /// Splits a `Ref` into multiple `Ref`s for different components of the
     /// borrowed data.
     ///
@@ -1372,6 +1406,58 @@
         RefMut { value: f(value), borrow }
     }
 
+    /// Makes a new `RefMut` for an optional component of the borrowed data. The
+    /// original guard is returned as an `Err(..)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RefCell` is already mutably borrowed, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RefMut::filter_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of a `RefCell` used through `Deref`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cell_filter_map)]
+    ///
+    /// use std::cell::{RefCell, RefMut};
+    ///
+    /// let c = RefCell::new(vec![1, 2, 3]);
+    ///
+    /// {
+    ///     let b1: RefMut<Vec<u32>> = c.borrow_mut();
+    ///     let mut b2: Result<RefMut<u32>, _> = RefMut::filter_map(b1, |v| v.get_mut(1));
+    ///
+    ///     if let Ok(mut b2) = b2 {
+    ///         *b2 += 2;
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(*c.borrow(), vec![1, 4, 3]);
+    /// ```
+    #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
+    #[inline]
+    pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+    {
+        // FIXME(nll-rfc#40): fix borrow-check
+        let RefMut { value, borrow } = orig;
+        let value = value as *mut T;
+        // SAFETY: function holds onto an exclusive reference for the duration
+        // of its call through `orig`, and the pointer is only de-referenced
+        // inside of the function call never allowing the exclusive reference to
+        // escape.
+        match f(unsafe { &mut *value }) {
+            Some(value) => Ok(RefMut { value, borrow }),
+            None => {
+                // SAFETY: same as above.
+                Err(RefMut { value: unsafe { &mut *value }, borrow })
+            }
+        }
+    }
+
     /// Splits a `RefMut` into multiple `RefMut`s for different components of the
     /// borrowed data.
     ///
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 38c6bfb..b983f49 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -541,7 +541,7 @@
     /// assert_eq!(result, Ordering::Equal);
     ///
     /// let x: (i64, i64, i64) = (1, 2, 7);
-    /// let y: (i64, i64, i64)  = (1, 5, 3);
+    /// let y: (i64, i64, i64) = (1, 5, 3);
     /// let result = x.0.cmp(&y.0).then_with(|| x.1.cmp(&y.1)).then_with(|| x.2.cmp(&y.2));
     ///
     /// assert_eq!(result, Ordering::Less);
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 0130586..7c1a9b8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -768,13 +768,6 @@
     #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
     pub fn size_of<T>() -> usize;
 
-    /// Moves a value to an uninitialized memory location.
-    ///
-    /// Drop glue is not run on the destination.
-    ///
-    /// The stabilized version of this intrinsic is [`core::ptr::write`](crate::ptr::write).
-    pub fn move_val_init<T>(dst: *mut T, src: T);
-
     /// The minimum alignment of a type.
     ///
     /// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of).
@@ -1849,6 +1842,7 @@
 #[inline]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
@@ -1933,6 +1927,7 @@
 #[inline]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 5766fd3..98b8dca 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -286,6 +286,7 @@
 
     #[inline]
     unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
+        let idx = self.index + idx;
         // SAFETY: the caller must uphold the contract for
         // `Iterator::__iterator_get_unchecked`.
         unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index ba8918b..111feb7 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -286,3 +286,43 @@
     NonZeroU128(u128);
     NonZeroUsize(usize);
 }
+
+macro_rules! nonzero_unsigned_is_power_of_two {
+    ( $( $Ty: ident )+ ) => {
+        $(
+            impl $Ty {
+
+                /// Returns `true` if and only if `self == (1 << k)` for some `k`.
+                ///
+                /// On many architectures, this function can perform better than `is_power_of_two()`
+                /// on the underlying integer type, as special handling of zero can be avoided.
+                ///
+                /// # Examples
+                ///
+                /// Basic usage:
+                ///
+                /// ```
+                /// #![feature(nonzero_is_power_of_two)]
+                ///
+                #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
+                /// assert!(eight.is_power_of_two());
+                #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
+                /// assert!(!ten.is_power_of_two());
+                /// ```
+                #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
+                #[inline]
+                pub const fn is_power_of_two(self) -> bool {
+                    // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
+                    // On the basic x86-64 target, this saves 3 instructions for the zero check.
+                    // On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction
+                    // compared to the `POPCNT` implementation on the underlying integer type.
+
+                    intrinsics::ctpop(self.get()) < 2
+                }
+
+            }
+        )+
+    }
+}
+
+nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 807f114..d2e1bac 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -883,12 +883,19 @@
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
-    if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
-        // Not panicking to keep codegen impact smaller.
-        abort();
+    // We are calling the intrinsics directly to avoid function calls in the generated code
+    // as `intrinsics::copy_nonoverlapping` is a wrapper function.
+    extern "rust-intrinsic" {
+        fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
-    // SAFETY: the caller must uphold the safety contract for `move_val_init`.
-    unsafe { intrinsics::move_val_init(&mut *dst, src) }
+
+    // SAFETY: the caller must guarantee that `dst` is valid for writes.
+    // `dst` cannot overlap `src` because the caller has mutable access
+    // to `dst` while `src` is owned by this function.
+    unsafe {
+        copy_nonoverlapping(&src as *const T, dst, 1);
+        intrinsics::forget(src);
+    }
 }
 
 /// Overwrites a memory location with the given value without reading or
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 6de2714..de8d7fc 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -889,6 +889,46 @@
     }
 
     /// Splits the slice into a slice of `N`-element arrays,
+    /// assuming that there's no remainder.
+    ///
+    /// # Safety
+    ///
+    /// This may only be called when
+    /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
+    /// - `N != 0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
+    /// let chunks: &[[char; 1]] =
+    ///     // SAFETY: 1-element chunks never have remainder
+    ///     unsafe { slice.as_chunks_unchecked() };
+    /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+    /// let chunks: &[[char; 3]] =
+    ///     // SAFETY: The slice length (6) is a multiple of 3
+    ///     unsafe { slice.as_chunks_unchecked() };
+    /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
+    ///
+    /// // These would be unsound:
+    /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
+    /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
+    /// ```
+    #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[inline]
+    pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
+        debug_assert_ne!(N, 0);
+        debug_assert_eq!(self.len() % N, 0);
+        let new_len =
+            // SAFETY: Our precondition is exactly what's needed to call this
+            unsafe { crate::intrinsics::exact_div(self.len(), N) };
+        // SAFETY: We cast a slice of `new_len * N` elements into
+        // a slice of `new_len` many `N` elements chunks.
+        unsafe { from_raw_parts(self.as_ptr().cast(), new_len) }
+    }
+
+    /// Splits the slice into a slice of `N`-element arrays,
     /// starting at the beginning of the slice,
     /// and a remainder slice with length strictly less than `N`.
     ///
@@ -912,12 +952,42 @@
         assert_ne!(N, 0);
         let len = self.len() / N;
         let (multiple_of_n, remainder) = self.split_at(len * N);
-        // SAFETY: We cast a slice of `len * N` elements into
-        // a slice of `len` many `N` elements chunks.
-        let array_slice: &[[T; N]] = unsafe { from_raw_parts(multiple_of_n.as_ptr().cast(), len) };
+        // SAFETY: We already panicked for zero, and ensured by construction
+        // that the length of the subslice is a multiple of N.
+        let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() };
         (array_slice, remainder)
     }
 
+    /// Splits the slice into a slice of `N`-element arrays,
+    /// starting at the end of the slice,
+    /// and a remainder slice with length strictly less than `N`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N` is 0. This check will most probably get changed to a compile time
+    /// error before this method gets stabilized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let slice = ['l', 'o', 'r', 'e', 'm'];
+    /// let (remainder, chunks) = slice.as_rchunks();
+    /// assert_eq!(remainder, &['l']);
+    /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
+    /// ```
+    #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[inline]
+    pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) {
+        assert_ne!(N, 0);
+        let len = self.len() / N;
+        let (remainder, multiple_of_n) = self.split_at(self.len() - len * N);
+        // SAFETY: We already panicked for zero, and ensured by construction
+        // that the length of the subslice is a multiple of N.
+        let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() };
+        (remainder, array_slice)
+    }
+
     /// Returns an iterator over `N` elements of the slice at a time, starting at the
     /// beginning of the slice.
     ///
@@ -953,6 +1023,48 @@
     }
 
     /// Splits the slice into a slice of `N`-element arrays,
+    /// assuming that there's no remainder.
+    ///
+    /// # Safety
+    ///
+    /// This may only be called when
+    /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
+    /// - `N != 0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
+    /// let chunks: &mut [[char; 1]] =
+    ///     // SAFETY: 1-element chunks never have remainder
+    ///     unsafe { slice.as_chunks_unchecked_mut() };
+    /// chunks[0] = ['L'];
+    /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+    /// let chunks: &mut [[char; 3]] =
+    ///     // SAFETY: The slice length (6) is a multiple of 3
+    ///     unsafe { slice.as_chunks_unchecked_mut() };
+    /// chunks[1] = ['a', 'x', '?'];
+    /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']);
+    ///
+    /// // These would be unsound:
+    /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5
+    /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
+    /// ```
+    #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[inline]
+    pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
+        debug_assert_ne!(N, 0);
+        debug_assert_eq!(self.len() % N, 0);
+        let new_len =
+            // SAFETY: Our precondition is exactly what's needed to call this
+            unsafe { crate::intrinsics::exact_div(self.len(), N) };
+        // SAFETY: We cast a slice of `new_len * N` elements into
+        // a slice of `new_len` many `N` elements chunks.
+        unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) }
+    }
+
+    /// Splits the slice into a slice of `N`-element arrays,
     /// starting at the beginning of the slice,
     /// and a remainder slice with length strictly less than `N`.
     ///
@@ -982,13 +1094,48 @@
         assert_ne!(N, 0);
         let len = self.len() / N;
         let (multiple_of_n, remainder) = self.split_at_mut(len * N);
-        let array_slice: &mut [[T; N]] =
-            // SAFETY: We cast a slice of `len * N` elements into
-            // a slice of `len` many `N` elements chunks.
-            unsafe { from_raw_parts_mut(multiple_of_n.as_mut_ptr().cast(), len) };
+        // SAFETY: We already panicked for zero, and ensured by construction
+        // that the length of the subslice is a multiple of N.
+        let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() };
         (array_slice, remainder)
     }
 
+    /// Splits the slice into a slice of `N`-element arrays,
+    /// starting at the end of the slice,
+    /// and a remainder slice with length strictly less than `N`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N` is 0. This check will most probably get changed to a compile time
+    /// error before this method gets stabilized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let v = &mut [0, 0, 0, 0, 0];
+    /// let mut count = 1;
+    ///
+    /// let (remainder, chunks) = v.as_rchunks_mut();
+    /// remainder[0] = 9;
+    /// for chunk in chunks {
+    ///     *chunk = [count; 2];
+    ///     count += 1;
+    /// }
+    /// assert_eq!(v, &[9, 1, 1, 2, 2]);
+    /// ```
+    #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[inline]
+    pub fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) {
+        assert_ne!(N, 0);
+        let len = self.len() / N;
+        let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N);
+        // SAFETY: We already panicked for zero, and ensured by construction
+        // that the length of the subslice is a multiple of N.
+        let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() };
+        (remainder, array_slice)
+    }
+
     /// Returns an iterator over `N` elements of the slice at a time, starting at the
     /// beginning of the slice.
     ///
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 6851f3f..42c9d9f 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -84,7 +84,7 @@
 
 impl<T, E> Poll<Option<Result<T, E>>> {
     /// Changes the success value of this `Poll` with the closure provided.
-    #[unstable(feature = "poll_map", issue = "63514")]
+    #[stable(feature = "poll_map", since = "1.51.0")]
     pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
     where
         F: FnOnce(T) -> U,
@@ -98,7 +98,7 @@
     }
 
     /// Changes the error value of this `Poll` with the closure provided.
-    #[unstable(feature = "poll_map", issue = "63514")]
+    #[stable(feature = "poll_map", since = "1.51.0")]
     pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
     where
         F: FnOnce(E) -> U,
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 691767e..bc5421b 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -2,6 +2,7 @@
 
 use core::cell::Cell;
 use core::convert::TryFrom;
+use core::iter::TrustedRandomAccess;
 use core::iter::*;
 
 /// An iterator wrapper that panics whenever `next` or `next_back` is called
@@ -602,6 +603,26 @@
 }
 
 #[test]
+fn test_zip_trusted_random_access_composition() {
+    let a = [0, 1, 2, 3, 4];
+    let b = a;
+    let c = a;
+
+    let a = a.iter().copied();
+    let b = b.iter().copied();
+    let mut c = c.iter().copied();
+    c.next();
+
+    let mut z1 = a.zip(b);
+    assert_eq!(z1.next().unwrap(), (0, 0));
+
+    let mut z2 = z1.zip(c);
+    fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
+    assert_trusted_random_access(&z2);
+    assert_eq!(z2.next().unwrap(), ((1, 1), 1));
+}
+
+#[test]
 fn test_iterator_step_by() {
     // Identity
     let mut it = (0..).step_by(1).take(3);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index bc737cd..98f5982 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -75,6 +75,7 @@
 #![feature(const_option)]
 #![feature(integer_atomics)]
 #![feature(slice_group_by)]
+#![feature(trusted_random_access)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate test;
diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs
index 1c172f4..32f05d1 100644
--- a/library/core/tests/num/dec2flt/mod.rs
+++ b/library/core/tests/num/dec2flt/mod.rs
@@ -21,7 +21,6 @@
     }};
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn ordinary() {
     test_literal!(1.0);
@@ -38,7 +37,6 @@
     test_literal!(2.2250738585072014e-308);
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn special_code_paths() {
     test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand
diff --git a/library/core/tests/num/dec2flt/rawfp.rs b/library/core/tests/num/dec2flt/rawfp.rs
index c098b9c..34a3720 100644
--- a/library/core/tests/num/dec2flt/rawfp.rs
+++ b/library/core/tests/num/dec2flt/rawfp.rs
@@ -81,7 +81,6 @@
     assert_eq!(rounded.k, adjusted_k + 1);
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn prev_float_monotonic() {
     let mut x = 1.0;
@@ -117,7 +116,6 @@
     assert_eq!(next_float(f64::INFINITY), f64::INFINITY);
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn next_prev_identity() {
     for &x in &SOME_FLOATS {
@@ -128,7 +126,6 @@
     }
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn next_float_monotonic() {
     let mut x = 0.49999999999999;
diff --git a/library/core/tests/num/flt2dec/strategy/dragon.rs b/library/core/tests/num/flt2dec/strategy/dragon.rs
index 3d985c6..fc2e724 100644
--- a/library/core/tests/num/flt2dec/strategy/dragon.rs
+++ b/library/core/tests/num/flt2dec/strategy/dragon.rs
@@ -13,7 +13,6 @@
     }
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn shortest_sanity_test() {
     f64_shortest_sanity_test(format_shortest);
diff --git a/library/core/tests/num/flt2dec/strategy/grisu.rs b/library/core/tests/num/flt2dec/strategy/grisu.rs
index 7e6c8ad..b59a3b9 100644
--- a/library/core/tests/num/flt2dec/strategy/grisu.rs
+++ b/library/core/tests/num/flt2dec/strategy/grisu.rs
@@ -33,7 +33,6 @@
     }
 }
 
-#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
 #[test]
 fn shortest_sanity_test() {
     f64_shortest_sanity_test(format_shortest);
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 0680b1f..829fc38 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -52,6 +52,9 @@
 /// hash, as determined by the [`Hash`] trait, or its equality, as determined by
 /// the [`Eq`] trait, changes while it is in the map. This is normally only
 /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will
+/// not result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
 ///
 /// The hash table implementation is a Rust port of Google's [SwissTable].
 /// The original C++ version of SwissTable can be found [here], and this
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index f49e580..baa3026 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -37,7 +37,9 @@
 /// item's hash, as determined by the [`Hash`] trait, or its equality, as
 /// determined by the [`Eq`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
-/// unsafe code.
+/// unsafe code. The behavior resulting from such a logic error is not
+/// specified, but will not result in undefined behavior. This could include
+/// panics, incorrect results, aborts, memory leaks, and non-termination.
 ///
 /// # Examples
 ///
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 16c18d6..8bae3da 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -271,6 +271,20 @@
         Ok(nread)
     }
 
+    // Small read_exacts from a BufReader are extremely common when used with a deserializer.
+    // The default implementation calls read in a loop, which results in surprisingly poor code
+    // generation for the common path where the buffer has enough bytes to fill the passed-in
+    // buffer.
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        if self.buffer().len() >= buf.len() {
+            buf.copy_from_slice(&self.buffer()[..buf.len()]);
+            self.consume(buf.len());
+            return Ok(());
+        }
+
+        crate::io::default_read_exact(self, buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
         if self.pos == self.cap && total_len >= self.buf.len() {
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index 66a64f6..f6c2b49 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -444,6 +444,18 @@
 }
 
 #[bench]
+fn bench_buffered_reader_small_reads(b: &mut test::Bencher) {
+    let data = (0..u8::MAX).cycle().take(1024 * 4).collect::<Vec<_>>();
+    b.iter(|| {
+        let mut reader = BufReader::new(&data[..]);
+        let mut buf = [0u8; 4];
+        for _ in 0..1024 {
+            reader.read_exact(&mut buf).unwrap();
+        }
+    });
+}
+
+#[bench]
 fn bench_buffered_writer(b: &mut test::Bencher) {
     b.iter(|| BufWriter::new(io::sink()));
 }
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 3f5b7c0..c87a565 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -416,6 +416,25 @@
     write(buf)
 }
 
+pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Result<()> {
+    while !buf.is_empty() {
+        match this.read(buf) {
+            Ok(0) => break,
+            Ok(n) => {
+                let tmp = buf;
+                buf = &mut tmp[n..];
+            }
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            Err(e) => return Err(e),
+        }
+    }
+    if !buf.is_empty() {
+        Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
+    } else {
+        Ok(())
+    }
+}
+
 /// The `Read` trait allows for reading bytes from a source.
 ///
 /// Implementors of the `Read` trait are called 'readers'.
@@ -766,23 +785,8 @@
     /// }
     /// ```
     #[stable(feature = "read_exact", since = "1.6.0")]
-    fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
-        while !buf.is_empty() {
-            match self.read(buf) {
-                Ok(0) => break,
-                Ok(n) => {
-                    let tmp = buf;
-                    buf = &mut tmp[n..];
-                }
-                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        if !buf.is_empty() {
-            Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
-        } else {
-            Ok(())
-        }
+    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
+        default_read_exact(self, buf)
     }
 
     /// Creates a "by reference" adaptor for this instance of `Read`.
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 945b436..ddcb404 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -314,10 +314,20 @@
             ) -> libc::c_int
         }
         let addchdir = match self.get_cwd() {
-            Some(cwd) => match posix_spawn_file_actions_addchdir_np.get() {
-                Some(f) => Some((f, cwd)),
-                None => return Ok(None),
-            },
+            Some(cwd) => {
+                if cfg!(target_os = "macos") {
+                    // There is a bug in macOS where a relative executable
+                    // path like "../myprogram" will cause `posix_spawn` to
+                    // successfully launch the program, but erroneously return
+                    // ENOENT when used with posix_spawn_file_actions_addchdir_np
+                    // which was introduced in macOS 10.15.
+                    return Ok(None);
+                }
+                match posix_spawn_file_actions_addchdir_np.get() {
+                    Some(f) => Some((f, cwd)),
+                    None => return Ok(None),
+                }
+            }
             None => None,
         };
 
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6d2d7bb..5350c9e 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -465,8 +465,21 @@
 
     def downloading_llvm(self):
         opt = self.get_toml('download-ci-llvm', 'llvm')
+        # This is currently all tier 1 targets (since others may not have CI
+        # artifacts)
+        # https://doc.rust-lang.org/rustc/platform-support.html#tier-1
+        supported_platforms = [
+            "aarch64-unknown-linux-gnu",
+            "i686-pc-windows-gnu",
+            "i686-pc-windows-msvc",
+            "i686-unknown-linux-gnu",
+            "x86_64-unknown-linux-gnu",
+            "x86_64-apple-darwin",
+            "x86_64-pc-windows-gnu",
+            "x86_64-pc-windows-msvc",
+        ]
         return opt == "true" \
-            or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu")
+            or (opt == "if-available" and self.build in supported_platforms)
 
     def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None):
         if date is None:
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index ec9ce4c..62065e2 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -814,12 +814,22 @@
             cargo.env("REAL_LIBRARY_PATH", e);
         }
 
+        // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
+        // from out of tree it shouldn't matter, since x.py is only used for
+        // building in-tree.
+        let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
         match self.build.config.color {
             Color::Always => {
                 cargo.arg("--color=always");
+                for log in &color_logs {
+                    cargo.env(log, "always");
+                }
             }
             Color::Never => {
                 cargo.arg("--color=never");
+                for log in &color_logs {
+                    cargo.env(log, "never");
+                }
             }
             Color::Auto => {} // nothing to do
         }
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 72a9793..c19bb53 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -73,7 +73,7 @@
 
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
-        let compiler = builder.compiler(0, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.build);
 
         let mut cargo = builder.cargo(
             compiler,
@@ -84,7 +84,10 @@
         );
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
-        builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
+        builder.info(&format!(
+            "Checking stage{} std artifacts ({} -> {})",
+            builder.top_stage, &compiler.host, target
+        ));
         run_cargo(
             builder,
             cargo,
@@ -94,9 +97,13 @@
             true,
         );
 
-        let libdir = builder.sysroot_libdir(compiler, target);
-        let hostdir = builder.sysroot_libdir(compiler, compiler.host);
-        add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
+        // We skip populating the sysroot in non-zero stage because that'll lead
+        // to rlib/rmeta conflicts if std gets built during this session.
+        if compiler.stage == 0 {
+            let libdir = builder.sysroot_libdir(compiler, target);
+            let hostdir = builder.sysroot_libdir(compiler, compiler.host);
+            add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
+        }
 
         // Then run cargo again, once we've put the rmeta files for the library
         // crates into the sysroot. This is needed because e.g., core's tests
@@ -124,8 +131,8 @@
             }
 
             builder.info(&format!(
-                "Checking std test/bench/example targets ({} -> {})",
-                &compiler.host, target
+                "Checking stage{} std test/bench/example targets ({} -> {})",
+                builder.top_stage, &compiler.host, target
             ));
             run_cargo(
                 builder,
@@ -163,10 +170,20 @@
     /// the `compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
     fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(0, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.build);
         let target = self.target;
 
-        builder.ensure(Std { target });
+        if compiler.stage != 0 {
+            // If we're not in stage 0, then we won't have a std from the beta
+            // compiler around. That means we need to make sure there's one in
+            // the sysroot for the compiler to find. Otherwise, we're going to
+            // fail when building crates that need to generate code (e.g., build
+            // scripts and their dependencies).
+            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
+            builder.ensure(crate::compile::Std { target, compiler });
+        } else {
+            builder.ensure(Std { target });
+        }
 
         let mut cargo = builder.cargo(
             compiler,
@@ -187,7 +204,10 @@
             cargo.arg("-p").arg(krate.name);
         }
 
-        builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
+        builder.info(&format!(
+            "Checking stage{} compiler artifacts ({} -> {})",
+            builder.top_stage, &compiler.host, target
+        ));
         run_cargo(
             builder,
             cargo,
@@ -225,7 +245,7 @@
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(0, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.build);
         let target = self.target;
         let backend = self.backend;
 
@@ -244,8 +264,8 @@
         rustc_cargo_env(builder, &mut cargo, target);
 
         builder.info(&format!(
-            "Checking {} artifacts ({} -> {})",
-            backend, &compiler.host.triple, target.triple
+            "Checking stage{} {} artifacts ({} -> {})",
+            builder.top_stage, backend, &compiler.host.triple, target.triple
         ));
 
         run_cargo(
@@ -280,7 +300,7 @@
             }
 
             fn run(self, builder: &Builder<'_>) {
-                let compiler = builder.compiler(0, builder.config.build);
+                let compiler = builder.compiler(builder.top_stage, builder.config.build);
                 let target = self.target;
 
                 builder.ensure(Rustc { target });
@@ -301,7 +321,8 @@
                 }
 
                 builder.info(&format!(
-                    "Checking {} artifacts ({} -> {})",
+                    "Checking stage{} {} artifacts ({} -> {})",
+                    builder.top_stage,
                     stringify!($name).to_lowercase(),
                     &compiler.host.triple,
                     target.triple
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index f4d89a8..ec1308a 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -377,6 +377,7 @@
     configure_args: Option<Vec<String>>,
     local_rebuild: Option<bool>,
     print_step_timings: Option<bool>,
+    check_stage: Option<u32>,
     doc_stage: Option<u32>,
     build_stage: Option<u32>,
     test_stage: Option<u32>,
@@ -676,6 +677,7 @@
 
         // See https://github.com/rust-lang/compiler-team/issues/326
         config.stage = match config.cmd {
+            Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0),
             Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0),
             Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1),
             Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1),
@@ -685,7 +687,6 @@
             // These are all bootstrap tools, which don't depend on the compiler.
             // The stage we pass shouldn't matter, but use 0 just in case.
             Subcommand::Clean { .. }
-            | Subcommand::Check { .. }
             | Subcommand::Clippy { .. }
             | Subcommand::Fix { .. }
             | Subcommand::Run { .. }
@@ -816,8 +817,10 @@
                 check_ci_llvm!(llvm.allow_old_toolchain);
                 check_ci_llvm!(llvm.polly);
 
-                // CI-built LLVM is shared
-                config.llvm_link_shared = true;
+                // CI-built LLVM can be either dynamic or static.
+                let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
+                let link_type = t!(std::fs::read_to_string(ci_llvm.join("link-type.txt")));
+                config.llvm_link_shared = link_type == "dynamic";
             }
 
             if config.llvm_thin_lto {
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index e2c2e19..af9c0fb 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1800,19 +1800,11 @@
     }
 }
 
-/// Maybe add libLLVM.so to the given destination lib-dir. It will only have
-/// been built if LLVM tools are linked dynamically.
+/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
 ///
-/// Note: This function does not yet support Windows, but we also don't support
-///       linking LLVM tools dynamically on Windows yet.
-fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) {
-    if !builder.config.llvm_link_shared {
-        // We do not need to copy LLVM files into the sysroot if it is not
-        // dynamically linked; it is already included into librustc_llvm
-        // statically.
-        return;
-    }
 
+/// Returns whether the files were actually copied.
+fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
     if let Some(config) = builder.config.target_config.get(&target) {
         if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
             // If the LLVM was externally provided, then we don't currently copy
@@ -1828,7 +1820,7 @@
             //
             // If the LLVM is coming from ourselves (just from CI) though, we
             // still want to install it, as it otherwise won't be available.
-            return;
+            return false;
         }
     }
 
@@ -1837,31 +1829,48 @@
     // clear why this is the case, though. llvm-config will emit the versioned
     // paths and we don't want those in the sysroot (as we're expecting
     // unversioned paths).
-    if target.contains("apple-darwin") {
+    if target.contains("apple-darwin") && builder.config.llvm_link_shared {
         let src_libdir = builder.llvm_out(target).join("lib");
         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
         if llvm_dylib_path.exists() {
             builder.install(&llvm_dylib_path, dst_libdir, 0o644);
         }
+        !builder.config.dry_run
     } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) {
-        let files = output(Command::new(llvm_config).arg("--libfiles"));
-        for file in files.lines() {
+        let mut cmd = Command::new(llvm_config);
+        cmd.arg("--libfiles");
+        builder.verbose(&format!("running {:?}", cmd));
+        let files = output(&mut cmd);
+        for file in files.trim_end().split(' ') {
             builder.install(Path::new(file), dst_libdir, 0o644);
         }
+        !builder.config.dry_run
+    } else {
+        false
     }
 }
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
-    maybe_install_llvm(builder, target, &dst_libdir);
+    // We do not need to copy LLVM files into the sysroot if it is not
+    // dynamically linked; it is already included into librustc_llvm
+    // statically.
+    if builder.config.llvm_link_shared {
+        maybe_install_llvm(builder, target, &dst_libdir);
+    }
 }
 
 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
 pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir =
         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
-    maybe_install_llvm(builder, target, &dst_libdir);
+    // We do not need to copy LLVM files into the sysroot if it is not
+    // dynamically linked; it is already included into librustc_llvm
+    // statically.
+    if builder.config.llvm_link_shared {
+        maybe_install_llvm(builder, target, &dst_libdir);
+    }
 }
 
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
@@ -1973,7 +1982,10 @@
         // `$ORIGIN/../lib` can find it. It may also be used as a dependency
         // of `rustc-dev` to support the inherited `-lLLVM` when using the
         // compiler libraries.
-        maybe_install_llvm(builder, target, &tarball.image_dir().join("lib"));
+        let dst_libdir = tarball.image_dir().join("lib");
+        maybe_install_llvm(builder, target, &dst_libdir);
+        let link_type = if builder.config.llvm_link_shared { "dynamic" } else { "static" };
+        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
 
         Some(tarball.generate())
     }
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index b29ecd6..fb5b058 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/80087
+Last change is for: https://github.com/rust-lang/rust/pull/80932
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index d6a45f1..55062e1 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -614,14 +614,10 @@
         };
 
         if let Subcommand::Check { .. } = &cmd {
-            if matches.opt_str("stage").is_some() {
-                println!("--stage not supported for x.py check, always treated as stage 0");
-                process::exit(1);
-            }
             if matches.opt_str("keep-stage").is_some()
                 || matches.opt_str("keep-stage-std").is_some()
             {
-                println!("--keep-stage not supported for x.py check, only one stage available");
+                println!("--keep-stage not yet supported for x.py check");
                 process::exit(1);
             }
         }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 6412df3..609ac8b 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -171,7 +171,6 @@
             .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
             .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets)
             .define("LLVM_INCLUDE_EXAMPLES", "OFF")
-            .define("LLVM_INCLUDE_TESTS", "OFF")
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
             .define("LLVM_ENABLE_TERMINFO", "OFF")
diff --git a/src/doc/unstable-book/src/language-features/intra-doc-pointers.md b/src/doc/unstable-book/src/language-features/intra-doc-pointers.md
new file mode 100644
index 0000000..fbc83f4
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/intra-doc-pointers.md
@@ -0,0 +1,15 @@
+# `intra-doc-pointers`
+
+The tracking issue for this feature is: [#80896]
+
+[#80896]: https://github.com/rust-lang/rust/issues/80896
+
+------------------------
+
+Rustdoc does not currently allow disambiguating between `*const` and `*mut`, and
+raw pointers in intra-doc links are unstable until it does.
+
+```rust
+#![feature(intra_doc_pointers)]
+//! [pointer::add]
+```
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 43fb53b..83114a7 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -313,12 +313,12 @@
         tcx: TyCtxt<'tcx>,
         pred: ty::Predicate<'tcx>,
     ) -> FxHashSet<GenericParamDef> {
-        let bound_predicate = pred.bound_atom();
+        let bound_predicate = pred.kind();
         let regions = match bound_predicate.skip_binder() {
-            ty::PredicateAtom::Trait(poly_trait_pred, _) => {
+            ty::PredicateKind::Trait(poly_trait_pred, _) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
             }
-            ty::PredicateAtom::Projection(poly_proj_pred) => {
+            ty::PredicateKind::Projection(poly_proj_pred) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
             }
             _ => return FxHashSet::default(),
@@ -463,8 +463,8 @@
             .iter()
             .filter(|p| {
                 !orig_bounds.contains(p)
-                    || match p.skip_binders() {
-                        ty::PredicateAtom::Trait(pred, _) => pred.def_id() == sized_trait,
+                    || match p.kind().skip_binder() {
+                        ty::PredicateKind::Trait(pred, _) => pred.def_id() == sized_trait,
                         _ => false,
                     }
             })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 545f432..3ddb2ad 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -219,7 +219,6 @@
 impl Clean<Item> for doctree::Module<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
         let mut items: Vec<Item> = vec![];
-        items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
         items.extend(self.mods.iter().map(|x| x.clean(cx)));
         items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
@@ -466,20 +465,20 @@
 
 impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
     fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
-        let bound_predicate = self.bound_atom();
+        let bound_predicate = self.kind();
         match bound_predicate.skip_binder() {
-            ty::PredicateAtom::Trait(pred, _) => Some(bound_predicate.rebind(pred).clean(cx)),
-            ty::PredicateAtom::RegionOutlives(pred) => pred.clean(cx),
-            ty::PredicateAtom::TypeOutlives(pred) => pred.clean(cx),
-            ty::PredicateAtom::Projection(pred) => Some(pred.clean(cx)),
+            ty::PredicateKind::Trait(pred, _) => Some(bound_predicate.rebind(pred).clean(cx)),
+            ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
+            ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
+            ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
 
-            ty::PredicateAtom::Subtype(..)
-            | ty::PredicateAtom::WellFormed(..)
-            | ty::PredicateAtom::ObjectSafe(..)
-            | ty::PredicateAtom::ClosureKind(..)
-            | ty::PredicateAtom::ConstEvaluatable(..)
-            | ty::PredicateAtom::ConstEquate(..)
-            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+            ty::PredicateKind::Subtype(..)
+            | ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
         }
     }
 }
@@ -744,19 +743,19 @@
             .flat_map(|(p, _)| {
                 let mut projection = None;
                 let param_idx = (|| {
-                    let bound_p = p.bound_atom();
+                    let bound_p = p.kind();
                     match bound_p.skip_binder() {
-                        ty::PredicateAtom::Trait(pred, _constness) => {
+                        ty::PredicateKind::Trait(pred, _constness) => {
                             if let ty::Param(param) = pred.self_ty().kind() {
                                 return Some(param.index);
                             }
                         }
-                        ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+                        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
                             if let ty::Param(param) = ty.kind() {
                                 return Some(param.index);
                             }
                         }
-                        ty::PredicateAtom::Projection(p) => {
+                        ty::PredicateKind::Projection(p) => {
                             if let ty::Param(param) = p.projection_ty.self_ty().kind() {
                                 projection = Some(bound_p.rebind(p));
                                 return Some(param.index);
@@ -1685,14 +1684,12 @@
                 let mut bounds = bounds
                     .iter()
                     .filter_map(|bound| {
-                        // Note: The substs of opaque types can contain unbound variables,
-                        // meaning that we have to use `ignore_quantifiers_with_unbound_vars` here.
-                        let bound_predicate = bound.bound_atom_with_opt_escaping(cx.tcx);
+                        let bound_predicate = bound.kind();
                         let trait_ref = match bound_predicate.skip_binder() {
-                            ty::PredicateAtom::Trait(tr, _constness) => {
+                            ty::PredicateKind::Trait(tr, _constness) => {
                                 bound_predicate.rebind(tr.trait_ref)
                             }
-                            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
                                 if let Some(r) = reg.clean(cx) {
                                     regions.push(GenericBound::Outlives(r));
                                 }
@@ -1711,8 +1708,8 @@
                         let bounds: Vec<_> = bounds
                             .iter()
                             .filter_map(|bound| {
-                                if let ty::PredicateAtom::Projection(proj) =
-                                    bound.bound_atom_with_opt_escaping(cx.tcx).skip_binder()
+                                if let ty::PredicateKind::Projection(proj) =
+                                    bound.kind().skip_binder()
                                 {
                                     if proj.projection_ty.trait_ref(cx.tcx)
                                         == trait_ref.skip_binder()
@@ -2015,7 +2012,7 @@
                 ItemKind::Fn(ref sig, ref generics, body_id) => {
                     clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
                 }
-                hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+                ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
                     let items = item_ids
                         .iter()
                         .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
@@ -2034,6 +2031,9 @@
                 ItemKind::ExternCrate(orig_name) => {
                     return clean_extern_crate(item, name, orig_name, cx);
                 }
+                ItemKind::Use(path, kind) => {
+                    return clean_use_statement(item, name, path, kind, cx);
+                }
                 _ => unreachable!("not yet converted"),
             };
 
@@ -2155,105 +2155,97 @@
     }]
 }
 
-impl Clean<Vec<Item>> for doctree::Import<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
-        // We need this comparison because some imports (for std types for example)
-        // are "inserted" as well but directly by the compiler and they should not be
-        // taken into account.
-        if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
-            return Vec::new();
-        }
-
-        let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline);
-        let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore;
-
-        if pub_underscore && please_inline {
-            rustc_errors::struct_span_err!(
-                cx.tcx.sess,
-                doc_meta_item.unwrap().span(),
-                E0780,
-                "anonymous imports cannot be inlined"
-            )
-            .span_label(self.span, "anonymous import")
-            .emit();
-        }
-
-        // We consider inlining the documentation of `pub use` statements, but we
-        // forcefully don't inline if this is not public or if the
-        // #[doc(no_inline)] attribute is present.
-        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
-        let mut denied = !self.vis.node.is_pub()
-            || pub_underscore
-            || self.attrs.iter().any(|a| {
-                a.has_name(sym::doc)
-                    && match a.meta_item_list() {
-                        Some(l) => {
-                            attr::list_contains_name(&l, sym::no_inline)
-                                || attr::list_contains_name(&l, sym::hidden)
-                        }
-                        None => false,
-                    }
-            });
-        // Also check whether imports were asked to be inlined, in case we're trying to re-export a
-        // crate in Rust 2018+
-        let path = self.path.clean(cx);
-        let inner = if self.glob {
-            if !denied {
-                let mut visited = FxHashSet::default();
-                if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
-                    return items;
-                }
-            }
-            Import::new_glob(resolve_use_source(cx, path), true)
-        } else {
-            let name = self.name;
-            if !please_inline {
-                if let Res::Def(DefKind::Mod, did) = path.res {
-                    if !did.is_local() && did.index == CRATE_DEF_INDEX {
-                        // if we're `pub use`ing an extern crate root, don't inline it unless we
-                        // were specifically asked for it
-                        denied = true;
-                    }
-                }
-            }
-            if !denied {
-                let mut visited = FxHashSet::default();
-
-                if let Some(mut items) = inline::try_inline(
-                    cx,
-                    cx.tcx.parent_module(self.id).to_def_id(),
-                    path.res,
-                    name,
-                    Some(self.attrs),
-                    &mut visited,
-                ) {
-                    items.push(Item {
-                        name: None,
-                        attrs: box self.attrs.clean(cx),
-                        source: self.span.clean(cx),
-                        def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
-                        visibility: self.vis.clean(cx),
-                        kind: box ImportItem(Import::new_simple(
-                            self.name,
-                            resolve_use_source(cx, path),
-                            false,
-                        )),
-                    });
-                    return items;
-                }
-            }
-            Import::new_simple(name, resolve_use_source(cx, path), true)
-        };
-
-        vec![Item {
-            name: None,
-            attrs: box self.attrs.clean(cx),
-            source: self.span.clean(cx),
-            def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
-            visibility: self.vis.clean(cx),
-            kind: box ImportItem(inner),
-        }]
+fn clean_use_statement(
+    import: &hir::Item<'_>,
+    name: Symbol,
+    path: &hir::Path<'_>,
+    kind: hir::UseKind,
+    cx: &DocContext<'_>,
+) -> Vec<Item> {
+    // We need this comparison because some imports (for std types for example)
+    // are "inserted" as well but directly by the compiler and they should not be
+    // taken into account.
+    if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
+        return Vec::new();
     }
+
+    let (doc_meta_item, please_inline) = import.attrs.lists(sym::doc).get_word_attr(sym::inline);
+    let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore;
+
+    if pub_underscore && please_inline {
+        rustc_errors::struct_span_err!(
+            cx.tcx.sess,
+            doc_meta_item.unwrap().span(),
+            E0780,
+            "anonymous imports cannot be inlined"
+        )
+        .span_label(import.span, "anonymous import")
+        .emit();
+    }
+
+    // We consider inlining the documentation of `pub use` statements, but we
+    // forcefully don't inline if this is not public or if the
+    // #[doc(no_inline)] attribute is present.
+    // Don't inline doc(hidden) imports so they can be stripped at a later stage.
+    let mut denied = !import.vis.node.is_pub()
+        || pub_underscore
+        || import.attrs.iter().any(|a| {
+            a.has_name(sym::doc)
+                && match a.meta_item_list() {
+                    Some(l) => {
+                        attr::list_contains_name(&l, sym::no_inline)
+                            || attr::list_contains_name(&l, sym::hidden)
+                    }
+                    None => false,
+                }
+        });
+
+    // Also check whether imports were asked to be inlined, in case we're trying to re-export a
+    // crate in Rust 2018+
+    let def_id = cx.tcx.hir().local_def_id(import.hir_id).to_def_id();
+    let path = path.clean(cx);
+    let inner = if kind == hir::UseKind::Glob {
+        if !denied {
+            let mut visited = FxHashSet::default();
+            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
+                return items;
+            }
+        }
+        Import::new_glob(resolve_use_source(cx, path), true)
+    } else {
+        if !please_inline {
+            if let Res::Def(DefKind::Mod, did) = path.res {
+                if !did.is_local() && did.index == CRATE_DEF_INDEX {
+                    // if we're `pub use`ing an extern crate root, don't inline it unless we
+                    // were specifically asked for it
+                    denied = true;
+                }
+            }
+        }
+        if !denied {
+            let mut visited = FxHashSet::default();
+
+            if let Some(mut items) = inline::try_inline(
+                cx,
+                cx.tcx.parent_module(import.hir_id).to_def_id(),
+                path.res,
+                name,
+                Some(import.attrs),
+                &mut visited,
+            ) {
+                items.push(Item::from_def_id_and_parts(
+                    def_id,
+                    None,
+                    ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
+                    cx,
+                ));
+                return items;
+            }
+        }
+        Import::new_simple(name, resolve_use_source(cx, path), true)
+    };
+
+    vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)]
 }
 
 impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 16aaa9c..d4d0a8c 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -129,7 +129,7 @@
         .predicates
         .iter()
         .filter_map(|(pred, _)| {
-            if let ty::PredicateAtom::Trait(pred, _) = pred.skip_binders() {
+            if let ty::PredicateKind::Trait(pred, _) = pred.kind().skip_binder() {
                 if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None }
             } else {
                 None
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index cf51162..3de97f2 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -500,6 +500,12 @@
                 }
             }
 
+            // Reset errors so that they won't be reported as compiler bugs when dropping the
+            // handler. Any errors in the tests will be reported when the test file is compiled,
+            // Note that we still need to cancel the errors above otherwise `DiagnosticBuilder`
+            // will panic on drop.
+            sess.span_diagnostic.reset_err_count();
+
             (found_main, found_extern_crate, found_macro)
         })
     });
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 4710c91..f90623c 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -2,7 +2,6 @@
 //! manner (and with prettier names) before cleaning.
 crate use self::StructType::*;
 
-use rustc_ast as ast;
 use rustc_span::{self, Span, Symbol};
 
 use rustc_hir as hir;
@@ -11,7 +10,6 @@
     crate name: Option<Symbol>,
     crate where_outer: Span,
     crate where_inner: Span,
-    crate imports: Vec<Import<'hir>>,
     crate mods: Vec<Module<'hir>>,
     crate id: hir::HirId,
     // (item, renamed)
@@ -28,7 +26,6 @@
             id: hir::CRATE_HIR_ID,
             where_outer: rustc_span::DUMMY_SP,
             where_inner: rustc_span::DUMMY_SP,
-            imports: Vec::new(),
             mods: Vec::new(),
             items: Vec::new(),
             foreigns: Vec::new(),
@@ -48,17 +45,6 @@
     Unit,
 }
 
-#[derive(Debug)]
-crate struct Import<'hir> {
-    crate name: Symbol,
-    crate id: hir::HirId,
-    crate vis: &'hir hir::Visibility<'hir>,
-    crate attrs: &'hir [ast::Attribute],
-    crate path: &'hir hir::Path<'hir>,
-    crate glob: bool,
-    crate span: Span,
-}
-
 crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
     match *vdata {
         hir::VariantData::Struct(..) => Plain,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 708d771..2694450 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -19,9 +19,8 @@
     builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS},
     Lint,
 };
-use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::Ident;
-use rustc_span::symbol::Symbol;
+use rustc_span::hygiene::{MacroKind, SyntaxContext};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
 
@@ -770,7 +769,12 @@
     let mut cache = cx.module_trait_cache.borrow_mut();
     let in_scope_traits = cache.entry(module).or_insert_with(|| {
         cx.enter_resolver(|resolver| {
-            resolver.traits_in_scope(module).into_iter().map(|candidate| candidate.def_id).collect()
+            let parent_scope = &ParentScope::module(resolver.get_module(module), resolver);
+            resolver
+                .traits_in_scope(None, parent_scope, SyntaxContext::root(), None)
+                .into_iter()
+                .map(|candidate| candidate.def_id)
+                .collect()
         })
     });
 
@@ -1190,7 +1194,7 @@
         };
 
         match res {
-            Res::Primitive(_) => {
+            Res::Primitive(prim) => {
                 if let Some((kind, id)) = self.kind_side_channel.take() {
                     // We're actually resolving an associated item of a primitive, so we need to
                     // verify the disambiguator (if any) matches the type of the associated item.
@@ -1201,6 +1205,29 @@
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
                     verify(kind, id)?;
+
+                    if prim == PrimitiveType::RawPointer
+                        && !self.cx.tcx.features().intra_doc_pointers
+                    {
+                        let span = super::source_span_for_markdown_range(
+                            cx,
+                            dox,
+                            &ori_link.range,
+                            &item.attrs,
+                        )
+                        .unwrap_or_else(|| {
+                            span_of_attrs(&item.attrs).unwrap_or(item.source.span())
+                        });
+
+                        rustc_session::parse::feature_err(
+                            &self.cx.tcx.sess.parse_sess,
+                            sym::intra_doc_pointers,
+                            span,
+                            "linking to associated items of raw pointers is experimental",
+                        )
+                        .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does")
+                        .emit();
+                    }
                 } else {
                     match disambiguator {
                         Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
@@ -1210,6 +1237,7 @@
                         }
                     }
                 }
+
                 Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
             }
             Res::Def(kind, id) => {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index f701352..7d161ca 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -316,15 +316,7 @@
                     }
                 }
 
-                om.imports.push(Import {
-                    name,
-                    id: item.hir_id,
-                    vis: &item.vis,
-                    attrs: &item.attrs,
-                    path,
-                    glob: is_glob,
-                    span: item.span,
-                });
+                om.items.push((item, renamed))
             }
             hir::ItemKind::Mod(ref m) => {
                 om.mods.push(self.visit_mod_contents(
diff --git a/src/test/codegen/intrinsics/move-val-init.rs b/src/test/codegen/intrinsics/move-val-init.rs
deleted file mode 100644
index 6222536..0000000
--- a/src/test/codegen/intrinsics/move-val-init.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-
-#![feature(core_intrinsics)]
-#![crate_type = "lib"]
-
-// test that `move_val_init` actually avoids big allocas
-
-use std::intrinsics::move_val_init;
-
-pub struct Big {
-    pub data: [u8; 65536]
-}
-
-// CHECK-LABEL: @test_mvi
-#[no_mangle]
-pub unsafe fn test_mvi(target: *mut Big, make_big: fn() -> Big) {
-    // CHECK: call void %make_big(%Big*{{[^%]*}} %target)
-    move_val_init(target, make_big());
-}
diff --git a/src/test/codegen/slice-as_chunks.rs b/src/test/codegen/slice-as_chunks.rs
new file mode 100644
index 0000000..48e3f73
--- /dev/null
+++ b/src/test/codegen/slice-as_chunks.rs
@@ -0,0 +1,33 @@
+// no-system-llvm
+// compile-flags: -O
+// only-64bit (because the LLVM type of i64 for usize shows up)
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(slice_as_chunks)]
+
+// CHECK-LABEL: @chunks4
+#[no_mangle]
+pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: lshr i64 %x.1, 2
+    // CHECK-NOT: shl
+    // CHECK-NOT: mul
+    // CHECK-NOT: udiv
+    // CHECK-NOT: urem
+    // CHECK: ret
+    x.as_chunks().0
+}
+
+// CHECK-LABEL: @chunks4_with_remainder
+#[no_mangle]
+pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
+    // CHECK: and i64 %x.1, -4
+    // CHECK: and i64 %x.1, 3
+    // CHECK: lshr exact
+    // CHECK-NOT: mul
+    // CHECK-NOT: udiv
+    // CHECK-NOT: urem
+    // CHECK: ret
+    x.as_chunks()
+}
diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py
index b0c5b16..6a92126 100644
--- a/src/test/rustdoc-json/compare.py
+++ b/src/test/rustdoc-json/compare.py
@@ -7,6 +7,9 @@
 # and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If
 # you're on windows, replace `\` with `/`.
 
+# WARNING: The error messages produced by this may be misleading, in the case of list re-ordering
+#          it may point to apparently unrelated keys.
+
 import copy
 import sys
 import json
diff --git a/src/test/rustdoc-json/nested.expected b/src/test/rustdoc-json/nested.expected
index 65bb0c5..80070e7 100644
--- a/src/test/rustdoc-json/nested.expected
+++ b/src/test/rustdoc-json/nested.expected
@@ -41,8 +41,8 @@
       "inner": {
         "is_crate": false,
         "items": [
-          "0:7",
-          "0:4"
+          "0:4",
+          "0:7"
         ]
       },
       "kind": "module",
diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs
new file mode 100644
index 0000000..3cfac94
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs
@@ -0,0 +1,6 @@
+//! [pointer::add]
+//~^ ERROR: experimental
+//! [pointer::wrapping_add]
+//~^ ERROR: experimental
+//! [pointer] // This is explicitly allowed
+//! [reference] // This is explicitly allowed
diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr
new file mode 100644
index 0000000..2c946ed
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr
@@ -0,0 +1,23 @@
+error[E0658]: linking to associated items of raw pointers is experimental
+  --> $DIR/feature-gate-intra-doc-pointers.rs:1:6
+   |
+LL | //! [pointer::add]
+   |      ^^^^^^^^^^^^
+   |
+   = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information
+   = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable
+   = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does
+
+error[E0658]: linking to associated items of raw pointers is experimental
+  --> $DIR/feature-gate-intra-doc-pointers.rs:3:6
+   |
+LL | //! [pointer::wrapping_add]
+   |      ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information
+   = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable
+   = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
index 114502b0..6785c4c 100644
--- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
+++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
@@ -1,4 +1,5 @@
 #![deny(broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
 // These are links that could reasonably expected to work, but don't.
 
 // `[]` isn't supported because it had too many false positives.
diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
index ea831e6..1747585 100644
--- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
+++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
@@ -1,5 +1,5 @@
 error: unresolved link to `T`
-  --> $DIR/non-path-primitives.rs:11:7
+  --> $DIR/non-path-primitives.rs:12:7
    |
 LL | //! [[T]::rotate_left]
    |       ^ no item named `T` in scope
@@ -12,7 +12,7 @@
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: unresolved link to `Z`
-  --> $DIR/non-path-primitives.rs:13:5
+  --> $DIR/non-path-primitives.rs:14:5
    |
 LL | //![Z]([T; N]::map)
    |     ^ no item named `Z` in scope
@@ -20,7 +20,7 @@
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: unresolved link to `Z`
-  --> $DIR/non-path-primitives.rs:16:6
+  --> $DIR/non-path-primitives.rs:17:6
    |
 LL | //! [Z][]
    |      ^ no item named `Z` in scope
@@ -28,7 +28,7 @@
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: unresolved link to `Z`
-  --> $DIR/non-path-primitives.rs:18:6
+  --> $DIR/non-path-primitives.rs:19:6
    |
 LL | //! [Z]: [T; N]::map
    |      ^ no item named `Z` in scope
@@ -36,31 +36,31 @@
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: unresolved link to `unit::eq`
-  --> $DIR/non-path-primitives.rs:27:6
+  --> $DIR/non-path-primitives.rs:28:6
    |
 LL | //! [unit::eq]
    |      ^^^^^^^^ the builtin type `unit` has no associated item named `eq`
 
 error: unresolved link to `tuple::eq`
-  --> $DIR/non-path-primitives.rs:28:6
+  --> $DIR/non-path-primitives.rs:29:6
    |
 LL | //! [tuple::eq]
    |      ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq`
 
 error: unresolved link to `fn::eq`
-  --> $DIR/non-path-primitives.rs:29:6
+  --> $DIR/non-path-primitives.rs:30:6
    |
 LL | //! [fn::eq]
    |      ^^^^^^ the builtin type `fn` has no associated item named `eq`
 
 error: unresolved link to `never::eq`
-  --> $DIR/non-path-primitives.rs:30:6
+  --> $DIR/non-path-primitives.rs:31:6
    |
 LL | //! [never::eq]
    |      ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
 
 error: unresolved link to `reference::deref`
-  --> $DIR/non-path-primitives.rs:34:6
+  --> $DIR/non-path-primitives.rs:35:6
    |
 LL | //! [reference::deref]
    |      ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
diff --git a/src/test/rustdoc-ui/issue-80992.rs b/src/test/rustdoc-ui/issue-80992.rs
new file mode 100644
index 0000000..8983439
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-80992.rs
@@ -0,0 +1,11 @@
+// check-pass
+// compile-flags:--test
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+pub fn test() -> Result<(), ()> {
+    //! ```compile_fail
+    //! fn test() -> Result< {}
+    //! ```
+    Ok(())
+}
diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout
new file mode 100644
index 0000000..1dd19f4
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-80992.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/issue-80992.rs - test (line 7) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs
index 2c7e7b5..48c667e 100644
--- a/src/test/rustdoc/intra-doc/non-path-primitives.rs
+++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs
@@ -1,5 +1,6 @@
 // ignore-tidy-linelength
 #![crate_name = "foo"]
+#![feature(intra_doc_pointers)]
 #![deny(broken_intra_doc_links)]
 
 // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
diff --git a/src/test/ui/issues/issue-28676.rs b/src/test/ui/abi/issue-28676.rs
similarity index 100%
rename from src/test/ui/issues/issue-28676.rs
rename to src/test/ui/abi/issue-28676.rs
diff --git a/src/test/ui/issues/issue-15730.rs b/src/test/ui/array-slice-vec/issue-15730.rs
similarity index 100%
rename from src/test/ui/issues/issue-15730.rs
rename to src/test/ui/array-slice-vec/issue-15730.rs
diff --git a/src/test/ui/associated-item/associated-item-two-bounds.rs b/src/test/ui/associated-item/associated-item-two-bounds.rs
new file mode 100644
index 0000000..25b0d5a
--- /dev/null
+++ b/src/test/ui/associated-item/associated-item-two-bounds.rs
@@ -0,0 +1,16 @@
+// This test is a regression test for #34792
+
+// check-pass
+
+pub struct A;
+pub struct B;
+
+pub trait Foo {
+    type T: PartialEq<A> + PartialEq<B>;
+}
+
+pub fn generic<F: Foo>(t: F::T, a: A, b: B) -> bool {
+    t == a && t == b
+}
+
+pub fn main() {}
diff --git a/src/test/ui/issues/issue-24338.rs b/src/test/ui/associated-types/issue-24338.rs
similarity index 100%
rename from src/test/ui/issues/issue-24338.rs
rename to src/test/ui/associated-types/issue-24338.rs
diff --git a/src/test/ui/issues/issue-48551.rs b/src/test/ui/associated-types/issue-48551.rs
similarity index 100%
rename from src/test/ui/issues/issue-48551.rs
rename to src/test/ui/associated-types/issue-48551.rs
diff --git a/src/test/ui/issues/issue-50301.rs b/src/test/ui/associated-types/issue-50301.rs
similarity index 100%
rename from src/test/ui/issues/issue-50301.rs
rename to src/test/ui/associated-types/issue-50301.rs
diff --git a/src/test/ui/object-method-numbering.rs b/src/test/ui/associated-types/object-method-numbering.rs
similarity index 100%
rename from src/test/ui/object-method-numbering.rs
rename to src/test/ui/associated-types/object-method-numbering.rs
diff --git a/src/test/ui/issues/issue-76547.nll.stderr b/src/test/ui/async-await/issue-76547.nll.stderr
similarity index 100%
rename from src/test/ui/issues/issue-76547.nll.stderr
rename to src/test/ui/async-await/issue-76547.nll.stderr
diff --git a/src/test/ui/issues/issue-76547.rs b/src/test/ui/async-await/issue-76547.rs
similarity index 100%
rename from src/test/ui/issues/issue-76547.rs
rename to src/test/ui/async-await/issue-76547.rs
diff --git a/src/test/ui/issues/issue-76547.stderr b/src/test/ui/async-await/issue-76547.stderr
similarity index 100%
rename from src/test/ui/issues/issue-76547.stderr
rename to src/test/ui/async-await/issue-76547.stderr
diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs
new file mode 100644
index 0000000..36f7160
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs
@@ -0,0 +1,33 @@
+// edition:2018
+
+use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}};
+
+async fn f() {
+    let room_ref = Arc::new(Vec::new());
+
+    let gameloop_handle = spawn(async { //~ ERROR E0373
+        game_loop(Arc::clone(&room_ref))
+    });
+    gameloop_handle.await;
+}
+
+fn game_loop(v: Arc<Vec<usize>>) {}
+
+fn spawn<F>(future: F) -> JoinHandle
+where
+    F: Future + Send + 'static,
+    F::Output: Send + 'static,
+{
+    loop {}
+}
+
+struct JoinHandle;
+
+impl Future for JoinHandle {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        loop {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr
new file mode 100644
index 0000000..01ffc48
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr
@@ -0,0 +1,21 @@
+error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function
+  --> $DIR/issue-78938-async-block.rs:8:39
+   |
+LL |       let gameloop_handle = spawn(async {
+   |  _______________________________________^
+LL | |         game_loop(Arc::clone(&room_ref))
+   | |                               -------- `room_ref` is borrowed here
+LL | |     });
+   | |_____^ may outlive borrowed value `room_ref`
+   |
+   = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use
+help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword
+   |
+LL |     let gameloop_handle = spawn(async move {
+LL |         game_loop(Arc::clone(&room_ref))
+LL |     });
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/src/test/ui/issues/issue-38940.rs b/src/test/ui/autoref-autoderef/issue-38940.rs
similarity index 100%
rename from src/test/ui/issues/issue-38940.rs
rename to src/test/ui/autoref-autoderef/issue-38940.rs
diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/autoref-autoderef/issue-38940.stderr
similarity index 100%
rename from src/test/ui/issues/issue-38940.stderr
rename to src/test/ui/autoref-autoderef/issue-38940.stderr
diff --git a/src/test/ui/issues/issue-25916.rs b/src/test/ui/binop/issue-25916.rs
similarity index 100%
rename from src/test/ui/issues/issue-25916.rs
rename to src/test/ui/binop/issue-25916.rs
diff --git a/src/test/ui/issues/issue-28837.rs b/src/test/ui/binop/issue-28837.rs
similarity index 100%
rename from src/test/ui/issues/issue-28837.rs
rename to src/test/ui/binop/issue-28837.rs
diff --git a/src/test/ui/issues/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr
similarity index 100%
rename from src/test/ui/issues/issue-28837.stderr
rename to src/test/ui/binop/issue-28837.stderr
diff --git a/src/test/ui/issues/issue-17263.rs b/src/test/ui/borrowck/issue-17263.rs
similarity index 100%
rename from src/test/ui/issues/issue-17263.rs
rename to src/test/ui/borrowck/issue-17263.rs
diff --git a/src/test/ui/issues/issue-17545.rs b/src/test/ui/borrowck/issue-17545.rs
similarity index 100%
rename from src/test/ui/issues/issue-17545.rs
rename to src/test/ui/borrowck/issue-17545.rs
diff --git a/src/test/ui/issues/issue-17545.stderr b/src/test/ui/borrowck/issue-17545.stderr
similarity index 100%
rename from src/test/ui/issues/issue-17545.stderr
rename to src/test/ui/borrowck/issue-17545.stderr
diff --git a/src/test/ui/issues/issue-20801.rs b/src/test/ui/borrowck/issue-20801.rs
similarity index 100%
rename from src/test/ui/issues/issue-20801.rs
rename to src/test/ui/borrowck/issue-20801.rs
diff --git a/src/test/ui/issues/issue-20801.stderr b/src/test/ui/borrowck/issue-20801.stderr
similarity index 100%
rename from src/test/ui/issues/issue-20801.stderr
rename to src/test/ui/borrowck/issue-20801.stderr
diff --git a/src/test/ui/issues/issue-24267-flow-exit.rs b/src/test/ui/borrowck/issue-24267-flow-exit.rs
similarity index 100%
rename from src/test/ui/issues/issue-24267-flow-exit.rs
rename to src/test/ui/borrowck/issue-24267-flow-exit.rs
diff --git a/src/test/ui/issues/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
similarity index 100%
rename from src/test/ui/issues/issue-24267-flow-exit.stderr
rename to src/test/ui/borrowck/issue-24267-flow-exit.stderr
diff --git a/src/test/ui/issues/issue-25793.rs b/src/test/ui/borrowck/issue-25793.rs
similarity index 100%
rename from src/test/ui/issues/issue-25793.rs
rename to src/test/ui/borrowck/issue-25793.rs
diff --git a/src/test/ui/issues/issue-25793.stderr b/src/test/ui/borrowck/issue-25793.stderr
similarity index 100%
rename from src/test/ui/issues/issue-25793.stderr
rename to src/test/ui/borrowck/issue-25793.stderr
diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs b/src/test/ui/borrowck/issue-27282-move-match-input-into-guard.rs
similarity index 100%
rename from src/test/ui/issues/issue-27282-move-match-input-into-guard.rs
rename to src/test/ui/borrowck/issue-27282-move-match-input-into-guard.rs
diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/borrowck/issue-27282-move-match-input-into-guard.stderr
similarity index 100%
rename from src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr
rename to src/test/ui/borrowck/issue-27282-move-match-input-into-guard.stderr
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs
rename to src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.rs
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
similarity index 100%
rename from src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr
rename to src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.rs
similarity index 100%
rename from src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs
rename to src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.rs
diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
similarity index 100%
rename from src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr
rename to src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
diff --git a/src/test/ui/issues/issue-45199.rs b/src/test/ui/borrowck/issue-45199.rs
similarity index 100%
rename from src/test/ui/issues/issue-45199.rs
rename to src/test/ui/borrowck/issue-45199.rs
diff --git a/src/test/ui/issues/issue-45199.stderr b/src/test/ui/borrowck/issue-45199.stderr
similarity index 100%
rename from src/test/ui/issues/issue-45199.stderr
rename to src/test/ui/borrowck/issue-45199.stderr
diff --git a/src/test/ui/issues/issue-46471.rs b/src/test/ui/borrowck/issue-46471.rs
similarity index 100%
rename from src/test/ui/issues/issue-46471.rs
rename to src/test/ui/borrowck/issue-46471.rs
diff --git a/src/test/ui/issues/issue-46471.stderr b/src/test/ui/borrowck/issue-46471.stderr
similarity index 100%
rename from src/test/ui/issues/issue-46471.stderr
rename to src/test/ui/borrowck/issue-46471.stderr
diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs
new file mode 100644
index 0000000..4b42f9d
--- /dev/null
+++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs
@@ -0,0 +1,10 @@
+// Regression test for #80913.
+
+fn main() {
+    let mut x = 42_i32;
+    let mut opt = Some(&mut x);
+    for _ in 0..5 {
+        if let Some(mut _x) = opt {}
+        //~^ ERROR: use of moved value
+    }
+}
diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
new file mode 100644
index 0000000..9373e4d
--- /dev/null
+++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value
+  --> $DIR/move-in-pattern-mut-in-loop.rs:7:21
+   |
+LL |         if let Some(mut _x) = opt {}
+   |                     ^^^^^^ value moved here, in previous iteration of loop
+   |
+   = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `opt.0`
+   |
+LL |         if let Some(ref mut _x) = opt {}
+   |                     ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs
new file mode 100644
index 0000000..2916d8c
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs
@@ -0,0 +1,31 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Check that precise paths are being reported back in the error message.
+
+
+enum MultiVariant {
+    Point(i32, i32),
+    Meta(i32)
+}
+
+fn main() {
+    let mut point = MultiVariant::Point(10, -10,);
+
+    let mut meta = MultiVariant::Meta(1);
+
+    let c = || {
+        if let MultiVariant::Point(ref mut x, _) = point {
+            *x += 1;
+        }
+
+        if let MultiVariant::Meta(ref mut v) = meta {
+            *v += 1;
+        }
+    };
+
+    let a = c;
+    let b = c; //~ ERROR use of moved value: `c` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr
new file mode 100644
index 0000000..de0bfe3
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr
@@ -0,0 +1,26 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-multi-variant-diagnostics.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0382]: use of moved value: `c`
+  --> $DIR/closure-origin-multi-variant-diagnostics.rs:30:13
+   |
+LL |     let a = c;
+   |             - value moved here
+LL |     let b = c;
+   |             ^ value used here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment
+  --> $DIR/closure-origin-multi-variant-diagnostics.rs:20:52
+   |
+LL |         if let MultiVariant::Point(ref mut x, _) = point {
+   |                                                    ^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
new file mode 100644
index 0000000..8486f03
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
@@ -0,0 +1,26 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Check that precise paths are being reported back in the error message.
+
+enum SingleVariant {
+    Point(i32, i32),
+}
+
+fn main() {
+    let mut point = SingleVariant::Point(10, -10);
+
+    let c = || {
+        // FIXME(project-rfc-2229#24): Change this to be a destructure pattern
+        // once this is fixed, to remove the warning.
+        if let SingleVariant::Point(ref mut x, _) = point {
+            //~^ WARNING: irrefutable if-let pattern
+            *x += 1;
+        }
+    };
+
+    let b = c;
+    let a = c; //~ ERROR use of moved value: `c` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
new file mode 100644
index 0000000..ad66f6d
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
@@ -0,0 +1,37 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-single-variant-diagnostics.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: irrefutable if-let pattern
+  --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
+   |
+LL | /         if let SingleVariant::Point(ref mut x, _) = point {
+LL | |
+LL | |             *x += 1;
+LL | |         }
+   | |_________^
+   |
+   = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+error[E0382]: use of moved value: `c`
+  --> $DIR/closure-origin-single-variant-diagnostics.rs:25:13
+   |
+LL |     let b = c;
+   |             - value moved here
+LL |     let a = c;
+   |             ^ value used here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment
+  --> $DIR/closure-origin-single-variant-diagnostics.rs:18:53
+   |
+LL |         if let SingleVariant::Point(ref mut x, _) = point {
+   |                                                     ^^^^^
+
+error: aborting due to previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs
new file mode 100644
index 0000000..103890f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs
@@ -0,0 +1,25 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Check that precise paths are being reported back in the error message.
+
+struct Y {
+    y: X
+}
+
+struct X {
+    a: u32,
+    b: u32,
+}
+
+fn main() {
+    let mut x = Y { y: X { a: 5, b: 0 } };
+    let hello = || {
+        x.y.a += 1;
+    };
+
+    let b = hello;
+    let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr
new file mode 100644
index 0000000..474d77b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr
@@ -0,0 +1,26 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-struct-diagnostics.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0382]: use of moved value: `hello`
+  --> $DIR/closure-origin-struct-diagnostics.rs:24:13
+   |
+LL |     let b = hello;
+   |             ----- value moved here
+LL |     let c = hello;
+   |             ^^^^^ value used here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.y.a` out of its environment
+  --> $DIR/closure-origin-struct-diagnostics.rs:20:9
+   |
+LL |         x.y.a += 1;
+   |         ^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs
new file mode 100644
index 0000000..6b078d2
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs
@@ -0,0 +1,16 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Check that precise paths are being reported back in the error message.
+
+fn main() {
+    let mut x = (5, 0);
+    let hello = || {
+        x.0 += 1;
+    };
+
+    let b = hello;
+    let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr
new file mode 100644
index 0000000..716728e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr
@@ -0,0 +1,26 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-tuple-diagnostics-1.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0382]: use of moved value: `hello`
+  --> $DIR/closure-origin-tuple-diagnostics-1.rs:15:13
+   |
+LL |     let b = hello;
+   |             ----- value moved here
+LL |     let c = hello;
+   |             ^^^^^ value used here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.0` out of its environment
+  --> $DIR/closure-origin-tuple-diagnostics-1.rs:11:9
+   |
+LL |         x.0 += 1;
+   |         ^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs
new file mode 100644
index 0000000..0638db6
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs
@@ -0,0 +1,15 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+struct S(String, String);
+
+fn expect_fn<F: Fn()>(_f: F) {}
+
+fn main() {
+    let s = S(format!("s"), format!("s"));
+    let c = || { //~ ERROR expected a closure that implements the `Fn`
+        let s = s.1;
+    };
+    expect_fn(c);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
new file mode 100644
index 0000000..77eb2a9
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
@@ -0,0 +1,23 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closure-origin-tuple-diagnostics.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/closure-origin-tuple-diagnostics.rs:11:13
+   |
+LL |     let c = || {
+   |             ^^ this closure implements `FnOnce`, not `Fn`
+LL |         let s = s.1;
+   |                 --- closure is `FnOnce` because it moves the variable `s.1` out of its environment
+LL |     };
+LL |     expect_fn(c);
+   |     --------- the requirement to implement `Fn` derives from here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/src/test/ui/command/command-current-dir.rs b/src/test/ui/command/command-current-dir.rs
new file mode 100644
index 0000000..91d8e4f
--- /dev/null
+++ b/src/test/ui/command/command-current-dir.rs
@@ -0,0 +1,49 @@
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::env;
+use std::fs;
+use std::path::Path;
+use std::process::Command;
+
+fn main() {
+    // Checks the behavior of current_dir when used with a relative exe path.
+    let me = env::current_exe().unwrap();
+    if matches!(env::args().skip(1).next().as_deref(), Some("current-dir")) {
+        let cwd = env::current_dir().unwrap();
+        assert_eq!(cwd.file_name().unwrap(), "bar");
+        std::process::exit(0);
+    }
+    let exe = me.file_name().unwrap();
+    let cwd = me.parent().unwrap();
+    eprintln!("cwd={:?}", cwd);
+    // Change directory to where the exectuable is located, since this test
+    // fundamentally needs to use relative paths. In some cases (like
+    // remote-test-server), the current_dir can be somewhere else, so make
+    // sure it is something we can use. We assume we can write to this
+    // directory.
+    env::set_current_dir(&cwd).unwrap();
+    let foo = cwd.join("foo");
+    let bar = cwd.join("bar");
+    fs::create_dir_all(&foo).unwrap();
+    fs::create_dir_all(&bar).unwrap();
+    fs::copy(&me, foo.join(exe)).unwrap();
+
+    // Unfortunately this is inconsistent based on the platform, see
+    // https://github.com/rust-lang/rust/issues/37868. On Windows,
+    // it is relative *before* changing the directory, and on Unix
+    // it is *after* changing the directory.
+    let relative_exe = if cfg!(windows) {
+        Path::new("foo").join(exe)
+    } else {
+        Path::new("../foo").join(exe)
+    };
+
+    let status = Command::new(relative_exe)
+        .arg("current-dir")
+        .current_dir("bar")
+        .status()
+        .unwrap();
+    assert!(status.success());
+}
diff --git a/src/test/ui/issues/issue-73899.rs b/src/test/ui/const-generics/issue-73899.rs
similarity index 100%
rename from src/test/ui/issues/issue-73899.rs
rename to src/test/ui/const-generics/issue-73899.rs
diff --git a/src/test/ui/issues/issue-75763.rs b/src/test/ui/const-generics/issue-75763.rs
similarity index 100%
rename from src/test/ui/issues/issue-75763.rs
rename to src/test/ui/const-generics/issue-75763.rs
diff --git a/src/test/ui/const-generics/late-bound-vars/in_closure.rs b/src/test/ui/const-generics/late-bound-vars/in_closure.rs
new file mode 100644
index 0000000..0aaeaff
--- /dev/null
+++ b/src/test/ui/const-generics/late-bound-vars/in_closure.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+const fn inner<'a>() -> usize where &'a (): Sized {
+    3
+}
+
+fn test<'a>() {
+    let _ = || {
+        let _: [u8; inner::<'a>()];
+        let _ = [0; inner::<'a>()];
+    };
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/const-generics/late-bound-vars/simple.rs b/src/test/ui/const-generics/late-bound-vars/simple.rs
new file mode 100644
index 0000000..2c411a3
--- /dev/null
+++ b/src/test/ui/const-generics/late-bound-vars/simple.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+const fn inner<'a>() -> usize where &'a (): Sized {
+    3
+}
+
+fn test<'a>() {
+    let _: [u8; inner::<'a>()];
+    let _ = [0; inner::<'a>()];
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/check_const-feature-gated.rs b/src/test/ui/consts/check_const-feature-gated.rs
similarity index 100%
rename from src/test/ui/check_const-feature-gated.rs
rename to src/test/ui/consts/check_const-feature-gated.rs
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
index bcd05b4..2975118 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
@@ -8,6 +8,12 @@
 // normalize-stderr-test "alloc\d+" -> "allocN"
 // normalize-stderr-test "size \d+" -> "size N"
 
+/// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error
+/// message. Use this whenever the message is "any use of this value will cause an error" instead of
+/// "it is undefined behavior to use this value".
+#[repr(transparent)]
+struct W<T>(T);
+
 #[repr(C)]
 union MaybeUninit<T: Copy> {
     uninit: (),
@@ -95,26 +101,22 @@
 
 // # trait object
 // bad trait object
-#[warn(const_err)]
-const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) };
-//~^ WARN any use of this value will cause an error [const_err]
+const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+//~^ ERROR it is undefined behavior to use this value
 // bad trait object
-#[warn(const_err)]
-const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-//~^ WARN any use of this value will cause an error [const_err]
+const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+//~^ ERROR it is undefined behavior to use this value
 // bad trait object
-#[warn(const_err)]
-const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) };
-//~^ WARN any use of this value will cause an error [const_err]
+const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+//~^ ERROR it is undefined behavior to use this value
 const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
 //~^ ERROR it is undefined behavior to use this value
 const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
 //~^ ERROR it is undefined behavior to use this value
 const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
 //~^ ERROR it is undefined behavior to use this value
-#[warn(const_err)]
-const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) };
-//~^ WARN any use of this value will cause an error [const_err]
+const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+//~^ ERROR it is undefined behavior to use this value
 
 // bad data *inside* the trait object
 const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
index ec5d465..be9ec16 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:31:1
+  --> $DIR/ub-wide-ptr.rs:37:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation)
@@ -7,7 +7,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:33:1
+  --> $DIR/ub-wide-ptr.rs:39:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0
@@ -15,7 +15,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:36:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -23,7 +23,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:39:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -31,7 +31,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:47:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object
@@ -39,7 +39,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:45:1
+  --> $DIR/ub-wide-ptr.rs:51:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
@@ -47,7 +47,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:48:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
@@ -55,7 +55,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:55:1
+  --> $DIR/ub-wide-ptr.rs:61:1
    |
 LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
 LL | |
@@ -67,7 +67,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:61:1
+  --> $DIR/ub-wide-ptr.rs:67:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation)
@@ -75,7 +75,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:64:1
+  --> $DIR/ub-wide-ptr.rs:70:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -83,7 +83,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:67:1
+  --> $DIR/ub-wide-ptr.rs:73:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation)
@@ -91,7 +91,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:70:1
+  --> $DIR/ub-wide-ptr.rs:76:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -99,7 +99,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:74:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean
@@ -107,7 +107,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:80:1
+  --> $DIR/ub-wide-ptr.rs:86:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean
@@ -115,7 +115,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:83:1
+  --> $DIR/ub-wide-ptr.rs:89:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean
@@ -123,7 +123,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:96:1
    |
 LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
 LL | |
@@ -134,50 +134,32 @@
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-warning: any use of this value will cause an error
-  --> $DIR/ub-wide-ptr.rs:99:55
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:104:1
    |
-LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) };
-   | ------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                                                       |
-   |                                                       memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
    |
-note: the lint level is defined here
-  --> $DIR/ub-wide-ptr.rs:98:8
-   |
-LL | #[warn(const_err)]
-   |        ^^^^^^^^^
-
-warning: any use of this value will cause an error
-  --> $DIR/ub-wide-ptr.rs:103:55
-   |
-LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                                                       |
-   |                                                       memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
-   |
-note: the lint level is defined here
-  --> $DIR/ub-wide-ptr.rs:102:8
-   |
-LL | #[warn(const_err)]
-   |        ^^^^^^^^^
-
-warning: any use of this value will cause an error
-  --> $DIR/ub-wide-ptr.rs:107:51
-   |
-LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) };
-   | --------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                                                   |
-   |                                                   unable to turn bytes into a pointer
-   |
-note: the lint level is defined here
-  --> $DIR/ub-wide-ptr.rs:106:8
-   |
-LL | #[warn(const_err)]
-   |        ^^^^^^^^^
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:109:1
+  --> $DIR/ub-wide-ptr.rs:107:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:110:1
+   |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@@ -185,7 +167,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:114:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -193,29 +175,23 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:113:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-warning: any use of this value will cause an error
-  --> $DIR/ub-wide-ptr.rs:116:63
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:118:1
    |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) };
-   | --------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                                                               |
-   |                                                               "pointer-to-integer cast" needs an rfc before being allowed inside constants
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0
    |
-note: the lint level is defined here
-  --> $DIR/ub-wide-ptr.rs:115:8
-   |
-LL | #[warn(const_err)]
-   |        ^^^^^^^^^
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
+  --> $DIR/ub-wide-ptr.rs:122:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
@@ -223,7 +199,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:124:1
+  --> $DIR/ub-wide-ptr.rs:126:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@@ -231,7 +207,7 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:126:1
+  --> $DIR/ub-wide-ptr.rs:128:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@@ -239,17 +215,17 @@
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:132:5
+  --> $DIR/ub-wide-ptr.rs:134:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:136:5
+  --> $DIR/ub-wide-ptr.rs:138:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
 
-error: aborting due to 24 previous errors; 4 warnings emitted
+error: aborting due to 28 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-suggest-feature.rs b/src/test/ui/consts/const-suggest-feature.rs
similarity index 100%
rename from src/test/ui/const-suggest-feature.rs
rename to src/test/ui/consts/const-suggest-feature.rs
diff --git a/src/test/ui/const-suggest-feature.stderr b/src/test/ui/consts/const-suggest-feature.stderr
similarity index 100%
rename from src/test/ui/const-suggest-feature.stderr
rename to src/test/ui/consts/const-suggest-feature.stderr
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs
new file mode 100644
index 0000000..810158a
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab.rs
@@ -0,0 +1,17 @@
+#![feature(intrinsics, staged_api, const_intrinsic_copy)]
+#![stable(feature = "core", since = "1.6.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    // Const stability attributes are not inherited from parent items.
+    extern "rust-intrinsic" {
+        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
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr
new file mode 100644
index 0000000..5a42823
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr
@@ -0,0 +1,9 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/intrinsic_without_const_stab.rs:13:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
new file mode 100644
index 0000000..bf2c441
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
@@ -0,0 +1,15 @@
+#![feature(intrinsics, staged_api, const_intrinsic_copy)]
+#![stable(feature = "core", since = "1.6.0")]
+
+extern "rust-intrinsic" {
+    fn copy<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[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
+}
+
+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
new file mode 100644
index 0000000..d4a2989
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
@@ -0,0 +1,9 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-17718-borrow-interior.rs b/src/test/ui/consts/issue-17718-borrow-interior.rs
similarity index 100%
rename from src/test/ui/issues/issue-17718-borrow-interior.rs
rename to src/test/ui/consts/issue-17718-borrow-interior.rs
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.rs b/src/test/ui/consts/issue-17718-const-bad-values.rs
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-bad-values.rs
rename to src/test/ui/consts/issue-17718-const-bad-values.rs
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/consts/issue-17718-const-bad-values.stderr
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-bad-values.stderr
rename to src/test/ui/consts/issue-17718-const-bad-values.stderr
diff --git a/src/test/ui/issues/issue-17718-const-borrow.rs b/src/test/ui/consts/issue-17718-const-borrow.rs
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-borrow.rs
rename to src/test/ui/consts/issue-17718-const-borrow.rs
diff --git a/src/test/ui/issues/issue-17718-const-borrow.stderr b/src/test/ui/consts/issue-17718-const-borrow.stderr
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-borrow.stderr
rename to src/test/ui/consts/issue-17718-const-borrow.stderr
diff --git a/src/test/ui/issues/issue-21562.rs b/src/test/ui/consts/issue-21562.rs
similarity index 100%
rename from src/test/ui/issues/issue-21562.rs
rename to src/test/ui/consts/issue-21562.rs
diff --git a/src/test/ui/issues/issue-21721.rs b/src/test/ui/consts/issue-21721.rs
similarity index 100%
rename from src/test/ui/issues/issue-21721.rs
rename to src/test/ui/consts/issue-21721.rs
diff --git a/src/test/ui/issues/issue-27890.rs b/src/test/ui/consts/issue-27890.rs
similarity index 100%
rename from src/test/ui/issues/issue-27890.rs
rename to src/test/ui/consts/issue-27890.rs
diff --git a/src/test/ui/issues/issue-28113.rs b/src/test/ui/consts/issue-28113.rs
similarity index 100%
rename from src/test/ui/issues/issue-28113.rs
rename to src/test/ui/consts/issue-28113.rs
diff --git a/src/test/ui/issues/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr
similarity index 100%
rename from src/test/ui/issues/issue-28113.stderr
rename to src/test/ui/consts/issue-28113.stderr
diff --git a/src/test/ui/issues/issue-29914-2.rs b/src/test/ui/consts/issue-29914-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-29914-2.rs
rename to src/test/ui/consts/issue-29914-2.rs
diff --git a/src/test/ui/issues/issue-29914-3.rs b/src/test/ui/consts/issue-29914-3.rs
similarity index 100%
rename from src/test/ui/issues/issue-29914-3.rs
rename to src/test/ui/consts/issue-29914-3.rs
diff --git a/src/test/ui/issues/issue-29914.rs b/src/test/ui/consts/issue-29914.rs
similarity index 100%
rename from src/test/ui/issues/issue-29914.rs
rename to src/test/ui/consts/issue-29914.rs
diff --git a/src/test/ui/issues/issue-29927-1.rs b/src/test/ui/consts/issue-29927-1.rs
similarity index 100%
rename from src/test/ui/issues/issue-29927-1.rs
rename to src/test/ui/consts/issue-29927-1.rs
diff --git a/src/test/ui/issues/issue-29927.rs b/src/test/ui/consts/issue-29927.rs
similarity index 100%
rename from src/test/ui/issues/issue-29927.rs
rename to src/test/ui/consts/issue-29927.rs
diff --git a/src/test/ui/issues/issue-32829-2.rs b/src/test/ui/consts/issue-32829-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-32829-2.rs
rename to src/test/ui/consts/issue-32829-2.rs
diff --git a/src/test/ui/issues/issue-32829-2.stderr b/src/test/ui/consts/issue-32829-2.stderr
similarity index 100%
rename from src/test/ui/issues/issue-32829-2.stderr
rename to src/test/ui/consts/issue-32829-2.stderr
diff --git a/src/test/ui/issues/issue-36163.rs b/src/test/ui/consts/issue-36163.rs
similarity index 100%
rename from src/test/ui/issues/issue-36163.rs
rename to src/test/ui/consts/issue-36163.rs
diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/consts/issue-36163.stderr
similarity index 100%
rename from src/test/ui/issues/issue-36163.stderr
rename to src/test/ui/consts/issue-36163.stderr
diff --git a/src/test/ui/issues/issue-43105.rs b/src/test/ui/consts/issue-43105.rs
similarity index 100%
rename from src/test/ui/issues/issue-43105.rs
rename to src/test/ui/consts/issue-43105.rs
diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/consts/issue-43105.stderr
similarity index 100%
rename from src/test/ui/issues/issue-43105.stderr
rename to src/test/ui/consts/issue-43105.stderr
diff --git a/src/test/ui/issues/issue-47789.rs b/src/test/ui/consts/issue-47789.rs
similarity index 100%
rename from src/test/ui/issues/issue-47789.rs
rename to src/test/ui/consts/issue-47789.rs
diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.rs b/src/test/ui/consts/issue-52023-array-size-pointer-cast.rs
similarity index 100%
rename from src/test/ui/issues/issue-52023-array-size-pointer-cast.rs
rename to src/test/ui/consts/issue-52023-array-size-pointer-cast.rs
diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr
similarity index 100%
rename from src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr
rename to src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr
diff --git a/src/test/ui/issues/issue-58435-ice-with-assoc-const.rs b/src/test/ui/consts/issue-58435-ice-with-assoc-const.rs
similarity index 100%
rename from src/test/ui/issues/issue-58435-ice-with-assoc-const.rs
rename to src/test/ui/consts/issue-58435-ice-with-assoc-const.rs
diff --git a/src/test/ui/issues/issue-6991.rs b/src/test/ui/consts/issue-6991.rs
similarity index 100%
rename from src/test/ui/issues/issue-6991.rs
rename to src/test/ui/consts/issue-6991.rs
diff --git a/src/test/ui/rustc-args-required-const.rs b/src/test/ui/consts/rustc-args-required-const.rs
similarity index 100%
rename from src/test/ui/rustc-args-required-const.rs
rename to src/test/ui/consts/rustc-args-required-const.rs
diff --git a/src/test/ui/rustc-args-required-const.stderr b/src/test/ui/consts/rustc-args-required-const.stderr
similarity index 100%
rename from src/test/ui/rustc-args-required-const.stderr
rename to src/test/ui/consts/rustc-args-required-const.stderr
diff --git a/src/test/ui/issues/issue-30018-nopanic.rs b/src/test/ui/drop/issue-30018-nopanic.rs
similarity index 100%
rename from src/test/ui/issues/issue-30018-nopanic.rs
rename to src/test/ui/drop/issue-30018-nopanic.rs
diff --git a/src/test/ui/issues/issue-28498-ugeh-with-lifetime-param.rs b/src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs
similarity index 100%
rename from src/test/ui/issues/issue-28498-ugeh-with-lifetime-param.rs
rename to src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs
diff --git a/src/test/ui/issues/issue-28498-ugeh-with-trait-bound.rs b/src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs
similarity index 100%
rename from src/test/ui/issues/issue-28498-ugeh-with-trait-bound.rs
rename to src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs
diff --git a/src/test/ui/issues/issue-29844.rs b/src/test/ui/dropck/issue-29844.rs
similarity index 100%
rename from src/test/ui/issues/issue-29844.rs
rename to src/test/ui/dropck/issue-29844.rs
diff --git a/src/test/ui/issues/issue-43398.rs b/src/test/ui/enum-discriminant/issue-43398.rs
similarity index 100%
rename from src/test/ui/issues/issue-43398.rs
rename to src/test/ui/enum-discriminant/issue-43398.rs
diff --git a/src/test/ui/issues/issue-43398.stderr b/src/test/ui/enum-discriminant/issue-43398.stderr
similarity index 100%
rename from src/test/ui/issues/issue-43398.stderr
rename to src/test/ui/enum-discriminant/issue-43398.stderr
diff --git a/src/test/ui/error-codes/E0283.rs b/src/test/ui/error-codes/E0283.rs
index 9bdcc9a..4d7c2f2 100644
--- a/src/test/ui/error-codes/E0283.rs
+++ b/src/test/ui/error-codes/E0283.rs
@@ -8,6 +8,18 @@
     fn create() -> u32 { 1 }
 }
 
+impl Impl {
+    fn new() -> Self {
+        Impl{}
+    }
+}
+
+impl Into<u32> for Impl {
+    fn into(self) -> u32 { 1 }
+}
+
+fn foo(bar: u32) {}
+
 struct AnotherImpl;
 
 impl Generator for AnotherImpl {
@@ -17,3 +29,9 @@
 fn main() {
     let cont: u32 = Generator::create(); //~ ERROR E0283
 }
+
+fn buzz() {
+    let foo_impl = Impl::new();
+    let bar = foo_impl.into() * 1u32; //~ ERROR E0283
+    foo(bar);
+}
diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr
index e95583c..2f0dfb6 100644
--- a/src/test/ui/error-codes/E0283.stderr
+++ b/src/test/ui/error-codes/E0283.stderr
@@ -1,5 +1,5 @@
 error[E0283]: type annotations needed
-  --> $DIR/E0283.rs:18:21
+  --> $DIR/E0283.rs:30:21
    |
 LL |     fn create() -> u32;
    |     ------------------- required by `Generator::create`
@@ -9,6 +9,18 @@
    |
    = note: cannot satisfy `_: Generator`
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/E0283.rs:35:24
+   |
+LL |     let bar = foo_impl.into() * 1u32;
+   |               ---------^^^^--
+   |               |        |
+   |               |        cannot infer type for type parameter `T` declared on the trait `Into`
+   |               this method call resolves to `T`
+   |               help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
+   |
+   = note: cannot satisfy `Impl: Into<_>`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs b/src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs
similarity index 100%
rename from src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs
rename to src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs
diff --git a/src/test/ui/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs
similarity index 100%
rename from src/test/ui/feature-gate-edition_macro_pats.rs
rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs
diff --git a/src/test/ui/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr
similarity index 100%
rename from src/test/ui/feature-gate-edition_macro_pats.stderr
rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr
diff --git a/src/test/ui/trace_macros-gate.rs b/src/test/ui/feature-gates/trace_macros-gate.rs
similarity index 100%
rename from src/test/ui/trace_macros-gate.rs
rename to src/test/ui/feature-gates/trace_macros-gate.rs
diff --git a/src/test/ui/trace_macros-gate.stderr b/src/test/ui/feature-gates/trace_macros-gate.stderr
similarity index 100%
rename from src/test/ui/trace_macros-gate.stderr
rename to src/test/ui/feature-gates/trace_macros-gate.stderr
diff --git a/src/test/ui/issues/issue-2936.rs b/src/test/ui/generics/issue-2936.rs
similarity index 100%
rename from src/test/ui/issues/issue-2936.rs
rename to src/test/ui/generics/issue-2936.rs
diff --git a/src/test/ui/hygiene/traits-in-scope.rs b/src/test/ui/hygiene/traits-in-scope.rs
new file mode 100644
index 0000000..548bb22
--- /dev/null
+++ b/src/test/ui/hygiene/traits-in-scope.rs
@@ -0,0 +1,53 @@
+// Macros with def-site hygiene still bring traits into scope.
+// It is not clear whether this is desirable behavior or not.
+// It is also not clear how to prevent it if it is not desirable.
+
+// check-pass
+
+#![feature(decl_macro)]
+#![feature(trait_alias)]
+
+mod traits {
+    pub trait Trait1 {
+        fn simple_import(&self) {}
+    }
+    pub trait Trait2 {
+        fn renamed_import(&self) {}
+    }
+    pub trait Trait3 {
+        fn underscore_import(&self) {}
+    }
+    pub trait Trait4 {
+        fn trait_alias(&self) {}
+    }
+
+    impl Trait1 for () {}
+    impl Trait2 for () {}
+    impl Trait3 for () {}
+    impl Trait4 for () {}
+}
+
+macro m1() {
+    use traits::Trait1;
+}
+macro m2() {
+    use traits::Trait2 as Alias;
+}
+macro m3() {
+    use traits::Trait3 as _;
+}
+macro m4() {
+    trait Alias = traits::Trait4;
+}
+
+fn main() {
+    m1!();
+    m2!();
+    m3!();
+    m4!();
+
+    ().simple_import();
+    ().renamed_import();
+    ().underscore_import();
+    ().trait_alias();
+}
diff --git a/src/test/ui/nested_impl_trait.rs b/src/test/ui/impl-trait/nested_impl_trait.rs
similarity index 100%
rename from src/test/ui/nested_impl_trait.rs
rename to src/test/ui/impl-trait/nested_impl_trait.rs
diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/impl-trait/nested_impl_trait.stderr
similarity index 100%
rename from src/test/ui/nested_impl_trait.stderr
rename to src/test/ui/impl-trait/nested_impl_trait.stderr
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs
similarity index 100%
rename from src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs
rename to src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.rs
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
similarity index 100%
rename from src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
rename to src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
diff --git a/src/test/ui/issues/issue-26873-onefile.rs b/src/test/ui/imports/issue-26873-onefile.rs
similarity index 100%
rename from src/test/ui/issues/issue-26873-onefile.rs
rename to src/test/ui/imports/issue-26873-onefile.rs
diff --git a/src/test/ui/issues/issue-32119.rs b/src/test/ui/imports/issue-32119.rs
similarity index 100%
rename from src/test/ui/issues/issue-32119.rs
rename to src/test/ui/imports/issue-32119.rs
diff --git a/src/test/ui/issues/issue-32222.rs b/src/test/ui/imports/issue-32222.rs
similarity index 100%
rename from src/test/ui/issues/issue-32222.rs
rename to src/test/ui/imports/issue-32222.rs
diff --git a/src/test/ui/intrinsics/intrinsic-move-val-cleanups.rs b/src/test/ui/intrinsics/intrinsic-move-val-cleanups.rs
deleted file mode 100644
index 9804c42..0000000
--- a/src/test/ui/intrinsics/intrinsic-move-val-cleanups.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-// run-pass
-#![allow(unused_braces)]
-#![allow(unused_unsafe)]
-#![allow(unreachable_code)]
-// ignore-emscripten no threads support
-#![allow(stable_features)]
-
-// This test is checking that the move_val_init intrinsic is
-// respecting cleanups for both of its argument expressions.
-//
-// In other words, if either DEST or SOURCE in
-//
-//   `intrinsics::move_val_init(DEST, SOURCE)
-//
-// introduce temporaries that require cleanup, and SOURCE panics, then
-// make sure the cleanups still occur.
-
-#![feature(core_intrinsics, sync_poison)]
-
-use std::cell::RefCell;
-use std::intrinsics;
-use std::sync::{Arc, LockResult, Mutex, MutexGuard};
-use std::thread;
-
-type LogEntry = (&'static str, i32);
-type Guarded = RefCell<Vec<LogEntry>>;
-#[derive(Clone)]
-struct Log(Arc<Mutex<Guarded>>);
-struct Acquired<'a>(MutexGuard<'a, Guarded>);
-type LogState = (MutexWas, &'static [LogEntry]);
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum MutexWas { Poisoned, NotPoisoned }
-
-impl Log {
-    fn lock(&self) -> LockResult<MutexGuard<RefCell<Vec<LogEntry>>>> { self.0.lock() }
-    fn acquire(&self) -> Acquired { Acquired(self.0.lock().unwrap()) }
-}
-
-impl<'a> Acquired<'a> {
-    fn log(&self, s: &'static str, i: i32) { self.0.borrow_mut().push((s, i)); }
-}
-
-const TEST1_EXPECT: LogState = (MutexWas::NotPoisoned,
-                                &[("double-check non-poisoning path", 1)
-                                  ]);
-
-fn test1(log: Log) {
-    {
-        let acq = log.acquire();
-        acq.log("double-check non-poisoning path", 1);
-    }
-    panic!("every test ends in a panic");
-}
-
-const TEST2_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("double-check poisoning path", 1),
-                                  ("and multiple log entries", 2),
-                                  ]);
-fn test2(log: Log) {
-    let acq = log.acquire();
-    acq.log("double-check poisoning path", 1);
-    acq.log("and multiple log entries", 2);
-    panic!("every test ends in a panic");
-}
-
-struct LogOnDrop<'a>(&'a Acquired<'a>, &'static str, i32);
-impl<'a> Drop for LogOnDrop<'a> {
-    fn drop(&mut self) {
-        self.0.log(self.1, self.2);
-    }
-}
-
-const TEST3_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("double-check destructors can log", 1),
-                                  ("drop d2", 2),
-                                  ("drop d1", 3),
-                                  ]);
-fn test3(log: Log) {
-    let acq = log.acquire();
-    acq.log("double-check destructors can log", 1);
-    let _d1 = LogOnDrop(&acq, "drop d1", 3);
-    let _d2 = LogOnDrop(&acq, "drop d2", 2);
-    panic!("every test ends in a panic");
-}
-
-// The *real* tests of panic-handling for move_val_init intrinsic
-// start here.
-
-const TEST4_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("neither arg panics", 1),
-                                  ("drop temp LOD", 2),
-                                  ("drop temp LOD", 3),
-                                  ("drop dest_b", 4),
-                                  ("drop dest_a", 5),
-                                  ]);
-fn test4(log: Log) {
-    let acq = log.acquire();
-    acq.log("neither arg panics", 1);
-    let mut dest_a = LogOnDrop(&acq, "a will be overwritten, not dropped", 0);
-    let mut dest_b = LogOnDrop(&acq, "b will be overwritten, not dropped", 0);
-    unsafe {
-        intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
-                                  LogOnDrop(&acq, "drop dest_a", 5));
-        intrinsics::move_val_init(&mut dest_b, { LogOnDrop(&acq, "drop temp LOD", 3);
-                                                 LogOnDrop(&acq, "drop dest_b", 4) });
-    }
-    panic!("every test ends in a panic");
-}
-
-
-// Check that move_val_init(PANIC, SOURCE_EXPR) never evaluates SOURCE_EXPR
-const TEST5_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("first arg panics", 1),
-                                  ("drop orig dest_a", 2),
-                                  ]);
-fn test5(log: Log) {
-    let acq = log.acquire();
-    acq.log("first arg panics", 1);
-    let mut _dest_a = LogOnDrop(&acq, "drop orig dest_a", 2);
-    unsafe {
-        intrinsics::move_val_init({ panic!("every test ends in a panic") },
-                                  LogOnDrop(&acq, "we never get here", 0));
-    }
-}
-
-// Check that move_val_init(DEST_EXPR, PANIC) cleans up temps from DEST_EXPR.
-const TEST6_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("second arg panics", 1),
-                                  ("drop temp LOD", 2),
-                                  ("drop orig dest_a", 3),
-                                  ]);
-fn test6(log: Log) {
-    let acq = log.acquire();
-    acq.log("second arg panics", 1);
-    let mut dest_a = LogOnDrop(&acq, "drop orig dest_a", 3);
-    unsafe {
-        intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
-                                  { panic!("every test ends in a panic"); });
-    }
-}
-
-// Check that move_val_init(DEST_EXPR, COMPLEX_PANIC) cleans up temps from COMPLEX_PANIC.
-const TEST7_EXPECT: LogState = (MutexWas::Poisoned,
-                                &[("second arg panics", 1),
-                                  ("drop temp LOD", 2),
-                                  ("drop temp LOD", 3),
-                                  ("drop orig dest_a", 4),
-                                  ]);
-fn test7(log: Log) {
-    let acq = log.acquire();
-    acq.log("second arg panics", 1);
-    let mut dest_a = LogOnDrop(&acq, "drop orig dest_a", 4);
-    unsafe {
-        intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
-                                  { LogOnDrop(&acq, "drop temp LOD", 3);
-                                    panic!("every test ends in a panic"); });
-    }
-}
-
-const TEST_SUITE: &'static [(&'static str, fn (Log), LogState)] =
-    &[("test1", test1, TEST1_EXPECT),
-      ("test2", test2, TEST2_EXPECT),
-      ("test3", test3, TEST3_EXPECT),
-      ("test4", test4, TEST4_EXPECT),
-      ("test5", test5, TEST5_EXPECT),
-      ("test6", test6, TEST6_EXPECT),
-      ("test7", test7, TEST7_EXPECT),
-      ];
-
-fn main() {
-    for &(name, test, expect) in TEST_SUITE {
-        let log = Log(Arc::new(Mutex::new(RefCell::new(Vec::new()))));
-        let ret = { let log = log.clone(); thread::spawn(move || test(log)).join() };
-        assert!(ret.is_err(), "{} must end with panic", name);
-        {
-            let l = log.lock();
-            match l {
-                Ok(acq) => {
-                    assert_eq!((MutexWas::NotPoisoned, &acq.borrow()[..]), expect);
-                    println!("{} (unpoisoned) log: {:?}", name, *acq);
-                }
-                Err(e) => {
-                    let acq = e.into_inner();
-                    assert_eq!((MutexWas::Poisoned, &acq.borrow()[..]), expect);
-                    println!("{} (poisoned) log: {:?}", name, *acq);
-                }
-            }
-        }
-    }
-}
diff --git a/src/test/ui/intrinsics/intrinsic-move-val.rs b/src/test/ui/intrinsics/intrinsic-move-val.rs
deleted file mode 100644
index b672f1e..0000000
--- a/src/test/ui/intrinsics/intrinsic-move-val.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// run-pass
-
-#![feature(box_syntax)]
-#![feature(intrinsics)]
-
-mod rusti {
-    extern "rust-intrinsic" {
-        pub fn move_val_init<T>(dst: *mut T, src: T);
-    }
-}
-
-pub fn main() {
-    unsafe {
-        // sanity check
-        check_drops_state(0, None);
-
-        let mut x: Option<Box<D>> = Some(box D(1));
-        assert_eq!(x.as_ref().unwrap().0, 1);
-
-        // A normal overwrite, to demonstrate `check_drops_state`.
-        x = Some(box D(2));
-
-        // At this point, one destructor has run, because the
-        // overwrite of `x` drops its initial value.
-        check_drops_state(1, Some(1));
-
-        let mut y: Option<Box<D>> = std::mem::zeroed();
-
-        // An initial binding does not overwrite anything.
-        check_drops_state(1, Some(1));
-
-        // Since `y` has been initialized via the `init` intrinsic, it
-        // would be unsound to directly overwrite its value via normal
-        // assignment.
-        //
-        // The code currently generated by the compiler is overly
-        // accepting, however, in that it will check if `y` is itself
-        // null and thus avoid the unsound action of attempting to
-        // free null. In other words, if we were to do a normal
-        // assignment like `y = box D(4);` here, it probably would not
-        // crash today. But the plan is that it may well crash in the
-        // future, (I believe).
-
-        // `x` is moved here; the manner in which this is tracked by the
-        // compiler is hidden.
-        rusti::move_val_init(&mut y, x);
-
-        // But what we *can* observe is how many times the destructor
-        // for `D` is invoked, and what the last value we saw was
-        // during such a destructor call. We do so after the end of
-        // this scope.
-
-        assert_eq!(y.as_ref().unwrap().0, 2);
-        y.as_mut().unwrap().0 = 3;
-        assert_eq!(y.as_ref().unwrap().0, 3);
-
-        check_drops_state(1, Some(1));
-    }
-
-    check_drops_state(2, Some(3));
-}
-
-static mut NUM_DROPS: i32 = 0;
-static mut LAST_DROPPED: Option<i32> = None;
-
-fn check_drops_state(num_drops: i32, last_dropped: Option<i32>) {
-    unsafe {
-        assert_eq!(NUM_DROPS, num_drops);
-        assert_eq!(LAST_DROPPED, last_dropped);
-    }
-}
-
-struct D(i32);
-impl Drop for D {
-    fn drop(&mut self) {
-        unsafe {
-            NUM_DROPS += 1;
-            LAST_DROPPED = Some(self.0);
-        }
-    }
-}
diff --git a/src/test/ui/issues/issue-15881-model-lexer-dotdotdot.rs b/src/test/ui/issues/issue-15881-model-lexer-dotdotdot.rs
deleted file mode 100644
index dee7f25..0000000
--- a/src/test/ui/issues/issue-15881-model-lexer-dotdotdot.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// run-pass
-#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
-#![allow(ellipsis_inclusive_range_patterns)]
-
-// regression test for the model lexer handling the DOTDOTDOT syntax (#15877)
-
-
-pub fn main() {
-    match 5_usize {
-      1_usize...5_usize => {}
-      _ => panic!("should match range"),
-    }
-    match 5_usize {
-      6_usize...7_usize => panic!("shouldn't match range"),
-      _ => {}
-    }
-    match 5_usize {
-      1_usize => panic!("should match non-first range"),
-      2_usize...6_usize => {}
-      _ => panic!("math is broken")
-    }
-    match 'c' {
-      'a'...'z' => {}
-      _ => panic!("should support char ranges")
-    }
-    match -3_isize {
-      -7...5 => {}
-      _ => panic!("should match signed range")
-    }
-    match 3.0f64 {
-      1.0...5.0 => {}
-      _ => panic!("should match float range")
-    }
-    match -1.5f64 {
-      -3.6...3.6 => {}
-      _ => panic!("should match negative float range")
-    }
-}
diff --git a/src/test/ui/expr_attr_paren_order.rs b/src/test/ui/lint/expr_attr_paren_order.rs
similarity index 100%
rename from src/test/ui/expr_attr_paren_order.rs
rename to src/test/ui/lint/expr_attr_paren_order.rs
diff --git a/src/test/ui/expr_attr_paren_order.stderr b/src/test/ui/lint/expr_attr_paren_order.stderr
similarity index 100%
rename from src/test/ui/expr_attr_paren_order.stderr
rename to src/test/ui/lint/expr_attr_paren_order.stderr
diff --git a/src/test/ui/issues/issue-17718-const-naming.rs b/src/test/ui/lint/issue-17718-const-naming.rs
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-naming.rs
rename to src/test/ui/lint/issue-17718-const-naming.rs
diff --git a/src/test/ui/issues/issue-17718-const-naming.stderr b/src/test/ui/lint/issue-17718-const-naming.stderr
similarity index 100%
rename from src/test/ui/issues/issue-17718-const-naming.stderr
rename to src/test/ui/lint/issue-17718-const-naming.stderr
diff --git a/src/test/ui/issues/issue-30302.rs b/src/test/ui/lint/issue-30302.rs
similarity index 100%
rename from src/test/ui/issues/issue-30302.rs
rename to src/test/ui/lint/issue-30302.rs
diff --git a/src/test/ui/issues/issue-30302.stderr b/src/test/ui/lint/issue-30302.stderr
similarity index 100%
rename from src/test/ui/issues/issue-30302.stderr
rename to src/test/ui/lint/issue-30302.stderr
diff --git a/src/test/ui/issues/issue-34798.rs b/src/test/ui/lint/issue-34798.rs
similarity index 100%
rename from src/test/ui/issues/issue-34798.rs
rename to src/test/ui/lint/issue-34798.rs
diff --git a/src/test/ui/trivial_casts.rs b/src/test/ui/lint/trivial_casts.rs
similarity index 100%
rename from src/test/ui/trivial_casts.rs
rename to src/test/ui/lint/trivial_casts.rs
diff --git a/src/test/ui/trivial_casts.stderr b/src/test/ui/lint/trivial_casts.stderr
similarity index 100%
rename from src/test/ui/trivial_casts.stderr
rename to src/test/ui/lint/trivial_casts.stderr
diff --git a/src/test/ui/inline-asm-bad-constraint.rs b/src/test/ui/llvm-asm/inline-asm-bad-constraint.rs
similarity index 100%
rename from src/test/ui/inline-asm-bad-constraint.rs
rename to src/test/ui/llvm-asm/inline-asm-bad-constraint.rs
diff --git a/src/test/ui/inline-asm-bad-constraint.stderr b/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr
similarity index 100%
rename from src/test/ui/inline-asm-bad-constraint.stderr
rename to src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr
diff --git a/src/test/ui/inline-asm-bad-operand.rs b/src/test/ui/llvm-asm/inline-asm-bad-operand.rs
similarity index 100%
rename from src/test/ui/inline-asm-bad-operand.rs
rename to src/test/ui/llvm-asm/inline-asm-bad-operand.rs
diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/llvm-asm/inline-asm-bad-operand.stderr
similarity index 100%
rename from src/test/ui/inline-asm-bad-operand.stderr
rename to src/test/ui/llvm-asm/inline-asm-bad-operand.stderr
diff --git a/src/test/ui/issues/issue-14936.rs b/src/test/ui/llvm-asm/issue-14936.rs
similarity index 100%
rename from src/test/ui/issues/issue-14936.rs
rename to src/test/ui/llvm-asm/issue-14936.rs
diff --git a/src/test/ui/issues/auxiliary/issue-40469.rs b/src/test/ui/macros/auxiliary/issue-40469.rs
similarity index 100%
rename from src/test/ui/issues/auxiliary/issue-40469.rs
rename to src/test/ui/macros/auxiliary/issue-40469.rs
diff --git a/src/test/ui/issues/issue-26322.rs b/src/test/ui/macros/issue-26322.rs
similarity index 100%
rename from src/test/ui/issues/issue-26322.rs
rename to src/test/ui/macros/issue-26322.rs
diff --git a/src/test/ui/issues/issue-40469.rs b/src/test/ui/macros/issue-40469.rs
similarity index 100%
rename from src/test/ui/issues/issue-40469.rs
rename to src/test/ui/macros/issue-40469.rs
diff --git a/src/test/ui/issues/issue-41803.rs b/src/test/ui/macros/issue-41803.rs
similarity index 100%
rename from src/test/ui/issues/issue-41803.rs
rename to src/test/ui/macros/issue-41803.rs
diff --git a/src/test/ui/issues/issue-5060.rs b/src/test/ui/macros/issue-5060.rs
similarity index 100%
rename from src/test/ui/issues/issue-5060.rs
rename to src/test/ui/macros/issue-5060.rs
diff --git a/src/test/ui/macros/issue-81006.rs b/src/test/ui/macros/issue-81006.rs
new file mode 100644
index 0000000..602eb59
--- /dev/null
+++ b/src/test/ui/macros/issue-81006.rs
@@ -0,0 +1,10 @@
+// check-fail
+
+// First format below would cause a panic, second would generate error with incorrect span
+
+fn main() {
+    let _ = format!("→{}→\n");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
+    let _ = format!("→{} \n");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
+}
diff --git a/src/test/ui/macros/issue-81006.stderr b/src/test/ui/macros/issue-81006.stderr
new file mode 100644
index 0000000..14a8cbe
--- /dev/null
+++ b/src/test/ui/macros/issue-81006.stderr
@@ -0,0 +1,14 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-81006.rs:6:23
+   |
+LL |     let _ = format!("→{}→\n");
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-81006.rs:8:23
+   |
+LL |     let _ = format!("→{} \n");
+   |                       ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/vec-macro-in-pattern.rs b/src/test/ui/macros/vec-macro-in-pattern.rs
new file mode 100644
index 0000000..ce4298b
--- /dev/null
+++ b/src/test/ui/macros/vec-macro-in-pattern.rs
@@ -0,0 +1,10 @@
+// This is a regression test for #61933
+// Verify that the vec![] macro may not be used in patterns
+// and that the resulting diagnostic is actually helpful.
+
+fn main() {
+    match Some(vec![42]) {
+        Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns
+        _ => {}
+    }
+}
diff --git a/src/test/ui/macros/vec-macro-in-pattern.stderr b/src/test/ui/macros/vec-macro-in-pattern.stderr
new file mode 100644
index 0000000..3dabebf
--- /dev/null
+++ b/src/test/ui/macros/vec-macro-in-pattern.stderr
@@ -0,0 +1,10 @@
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/vec-macro-in-pattern.rs:7:14
+   |
+LL |         Some(vec![43]) => {}
+   |              ^^^^^^^^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-66851.rs b/src/test/ui/mir/issue-66851.rs
similarity index 100%
rename from src/test/ui/issues/issue-66851.rs
rename to src/test/ui/mir/issue-66851.rs
diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs
new file mode 100644
index 0000000..c818f29
--- /dev/null
+++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags: -Z mir-opt-level=3
+
+#![crate_type="lib"]
+#![feature(lang_items)]
+#![no_std]
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+impl<T: ?Sized> Drop for Box<T> {
+    fn drop(&mut self) {
+    }
+}
+
+#[lang = "box_free"]
+#[inline(always)]
+unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+    dealloc(ptr)
+}
+
+#[inline(never)]
+fn dealloc<T: ?Sized>(_: *mut T) {
+}
+
+pub struct Foo<T>(T);
+
+pub fn foo(a: Option<Box<Foo<usize>>>) -> usize {
+    let f = match a {
+        None => Foo(0),
+        Some(vec) => *vec,
+    };
+    f.0
+}
diff --git a/src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs b/src/test/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
similarity index 100%
rename from src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs
rename to src/test/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
diff --git a/src/test/ui/issues/issue-51345-2.rs b/src/test/ui/nll/issue-51345-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-51345-2.rs
rename to src/test/ui/nll/issue-51345-2.rs
diff --git a/src/test/ui/issues/issue-51770.rs b/src/test/ui/nll/issue-51770.rs
similarity index 100%
rename from src/test/ui/issues/issue-51770.rs
rename to src/test/ui/nll/issue-51770.rs
diff --git a/src/test/ui/issues/issue-54943-3.rs b/src/test/ui/nll/issue-54943-3.rs
similarity index 100%
rename from src/test/ui/issues/issue-54943-3.rs
rename to src/test/ui/nll/issue-54943-3.rs
diff --git a/src/test/ui/issues/issue-55511.rs b/src/test/ui/nll/issue-55511.rs
similarity index 100%
rename from src/test/ui/issues/issue-55511.rs
rename to src/test/ui/nll/issue-55511.rs
diff --git a/src/test/ui/issues/issue-55511.stderr b/src/test/ui/nll/issue-55511.stderr
similarity index 100%
rename from src/test/ui/issues/issue-55511.stderr
rename to src/test/ui/nll/issue-55511.stderr
diff --git a/src/test/ui/non-built-in-quote.rs b/src/test/ui/non-built-in-quote.rs
deleted file mode 100644
index 92efa99..0000000
--- a/src/test/ui/non-built-in-quote.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-macro_rules! quote_tokens { () => (()) }
-
-pub fn main() {
-    quote_tokens!();
-}
diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr
similarity index 100%
rename from src/test/ui/issues/issue-8460-const.noopt.stderr
rename to src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr
diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr
similarity index 100%
rename from src/test/ui/issues/issue-8460-const.opt.stderr
rename to src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr
diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr
similarity index 100%
rename from src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr
rename to src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr
diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/numbers-arithmetic/issue-8460-const.rs
similarity index 100%
rename from src/test/ui/issues/issue-8460-const.rs
rename to src/test/ui/numbers-arithmetic/issue-8460-const.rs
diff --git a/src/test/ui/issues/issue-8460.rs b/src/test/ui/numbers-arithmetic/issue-8460.rs
similarity index 100%
rename from src/test/ui/issues/issue-8460.rs
rename to src/test/ui/numbers-arithmetic/issue-8460.rs
diff --git a/src/test/ui/issues/auxiliary/issue-21146-inc.rs b/src/test/ui/parser/auxiliary/issue-21146-inc.rs
similarity index 100%
rename from src/test/ui/issues/auxiliary/issue-21146-inc.rs
rename to src/test/ui/parser/auxiliary/issue-21146-inc.rs
diff --git a/src/test/ui/can-begin-expr-check.rs b/src/test/ui/parser/can-begin-expr-check.rs
similarity index 100%
rename from src/test/ui/can-begin-expr-check.rs
rename to src/test/ui/parser/can-begin-expr-check.rs
diff --git a/src/test/ui/can-begin-expr-check.stderr b/src/test/ui/parser/can-begin-expr-check.stderr
similarity index 100%
rename from src/test/ui/can-begin-expr-check.stderr
rename to src/test/ui/parser/can-begin-expr-check.stderr
diff --git a/src/test/ui/issues/issue-20616-1.rs b/src/test/ui/parser/issue-20616-1.rs
similarity index 100%
rename from src/test/ui/issues/issue-20616-1.rs
rename to src/test/ui/parser/issue-20616-1.rs
diff --git a/src/test/ui/issues/issue-20616-1.stderr b/src/test/ui/parser/issue-20616-1.stderr
similarity index 100%
rename from src/test/ui/issues/issue-20616-1.stderr
rename to src/test/ui/parser/issue-20616-1.stderr
diff --git a/src/test/ui/issues/issue-20616-2.rs b/src/test/ui/parser/issue-20616-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-20616-2.rs
rename to src/test/ui/parser/issue-20616-2.rs
diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/parser/issue-20616-2.stderr
similarity index 100%
rename from src/test/ui/issues/issue-20616-2.stderr
rename to src/test/ui/parser/issue-20616-2.stderr
diff --git a/src/test/ui/issues/issue-21146.rs b/src/test/ui/parser/issue-21146.rs
similarity index 100%
rename from src/test/ui/issues/issue-21146.rs
rename to src/test/ui/parser/issue-21146.rs
diff --git a/src/test/ui/issues/issue-21146.stderr b/src/test/ui/parser/issue-21146.stderr
similarity index 100%
rename from src/test/ui/issues/issue-21146.stderr
rename to src/test/ui/parser/issue-21146.stderr
diff --git a/src/test/ui/issues/issue-34222-1.rs b/src/test/ui/parser/issue-34222-1.rs
similarity index 100%
rename from src/test/ui/issues/issue-34222-1.rs
rename to src/test/ui/parser/issue-34222-1.rs
diff --git a/src/test/ui/issues/issue-34222-1.stderr b/src/test/ui/parser/issue-34222-1.stderr
similarity index 100%
rename from src/test/ui/issues/issue-34222-1.stderr
rename to src/test/ui/parser/issue-34222-1.stderr
diff --git a/src/test/ui/issues/issue-43196.rs b/src/test/ui/parser/issue-43196.rs
similarity index 100%
rename from src/test/ui/issues/issue-43196.rs
rename to src/test/ui/parser/issue-43196.rs
diff --git a/src/test/ui/issues/issue-43196.stderr b/src/test/ui/parser/issue-43196.stderr
similarity index 100%
rename from src/test/ui/issues/issue-43196.stderr
rename to src/test/ui/parser/issue-43196.stderr
diff --git a/src/test/ui/issues/issue-44021.rs b/src/test/ui/parser/issue-44021.rs
similarity index 100%
rename from src/test/ui/issues/issue-44021.rs
rename to src/test/ui/parser/issue-44021.rs
diff --git a/src/test/ui/issues/issue-44021.stderr b/src/test/ui/parser/issue-44021.stderr
similarity index 100%
rename from src/test/ui/issues/issue-44021.stderr
rename to src/test/ui/parser/issue-44021.stderr
diff --git a/src/test/ui/issues/issue-45296.rs b/src/test/ui/parser/issue-45296.rs
similarity index 100%
rename from src/test/ui/issues/issue-45296.rs
rename to src/test/ui/parser/issue-45296.rs
diff --git a/src/test/ui/issues/issue-45296.stderr b/src/test/ui/parser/issue-45296.stderr
similarity index 100%
rename from src/test/ui/issues/issue-45296.stderr
rename to src/test/ui/parser/issue-45296.stderr
diff --git a/src/test/ui/issues/issue-46186.fixed b/src/test/ui/parser/issue-46186.fixed
similarity index 100%
rename from src/test/ui/issues/issue-46186.fixed
rename to src/test/ui/parser/issue-46186.fixed
diff --git a/src/test/ui/issues/issue-46186.rs b/src/test/ui/parser/issue-46186.rs
similarity index 100%
rename from src/test/ui/issues/issue-46186.rs
rename to src/test/ui/parser/issue-46186.rs
diff --git a/src/test/ui/issues/issue-46186.stderr b/src/test/ui/parser/issue-46186.stderr
similarity index 100%
rename from src/test/ui/issues/issue-46186.stderr
rename to src/test/ui/parser/issue-46186.stderr
diff --git a/src/test/ui/issues/issue-51602.rs b/src/test/ui/parser/issue-51602.rs
similarity index 100%
rename from src/test/ui/issues/issue-51602.rs
rename to src/test/ui/parser/issue-51602.rs
diff --git a/src/test/ui/issues/issue-51602.stderr b/src/test/ui/parser/issue-51602.stderr
similarity index 100%
rename from src/test/ui/issues/issue-51602.stderr
rename to src/test/ui/parser/issue-51602.stderr
diff --git a/src/test/ui/issues/issue-52496.rs b/src/test/ui/parser/issue-52496.rs
similarity index 100%
rename from src/test/ui/issues/issue-52496.rs
rename to src/test/ui/parser/issue-52496.rs
diff --git a/src/test/ui/issues/issue-52496.stderr b/src/test/ui/parser/issue-52496.stderr
similarity index 100%
rename from src/test/ui/issues/issue-52496.stderr
rename to src/test/ui/parser/issue-52496.stderr
diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/parser/issue-58856-2.rs
similarity index 100%
rename from src/test/ui/issues/issue-58856-2.rs
rename to src/test/ui/parser/issue-58856-2.rs
diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/parser/issue-58856-2.stderr
similarity index 100%
rename from src/test/ui/issues/issue-58856-2.stderr
rename to src/test/ui/parser/issue-58856-2.stderr
diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/parser/issue-60075.rs
similarity index 100%
rename from src/test/ui/issues/issue-60075.rs
rename to src/test/ui/parser/issue-60075.rs
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/parser/issue-60075.stderr
similarity index 100%
rename from src/test/ui/issues/issue-60075.stderr
rename to src/test/ui/parser/issue-60075.stderr
diff --git a/src/test/ui/issues/issue-62554.rs b/src/test/ui/parser/issue-62554.rs
similarity index 100%
rename from src/test/ui/issues/issue-62554.rs
rename to src/test/ui/parser/issue-62554.rs
diff --git a/src/test/ui/issues/issue-62554.stderr b/src/test/ui/parser/issue-62554.stderr
similarity index 100%
rename from src/test/ui/issues/issue-62554.stderr
rename to src/test/ui/parser/issue-62554.stderr
diff --git a/src/test/ui/issues/issue-66473.rs b/src/test/ui/parser/issue-66473.rs
similarity index 100%
rename from src/test/ui/issues/issue-66473.rs
rename to src/test/ui/parser/issue-66473.rs
Binary files differ
diff --git a/src/test/ui/issues/issue-66473.stderr b/src/test/ui/parser/issue-66473.stderr
similarity index 100%
rename from src/test/ui/issues/issue-66473.stderr
rename to src/test/ui/parser/issue-66473.stderr
Binary files differ
diff --git a/src/test/ui/issues/issue-72253.rs b/src/test/ui/parser/issue-72253.rs
similarity index 100%
rename from src/test/ui/issues/issue-72253.rs
rename to src/test/ui/parser/issue-72253.rs
diff --git a/src/test/ui/issues/issue-72253.stderr b/src/test/ui/parser/issue-72253.stderr
similarity index 100%
rename from src/test/ui/issues/issue-72253.stderr
rename to src/test/ui/parser/issue-72253.stderr
diff --git a/src/test/ui/issues/issue-72373.rs b/src/test/ui/parser/issue-72373.rs
similarity index 100%
rename from src/test/ui/issues/issue-72373.rs
rename to src/test/ui/parser/issue-72373.rs
diff --git a/src/test/ui/issues/issue-72373.stderr b/src/test/ui/parser/issue-72373.stderr
similarity index 100%
rename from src/test/ui/issues/issue-72373.stderr
rename to src/test/ui/parser/issue-72373.stderr
diff --git a/src/test/ui/issues/issue-75599.rs b/src/test/ui/parser/issue-75599.rs
similarity index 100%
rename from src/test/ui/issues/issue-75599.rs
rename to src/test/ui/parser/issue-75599.rs
diff --git a/src/test/ui/issue-76597.fixed b/src/test/ui/parser/issue-76597.fixed
similarity index 100%
rename from src/test/ui/issue-76597.fixed
rename to src/test/ui/parser/issue-76597.fixed
diff --git a/src/test/ui/issue-76597.rs b/src/test/ui/parser/issue-76597.rs
similarity index 100%
rename from src/test/ui/issue-76597.rs
rename to src/test/ui/parser/issue-76597.rs
diff --git a/src/test/ui/issue-76597.stderr b/src/test/ui/parser/issue-76597.stderr
similarity index 100%
rename from src/test/ui/issue-76597.stderr
rename to src/test/ui/parser/issue-76597.stderr
diff --git a/src/test/ui/lifetime_starts_expressions.rs b/src/test/ui/parser/lifetime_starts_expressions.rs
similarity index 100%
rename from src/test/ui/lifetime_starts_expressions.rs
rename to src/test/ui/parser/lifetime_starts_expressions.rs
diff --git a/src/test/ui/lifetime_starts_expressions.stderr b/src/test/ui/parser/lifetime_starts_expressions.stderr
similarity index 100%
rename from src/test/ui/lifetime_starts_expressions.stderr
rename to src/test/ui/parser/lifetime_starts_expressions.stderr
diff --git a/src/test/ui/issues/issue-12582.rs b/src/test/ui/pattern/issue-12582.rs
similarity index 100%
rename from src/test/ui/issues/issue-12582.rs
rename to src/test/ui/pattern/issue-12582.rs
diff --git a/src/test/ui/issues/issue-14221.rs b/src/test/ui/pattern/issue-14221.rs
similarity index 100%
rename from src/test/ui/issues/issue-14221.rs
rename to src/test/ui/pattern/issue-14221.rs
diff --git a/src/test/ui/issues/issue-14221.stderr b/src/test/ui/pattern/issue-14221.stderr
similarity index 100%
rename from src/test/ui/issues/issue-14221.stderr
rename to src/test/ui/pattern/issue-14221.stderr
diff --git a/src/test/ui/issues/issue-22546.rs b/src/test/ui/pattern/issue-22546.rs
similarity index 100%
rename from src/test/ui/issues/issue-22546.rs
rename to src/test/ui/pattern/issue-22546.rs
diff --git a/src/test/ui/issues/issue-6449.rs b/src/test/ui/pattern/issue-6449.rs
similarity index 100%
rename from src/test/ui/issues/issue-6449.rs
rename to src/test/ui/pattern/issue-6449.rs
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
similarity index 100%
rename from src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
rename to src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
similarity index 100%
rename from src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
rename to src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
diff --git a/src/test/ui/size-and-align.rs b/src/test/ui/pattern/size-and-align.rs
similarity index 100%
rename from src/test/ui/size-and-align.rs
rename to src/test/ui/pattern/size-and-align.rs
diff --git a/src/test/ui/issues/issue-29161.rs b/src/test/ui/privacy/issue-29161.rs
similarity index 100%
rename from src/test/ui/issues/issue-29161.rs
rename to src/test/ui/privacy/issue-29161.rs
diff --git a/src/test/ui/issues/issue-29161.stderr b/src/test/ui/privacy/issue-29161.stderr
similarity index 100%
rename from src/test/ui/issues/issue-29161.stderr
rename to src/test/ui/privacy/issue-29161.stderr
diff --git a/src/test/ui/issues/issue-30079.rs b/src/test/ui/privacy/issue-30079.rs
similarity index 100%
rename from src/test/ui/issues/issue-30079.rs
rename to src/test/ui/privacy/issue-30079.rs
diff --git a/src/test/ui/issues/issue-30079.stderr b/src/test/ui/privacy/issue-30079.stderr
similarity index 100%
rename from src/test/ui/issues/issue-30079.stderr
rename to src/test/ui/privacy/issue-30079.stderr
diff --git a/src/test/ui/priv-in-bad-locations.rs b/src/test/ui/privacy/priv-in-bad-locations.rs
similarity index 100%
rename from src/test/ui/priv-in-bad-locations.rs
rename to src/test/ui/privacy/priv-in-bad-locations.rs
diff --git a/src/test/ui/priv-in-bad-locations.stderr b/src/test/ui/privacy/priv-in-bad-locations.stderr
similarity index 100%
rename from src/test/ui/priv-in-bad-locations.stderr
rename to src/test/ui/privacy/priv-in-bad-locations.stderr
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
index 142efb3..5f45f68 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
@@ -1,5 +1,5 @@
+// edition:2018
 // aux-build:builtin-attrs.rs
-
 #![feature(decl_macro)] //~ ERROR `feature` is ambiguous
 
 extern crate builtin_attrs;
@@ -31,3 +31,7 @@
     Bench;
     NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
 }
+
+use deny as allow;
+#[allow(unused)] //~ ERROR `allow` is ambiguous (built-in attribute vs any other name)
+fn builtin_renamed() {}
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
index 276ee1c..dfd60dc 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
@@ -60,6 +60,20 @@
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
+error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
+  --> $DIR/ambiguous-builtin-attrs.rs:36:3
+   |
+LL | #[allow(unused)]
+   |   ^^^^^ ambiguous name
+   |
+   = note: `allow` could refer to a built-in attribute
+note: `allow` could also refer to the built-in attribute imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:35:5
+   |
+LL | use deny as allow;
+   |     ^^^^^^^^^^^^^
+   = help: use `crate::allow` to refer to this built-in attribute unambiguously
+
 error[E0659]: `feature` is ambiguous (built-in attribute vs any other name)
   --> $DIR/ambiguous-builtin-attrs.rs:3:4
    |
@@ -80,7 +94,7 @@
 LL | fn non_macro_expanded_location<#[repr(C)] T>() {
    |                                       ^   - not a struct, enum, or union
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0425, E0517, E0659.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/unreachable-code-ret.rs b/src/test/ui/reachable/unreachable-code-ret.rs
similarity index 100%
rename from src/test/ui/unreachable-code-ret.rs
rename to src/test/ui/reachable/unreachable-code-ret.rs
diff --git a/src/test/ui/unreachable-code-ret.stderr b/src/test/ui/reachable/unreachable-code-ret.stderr
similarity index 100%
rename from src/test/ui/unreachable-code-ret.stderr
rename to src/test/ui/reachable/unreachable-code-ret.stderr
diff --git a/src/test/ui/issues/issue-12470.rs b/src/test/ui/regions/issue-12470.rs
similarity index 100%
rename from src/test/ui/issues/issue-12470.rs
rename to src/test/ui/regions/issue-12470.rs
diff --git a/src/test/ui/issues/issue-12470.stderr b/src/test/ui/regions/issue-12470.stderr
similarity index 100%
rename from src/test/ui/issues/issue-12470.stderr
rename to src/test/ui/regions/issue-12470.stderr
diff --git a/src/test/ui/issues/issue-24085.rs b/src/test/ui/regions/issue-24085.rs
similarity index 100%
rename from src/test/ui/issues/issue-24085.rs
rename to src/test/ui/regions/issue-24085.rs
diff --git a/src/test/ui/issues/issue-2718.rs b/src/test/ui/regions/issue-2718.rs
similarity index 100%
rename from src/test/ui/issues/issue-2718.rs
rename to src/test/ui/regions/issue-2718.rs
diff --git a/src/test/ui/issues/issue-28848.nll.stderr b/src/test/ui/regions/issue-28848.nll.stderr
similarity index 100%
rename from src/test/ui/issues/issue-28848.nll.stderr
rename to src/test/ui/regions/issue-28848.nll.stderr
diff --git a/src/test/ui/issues/issue-28848.rs b/src/test/ui/regions/issue-28848.rs
similarity index 100%
rename from src/test/ui/issues/issue-28848.rs
rename to src/test/ui/regions/issue-28848.rs
diff --git a/src/test/ui/issues/issue-28848.stderr b/src/test/ui/regions/issue-28848.stderr
similarity index 100%
rename from src/test/ui/issues/issue-28848.stderr
rename to src/test/ui/regions/issue-28848.stderr
diff --git a/src/test/ui/issues/issue-5243.rs b/src/test/ui/regions/issue-5243.rs
similarity index 100%
rename from src/test/ui/issues/issue-5243.rs
rename to src/test/ui/regions/issue-5243.rs
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index fee8b06..9220823 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,4 +1,4 @@
-error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,))`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)))`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
index cc57071..656564f 100644
--- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
@@ -22,7 +22,7 @@
 impl UnstableTrait for StableType {}
 
 #[unstable(feature = "x", issue = "none")]
-//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl]
+//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
 impl StableTrait for StableType {}
 
 fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
index 1915d03..a11479c 100644
--- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
@@ -4,7 +4,7 @@
 LL | #[unstable(feature = "x", issue = "none")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default
+   = note: `#[deny(ineffective_unstable_trait_impl)]` on by default
    = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.fixed b/src/test/ui/suggestions/vec-macro-in-pattern.fixed
deleted file mode 100644
index e1695d6..0000000
--- a/src/test/ui/suggestions/vec-macro-in-pattern.fixed
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-rustfix
-fn main() {
-    // everything after `.as_ref` should be suggested
-    match Some(vec![3]).as_ref().map(|v| v.as_slice()) {
-        Some([_x]) => (), //~ ERROR unexpected `(` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.rs b/src/test/ui/suggestions/vec-macro-in-pattern.rs
deleted file mode 100644
index 4843629..0000000
--- a/src/test/ui/suggestions/vec-macro-in-pattern.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-rustfix
-fn main() {
-    // everything after `.as_ref` should be suggested
-    match Some(vec![3]).as_ref().map(|v| v.as_slice()) {
-        Some(vec![_x]) => (), //~ ERROR unexpected `(` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.stderr b/src/test/ui/suggestions/vec-macro-in-pattern.stderr
deleted file mode 100644
index f9d0464..0000000
--- a/src/test/ui/suggestions/vec-macro-in-pattern.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: unexpected `(` after qualified path
-  --> $DIR/vec-macro-in-pattern.rs:5:14
-   |
-LL |         Some(vec![_x]) => (),
-   |              ^^^^^^^^
-   |              |
-   |              unexpected `(` after qualified path
-   |              the qualified path
-   |              in this macro invocation
-   |              help: use a slice pattern here instead: `[_x]`
-   |
-   = help: for more information, see https://doc.rust-lang.org/edition-guide/rust-2018/slice-patterns.html
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/eprint-on-tls-drop.rs b/src/test/ui/threads-sendsync/eprint-on-tls-drop.rs
similarity index 100%
rename from src/test/ui/eprint-on-tls-drop.rs
rename to src/test/ui/threads-sendsync/eprint-on-tls-drop.rs
diff --git a/src/test/ui/issues/issue-6334.rs b/src/test/ui/traits/issue-6334.rs
similarity index 100%
rename from src/test/ui/issues/issue-6334.rs
rename to src/test/ui/traits/issue-6334.rs
diff --git a/src/test/ui/issues/issue-65673.rs b/src/test/ui/traits/issue-65673.rs
similarity index 100%
rename from src/test/ui/issues/issue-65673.rs
rename to src/test/ui/traits/issue-65673.rs
diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/traits/issue-65673.stderr
similarity index 100%
rename from src/test/ui/issues/issue-65673.stderr
rename to src/test/ui/traits/issue-65673.stderr
diff --git a/src/test/ui/issues/issue-9394-inherited-trait-calls.rs b/src/test/ui/traits/issue-9394-inherited-trait-calls.rs
similarity index 100%
rename from src/test/ui/issues/issue-9394-inherited-trait-calls.rs
rename to src/test/ui/traits/issue-9394-inherited-trait-calls.rs
diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr
index ba393ff..755eec2 100644
--- a/src/test/ui/type/ascription/issue-47666.stderr
+++ b/src/test/ui/type/ascription/issue-47666.stderr
@@ -1,4 +1,4 @@
-error: expected type, found reserved keyword `box`
+error: expected type, found `<[_]>::into_vec(box [0, 1])`
   --> $DIR/issue-47666.rs:3:25
    |
 LL |     let _ = Option:Some(vec![0, 1]);
diff --git a/src/test/ui/typestate-cfg-nesting.rs b/src/test/ui/typestate-cfg-nesting.rs
deleted file mode 100644
index 5718e0e..0000000
--- a/src/test/ui/typestate-cfg-nesting.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_assignments)]
-#![allow(unknown_lints)]
-// pretty-expanded FIXME #23616
-
-#![allow(dead_assignment)]
-#![allow(unused_variables)]
-
-fn f() {
-    let x = 10; let mut y = 11;
-    if true { match x { _ => { y = x; } } } else { }
-}
-
-pub fn main() {
-    let x = 10;
-    let mut y = 11;
-    if true { while false { y = x; } } else { }
-}
diff --git a/src/test/ui/underscore-imports/hygiene.rs b/src/test/ui/underscore-imports/hygiene.rs
index a254f6e..c4db652 100644
--- a/src/test/ui/underscore-imports/hygiene.rs
+++ b/src/test/ui/underscore-imports/hygiene.rs
@@ -1,5 +1,6 @@
-// Make sure that underscore imports have the same hygiene considerations as
-// other imports.
+// Make sure that underscore imports have the same hygiene considerations as other imports.
+
+// check-pass
 
 #![feature(decl_macro)]
 
@@ -7,7 +8,6 @@
     pub use std::ops::Deref as _;
 }
 
-
 macro glob_import() {
     pub use crate::x::*;
 }
@@ -35,6 +35,6 @@
     use crate::z::*;
     glob_import!();
     underscore_import!();
-    (&()).deref();              //~ ERROR no method named `deref`
-    (&mut ()).deref_mut();      //~ ERROR no method named `deref_mut`
+    (&()).deref();
+    (&mut ()).deref_mut();
 }
diff --git a/src/test/ui/underscore-imports/hygiene.stderr b/src/test/ui/underscore-imports/hygiene.stderr
deleted file mode 100644
index 2983613..0000000
--- a/src/test/ui/underscore-imports/hygiene.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0599]: no method named `deref` found for reference `&()` in the current scope
-  --> $DIR/hygiene.rs:38:11
-   |
-LL |     (&()).deref();
-   |           ^^^^^ method not found in `&()`
-   |
-   = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
-   |
-LL | use std::ops::Deref;
-   |
-
-error[E0599]: no method named `deref_mut` found for mutable reference `&mut ()` in the current scope
-  --> $DIR/hygiene.rs:39:15
-   |
-LL |     (&mut ()).deref_mut();
-   |               ^^^^^^^^^ method not found in `&mut ()`
-   |
-   = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
-   |
-LL | use std::ops::DerefMut;
-   |
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
similarity index 100%
rename from src/test/ui/issues/issue-45087-unreachable-unsafe.rs
rename to src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
diff --git a/src/test/ui/issues/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
similarity index 100%
rename from src/test/ui/issues/issue-45087-unreachable-unsafe.stderr
rename to src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
diff --git a/src/test/ui/unsafe/unsafe-move-val-init.rs b/src/test/ui/unsafe/unsafe-move-val-init.rs
deleted file mode 100644
index 24249a7..0000000
--- a/src/test/ui/unsafe/unsafe-move-val-init.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(core_intrinsics)]
-
-use std::intrinsics;
-
-// `move_val_init` has an odd desugaring, check that it is still treated
-// as unsafe.
-fn main() {
-    intrinsics::move_val_init(1 as *mut u32, 1);
-    //~^ ERROR dereference of raw pointer is unsafe
-}
diff --git a/src/test/ui/unsafe/unsafe-move-val-init.stderr b/src/test/ui/unsafe/unsafe-move-val-init.stderr
deleted file mode 100644
index 44c2aae..0000000
--- a/src/test/ui/unsafe/unsafe-move-val-init.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-move-val-init.rs:8:5
-   |
-LL |     intrinsics::move_val_init(1 as *mut u32, 1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
-   |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/wasm/wasm-hang-issue-76281.rs b/src/test/ui/wasm/wasm-hang-issue-76281.rs
new file mode 100644
index 0000000..a4adfa6
--- /dev/null
+++ b/src/test/ui/wasm/wasm-hang-issue-76281.rs
@@ -0,0 +1,12 @@
+// only-wasm32
+// compile-flags: -C opt-level=2
+// build-pass
+
+// Regression test for #76281.
+// This seems like an issue related to LLVM rather than
+// libs-impl so place here.
+
+fn main() {
+    let mut v: Vec<&()> = Vec::new();
+    v.sort_by_key(|&r| r as *const ());
+}
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index de8da99..64864c2 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,138 @@
 
 ## Unreleased / In Rust Nightly
 
-[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master)
+[4911ab1...master](https://github.com/rust-lang/rust-clippy/compare/4911ab1...master)
+
+## Rust 1.50
+
+Current beta, release 2021-02-11
+
+[b20d4c1...4911ab1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4911ab1)
+
+### New Lints
+
+* [`suspicious_operation_groupings`] [#6086](https://github.com/rust-lang/rust-clippy/pull/6086)
+* [`size_of_in_element_count`] [#6394](https://github.com/rust-lang/rust-clippy/pull/6394)
+* [`unnecessary_wraps`] [#6070](https://github.com/rust-lang/rust-clippy/pull/6070)
+* [`let_underscore_drop`] [#6305](https://github.com/rust-lang/rust-clippy/pull/6305)
+* [`collapsible_match`] [#6402](https://github.com/rust-lang/rust-clippy/pull/6402)
+* [`redundant_else`] [#6330](https://github.com/rust-lang/rust-clippy/pull/6330)
+* [`zero_sized_map_values`] [#6218](https://github.com/rust-lang/rust-clippy/pull/6218)
+* [`print_stderr`] [#6367](https://github.com/rust-lang/rust-clippy/pull/6367)
+* [`string_from_utf8_as_bytes`] [#6134](https://github.com/rust-lang/rust-clippy/pull/6134)
+
+### Moves and Deprecations
+
+* Previously deprecated [`str_to_string`] and [`string_to_string`] have been un-deprecated
+  as `restriction` lints [#6333](https://github.com/rust-lang/rust-clippy/pull/6333)
+* Deprecate [`panic_params`] lint. This is now available in rustc as `panic_fmt`
+  [#6351](https://github.com/rust-lang/rust-clippy/pull/6351)
+* Move [`map_err_ignore`] to `restriction`
+  [#6416](https://github.com/rust-lang/rust-clippy/pull/6416)
+* Move [`await_holding_refcell_ref`] to `pedantic`
+  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
+* Move [`await_holding_lock`] to `pedantic`
+  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
+
+### Enhancements
+
+* Add the `unreadable-literal-lint-fractions` configuration to disable
+  the `unreadable_literal` lint for fractions
+  [#6421](https://github.com/rust-lang/rust-clippy/pull/6421)
+* [`clone_on_copy`]: Now shows the type in the lint message
+  [#6443](https://github.com/rust-lang/rust-clippy/pull/6443)
+* [`redundant_pattern_matching`]: Now also lints on `std::task::Poll`
+  [#6339](https://github.com/rust-lang/rust-clippy/pull/6339)
+* [`redundant_pattern_matching`]: Additionally also lints on `std::net::IpAddr`
+  [#6377](https://github.com/rust-lang/rust-clippy/pull/6377)
+* [`search_is_some`]: Now suggests `contains` instead of `find(foo).is_some()`
+  [#6119](https://github.com/rust-lang/rust-clippy/pull/6119)
+* [`clone_double_ref`]: Now prints the reference type in the lint message
+  [#6442](https://github.com/rust-lang/rust-clippy/pull/6442)
+* [`modulo_one`]: Now also lints on -1.
+  [#6360](https://github.com/rust-lang/rust-clippy/pull/6360)
+* [`empty_loop`]: Now lints no_std crates, too
+  [#6205](https://github.com/rust-lang/rust-clippy/pull/6205)
+* [`or_fun_call`]: Now also lints when indexing `HashMap` or `BTreeMap`
+  [#6267](https://github.com/rust-lang/rust-clippy/pull/6267)
+* [`wrong_self_convention`]: Now also lints in trait definitions
+  [#6316](https://github.com/rust-lang/rust-clippy/pull/6316)
+* [`needless_borrow`]: Print the type in the lint message
+  [#6449](https://github.com/rust-lang/rust-clippy/pull/6449)
+
+[msrv_readme]: https://github.com/rust-lang/rust-clippy#specifying-the-minimum-supported-rust-version
+
+### False Positive Fixes
+
+* [`manual_range_contains`]: No longer lints in `const fn`
+  [#6382](https://github.com/rust-lang/rust-clippy/pull/6382)
+* [`unnecessary_lazy_evaluations`]: No longer lints if closure argument is used
+  [#6370](https://github.com/rust-lang/rust-clippy/pull/6370)
+* [`match_single_binding`]: Now ignores cases with `#[cfg()]` macros
+  [#6435](https://github.com/rust-lang/rust-clippy/pull/6435)
+* [`match_like_matches_macro`]: No longer lints on arms with attributes
+  [#6290](https://github.com/rust-lang/rust-clippy/pull/6290)
+* [`map_clone`]: No longer lints with deref and clone
+  [#6269](https://github.com/rust-lang/rust-clippy/pull/6269)
+* [`map_clone`]: No longer lints in the case of &mut
+  [#6301](https://github.com/rust-lang/rust-clippy/pull/6301)
+* [`needless_update`]: Now ignores `non_exhaustive` structs
+  [#6464](https://github.com/rust-lang/rust-clippy/pull/6464)
+* [`needless_collect`]: No longer lints when a collect is needed multiple times
+  [#6313](https://github.com/rust-lang/rust-clippy/pull/6313)
+* [`unnecessary_cast`] No longer lints cfg-dependent types
+  [#6369](https://github.com/rust-lang/rust-clippy/pull/6369)
+* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
+  Both now ignore enums with frozen variants
+  [#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
+
+
+### Suggestion Fixes/Improvements
+
+* [`vec_box`]: Provide correct type scope suggestion
+  [#6271](https://github.com/rust-lang/rust-clippy/pull/6271)
+* [`manual_range_contains`]: Give correct suggestion when using floats
+  [#6320](https://github.com/rust-lang/rust-clippy/pull/6320)
+* [`unnecessary_lazy_evaluations`]: Don't always mark suggestion as MachineApplicable
+  [#6272](https://github.com/rust-lang/rust-clippy/pull/6272)
+* [`manual_async_fn`]: Improve suggestion formatting
+  [#6294](https://github.com/rust-lang/rust-clippy/pull/6294)
+* [`unnecessary_cast`]: Fix incorrectly formatted float literal suggestion
+  [#6362](https://github.com/rust-lang/rust-clippy/pull/6362)
+
+### ICE Fixes
+
+* Fix a crash in [`from_iter_instead_of_collect`]
+  [#6304](https://github.com/rust-lang/rust-clippy/pull/6304)
+* Fix a silent crash when parsing doc comments in [`needless_doctest_main`]
+  [#6458](https://github.com/rust-lang/rust-clippy/pull/6458)
+
+### Documentation Improvements
+
+* The lint website search has been improved ([#6477](https://github.com/rust-lang/rust-clippy/pull/6477)):
+  * Searching for lints with dashes and spaces is possible now. For example
+    `missing-errors-doc` and `missing errors doc` are now valid aliases for lint names
+  * Improved fuzzy search in lint descriptions
+* Various README improvements
+  [#6287](https://github.com/rust-lang/rust-clippy/pull/6287)
+* Add known problems to [`comparison_chain`] documentation
+  [#6390](https://github.com/rust-lang/rust-clippy/pull/6390)
+* Fix example used in [`cargo_common_metadata`]
+  [#6293](https://github.com/rust-lang/rust-clippy/pull/6293)
+* Improve [`map_clone`] documentation
+  [#6340](https://github.com/rust-lang/rust-clippy/pull/6340)
+
+### Others
+
+* You can now tell Clippy about the MSRV your project supports. Please refer to
+  the specific README section to learn more about MSRV support [here][msrv_readme]
+  [#6201](https://github.com/rust-lang/rust-clippy/pull/6201)
+* Add `--no-deps` option to avoid running on path dependencies in workspaces
+  [#6188](https://github.com/rust-lang/rust-clippy/pull/6188)
 
 ## Rust 1.49
 
-Current beta, release 2020-12-31
+Current stable, released 2020-12-31
 
 [e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 
@@ -116,7 +243,7 @@
 
 ## Rust 1.48
 
-Current stable, released 2020-11-19
+Released 2020-11-19
 
 [09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 
@@ -1769,6 +1896,7 @@
 [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
 [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
+[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
@@ -1973,6 +2101,7 @@
 [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
+[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
@@ -2012,6 +2141,7 @@
 [`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 [`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 [`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
+[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
@@ -2152,6 +2282,7 @@
 [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
+[`vec_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
 [`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs
index 645098e..b877806 100644
--- a/src/tools/clippy/clippy_dev/src/bless.rs
+++ b/src/tools/clippy/clippy_dev/src/bless.rs
@@ -5,7 +5,7 @@
 use std::ffi::OsStr;
 use std::fs;
 use std::lazy::SyncLazy;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use walkdir::WalkDir;
 
 use crate::clippy_project_root;
@@ -16,27 +16,41 @@
     None => env::current_dir().unwrap().join("target"),
 });
 
-pub fn bless() {
-    let test_dirs = [
+static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
+    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
+    let mut path = PathBuf::from(&**CARGO_TARGET_DIR);
+    path.push(profile);
+    path.push("cargo-clippy");
+    fs::metadata(path).ok()?.modified().ok()
+});
+
+pub fn bless(ignore_timestamp: bool) {
+    let test_suite_dirs = [
         clippy_project_root().join("tests").join("ui"),
+        clippy_project_root().join("tests").join("ui-internal"),
         clippy_project_root().join("tests").join("ui-toml"),
         clippy_project_root().join("tests").join("ui-cargo"),
     ];
-    for test_dir in &test_dirs {
-        WalkDir::new(test_dir)
+    for test_suite_dir in &test_suite_dirs {
+        WalkDir::new(test_suite_dir)
             .into_iter()
             .filter_map(Result::ok)
             .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
             .for_each(|f| {
-                update_reference_file(f.path().with_extension("stdout"));
-                update_reference_file(f.path().with_extension("stderr"));
-                update_reference_file(f.path().with_extension("fixed"));
+                let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
+                for &ext in &["stdout", "stderr", "fixed"] {
+                    update_reference_file(
+                        f.path().with_extension(ext),
+                        test_name.with_extension(ext),
+                        ignore_timestamp,
+                    );
+                }
             });
     }
 }
 
-fn update_reference_file(reference_file_path: PathBuf) {
-    let test_output_path = build_dir().join(PathBuf::from(reference_file_path.file_name().unwrap()));
+fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) {
+    let test_output_path = build_dir().join(test_name);
     let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
 
     // If compiletest did not write any changes during the test run,
@@ -45,6 +59,11 @@
         return;
     }
 
+    // If the test output was not updated since the last clippy build, it may be outdated
+    if !ignore_timestamp && !updated_since_clippy_build(&test_output_path).unwrap_or(true) {
+        return;
+    }
+
     let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
     let reference_file = fs::read(&reference_file_path).unwrap_or_default();
 
@@ -64,6 +83,12 @@
     }
 }
 
+fn updated_since_clippy_build(path: &Path) -> Option<bool> {
+    let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
+    let modified = fs::metadata(path).ok()?.modified().ok()?;
+    Some(modified >= clippy_build_time)
+}
+
 fn build_dir() -> PathBuf {
     let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
     let mut path = PathBuf::new();
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 4fdae38..2ea56c4 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -7,8 +7,8 @@
     let matches = get_clap_config();
 
     match matches.subcommand() {
-        ("bless", Some(_)) => {
-            bless::bless();
+        ("bless", Some(matches)) => {
+            bless::bless(matches.is_present("ignore-timestamp"));
         },
         ("fmt", Some(matches)) => {
             fmt::run(matches.is_present("check"), matches.is_present("verbose"));
@@ -47,7 +47,15 @@
 
 fn get_clap_config<'a>() -> ArgMatches<'a> {
     App::new("Clippy developer tooling")
-        .subcommand(SubCommand::with_name("bless").about("bless the test output changes"))
+        .subcommand(
+            SubCommand::with_name("bless")
+                .about("bless the test output changes")
+                .arg(
+                    Arg::with_name("ignore-timestamp")
+                        .long("ignore-timestamp")
+                        .help("Include files updated before clippy was built"),
+                ),
+        )
         .subcommand(
             SubCommand::with_name("fmt")
                 .about("Run rustfmt on all projects and tests")
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 3edbe723..652d1fa 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -10,11 +10,10 @@
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
 };
-use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 use rustc_span::symbol::{Symbol, SymbolStr};
@@ -157,33 +156,6 @@
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for `allow`/`warn`/`deny`/`forbid` attributes with scoped clippy
-    /// lints and if those lints exist in clippy. If there is an uppercase letter in the lint name
-    /// (not the tool name) and a lowercase version of this lint exists, it will suggest to lowercase
-    /// the lint name.
-    ///
-    /// **Why is this bad?** A lint attribute with a mistyped lint name won't have an effect.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// Bad:
-    /// ```rust
-    /// #![warn(if_not_els)]
-    /// #![deny(clippy::All)]
-    /// ```
-    ///
-    /// Good:
-    /// ```rust
-    /// #![warn(if_not_else)]
-    /// #![deny(clippy::all)]
-    /// ```
-    pub UNKNOWN_CLIPPY_LINTS,
-    style,
-    "unknown_lints for scoped Clippy lints"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
     ///
     /// **Why is this bad?** Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
@@ -272,7 +244,6 @@
     INLINE_ALWAYS,
     DEPRECATED_SEMVER,
     USELESS_ATTRIBUTE,
-    UNKNOWN_CLIPPY_LINTS,
     BLANKET_CLIPPY_RESTRICTION_LINTS,
 ]);
 
@@ -399,7 +370,7 @@
         if let Some(meta_item) = lint.meta_item();
         if meta_item.path.segments.len() > 1;
         if let tool_name = meta_item.path.segments[0].ident;
-        if tool_name.as_str() == "clippy";
+        if tool_name.name == sym::clippy;
         let lint_name = meta_item.path.segments.last().unwrap().ident.name;
         then {
             return Some(lint_name.as_str());
@@ -409,48 +380,9 @@
 }
 
 fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
-    let lint_store = cx.lints();
     for lint in items {
         if let Some(lint_name) = extract_clippy_lint(lint) {
-            if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym::clippy))
-            {
-                span_lint_and_then(
-                    cx,
-                    UNKNOWN_CLIPPY_LINTS,
-                    lint.span(),
-                    &format!("unknown clippy lint: clippy::{}", lint_name),
-                    |diag| {
-                        let name_lower = lint_name.to_lowercase();
-                        let symbols = lint_store
-                            .get_lints()
-                            .iter()
-                            .map(|l| Symbol::intern(&l.name_lower()))
-                            .collect::<Vec<_>>();
-                        let sugg = find_best_match_for_name(
-                            &symbols,
-                            Symbol::intern(&format!("clippy::{}", name_lower)),
-                            None,
-                        );
-                        if lint_name.chars().any(char::is_uppercase)
-                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok()
-                        {
-                            diag.span_suggestion(
-                                lint.span(),
-                                "lowercase the lint name",
-                                format!("clippy::{}", name_lower),
-                                Applicability::MachineApplicable,
-                            );
-                        } else if let Some(sugg) = sugg {
-                            diag.span_suggestion(
-                                lint.span(),
-                                "did you mean",
-                                sugg.to_string(),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    },
-                );
-            } else if lint_name == "restriction" && ident != "allow" {
+            if lint_name == "restriction" && ident != "allow" {
                 span_lint_and_help(
                     cx,
                     BLANKET_CLIPPY_RESTRICTION_LINTS,
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 42bff56..93ccc76 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -23,9 +23,7 @@
 
 declare_clippy_lint! {
     /// **What it does:** Checks for nested `if` statements which can be collapsed
-    /// by `&&`-combining their conditions and for `else { if ... }` expressions
-    /// that
-    /// can be collapsed to `else if ...`.
+    /// by `&&`-combining their conditions.
     ///
     /// **Why is this bad?** Each `if`-statement adds one level of nesting, which
     /// makes code look more complex than it really is.
@@ -40,7 +38,31 @@
     ///     }
     /// }
     ///
-    /// // or
+    /// ```
+    ///
+    /// Should be written:
+    ///
+    /// ```rust.ignore
+    /// if x && y {
+    ///     …
+    /// }
+    /// ```
+    pub COLLAPSIBLE_IF,
+    style,
+    "nested `if`s that can be collapsed (e.g., `if x { if y { ... } }`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for collapsible `else { if ... }` expressions
+    /// that can be collapsed to `else if ...`.
+    ///
+    /// **Why is this bad?** Each `if`-statement adds one level of nesting, which
+    /// makes code look more complex than it really is.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
     ///
     /// if x {
     ///     …
@@ -54,24 +76,18 @@
     /// Should be written:
     ///
     /// ```rust.ignore
-    /// if x && y {
-    ///     …
-    /// }
-    ///
-    /// // or
-    ///
     /// if x {
     ///     …
     /// } else if y {
     ///     …
     /// }
     /// ```
-    pub COLLAPSIBLE_IF,
+    pub COLLAPSIBLE_ELSE_IF,
     style,
-    "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)"
+    "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)"
 }
 
-declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF]);
+declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
 
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
@@ -112,7 +128,7 @@
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
-                COLLAPSIBLE_IF,
+                COLLAPSIBLE_ELSE_IF,
                 block.span,
                 "this `else { if .. }` block can be collapsed",
                 "collapse nested if block",
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index ae1143b..90d31de 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -13,7 +13,7 @@
     /// repetitive
     ///
     /// **Known problems:** The match statement may be slower due to the compiler
-    /// not inlining the call to cmp. See issue #5354
+    /// not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354)
     ///
     /// **Example:**
     /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 6f48ffe..944aaaf 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -112,7 +112,8 @@
             if let Some(&Expr {
                 kind: ExprKind::If(_, _, Some(ref else_expr)),
                 ..
-            }) = get_parent_expr(cx, expr) {
+            }) = get_parent_expr(cx, expr)
+            {
                 if else_expr.hir_id == expr.hir_id {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index a7aa2cb..48899b3 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -1,5 +1,5 @@
 use crate::utils::{is_copy, match_path, paths, span_lint_and_note};
-use rustc_hir::{Item, ItemKind, Impl};
+use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index b0d7c7b..f722481 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,4 +1,6 @@
-use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet};
+use crate::utils::{
+    any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet_with_macro_callsite,
+};
 use crate::utils::{span_lint_and_note, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
@@ -6,6 +8,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{Ident, Symbol};
@@ -118,6 +121,8 @@
                 // only take `let ...` statements
                 if let StmtKind::Local(local) = stmt.kind;
                 if let Some(expr) = local.init;
+                if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
+                if !in_external_macro(cx.tcx.sess, expr.span);
                 // only take bindings to identifiers
                 if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
                 // only when assigning `... = Default::default()`
@@ -187,7 +192,7 @@
                     .into_iter()
                     .map(|(field, rhs)| {
                         // extract and store the assigned value for help message
-                        let value_snippet = snippet(cx, rhs.span, "..");
+                        let value_snippet = snippet_with_macro_callsite(cx, rhs.span, "..");
                         format!("{}: {}", field, value_snippet)
                     })
                     .collect::<Vec<String>>()
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index bec0c9f..47b3cc3 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -163,6 +163,19 @@
 }
 
 declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** This lint has been uplifted to rustc and is now called
+    /// `panic_fmt`.
     pub PANIC_PARAMS,
     "this lint has been uplifted to rustc and is now called `panic_fmt`"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** This lint has been integrated into the `unknown_lints`
+    /// rustc lint.
+    pub UNKNOWN_CLIPPY_LINTS,
+    "this lint has been integrated into the `unknown_lints` rustc lint"
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index b55f59f..b1e3636 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -7,7 +7,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
-    BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Impl, TraitRef, UnsafeSource, Unsafety,
+    BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index a249117..853b3af 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -8,8 +8,12 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for `enum`s with no variants.
     ///
+    /// As of this writing, the `never_type` is still a
+    /// nightly-only experimental API. Therefore, this lint is only triggered
+    /// if the `never_type` is enabled.
+    ///
     /// **Why is this bad?** If you want to introduce a type which
-    /// can't be instantiated, you should use `!` (the never type),
+    /// can't be instantiated, you should use `!` (the primitive type "never"),
     /// or a wrapper around it, because `!` has more extensive
     /// compiler support (type inference, etc...) and wrappers
     /// around it are the conventional way to define an uninhabited type.
@@ -40,6 +44,11 @@
 
 impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        // Only suggest the `never_type` if the feature is enabled
+        if !cx.tcx.features().never_type {
+            return;
+        }
+
         let did = cx.tcx.hir().local_def_id(item.hir_id);
         if let ItemKind::Enum(..) = item.kind {
             let ty = cx.tcx.type_of(did);
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 5508769..40e93da 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,15 +1,16 @@
 use rustc_hir::intravisit;
-use rustc_hir::{self, Body, FnDecl, HirId, HirIdSet, ItemKind, Impl, Node};
+use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
+use rustc_span::symbol::kw;
 use rustc_target::abi::LayoutOf;
 use rustc_target::spec::abi::Abi;
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
-use crate::utils::span_lint;
+use crate::utils::{contains_ty, span_lint};
 
 #[derive(Copy, Clone)]
 pub struct BoxedLocal {
@@ -51,6 +52,7 @@
 struct EscapeDelegate<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     set: HirIdSet,
+    trait_self_ty: Option<Ty<'a>>,
     too_large_for_stack: u64,
 }
 
@@ -72,19 +74,34 @@
             }
         }
 
-        // If the method is an impl for a trait, don't warn.
         let parent_id = cx.tcx.hir().get_parent_item(hir_id);
         let parent_node = cx.tcx.hir().find(parent_id);
 
+        let mut trait_self_ty = None;
         if let Some(Node::Item(item)) = parent_node {
+            // If the method is an impl for a trait, don't warn.
             if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = item.kind {
                 return;
             }
+
+            // find `self` ty for this trait if relevant
+            if let ItemKind::Trait(_, _, _, _, items) = item.kind {
+                for trait_item in items {
+                    if trait_item.id.hir_id == hir_id {
+                        // be sure we have `self` parameter in this function
+                        if let AssocItemKind::Fn { has_self: true } = trait_item.kind {
+                            trait_self_ty =
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.hir_id.owner.to_def_id()).self_ty());
+                        }
+                    }
+                }
+            }
         }
 
         let mut v = EscapeDelegate {
             cx,
             set: HirIdSet::default(),
+            trait_self_ty,
             too_large_for_stack: self.too_large_for_stack,
         };
 
@@ -153,10 +170,17 @@
                     return;
                 }
 
+                // skip if there is a `self` parameter binding to a type
+                // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
+                if let Some(trait_self_ty) = self.trait_self_ty {
+                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) {
+                        return;
+                    }
+                }
+
                 if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) {
                     self.set.insert(cmt.hir_id);
                 }
-                return;
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 53df3ab..1a722d3 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -22,7 +22,7 @@
     /// **Known problems:** If creating the closure inside the closure has a side-
     /// effect then moving the closure creation out will change when that side-
     /// effect runs.
-    /// See rust-lang/rust-clippy#1439 for more details.
+    /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
     ///
     /// **Example:**
     /// ```rust,ignore
@@ -45,8 +45,9 @@
     ///
     /// **Why is this bad?** It's unnecessary to create the closure.
     ///
-    /// **Known problems:** rust-lang/rust-clippy#3071, rust-lang/rust-clippy#4002,
-    /// rust-lang/rust-clippy#3942
+    /// **Known problems:** [#3071](https://github.com/rust-lang/rust-clippy/issues/3071),
+    /// [#3942](https://github.com/rust-lang/rust-clippy/issues/3942),
+    /// [#4002](https://github.com/rust-lang/rust-clippy/issues/4002)
     ///
     ///
     /// **Example:**
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 1e7e5f5..b010abd 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -70,7 +70,7 @@
                 span_lint_and_help(
                     cx,
                     FROM_OVER_INTO,
-                    item.span,
+                    cx.tcx.sess.source_map().guess_head_span(item.span),
                     "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
                     None,
                     "consider to implement `From` instead",
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index f9697af..a3a38fa 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,7 +4,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{Opaque, PredicateAtom::Trait};
+use rustc_middle::ty::{Opaque, PredicateKind::Trait};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
@@ -97,7 +97,7 @@
                                         &obligation,
                                     );
                                     if let Trait(trait_pred, _) =
-                                        obligation.predicate.skip_binders()
+                                        obligation.predicate.kind().skip_binder()
                                     {
                                         db.note(&format!(
                                             "`{}` doesn't implement `{}`",
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index 2e55094..58511c6 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -145,7 +145,7 @@
 fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
         if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind;
-        if path.ident.to_string() == "lock";
+        if path.ident.as_str() == "lock";
         let ty = cx.typeck_results().expr_ty(&args[0]);
         if is_type_diagnostic_item(cx, ty, sym!(mutex_type));
         then {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index e287aec..ea26c84 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -2,7 +2,7 @@
 
 use crate::utils::{in_macro, span_lint_and_then};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{def_id, Crate, Item, ItemKind, Impl};
+use rustc_hir::{def_id, Crate, Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 5474b30..e95caf6 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -3,7 +3,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, Impl, TraitItemRef};
+use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, Impl, ImplItemRef, Item, ItemKind, TraitItemRef};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 35b057d..781282c 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -271,6 +271,7 @@
 mod needless_borrowed_ref;
 mod needless_continue;
 mod needless_pass_by_value;
+mod needless_question_mark;
 mod needless_update;
 mod neg_cmp_op_on_partial_ord;
 mod neg_multiply;
@@ -341,6 +342,7 @@
 mod use_self;
 mod useless_conversion;
 mod vec;
+mod vec_init_then_push;
 mod vec_resize_to_zero;
 mod verbose_file_reads;
 mod wildcard_dependencies;
@@ -500,6 +502,10 @@
         "clippy::panic_params",
         "this lint has been uplifted to rustc and is now called `panic_fmt`",
     );
+    store.register_removed(
+        "clippy::unknown_clippy_lints",
+        "this lint has been integrated into the `unknown_lints` rustc lint",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -524,6 +530,8 @@
         &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
         #[cfg(feature = "internal-lints")]
         &utils::internal_lints::PRODUCE_ICE,
+        #[cfg(feature = "internal-lints")]
+        &utils::internal_lints::UNNECESSARY_SYMBOL_STR,
         &approx_const::APPROX_CONSTANT,
         &arithmetic::FLOAT_ARITHMETIC,
         &arithmetic::INTEGER_ARITHMETIC,
@@ -541,7 +549,6 @@
         &attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
         &attrs::INLINE_ALWAYS,
         &attrs::MISMATCHED_TARGET_OS,
-        &attrs::UNKNOWN_CLIPPY_LINTS,
         &attrs::USELESS_ATTRIBUTE,
         &await_holding_invalid::AWAIT_HOLDING_LOCK,
         &await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
@@ -556,6 +563,7 @@
         &cargo_common_metadata::CARGO_COMMON_METADATA,
         &checked_conversions::CHECKED_CONVERSIONS,
         &cognitive_complexity::COGNITIVE_COMPLEXITY,
+        &collapsible_if::COLLAPSIBLE_ELSE_IF,
         &collapsible_if::COLLAPSIBLE_IF,
         &collapsible_match::COLLAPSIBLE_MATCH,
         &comparison_chain::COMPARISON_CHAIN,
@@ -799,6 +807,7 @@
         &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
         &needless_continue::NEEDLESS_CONTINUE,
         &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
+        &needless_question_mark::NEEDLESS_QUESTION_MARK,
         &needless_update::NEEDLESS_UPDATE,
         &neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
         &neg_multiply::NEG_MULTIPLY,
@@ -908,6 +917,7 @@
         &types::LET_UNIT_VALUE,
         &types::LINKEDLIST,
         &types::OPTION_OPTION,
+        &types::PTR_AS_PTR,
         &types::RC_BUFFER,
         &types::REDUNDANT_ALLOCATION,
         &types::TYPE_COMPLEXITY,
@@ -935,6 +945,7 @@
         &use_self::USE_SELF,
         &useless_conversion::USELESS_CONVERSION,
         &vec::USELESS_VEC,
+        &vec_init_then_push::VEC_INIT_THEN_PUSH,
         &vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
         &verbose_file_reads::VERBOSE_FILE_READS,
         &wildcard_dependencies::WILDCARD_DEPENDENCIES,
@@ -1019,6 +1030,7 @@
     store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
     store.register_late_pass(move || box use_self::UseSelf::new(msrv));
     store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv));
 
     store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
     store.register_late_pass(|| box map_clone::MapClone);
@@ -1215,6 +1227,8 @@
     store.register_late_pass(|| box strings::StrToString);
     store.register_late_pass(|| box strings::StringToString);
     store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+    store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1341,6 +1355,7 @@
         LintId::of(&types::LET_UNIT_VALUE),
         LintId::of(&types::LINKEDLIST),
         LintId::of(&types::OPTION_OPTION),
+        LintId::of(&types::PTR_AS_PTR),
         LintId::of(&unicode::NON_ASCII_LITERAL),
         LintId::of(&unicode::UNICODE_NOT_NFC),
         LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
@@ -1362,6 +1377,7 @@
         LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
         LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
         LintId::of(&utils::internal_lints::PRODUCE_ICE),
+        LintId::of(&utils::internal_lints::UNNECESSARY_SYMBOL_STR),
     ]);
 
     store.register_group(true, "clippy::all", Some("clippy"), vec![
@@ -1375,7 +1391,6 @@
         LintId::of(&attrs::DEPRECATED_CFG_ATTR),
         LintId::of(&attrs::DEPRECATED_SEMVER),
         LintId::of(&attrs::MISMATCHED_TARGET_OS),
-        LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
         LintId::of(&attrs::USELESS_ATTRIBUTE),
         LintId::of(&bit_mask::BAD_BIT_MASK),
         LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
@@ -1384,6 +1399,7 @@
         LintId::of(&booleans::LOGIC_BUG),
         LintId::of(&booleans::NONMINIMAL_BOOL),
         LintId::of(&bytecount::NAIVE_BYTECOUNT),
+        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
         LintId::of(&collapsible_if::COLLAPSIBLE_IF),
         LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
         LintId::of(&comparison_chain::COMPARISON_CHAIN),
@@ -1545,6 +1561,7 @@
         LintId::of(&needless_bool::BOOL_COMPARISON),
         LintId::of(&needless_bool::NEEDLESS_BOOL),
         LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+        LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK),
         LintId::of(&needless_update::NEEDLESS_UPDATE),
         LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
         LintId::of(&neg_multiply::NEG_MULTIPLY),
@@ -1636,6 +1653,7 @@
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&vec::USELESS_VEC),
+        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
         LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
         LintId::of(&write::PRINTLN_EMPTY_STRING),
         LintId::of(&write::PRINT_LITERAL),
@@ -1650,9 +1668,9 @@
         LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
         LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
-        LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
         LintId::of(&blacklisted_name::BLACKLISTED_NAME),
         LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
+        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
         LintId::of(&collapsible_if::COLLAPSIBLE_IF),
         LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
         LintId::of(&comparison_chain::COMPARISON_CHAIN),
@@ -1803,6 +1821,7 @@
         LintId::of(&needless_bool::BOOL_COMPARISON),
         LintId::of(&needless_bool::NEEDLESS_BOOL),
         LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+        LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK),
         LintId::of(&needless_update::NEEDLESS_UPDATE),
         LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
         LintId::of(&no_effect::NO_EFFECT),
@@ -1935,6 +1954,7 @@
         LintId::of(&types::BOX_VEC),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&vec::USELESS_VEC),
+        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
     ]);
 
     store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 281964e..1c5ab28 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -218,7 +218,7 @@
     /// **Why is this bad?** The `while let` loop is usually shorter and more
     /// readable.
     ///
-    /// **Known problems:** Sometimes the wrong binding is displayed (#383).
+    /// **Known problems:** Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)).
     ///
     /// **Example:**
     /// ```rust,no_run
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 29439e5..89f5b2f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -9,7 +9,7 @@
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** It checks for manual implementations of `async` functions.
@@ -137,7 +137,7 @@
         if let Some(args) = segment.args;
         if args.bindings.len() == 1;
         let binding = &args.bindings[0];
-        if binding.ident.as_str() == "Output";
+        if binding.ident.name == sym::Output;
         if let TypeBindingKind::Equality{ty: output} = binding.kind;
         then {
             return Some(output)
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 220240a..1818836 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -53,7 +53,7 @@
         if_chain! {
             if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
             if args.len() == 2;
-            if method.ident.as_str() == "map";
+            if method.ident.name == sym::map;
             let ty = cx.typeck_results().expr_ty(&args[0]);
             if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR);
             if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs
index 6b78238..9f9c108 100644
--- a/src/tools/clippy/clippy_lints/src/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/map_identity.rs
@@ -63,7 +63,7 @@
 fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> {
     if_chain! {
         if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
-        if args.len() == 2 && method.ident.as_str() == "map";
+        if args.len() == 2 && method.ident.name == sym::map;
         let caller_ty = cx.typeck_results().expr_ty(&args[0]);
         if match_trait_method(cx, expr, &paths::ITERATOR)
             || is_type_diagnostic_item(cx, caller_ty, sym::result_type)
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 6e81027..7adf6bd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1697,7 +1697,7 @@
             if let ty::Opaque(def_id, _) = *ret_ty.kind() {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                    if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
+                    if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
                         // walk the associated type and check for Self
                         if contains_ty(projection_predicate.ty, self_ty) {
                             return;
@@ -3096,7 +3096,7 @@
             if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind;
 
             if path.segments.len() == 1;
-            if path.segments[0].ident.as_str() == binding_ident.as_str();
+            if path.segments[0].ident.name == binding_ident.name;
 
             then {
                 apply_lint("called `flat_map(|x| x)` on an `Iterator`");
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index 004dd50..8d0c3b8 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -89,9 +89,9 @@
                 if let [obj, _] = args;
                 if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
                 then {
-                    if path.ident.as_str() == sym!(max).as_str() {
+                    if path.ident.name == sym!(max) {
                         fetch_const(cx, args, MinMax::Max)
-                    } else if path.ident.as_str() == sym!(min).as_str() {
+                    } else if path.ident.name == sym!(min) {
                         fetch_const(cx, args, MinMax::Min)
                     } else {
                         None
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 27f1074..0e49eaa 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -63,7 +63,7 @@
             if let Some(meta) = list.get(0);
             if let Some(name) = meta.ident();
             then {
-                name.as_str() == "include"
+                name.name == sym::include
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 6b9a37b..d795f12 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,9 +3,7 @@
 //! This lint is **warn** by default
 
 use crate::utils::sugg::Sugg;
-use crate::utils::{
-    is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg,
-};
+use crate::utils::{is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index bff53eb..f1c0669 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -2,7 +2,7 @@
 //!
 //! This lint is **warn** by default
 
-use crate::utils::{snippet_opt, span_lint_and_then};
+use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
@@ -10,7 +10,6 @@
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for address of operations (`&`) that are going to
@@ -116,7 +115,7 @@
     }
 
     fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) {
+        if is_automatically_derived(item.attrs) {
             debug_assert!(self.derived_item.is_none());
             self.derived_item = Some(item.hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index a435f86..89fe2c1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -8,11 +8,12 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, ItemKind, Impl, Node, PatKind, QPath, TyKind};
+use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, TypeFoldable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
@@ -115,13 +116,11 @@
             .filter(|p| !p.is_global())
             .filter_map(|obligation| {
                 // Note that we do not want to deal with qualified predicates here.
-                if let ty::PredicateKind::Atom(ty::PredicateAtom::Trait(pred, _)) = obligation.predicate.kind() {
-                    if pred.def_id() == sized_trait {
-                        return None;
-                    }
-                    Some(pred)
-                } else {
-                    None
+                match obligation.predicate.kind().no_bound_vars() {
+                    Some(ty::PredicateKind::Trait(pred, _)) if pred.def_id() != sized_trait => {
+                        Some(pred)
+                    },
+                    _ => None,
                 }
             })
             .collect::<Vec<_>>();
@@ -153,7 +152,7 @@
             // Ignore `self`s.
             if idx == 0 {
                 if let PatKind::Binding(.., ident, _) = arg.pat.kind {
-                    if ident.as_str() == "self" {
+                    if ident.name == kw::SelfLower {
                         continue;
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
new file mode 100644
index 0000000..9e9b79e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -0,0 +1,232 @@
+use rustc_errors::Applicability;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::DefIdTree;
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+
+use crate::utils;
+use if_chain::if_chain;
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Suggests alternatives for useless applications of `?` in terminating expressions
+    ///
+    /// **Why is this bad?** There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct TO {
+    ///     magic: Option<usize>,
+    /// }
+    ///
+    /// fn f(to: TO) -> Option<usize> {
+    ///     Some(to.magic?)
+    /// }
+    ///
+    /// struct TR {
+    ///     magic: Result<usize, bool>,
+    /// }
+    ///
+    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    ///     tr.and_then(|t| Ok(t.magic?))
+    /// }
+    ///
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct TO {
+    ///     magic: Option<usize>,
+    /// }
+    ///
+    /// fn f(to: TO) -> Option<usize> {
+    ///    to.magic
+    /// }
+    ///
+    /// struct TR {
+    ///     magic: Result<usize, bool>,
+    /// }
+    ///
+    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    ///     tr.and_then(|t| t.magic)
+    /// }
+    /// ```
+    pub NEEDLESS_QUESTION_MARK,
+    complexity,
+    "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
+}
+
+const NEEDLESS_QUESTION_MARK_RESULT_MSRV: RustcVersion = RustcVersion::new(1, 13, 0);
+const NEEDLESS_QUESTION_MARK_OPTION_MSRV: RustcVersion = RustcVersion::new(1, 22, 0);
+
+pub struct NeedlessQuestionMark {
+    msrv: Option<RustcVersion>,
+}
+
+impl NeedlessQuestionMark {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
+
+#[derive(Debug)]
+enum SomeOkCall<'a> {
+    SomeCall(&'a Expr<'a>, &'a Expr<'a>),
+    OkCall(&'a Expr<'a>, &'a Expr<'a>),
+}
+
+impl LateLintPass<'_> for NeedlessQuestionMark {
+    /*
+     * The question mark operator is compatible with both Result<T, E> and Option<T>,
+     * from Rust 1.13 and 1.22 respectively.
+     */
+
+    /*
+     * What do we match:
+     * Expressions that look like this:
+     * Some(option?), Ok(result?)
+     *
+     * Where do we match:
+     *      Last expression of a body
+     *      Return statement
+     *      A body's value (single line closure)
+     *
+     * What do we not match:
+     *      Implicit calls to `from(..)` on the error value
+     */
+
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        let e = match &expr.kind {
+            ExprKind::Ret(Some(e)) => e,
+            _ => return,
+        };
+
+        if let Some(ok_some_call) = is_some_or_ok_call(self, cx, e) {
+            emit_lint(cx, &ok_some_call);
+        }
+    }
+
+    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
+        // Function / Closure block
+        let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind {
+            block.expr
+        } else {
+            // Single line closure
+            Some(&body.value)
+        };
+
+        if_chain! {
+            if let Some(expr) = expr_opt;
+            if let Some(ok_some_call) = is_some_or_ok_call(self, cx, expr);
+            then {
+                emit_lint(cx, &ok_some_call);
+            }
+        };
+    }
+
+    extract_msrv_attr!(LateContext);
+}
+
+fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
+    let (entire_expr, inner_expr) = match expr {
+        SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner),
+    };
+
+    utils::span_lint_and_sugg(
+        cx,
+        NEEDLESS_QUESTION_MARK,
+        entire_expr.span,
+        "Question mark operator is useless here",
+        "try",
+        format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn is_some_or_ok_call<'a>(
+    nqml: &NeedlessQuestionMark,
+    cx: &'a LateContext<'_>,
+    expr: &'a Expr<'_>,
+) -> Option<SomeOkCall<'a>> {
+    if_chain! {
+        // Check outer expression matches CALL_IDENT(ARGUMENT) format
+        if let ExprKind::Call(path, args) = &expr.kind;
+        if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind;
+        if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res);
+
+        // Extract inner expression from ARGUMENT
+        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind;
+        if let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
+        if args.len() == 1;
+
+        if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind;
+        then {
+            // Extract inner expr type from match argument generated by
+            // question mark operator
+            let inner_expr = &args[0];
+
+            let inner_ty = cx.typeck_results().expr_ty(inner_expr);
+            let outer_ty = cx.typeck_results().expr_ty(expr);
+
+            // Check if outer and inner type are Option
+            let outer_is_some = utils::is_type_diagnostic_item(cx, outer_ty, sym::option_type);
+            let inner_is_some = utils::is_type_diagnostic_item(cx, inner_ty, sym::option_type);
+
+            // Check for Option MSRV
+            let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV);
+            if outer_is_some && inner_is_some && meets_option_msrv {
+                return Some(SomeOkCall::SomeCall(expr, inner_expr));
+            }
+
+            // Check if outer and inner type are Result
+            let outer_is_result = utils::is_type_diagnostic_item(cx, outer_ty, sym::result_type);
+            let inner_is_result = utils::is_type_diagnostic_item(cx, inner_ty, sym::result_type);
+
+            // Additional check: if the error type of the Result can be converted
+            // via the From trait, then don't match
+            let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);
+
+            // Must meet Result MSRV
+            let meets_result_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV);
+            if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv {
+                return Some(SomeOkCall::OkCall(expr, inner_expr));
+            }
+        }
+    }
+
+    None
+}
+
+fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool {
+    return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr);
+}
+
+fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool {
+    if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() {
+        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
+            if let Some(variant_id) = cx.tcx.parent(id) {
+                return variant_id == ok_id;
+            }
+        }
+    }
+    false
+}
+
+fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool {
+    if let Some(some_id) = cx.tcx.lang_items().option_some_variant() {
+        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
+            if let Some(variant_id) = cx.tcx.parent(id) {
+                return variant_id == some_id;
+            }
+        }
+    }
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 391f893..7bdf975 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -66,7 +66,7 @@
 /// Returns true iff the given expression is the result of calling `Result::ok`
 fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
     if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
-        path.ident.name.to_ident_string() == "ok"
+        path.ident.name.as_str() == "ok"
             && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type)
     } else {
         false
@@ -110,7 +110,7 @@
 fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
         let mut should_wrap = false;
-        
+
         if let Some(Expr {
             kind:
                 ExprKind::Match(
@@ -124,7 +124,11 @@
         }) = parent.expr
         {
             should_wrap = expr.hir_id == arms[1].body.hir_id;
-        } else if let Some(Expr { kind: ExprKind::If(_, _, Some(else_clause)), .. }) = parent.expr {
+        } else if let Some(Expr {
+            kind: ExprKind::If(_, _, Some(else_clause)),
+            ..
+        }) = parent.expr
+        {
             should_wrap = expr.hir_id == else_clause.hir_id;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 04b6e5d..ed31493 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -1,6 +1,6 @@
 use crate::utils::{is_automatically_derived, span_lint_hir};
 use if_chain::if_chain;
-use rustc_hir::{Item, ItemKind, Impl};
+use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 7814065..d96a9b0 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -6,7 +6,7 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node, PatKind, Impl};
+use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -63,7 +63,7 @@
     ///
     /// **Why is this bad?** Arguments passed by value might result in an unnecessary
     /// shallow copy, taking up more space in the stack and requiring a call to
-    /// `memcpy`, which which can be expensive.
+    /// `memcpy`, which can be expensive.
     ///
     /// **Example:**
     ///
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index b832add..c6329a1 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -8,8 +8,8 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Impl,
-    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
+    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
+    ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 803ebad..8cd6692 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -13,7 +13,7 @@
     /// **Why is this bad?** Since `&` is Copy, it's useless to have a
     /// reference on `Option<&T>`.
     ///
-    /// **Known problems:** It may be irrevelent to use this lint on
+    /// **Known problems:** It may be irrelevant to use this lint on
     /// public API code as it will make a breaking change to apply it.
     ///
     /// **Example:**
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 35827e0..63548d8 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -202,7 +202,7 @@
                     check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
                 }
             },
-            | MatchSource::IfLetDesugar {
+            MatchSource::IfLetDesugar {
                 contains_else_clause: true,
             } => {
                 if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
@@ -217,6 +217,9 @@
 }
 
 fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
+    if ret_span.from_expansion() {
+        return;
+    }
     match inner_span {
         Some(inner_span) => {
             if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index ca4fd9f..44e7397 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -1,5 +1,5 @@
 use crate::utils::{get_trait_def_id, paths, span_lint};
-use rustc_hir::{Item, ItemKind, Impl};
+use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index f2f3dfa..24da056 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -396,5 +396,5 @@
 }
 
 fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool {
-    !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.as_str() == name.as_str()
+    !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.name == name
 }
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 386987e..699fd51 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -91,7 +91,7 @@
             if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind;
             if rhs2.segments.len() == 1;
 
-            if ident.as_str() == rhs2.segments[0].ident.as_str();
+            if ident.name == rhs2.segments[0].ident.name;
             if eq_expr_value(cx, tmp_init, lhs1);
             if eq_expr_value(cx, rhs1, lhs2);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
index 675eaf4..c53727b 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
@@ -1,7 +1,7 @@
 use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint};
 use if_chain::if_chain;
 use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Impl};
+use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index 2696c5e..3b5a83d 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -8,7 +8,6 @@
 use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
     BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId,
@@ -19,7 +18,8 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckResults};
+use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults};
+use rustc_semver::RustcVersion;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::Span;
@@ -30,11 +30,13 @@
 
 use crate::consts::{constant, Constant};
 use crate::utils::paths;
+use crate::utils::sugg::Sugg;
 use crate::utils::{
-    clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item,
-    last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral,
-    qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite,
-    span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
+    clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_hir_ty_cfg_dependant,
+    is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args,
+    multispan_sugg, numeric_literal::NumericLiteral, qpath_res, reindent_multiline, sext, snippet, snippet_opt,
+    snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
+    span_lint_and_then, unsext,
 };
 
 declare_clippy_lint! {
@@ -73,7 +75,7 @@
     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
     /// the heap. So if you `Box` its contents, you just add another level of indirection.
     ///
-    /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see #3530,
+    /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
     /// 1st comment).
     ///
     /// **Example:**
@@ -1279,8 +1281,8 @@
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for casts from a less-strictly-aligned pointer to a
-    /// more-strictly-aligned pointer
+    /// **What it does:** Checks for casts, using `as` or `pointer::cast`,
+    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
     ///
     /// **Why is this bad?** Dereferencing the resulting pointer may be undefined
     /// behavior.
@@ -1293,6 +1295,9 @@
     /// ```rust
     /// let _ = (&1u8 as *const u8) as *const u16;
     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
+    ///
+    /// (&1u8 as *const u8).cast::<u16>();
+    /// (&mut 1u8 as *mut u8).cast::<u16>();
     /// ```
     pub CAST_PTR_ALIGNMENT,
     pedantic,
@@ -1634,12 +1639,8 @@
             return;
         }
         if let ExprKind::Cast(ref ex, cast_to) = expr.kind {
-            if let TyKind::Path(QPath::Resolved(_, path)) = cast_to.kind {
-                if let Res::Def(_, def_id) = path.res {
-                    if cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr) {
-                        return;
-                    }
-                }
+            if is_hir_ty_cfg_dependant(cx, cast_to) {
+                return;
             }
             let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
@@ -1689,6 +1690,19 @@
             }
 
             lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
+        } else if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind {
+            if_chain! {
+            if method_path.ident.name == sym!(cast);
+            if let Some(generic_args) = method_path.args;
+            if let [GenericArg::Type(cast_to)] = generic_args.args;
+            // There probably is no obvious reason to do this, just to be consistent with `as` cases.
+            if !is_hir_ty_cfg_dependant(cx, cast_to);
+            then {
+                let (cast_from, cast_to) =
+                    (cx.typeck_results().expr_ty(&args[0]), cx.typeck_results().expr_ty(expr));
+                lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
+            }
+            }
         }
     }
 }
@@ -2873,3 +2887,93 @@
         }
     }
 }
+
+const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0);
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Checks for `as` casts between raw pointers without changing its mutability,
+    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+    ///
+    /// **Why is this bad?**
+    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
+    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr: *mut u32 = &mut 42_u32;
+    /// let _ = ptr as *const i32;
+    /// let _ = mut_ptr as *mut i32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr: *mut u32 = &mut 42_u32;
+    /// let _ = ptr.cast::<i32>();
+    /// let _ = mut_ptr.cast::<i32>();
+    /// ```
+    pub PTR_AS_PTR,
+    pedantic,
+    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
+}
+
+pub struct PtrAsPtr {
+    msrv: Option<RustcVersion>,
+}
+
+impl PtrAsPtr {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(PtrAsPtr => [PTR_AS_PTR]);
+
+impl<'tcx> LateLintPass<'tcx> for PtrAsPtr {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &PTR_AS_PTR_MSRV) {
+            return;
+        }
+
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
+            let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
+            if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
+            if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
+            if matches!((from_mutbl, to_mutbl),
+                (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
+            // The `U` in `pointer::cast` have to be `Sized`
+            // as explained here: https://github.com/rust-lang/rust/issues/60602.
+            if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
+                let turbofish = match &cast_to_hir_ty.kind {
+                        TyKind::Infer => Cow::Borrowed(""),
+                        TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
+                        _ => Cow::Owned(format!("::<{}>", to_pointee_ty)),
+                    };
+                span_lint_and_sugg(
+                    cx,
+                    PTR_AS_PTR,
+                    expr.span,
+                    "`as` casting between raw pointers without changing its mutability",
+                    "try `pointer::cast`, a safer alternative",
+                    format!("{}.cast{}()", cast_expr_sugg.maybe_par(), turbofish),
+                    applicability,
+                );
+            }
+        }
+    }
+
+    extract_msrv_attr!(LateContext);
+}
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 2501635..c6ae8b9 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -4,7 +4,7 @@
 use rustc_hir::{Expr, ExprKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_middle::ty::{GenericPredicates, PredicateAtom, ProjectionPredicate, TraitPredicate};
+use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{BytePos, Span};
 
@@ -42,7 +42,7 @@
     let mut preds = Vec::new();
     for (pred, _) in generics.predicates {
         if_chain! {
-            if let PredicateAtom::Trait(poly_trait_pred, _) = pred.skip_binders();
+            if let PredicateKind::Trait(poly_trait_pred, _) = pred.kind().skip_binder();
             let trait_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(poly_trait_pred));
             if let Some(trait_def_id) = trait_id;
             if trait_def_id == trait_pred.trait_ref.def_id;
@@ -60,7 +60,7 @@
     pred: TraitPredicate<'tcx>,
 ) -> Option<ProjectionPredicate<'tcx>> {
     generics.predicates.iter().find_map(|(proj_pred, _)| {
-        if let ty::PredicateAtom::Projection(proj_pred) = proj_pred.skip_binders() {
+        if let ty::PredicateKind::Projection(proj_pred) = proj_pred.kind().skip_binder() {
             let projection_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(proj_pred));
             if projection_pred.projection_ty.substs == pred.trait_ref.substs {
                 return Some(projection_pred);
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 0bccfc1..9b45d38 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -183,7 +183,7 @@
             Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
         ] = &closure_body.params;
         if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
-        if method_path.ident.name.to_ident_string() == "cmp";
+        if method_path.ident.name == sym::cmp;
         then {
             let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                 &cx,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 07cd752..8ac5dd6 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -5,7 +5,7 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Impl, Node};
+use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index a617179..5349c4f 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,7 +1,7 @@
 use if_chain::if_chain;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor};
-use rustc_hir::{HirId, ImplItem, ImplItemKind, ItemKind, Impl, Path};
+use rustc_hir::{HirId, Impl, ImplItem, ImplItemKind, ItemKind, Path};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 6a87f53..b82909e 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,6 +1,5 @@
 use crate::utils::{
-    differing_macro_contexts, is_type_diagnostic_item, span_lint_and_then,
-    usage::is_potentially_mutated,
+    differing_macro_contexts, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated,
 };
 use if_chain::if_chain;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index b82ea66..72d1ca7 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -28,8 +28,8 @@
     /// feels inconsistent.
     ///
     /// **Known problems:**
-    /// - False positive when using associated types (#2843)
-    /// - False positives in some situations when using generics (#3410)
+    /// - False positive when using associated types ([#2843](https://github.com/rust-lang/rust-clippy/issues/2843))
+    /// - False positives in some situations when using generics ([#3410](https://github.com/rust-lang/rust-clippy/issues/3410))
     ///
     /// **Example:**
     /// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index efa9c3f..c533485 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -80,10 +80,10 @@
                         );
                     }
                 }
-                if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
+                if match_trait_method(cx, e, &paths::INTO_ITERATOR) && name.ident.name == sym::into_iter {
                     if let Some(parent_expr) = get_parent_expr(cx, e) {
                         if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
-                            if &*parent_name.ident.as_str() != "into_iter" {
+                            if parent_name.ident.name != sym::into_iter {
                                 return;
                             }
                         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/attrs.rs b/src/tools/clippy/clippy_lints/src/utils/attrs.rs
index 24052a2..8d28421 100644
--- a/src/tools/clippy/clippy_lints/src/utils/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/attrs.rs
@@ -1,6 +1,7 @@
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_session::Session;
+use rustc_span::sym;
 use std::str::FromStr;
 
 /// Deprecation status of attributes known by Clippy.
@@ -64,11 +65,11 @@
             return false;
         };
         let attr_segments = &attr.path.segments;
-        if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" {
+        if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy {
             BUILTIN_ATTRIBUTES
                 .iter()
-                .find_map(|(builtin_name, deprecation_status)| {
-                    if *builtin_name == attr_segments[1].ident.to_string() {
+                .find_map(|&(builtin_name, ref deprecation_status)| {
+                    if attr_segments[1].ident.name.as_str() == builtin_name {
                         Some(deprecation_status)
                     } else {
                         None
@@ -99,7 +100,7 @@
                             },
                             DeprecationStatus::None => {
                                 diag.cancel();
-                                attr_segments[1].ident.to_string() == name
+                                attr_segments[1].ident.name.as_str() == name
                             },
                         }
                     },
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 062df68..10120a8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -86,7 +86,7 @@
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
             },
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
-                both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
+                both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
             },
             (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
                 self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
@@ -102,7 +102,7 @@
                     })
             },
             (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
-                both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
+                both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
                     && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
@@ -124,7 +124,7 @@
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
             (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
-                lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str())
+                lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
             },
             (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
                 ls == rs
@@ -191,7 +191,7 @@
 
     pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
         let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right);
-        li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp)
+        li.name == ri.name && self.eq_pat(lp, rp)
     }
 
     /// Checks whether two patterns are the same.
@@ -205,7 +205,7 @@
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
             (&PatKind::Binding(ref lb, .., ref li, ref lp), &PatKind::Binding(ref rb, .., ref ri, ref rp)) => {
-                lb == rb && li.name.as_str() == ri.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
+                lb == rb && li.name == ri.name && both(lp, rp, |l, r| self.eq_pat(l, r))
             },
             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
             (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
@@ -266,8 +266,7 @@
     pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
         // The == of idents doesn't work with different contexts,
         // we have to be explicit about hygiene
-        left.ident.as_str() == right.ident.as_str()
-            && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
+        left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
     }
 
     pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 407f06f..7aa1752 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -10,9 +10,12 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind};
+use rustc_hir::{
+    BinOpKind, Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind, UnOp,
+};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::mir::interpret::ConstValue;
@@ -272,6 +275,28 @@
     "interning a symbol that is pre-interned and defined as a constant"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for unnecessary conversion from Symbol to a string.
+    ///
+    /// **Why is this bad?** It's faster use symbols directly intead of strings.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust,ignore
+    /// symbol.as_str() == "clippy";
+    /// ```
+    ///
+    /// Good:
+    /// ```rust,ignore
+    /// symbol == sym::clippy;
+    /// ```
+    pub UNNECESSARY_SYMBOL_STR,
+    internal,
+    "unnecessary conversion between Symbol and string"
+}
+
 declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 
 impl EarlyLintPass for ClippyLintsInternal {
@@ -868,11 +893,11 @@
 
 #[derive(Default)]
 pub struct InterningDefinedSymbol {
-    // Maps the symbol value to the constant name.
-    symbol_map: FxHashMap<u32, String>,
+    // Maps the symbol value to the constant DefId.
+    symbol_map: FxHashMap<u32, DefId>,
 }
 
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL]);
+impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
 
 impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
     fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
@@ -880,16 +905,18 @@
             return;
         }
 
-        if let Some(Res::Def(_, def_id)) = path_to_res(cx, &paths::SYM_MODULE) {
-            for item in cx.tcx.item_children(def_id).iter() {
-                if_chain! {
-                    if let Res::Def(DefKind::Const, item_def_id) = item.res;
-                    let ty = cx.tcx.type_of(item_def_id);
-                    if match_type(cx, ty, &paths::SYMBOL);
-                    if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
-                    if let Ok(value) = value.to_u32();
-                    then {
-                        self.symbol_map.insert(value, item.ident.to_string());
+        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
+            if let Some(Res::Def(_, def_id)) = path_to_res(cx, module) {
+                for item in cx.tcx.item_children(def_id).iter() {
+                    if_chain! {
+                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
+                        let ty = cx.tcx.type_of(item_def_id);
+                        if match_type(cx, ty, &paths::SYMBOL);
+                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
+                        if let Ok(value) = value.to_u32();
+                        then {
+                            self.symbol_map.insert(value, item_def_id);
+                        }
                     }
                 }
             }
@@ -903,7 +930,7 @@
             if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
             if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
             let value = Symbol::intern(&arg).as_u32();
-            if let Some(symbol_const) = self.symbol_map.get(&value);
+            if let Some(&def_id) = self.symbol_map.get(&value);
             then {
                 span_lint_and_sugg(
                     cx,
@@ -911,10 +938,135 @@
                     is_expn_of(expr.span, "sym").unwrap_or(expr.span),
                     "interning a defined symbol",
                     "try",
-                    format!("rustc_span::symbol::sym::{}", symbol_const),
+                    cx.tcx.def_path_str(def_id),
                     Applicability::MachineApplicable,
                 );
             }
         }
+        if let ExprKind::Binary(op, left, right) = expr.kind {
+            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
+                let data = [
+                    (left, self.symbol_str_expr(left, cx)),
+                    (right, self.symbol_str_expr(right, cx)),
+                ];
+                match data {
+                    // both operands are a symbol string
+                    [(_, Some(left)), (_, Some(right))] => {
+                        span_lint_and_sugg(
+                            cx,
+                            UNNECESSARY_SYMBOL_STR,
+                            expr.span,
+                            "unnecessary `Symbol` to string conversion",
+                            "try",
+                            format!(
+                                "{} {} {}",
+                                left.as_symbol_snippet(cx),
+                                op.node.as_str(),
+                                right.as_symbol_snippet(cx),
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    },
+                    // one of the operands is a symbol string
+                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
+                        // creating an owned string for comparison
+                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
+                            span_lint_and_sugg(
+                                cx,
+                                UNNECESSARY_SYMBOL_STR,
+                                expr.span,
+                                "unnecessary string allocation",
+                                "try",
+                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    },
+                    // nothing found
+                    [(_, None), (_, None)] => {},
+                }
+            }
+        }
+    }
+}
+
+impl InterningDefinedSymbol {
+    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
+        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
+        static SYMBOL_STR_PATHS: &[&[&str]] = &[
+            &paths::SYMBOL_AS_STR,
+            &paths::SYMBOL_TO_IDENT_STRING,
+            &paths::TO_STRING_METHOD,
+        ];
+        // SymbolStr might be de-referenced: `&*symbol.as_str()`
+        let call = if_chain! {
+            if let ExprKind::AddrOf(_, _, e) = expr.kind;
+            if let ExprKind::Unary(UnOp::UnDeref, e) = e.kind;
+            then { e } else { expr }
+        };
+        if_chain! {
+            // is a method call
+            if let ExprKind::MethodCall(_, _, [item], _) = call.kind;
+            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
+            let ty = cx.typeck_results().expr_ty(item);
+            // ...on either an Ident or a Symbol
+            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
+                Some(false)
+            } else if match_type(cx, ty, &paths::IDENT) {
+                Some(true)
+            } else {
+                None
+            };
+            // ...which converts it to a string
+            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
+            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+            then {
+                let is_to_owned = path.last().unwrap().ends_with("string");
+                return Some(SymbolStrExpr::Expr {
+                    item,
+                    is_ident,
+                    is_to_owned,
+                });
+            }
+        }
+        // is a string constant
+        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
+            let value = Symbol::intern(&s).as_u32();
+            // ...which matches a symbol constant
+            if let Some(&def_id) = self.symbol_map.get(&value) {
+                return Some(SymbolStrExpr::Const(def_id));
+            }
+        }
+        None
+    }
+}
+
+enum SymbolStrExpr<'tcx> {
+    /// a string constant with a corresponding symbol constant
+    Const(DefId),
+    /// a "symbol to string" expression like `symbol.as_str()`
+    Expr {
+        /// part that evaluates to `Symbol` or `Ident`
+        item: &'tcx Expr<'tcx>,
+        is_ident: bool,
+        /// whether an owned `String` is created like `to_ident_string()`
+        is_to_owned: bool,
+    },
+}
+
+impl<'tcx> SymbolStrExpr<'tcx> {
+    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
+    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
+        match *self {
+            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
+            Self::Expr { item, is_ident, .. } => {
+                let mut snip = snippet(cx, item.span.source_callsite(), "..");
+                if is_ident {
+                    // get `Ident.name`
+                    snip.to_mut().push_str(".name");
+                }
+                snip
+            },
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 3e39a47..9b26251 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -1,5 +1,5 @@
 #[macro_use]
-pub mod sym;
+pub mod sym_helper;
 
 #[allow(clippy::module_name_repetitions)]
 pub mod ast_utils;
@@ -56,8 +56,8 @@
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
-use rustc_span::sym as rustc_sym;
-use rustc_span::symbol::{self, kw, Symbol};
+use rustc_span::sym;
+use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
 use rustc_trait_selection::traits::query::normalize::AtExt;
@@ -1121,7 +1121,7 @@
 /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 /// implementations have.
 pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| attr.has_name(rustc_sym::automatically_derived))
+    attrs.iter().any(|attr| attr.has_name(sym::automatically_derived))
 }
 
 /// Remove blocks around an expression.
@@ -1434,12 +1434,13 @@
     let map = cx.tcx.hir();
     let parent_id = map.get_parent_node(expr.hir_id);
     let parent_node = map.get(parent_id);
-    if let Node::Expr(Expr { kind: ExprKind::If(_, _, _), .. }) = parent_node {
-        true
-    }
-    else {
-        false
-    }
+    matches!(
+        parent_node,
+        Node::Expr(Expr {
+            kind: ExprKind::If(_, _, _),
+            ..
+        })
+    )
 }
 
 // Finds the attribute with the given name, if any
@@ -1470,7 +1471,7 @@
         ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
-                if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() {
+                if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
                     if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
                     }
@@ -1514,7 +1515,7 @@
 pub fn is_no_std_crate(krate: &Crate<'_>) -> bool {
     krate.item.attrs.iter().any(|attr| {
         if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
-            attr.path == symbol::sym::no_std
+            attr.path == sym::no_std
         } else {
             false
         }
@@ -1686,6 +1687,18 @@
     }};
 }
 
+pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
+    if_chain! {
+        if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
+        if let Res::Def(_, def_id) = path.res;
+        then {
+            cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
+        } else {
+            false
+        }
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::{reindent_multiline, without_block_comments};
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 2080a49..c0b203b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -54,6 +54,10 @@
 pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
 pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
+#[cfg(feature = "internal-lints")]
+pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
+#[cfg(feature = "internal-lints")]
+pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
 pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
 pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
@@ -65,6 +69,8 @@
 pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"];
 pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
 #[cfg(feature = "internal-lints")]
+pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
+#[cfg(feature = "internal-lints")]
 pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
 pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
 #[cfg(feature = "internal-lints")]
@@ -148,8 +154,12 @@
 #[cfg(feature = "internal-lints")]
 pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
 #[cfg(feature = "internal-lints")]
+pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
+#[cfg(feature = "internal-lints")]
 pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
 #[cfg(feature = "internal-lints")]
+pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
+#[cfg(feature = "internal-lints")]
 pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 #[cfg(feature = "internal-lints")]
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
index 7cb7d0a..a482017 100644
--- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
@@ -19,18 +19,18 @@
     loop {
         let predicates = tcx.predicates_of(current);
         for (predicate, _) in predicates.predicates {
-            match predicate.skip_binders() {
-                ty::PredicateAtom::RegionOutlives(_)
-                | ty::PredicateAtom::TypeOutlives(_)
-                | ty::PredicateAtom::WellFormed(_)
-                | ty::PredicateAtom::Projection(_)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..)
-                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
-                ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
-                ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
-                ty::PredicateAtom::Trait(pred, _) => {
+            match predicate.kind().skip_binder() {
+                ty::PredicateKind::RegionOutlives(_)
+                | ty::PredicateKind::TypeOutlives(_)
+                | ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::Projection(_)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+                ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
+                ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
+                ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
+                ty::PredicateKind::Trait(pred, _) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/sym.rs b/src/tools/clippy/clippy_lints/src/utils/sym_helper.rs
similarity index 68%
rename from src/tools/clippy/clippy_lints/src/utils/sym.rs
rename to src/tools/clippy/clippy_lints/src/utils/sym_helper.rs
index 273288c..f47dc80 100644
--- a/src/tools/clippy/clippy_lints/src/utils/sym.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/sym_helper.rs
@@ -1,4 +1,5 @@
 #[macro_export]
+/// Convenience wrapper around rustc's `Symbol::intern`
 macro_rules! sym {
     ($tt:tt) => {
         rustc_span::symbol::Symbol::intern(stringify!($tt))
diff --git a/src/tools/clippy/clippy_lints/src/utils/visitors.rs b/src/tools/clippy/clippy_lints/src/utils/visitors.rs
index b769a18..ebf69df 100644
--- a/src/tools/clippy/clippy_lints/src/utils/visitors.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/visitors.rs
@@ -107,7 +107,7 @@
                         if let Some(el) = else_opt {
                             self.visit_expr(el);
                         }
-                    }
+                    },
                     hir::ExprKind::Match(cond, arms, _) => {
                         self.inside_stmt(true).visit_expr(cond);
                         for arm in arms {
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
new file mode 100644
index 0000000..e632a7e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -0,0 +1,187 @@
+use crate::utils::{is_type_diagnostic_item, match_def_path, paths, snippet, span_lint_and_sugg};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{symbol::sym, Span, Symbol};
+use std::convert::TryInto;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `push` immediately after creating a new `Vec`.
+    ///
+    /// **Why is this bad?** The `vec![]` macro is both more performant and easier to read than
+    /// multiple `push` calls.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let mut v = Vec::new();
+    /// v.push(0);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let v = vec![0];
+    /// ```
+    pub VEC_INIT_THEN_PUSH,
+    perf,
+    "`push` immediately after `Vec` creation"
+}
+
+impl_lint_pass!(VecInitThenPush => [VEC_INIT_THEN_PUSH]);
+
+#[derive(Default)]
+pub struct VecInitThenPush {
+    searcher: Option<VecPushSearcher>,
+}
+
+#[derive(Clone, Copy)]
+enum VecInitKind {
+    New,
+    WithCapacity(u64),
+}
+struct VecPushSearcher {
+    init: VecInitKind,
+    name: Symbol,
+    lhs_is_local: bool,
+    lhs_span: Span,
+    err_span: Span,
+    found: u64,
+}
+impl VecPushSearcher {
+    fn display_err(&self, cx: &LateContext<'_>) {
+        match self.init {
+            _ if self.found == 0 => return,
+            VecInitKind::WithCapacity(x) if x > self.found => return,
+            _ => (),
+        };
+
+        let mut s = if self.lhs_is_local {
+            String::from("let ")
+        } else {
+            String::new()
+        };
+        s.push_str(&snippet(cx, self.lhs_span, ".."));
+        s.push_str(" = vec![..];");
+
+        span_lint_and_sugg(
+            cx,
+            VEC_INIT_THEN_PUSH,
+            self.err_span,
+            "calls to `push` immediately after creation",
+            "consider using the `vec![]` macro",
+            s,
+            Applicability::HasPlaceholders,
+        );
+    }
+}
+
+impl LateLintPass<'_> for VecInitThenPush {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+        self.searcher = None;
+        if_chain! {
+            if !in_external_macro(cx.sess(), local.span);
+            if let Some(init) = local.init;
+            if let PatKind::Binding(BindingAnnotation::Mutable, _, ident, None) = local.pat.kind;
+            if let Some(init_kind) = get_vec_init_kind(cx, init);
+            then {
+                self.searcher = Some(VecPushSearcher {
+                        init: init_kind,
+                        name: ident.name,
+                        lhs_is_local: true,
+                        lhs_span: local.ty.map_or(local.pat.span, |t| local.pat.span.to(t.span)),
+                        err_span: local.span,
+                        found: 0,
+                    });
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if self.searcher.is_none() {
+            if_chain! {
+                if !in_external_macro(cx.sess(), expr.span);
+                if let ExprKind::Assign(left, right, _) = expr.kind;
+                if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind;
+                if let Some(name) = path.segments.get(0);
+                if let Some(init_kind) = get_vec_init_kind(cx, right);
+                then {
+                    self.searcher = Some(VecPushSearcher {
+                        init: init_kind,
+                        name: name.ident.name,
+                        lhs_is_local: false,
+                        lhs_span: left.span,
+                        err_span: expr.span,
+                        found: 0,
+                    });
+                }
+            }
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let Some(searcher) = self.searcher.take() {
+            if_chain! {
+                if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind;
+                if let ExprKind::MethodCall(path, _, [self_arg, _], _) = expr.kind;
+                if path.ident.name.as_str() == "push";
+                if let ExprKind::Path(QPath::Resolved(_, self_path)) = self_arg.kind;
+                if let [self_name] = self_path.segments;
+                if self_name.ident.name == searcher.name;
+                then {
+                    self.searcher = Some(VecPushSearcher {
+                        found: searcher.found + 1,
+                        err_span: searcher.err_span.to(stmt.span),
+                        .. searcher
+                    });
+                } else {
+                    searcher.display_err(cx);
+                }
+            }
+        }
+    }
+
+    fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
+        if let Some(searcher) = self.searcher.take() {
+            searcher.display_err(cx);
+        }
+    }
+}
+
+fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
+    if let ExprKind::Call(func, args) = expr.kind {
+        match func.kind {
+            ExprKind::Path(QPath::TypeRelative(ty, name))
+                if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type) =>
+            {
+                if name.ident.name == sym::new {
+                    return Some(VecInitKind::New);
+                } else if name.ident.name.as_str() == "with_capacity" {
+                    return args.get(0).and_then(|arg| {
+                        if_chain! {
+                            if let ExprKind::Lit(lit) = &arg.kind;
+                            if let LitKind::Int(num, _) = lit.node;
+                            then {
+                                Some(VecInitKind::WithCapacity(num.try_into().ok()?))
+                            } else {
+                                None
+                            }
+                        }
+                    });
+                }
+            }
+            ExprKind::Path(QPath::Resolved(_, path))
+                if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
+                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type) =>
+            {
+                return Some(VecInitKind::New);
+            }
+            _ => (),
+        }
+    }
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 5683a71..10005a7 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -7,7 +7,8 @@
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::BytePos;
+use rustc_span::symbol::kw;
+use rustc_span::{sym, BytePos};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `use Enum::*`.
@@ -198,12 +199,12 @@
 // Allow "...prelude::..::*" imports.
 // Many crates have a prelude, and it is imported as a glob by design.
 fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
-    segments.iter().any(|ps| ps.ident.as_str() == "prelude")
+    segments.iter().any(|ps| ps.ident.name == sym::prelude)
 }
 
 // Allow "super::*" imports in tests.
 fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
-    segments.len() == 1 && segments[0].ident.as_str() == "super"
+    segments.len() == 1 && segments[0].ident.name == kw::Super
 }
 
 fn is_test_module_or_function(item: &Item<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 337f7a2..af324f8 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -10,7 +10,8 @@
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_parse::parser;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, BytePos, Span, Symbol};
+use rustc_span::symbol::kw;
+use rustc_span::{sym, BytePos, Span};
 
 declare_clippy_lint! {
     /// **What it does:** This lint warns when you use `println!("")` to
@@ -301,7 +302,7 @@
             }
         } else if mac.path == sym!(writeln) {
             if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
-                if fmt_str.symbol == Symbol::intern("") {
+                if fmt_str.symbol == kw::Empty {
                     let mut applicability = Applicability::MachineApplicable;
                     // FIXME: remove this `#[allow(...)]` once the issue #5822 gets fixed
                     #[allow(clippy::option_if_let_else)]
@@ -484,7 +485,7 @@
 
     fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
         if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
-            if fmt_str.symbol == Symbol::intern("") {
+            if fmt_str.symbol == kw::Empty {
                 let name = mac.path.segments[0].ident.name;
                 span_lint_and_sugg(
                     cx,
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 60dfdb7..1a7a30c 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -147,10 +147,14 @@
 
 Manually testing against an example file can be useful if you have added some
 `println!`s and the test suite output becomes unreadable. To try Clippy with
-your local modifications, run `env CLIPPY_TESTS=true cargo run --bin
-clippy-driver -- -L ./target/debug input.rs` from the working copy root.
+your local modifications, run
 
-With tests in place, let's have a look at implementing our lint now.
+```
+env __CLIPPY_INTERNAL_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs
+```
+
+from the working copy root. With tests in place, let's have a look at
+implementing our lint now.
 
 ## Lint declaration
 
diff --git a/src/tools/clippy/doc/roadmap-2021.md b/src/tools/clippy/doc/roadmap-2021.md
new file mode 100644
index 0000000..fe8b080
--- /dev/null
+++ b/src/tools/clippy/doc/roadmap-2021.md
@@ -0,0 +1,235 @@
+# Roadmap 2021
+
+# Summary
+
+This Roadmap lays out the plans for Clippy in 2021:
+
+- Improving usability and reliability
+- Improving experience of contributors and maintainers
+- Develop and specify processes
+
+Members of the Clippy team will be assigned tasks from one or more of these
+topics. The team member is then responsible to complete the assigned tasks. This
+can either be done by implementing them or by providing mentorship to interested
+contributors.
+
+# Motivation
+
+With the ongoing growth of the Rust language and with that of the whole
+ecosystem, also Clippy gets more and more users and contributors. This is good
+for the project, but also brings challenges along. Some of these challenges are:
+
+- More issues about reliability or usability are popping up
+- Traffic is hard to handle for a small team
+- Bigger projects don't get completed due to the lack of processes and/or time
+  of the team members
+
+Additionally, according to the [Rust Roadmap 2021], clear processes should be
+defined by every team and unified across teams. This Roadmap is the first step
+towards this.
+
+[Rust Roadmap 2021]: https://github.com/rust-lang/rfcs/pull/3037
+
+# Explanation
+
+This section will explain the things that should be done in 2021. It is
+important to note, that this document focuses on the "What?", not the "How?".
+The later will be addressed in follow-up tracking issue, with an assigned team
+member.
+
+The following is split up in two major sections. The first section covers the
+user facing plans, the second section the internal plans.
+
+## User Facing
+
+Clippy should be as pleasant to use and configure as possible. This section
+covers plans that should be implemented to improve the situation of Clippy in
+this regard.
+
+### Usability
+
+In the following, plans to improve the usability are covered.
+
+#### No Output After `cargo check`
+
+Currently when `cargo clippy` is run after `cargo check`, it does not produce
+any output. This is especially problematic since `rust-analyzer` is on the rise
+and it uses `cargo check` for checking code. A fix is already implemented, but
+it still has to be pushed over the finish line. This also includes the
+stabilization of the `cargo clippy --fix` command or the support of multi-span
+suggestions in `rustfix`.
+
+- [#4612](https://github.com/rust-lang/rust-clippy/issues/4612)
+
+#### `lints.toml` Configuration
+
+This is something that comes up every now and then: a reusable configuration
+file, where lint levels can be defined. Discussions about this often lead to
+nothing specific or to "we need an RFC for this". And this is exactly what needs
+to be done. Get together with the cargo team and write an RFC and implement such
+a configuration file somehow and somewhere.
+
+- [#3164](https://github.com/rust-lang/rust-clippy/issues/3164)
+- [cargo#5034](https://github.com/rust-lang/cargo/issues/5034)
+- [IRLO](https://internals.rust-lang.org/t/proposal-cargo-lint-configuration/9135/8)
+
+#### Lint Groups
+
+There are more and more issues about managing lints in Clippy popping up. Lints
+are hard to implement with a guarantee of no/few false positives (FPs). One way
+to address this might be to introduce more lint groups to give users the ability
+to better manage lints, or improve the process of classifying lints, so that
+disabling lints due to FPs becomes rare. It is important to note, that Clippy
+lints are less conservative than `rustc` lints, which won't change in the
+future.
+
+- [#5537](https://github.com/rust-lang/rust-clippy/issues/5537)
+- [#6366](https://github.com/rust-lang/rust-clippy/issues/6366)
+
+### Reliability
+
+In the following, plans to improve the reliability are covered.
+
+#### False Positive Rate
+
+In the worst case, new lints are only available in nightly for 2 weeks, before
+hitting beta and ultimately stable. This and the fact that fewer people use
+nightly Rust nowadays makes it more probable that a lint with many FPs hits
+stable. This leads to annoyed users, that will disable these new lints in the
+best case and to more annoyed users, that will stop using Clippy in the worst.
+A process should be developed and implemented to prevent this from happening.
+
+- [#6429](https://github.com/rust-lang/rust-clippy/issues/6429)
+
+## Internal
+
+(The end of) 2020 has shown, that Clippy has to think about the available
+resources, especially regarding management and maintenance of the project. This
+section address issues affecting team members and contributors.
+
+### Management
+
+In 2020 Clippy achieved over 1000 open issues with regularly between 25-35 open
+PRs. This is simultaneously a win and a loss. More issues and PRs means more
+people are interested in Clippy and in contributing to it. On the other hand, it
+means for team members more work and for contributors longer wait times for
+reviews. The following will describe plans how to improve the situation for both
+team members and contributors.
+
+#### Clear Expectations for Team Members
+
+According to the [Rust Roadmap 2021], a document specifying what it means to be
+a member of the team should be produced. This should not put more pressure on
+the team members, but rather help them and interested folks to know what the
+expectations are. With this it should also be easier to recruit new team members
+and may encourage people to get in touch, if they're interested to join.
+
+#### Scaling up the Team
+
+More people means less work for each individual. Together with the document
+about expectations for team members, a document defining the process of how to
+join the team should be produced. This can also increase the stability of the
+team, in case of current members dropping out (temporarily). There can also be
+different roles in the team, like people triaging vs. people reviewing.
+
+#### Regular Meetings
+
+Other teams have regular meetings. Clippy is big enough that it might be worth
+to also do them. Especially if more people join the team, this can be important
+for sync-ups. Besides the asynchronous communication, that works well for
+working on separate lints, a meeting adds a synchronous alternative at a known
+time. This is especially helpful if there are bigger things that need to be
+discussed (like the projects in this roadmap). For starters bi-weekly meetings
+before Rust syncs might make sense.
+
+#### Triaging
+
+To get a handle on the influx of open issues, a process for triaging issues and
+PRs should be developed. Officially, Clippy follows the Rust triage process, but
+currently no one enforces it. This can be improved by sharing triage teams
+across projects or by implementing dashboards / tools which simplify triaging.
+
+### Development
+
+Improving the developer and contributor experience is something the Clippy team
+works on regularly. Though, some things might need special attention and
+planing. These topics are listed in the following.
+
+#### Process for New and Existing Lints
+
+As already mentioned above, classifying new lints gets quite hard, because the
+probability of a buggy lint getting into stable is quite high. A process should
+be implemented on how to classify lints. In addition, a test system should be
+developed to find out which lints are currently problematic in real world code
+to fix or disable them.
+
+- [#6429 (comment)](https://github.com/rust-lang/rust-clippy/issues/6429#issuecomment-741056379)
+- [#6429 (comment)](https://github.com/rust-lang/rust-clippy/issues/6429#issuecomment-741153345)
+
+#### Processes
+
+Related to the point before, a process for suggesting and discussing major
+changes should be implemented. It's also not clearly defined when a lint should
+be enabled or disabled by default. This can also be improved by the test system
+mentioned above.
+
+#### Dev-Tools
+
+There's already `cargo dev` which makes Clippy development easier and more
+pleasant. This can still be expanded, so that it covers more areas of the
+development process.
+
+- [#5394](https://github.com/rust-lang/rust-clippy/issues/5394)
+
+#### Contributor Guide
+
+Similar to a Clippy Book, which describes how to use Clippy, a book about how to
+contribute to Clippy might be helpful for new and existing contributors. There's
+already the `doc` directory in the Clippy repo, this can be turned into a
+`mdbook`.
+
+#### `rustc` integration
+
+Recently Clippy was integrated with `git subtree` into the `rust-lang/rust`
+repository. This made syncing between the two repositories easier. A
+`#[non_exhaustive]` list of things that still can be improved is:
+
+1. Use the same `rustfmt` version and configuration as `rustc`.
+2. Make `cargo dev` work in the Rust repo, just as it works in the Clippy repo.
+   E.g. `cargo dev bless` or `cargo dev update_lints`. And even add more things
+   to it that might be useful for the Rust repo, e.g. `cargo dev deprecate`.
+3. Easier sync process. The `subtree` situation is not ideal.
+
+## Prioritization
+
+The most pressing issues for users of Clippy are of course the user facing
+issues. So there should be a priority on those issues, but without losing track
+of the internal issues listed in this document.
+
+Getting the FP rate of warn/deny-by-default lints under control should have the
+highest priority. Other user facing issues should also get a high priority, but
+shouldn't be in the way of addressing internal issues.
+
+To better manage the upcoming projects, the basic internal processes, like
+meetings, tracking issues and documentation, should be established as soon as
+possible. They might even be necessary to properly manage the projects,
+regarding the user facing issues.
+
+# Prior Art
+
+## Rust Roadmap
+
+Rust's roadmap process was established by [RFC 1728] in 2016. Since then every
+year a roadmap was published, that defined the bigger plans for the coming
+years. This years roadmap can be found [here][Rust Roadmap 2021].
+
+[RFC 1728]: https://rust-lang.github.io/rfcs/1728-north-star.html
+
+# Drawbacks
+
+## Big Roadmap
+
+This roadmap is pretty big and not all items listed in this document might be
+addressed during 2021. Because this is the first roadmap for Clippy, having open
+tasks at the end of 2021 is fine, but they should be revisited in the 2022
+roadmap.
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index c579bee..7293507 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-01-02"
+channel = "nightly-2021-01-15"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index e490ee5..f5f6c09 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -298,7 +298,7 @@
         // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
         //    - IF `--no-deps` is not set (`!no_deps`) OR
         //    - IF `--no-deps` is set and Clippy is run on the specified primary package
-        let clippy_tests_set = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true");
+        let clippy_tests_set = env::var("__CLIPPY_INTERNAL_TESTS").map_or(false, |val| val == "true");
         let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some();
         let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index ec3af94..ea80033 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -254,7 +254,7 @@
 
 fn prepare_env() {
     set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
-    set_var("CLIPPY_TESTS", "true");
+    set_var("__CLIPPY_INTERNAL_TESTS", "true");
     //set_var("RUST_BACKTRACE", "0");
 }
 
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
index c6b84d2..9ab845a 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
@@ -14,13 +14,16 @@
 
 fn main() {
     // Direct use of Symbol::intern
-    let _ = rustc_span::symbol::sym::f32;
+    let _ = rustc_span::sym::f32;
 
     // Using a sym macro
-    let _ = rustc_span::symbol::sym::f32;
+    let _ = rustc_span::sym::f32;
 
     // Correct suggestion when symbol isn't stringified constant name
-    let _ = rustc_span::symbol::sym::proc_dash_macro;
+    let _ = rustc_span::sym::proc_dash_macro;
+
+    // interning a keyword
+    let _ = rustc_span::symbol::kw::SelfLower;
 
     // Interning a symbol that is not defined
     let _ = Symbol::intern("xyz123");
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
index 9ec82d4..a58e182 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
@@ -22,6 +22,9 @@
     // Correct suggestion when symbol isn't stringified constant name
     let _ = Symbol::intern("proc-macro");
 
+    // interning a keyword
+    let _ = Symbol::intern("self");
+
     // Interning a symbol that is not defined
     let _ = Symbol::intern("xyz123");
     let _ = sym!(xyz123);
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
index 74b906c..50c1c26 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
@@ -2,7 +2,7 @@
   --> $DIR/interning_defined_symbol.rs:17:13
    |
 LL |     let _ = Symbol::intern("f32");
-   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32`
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32`
    |
 note: the lint level is defined here
   --> $DIR/interning_defined_symbol.rs:2:9
@@ -15,13 +15,19 @@
   --> $DIR/interning_defined_symbol.rs:20:13
    |
 LL |     let _ = sym!(f32);
-   |             ^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32`
+   |             ^^^^^^^^^ help: try: `rustc_span::sym::f32`
 
 error: interning a defined symbol
   --> $DIR/interning_defined_symbol.rs:23:13
    |
 LL |     let _ = Symbol::intern("proc-macro");
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::proc_dash_macro`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro`
 
-error: aborting due to 3 previous errors
+error: interning a defined symbol
+  --> $DIR/interning_defined_symbol.rs:26:13
+   |
+LL |     let _ = Symbol::intern("self");
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::kw::SelfLower`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
new file mode 100644
index 0000000..2ec0efe
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+#![feature(rustc_private)]
+#![deny(clippy::internal)]
+#![allow(clippy::unnecessary_operation, unused_must_use)]
+
+extern crate rustc_span;
+
+use rustc_span::symbol::{Ident, Symbol};
+
+fn main() {
+    Symbol::intern("foo") == rustc_span::sym::clippy;
+    Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower;
+    Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper;
+    Ident::invalid().name == rustc_span::sym::clippy;
+    rustc_span::sym::clippy == Ident::invalid().name;
+}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
new file mode 100644
index 0000000..87e1b3a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+#![feature(rustc_private)]
+#![deny(clippy::internal)]
+#![allow(clippy::unnecessary_operation, unused_must_use)]
+
+extern crate rustc_span;
+
+use rustc_span::symbol::{Ident, Symbol};
+
+fn main() {
+    Symbol::intern("foo").as_str() == "clippy";
+    Symbol::intern("foo").to_string() == "self";
+    Symbol::intern("foo").to_ident_string() != "Self";
+    &*Ident::invalid().as_str() == "clippy";
+    "clippy" == Ident::invalid().to_string();
+}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
new file mode 100644
index 0000000..b1284b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
@@ -0,0 +1,39 @@
+error: unnecessary `Symbol` to string conversion
+  --> $DIR/unnecessary_symbol_str.rs:11:5
+   |
+LL |     Symbol::intern("foo").as_str() == "clippy";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy`
+   |
+note: the lint level is defined here
+  --> $DIR/unnecessary_symbol_str.rs:3:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]`
+
+error: unnecessary `Symbol` to string conversion
+  --> $DIR/unnecessary_symbol_str.rs:12:5
+   |
+LL |     Symbol::intern("foo").to_string() == "self";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower`
+
+error: unnecessary `Symbol` to string conversion
+  --> $DIR/unnecessary_symbol_str.rs:13:5
+   |
+LL |     Symbol::intern("foo").to_ident_string() != "Self";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper`
+
+error: unnecessary `Symbol` to string conversion
+  --> $DIR/unnecessary_symbol_str.rs:14:5
+   |
+LL |     &*Ident::invalid().as_str() == "clippy";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::invalid().name == rustc_span::sym::clippy`
+
+error: unnecessary `Symbol` to string conversion
+  --> $DIR/unnecessary_symbol_str.rs:15:5
+   |
+LL |     "clippy" == Ident::invalid().to_string();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::invalid().name`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 1832482..d6ecd85 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -94,3 +94,19 @@
         }
     };
 }
+
+#[macro_export]
+macro_rules! field_reassign_with_default {
+    () => {
+        #[derive(Default)]
+        struct A {
+            pub i: i32,
+            pub j: i64,
+        }
+        fn lint() {
+            let mut a: A = Default::default();
+            a.i = 42;
+            a;
+        }
+    };
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index 7c4e4a1..2489168 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -4,6 +4,7 @@
 #![crate_type = "proc-macro"]
 #![feature(repr128, proc_macro_quote)]
 #![allow(incomplete_features)]
+#![allow(clippy::field_reassign_with_default)]
 #![allow(clippy::eq_op)]
 
 extern crate proc_macro;
@@ -23,3 +24,20 @@
     };
     output
 }
+
+#[proc_macro_derive(FieldReassignWithDefault)]
+pub fn derive_foo(_input: TokenStream) -> TokenStream {
+    quote! {
+        #[derive(Default)]
+        struct A {
+            pub i: i32,
+            pub j: i64,
+        }
+        #[automatically_derived]
+        fn lint() {
+            let mut a: A = Default::default();
+            a.i = 42;
+            a;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_alignment.rs b/src/tools/clippy/tests/ui/cast_alignment.rs
index 4c08935..d011e84 100644
--- a/src/tools/clippy/tests/ui/cast_alignment.rs
+++ b/src/tools/clippy/tests/ui/cast_alignment.rs
@@ -12,6 +12,10 @@
     (&1u8 as *const u8) as *const u16;
     (&mut 1u8 as *mut u8) as *mut u16;
 
+    // cast to more-strictly-aligned type, but with the `pointer::cast` function.
+    (&1u8 as *const u8).cast::<u16>();
+    (&mut 1u8 as *mut u8).cast::<u16>();
+
     /* These should be ok */
 
     // not a pointer type
diff --git a/src/tools/clippy/tests/ui/cast_alignment.stderr b/src/tools/clippy/tests/ui/cast_alignment.stderr
index 79219f8..7998b78 100644
--- a/src/tools/clippy/tests/ui/cast_alignment.stderr
+++ b/src/tools/clippy/tests/ui/cast_alignment.stderr
@@ -12,5 +12,17 @@
 LL |     (&mut 1u8 as *mut u8) as *mut u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
+  --> $DIR/cast_alignment.rs:16:5
+   |
+LL |     (&1u8 as *const u8).cast::<u16>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
+  --> $DIR/cast_alignment.rs:17:5
+   |
+LL |     (&mut 1u8 as *mut u8).cast::<u16>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
index 1f0ca10..d924625 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed
@@ -5,7 +5,8 @@
     clippy::redundant_clone,
     clippy::deref_addrof,
     clippy::no_effect,
-    clippy::unnecessary_operation
+    clippy::unnecessary_operation,
+    clippy::vec_init_then_push
 )]
 
 use std::cell::RefCell;
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
index ca39a65..97f4946 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy.rs
@@ -5,7 +5,8 @@
     clippy::redundant_clone,
     clippy::deref_addrof,
     clippy::no_effect,
-    clippy::unnecessary_operation
+    clippy::unnecessary_operation,
+    clippy::vec_init_then_push
 )]
 
 use std::cell::RefCell;
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index 14a7008..7a70688 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -1,5 +1,5 @@
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:22:5
+  --> $DIR/clone_on_copy.rs:23:5
    |
 LL |     42.clone();
    |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
@@ -7,25 +7,25 @@
    = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:26:5
+  --> $DIR/clone_on_copy.rs:27:5
    |
 LL |     (&42).clone();
    |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:29:5
+  --> $DIR/clone_on_copy.rs:30:5
    |
 LL |     rc.borrow().clone();
    |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
 
 error: using `clone` on type `char` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:35:14
+  --> $DIR/clone_on_copy.rs:36:14
    |
 LL |     is_ascii('z'.clone());
    |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:39:14
+  --> $DIR/clone_on_copy.rs:40:14
    |
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
index ce2a1c2..fa4bc30 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
@@ -3,6 +3,8 @@
 
 #[rustfmt::skip]
 #[warn(clippy::collapsible_if)]
+#[warn(clippy::collapsible_else_if)]
+
 fn main() {
     let x = "hello";
     let y = "world";
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs
index 99c40b8..bf6c1d1 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs
@@ -3,6 +3,8 @@
 
 #[rustfmt::skip]
 #[warn(clippy::collapsible_if)]
+#[warn(clippy::collapsible_else_if)]
+
 fn main() {
     let x = "hello";
     let y = "world";
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr
index 3d1c458..ee3e11a 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr
@@ -1,5 +1,5 @@
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:12:12
+  --> $DIR/collapsible_else_if.rs:14:12
    |
 LL |       } else {
    |  ____________^
@@ -9,7 +9,7 @@
 LL | |     }
    | |_____^
    |
-   = note: `-D clippy::collapsible-if` implied by `-D warnings`
+   = note: `-D clippy::collapsible-else-if` implied by `-D warnings`
 help: collapse nested if block
    |
 LL |     } else if y == "world" {
@@ -18,7 +18,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:20:12
+  --> $DIR/collapsible_else_if.rs:22:12
    |
 LL |       } else {
    |  ____________^
@@ -36,7 +36,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:28:12
+  --> $DIR/collapsible_else_if.rs:30:12
    |
 LL |       } else {
    |  ____________^
@@ -59,7 +59,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:39:12
+  --> $DIR/collapsible_else_if.rs:41:12
    |
 LL |       } else {
    |  ____________^
@@ -82,7 +82,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:50:12
+  --> $DIR/collapsible_else_if.rs:52:12
    |
 LL |       } else {
    |  ____________^
@@ -105,7 +105,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:61:12
+  --> $DIR/collapsible_else_if.rs:63:12
    |
 LL |       } else {
    |  ____________^
@@ -128,7 +128,7 @@
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_else_if.rs:72:12
+  --> $DIR/collapsible_else_if.rs:74:12
    |
 LL |       } else {
    |  ____________^
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index e1ee8db..4a53802 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -9,5 +9,6 @@
 #[warn(clippy::drop_bounds)]
 #[warn(clippy::temporary_cstring_as_ptr)]
 #[warn(clippy::panic_params)]
+#[warn(clippy::unknown_clippy_lints)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index edbb891..3429317 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -66,11 +66,17 @@
 LL | #[warn(clippy::panic_params)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
+error: lint `clippy::unknown_clippy_lints` has been removed: `this lint has been integrated into the `unknown_lints` rustc lint`
+  --> $DIR/deprecated.rs:12:8
+   |
+LL | #[warn(clippy::unknown_clippy_lints)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::unstable_as_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_enum.rs b/src/tools/clippy/tests/ui/empty_enum.rs
index 12428f2..a2e5c13 100644
--- a/src/tools/clippy/tests/ui/empty_enum.rs
+++ b/src/tools/clippy/tests/ui/empty_enum.rs
@@ -1,6 +1,7 @@
 #![allow(dead_code)]
 #![warn(clippy::empty_enum)]
-
+// Enable never type to test empty enum lint
+#![feature(never_type)]
 enum Empty {}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum.stderr b/src/tools/clippy/tests/ui/empty_enum.stderr
index 466dfbe..7125e5f 100644
--- a/src/tools/clippy/tests/ui/empty_enum.stderr
+++ b/src/tools/clippy/tests/ui/empty_enum.stderr
@@ -1,5 +1,5 @@
 error: enum with no variants
-  --> $DIR/empty_enum.rs:4:1
+  --> $DIR/empty_enum.rs:5:1
    |
 LL | enum Empty {}
    | ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs b/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs
new file mode 100644
index 0000000..3866773
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs
@@ -0,0 +1,7 @@
+#![allow(dead_code)]
+#![warn(clippy::empty_enum)]
+
+// `never_type` is not enabled; this test has no stderr file
+enum Empty {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/escape_analysis.rs
index 0700448..d26f48f 100644
--- a/src/tools/clippy/tests/ui/escape_analysis.rs
+++ b/src/tools/clippy/tests/ui/escape_analysis.rs
@@ -182,3 +182,23 @@
 
 #[rustfmt::skip] // Forces rustfmt to not add ABI
 pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
+
+// Issue #4804 - default implementation in trait
+mod issue4804 {
+    trait DefaultTraitImplTest {
+        // don't warn on `self`
+        fn default_impl(self: Box<Self>) -> u32 {
+            5
+        }
+
+        // warn on `x: Box<u32>`
+        fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
+            4
+        }
+    }
+
+    trait WarnTrait {
+        // warn on `x: Box<u32>`
+        fn foo(x: Box<u32>) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/escape_analysis.stderr b/src/tools/clippy/tests/ui/escape_analysis.stderr
index c86a769..4a82b44 100644
--- a/src/tools/clippy/tests/ui/escape_analysis.stderr
+++ b/src/tools/clippy/tests/ui/escape_analysis.stderr
@@ -12,5 +12,17 @@
 LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
    |            ^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:195:44
+   |
+LL |         fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
+   |                                            ^
+
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:202:16
+   |
+LL |         fn foo(x: Box<u32>) {}
+   |                ^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
index 3e09210..9fc208f 100644
--- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
@@ -1,5 +1,18 @@
+// aux-build:proc_macro_derive.rs
+// aux-build:macro_rules.rs
+
 #![warn(clippy::field_reassign_with_default)]
 
+#[macro_use]
+extern crate proc_macro_derive;
+#[macro_use]
+extern crate macro_rules;
+
+// Don't lint on derives that derive `Default`
+// See https://github.com/rust-lang/rust-clippy/issues/6545
+#[derive(FieldReassignWithDefault)]
+struct DerivedStruct;
+
 #[derive(Default)]
 struct A {
     i: i32,
@@ -11,6 +24,11 @@
     j: i64,
 }
 
+#[derive(Default)]
+struct C {
+    i: Vec<i32>,
+    j: i64,
+}
 /// Implements .next() that returns a different number each time.
 struct SideEffect(i32);
 
@@ -111,6 +129,13 @@
     // don't lint - some private fields
     let mut x = m::F::default();
     x.a = 1;
+
+    // don't expand macros in the suggestion (#6522)
+    let mut a: C = C::default();
+    a.i = vec![1];
+
+    // Don't lint in external macros
+    field_reassign_with_default!();
 }
 
 mod m {
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
index 9a2bc77..2f0f28f 100644
--- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
@@ -1,75 +1,87 @@
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:30:5
+  --> $DIR/field_reassign_with_default.rs:48:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
    = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
-note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:29:5
+note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:47:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:70:5
+  --> $DIR/field_reassign_with_default.rs:88:5
    |
 LL |     a.j = 43;
    |     ^^^^^^^^^
    |
-note: consider initializing the variable with `A { j: 43, i: 42 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:69:5
+note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:87:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:75:5
+  --> $DIR/field_reassign_with_default.rs:93:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
-note: consider initializing the variable with `A { i: 42, j: 44 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:74:5
+note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:92:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:81:5
+  --> $DIR/field_reassign_with_default.rs:99:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
-note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:80:5
+note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:98:5
    |
 LL |     let mut a = A::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:91:5
+  --> $DIR/field_reassign_with_default.rs:109:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: consider initializing the variable with `A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:90:5
+note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:108:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:95:5
+  --> $DIR/field_reassign_with_default.rs:113:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: consider initializing the variable with `A { i: Default::default(), j: 45 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:94:5
+note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:112:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:135:5
+   |
+LL |     a.i = vec![1];
+   |     ^^^^^^^^^^^^^^
+   |
+note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:134:5
+   |
+LL |     let mut a: C = C::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index 18f56f8..b101d27 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -1,12 +1,8 @@
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
   --> $DIR/from_over_into.rs:6:1
    |
-LL | / impl Into<StringWrapper> for String {
-LL | |     fn into(self) -> StringWrapper {
-LL | |         StringWrapper(self)
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Into<StringWrapper> for String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::from-over-into` implied by `-D warnings`
    = help: consider to implement `From` instead
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index 8d54f75..e83ce47 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -1,6 +1,7 @@
 #![warn(clippy::if_same_then_else)]
 #![allow(
     clippy::blacklisted_name,
+    clippy::collapsible_else_if,
     clippy::collapsible_if,
     clippy::ifs_same_cond,
     clippy::needless_return,
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
index da2be6c..f98e30f 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
@@ -1,5 +1,5 @@
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:20:12
+  --> $DIR/if_same_then_else2.rs:21:12
    |
 LL |       } else {
    |  ____________^
@@ -13,7 +13,7 @@
    |
    = note: `-D clippy::if-same-then-else` implied by `-D warnings`
 note: same as this
-  --> $DIR/if_same_then_else2.rs:11:13
+  --> $DIR/if_same_then_else2.rs:12:13
    |
 LL |       if true {
    |  _____________^
@@ -26,7 +26,7 @@
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:34:12
+  --> $DIR/if_same_then_else2.rs:35:12
    |
 LL |       } else {
    |  ____________^
@@ -36,7 +36,7 @@
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:32:13
+  --> $DIR/if_same_then_else2.rs:33:13
    |
 LL |       if true {
    |  _____________^
@@ -45,7 +45,7 @@
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:41:12
+  --> $DIR/if_same_then_else2.rs:42:12
    |
 LL |       } else {
    |  ____________^
@@ -55,7 +55,7 @@
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:39:13
+  --> $DIR/if_same_then_else2.rs:40:13
    |
 LL |       if true {
    |  _____________^
@@ -64,7 +64,7 @@
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:91:12
+  --> $DIR/if_same_then_else2.rs:92:12
    |
 LL |       } else {
    |  ____________^
@@ -74,7 +74,7 @@
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:89:21
+  --> $DIR/if_same_then_else2.rs:90:21
    |
 LL |       let _ = if true {
    |  _____________________^
@@ -83,7 +83,7 @@
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:98:12
+  --> $DIR/if_same_then_else2.rs:99:12
    |
 LL |       } else {
    |  ____________^
@@ -93,7 +93,7 @@
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:96:13
+  --> $DIR/if_same_then_else2.rs:97:13
    |
 LL |       if true {
    |  _____________^
@@ -102,7 +102,7 @@
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:123:12
+  --> $DIR/if_same_then_else2.rs:124:12
    |
 LL |       } else {
    |  ____________^
@@ -112,7 +112,7 @@
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:120:20
+  --> $DIR/if_same_then_else2.rs:121:20
    |
 LL |       } else if true {
    |  ____________________^
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed
new file mode 100644
index 0000000..70218f3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed
@@ -0,0 +1,163 @@
+// run-rustfix
+
+#![warn(clippy::needless_question_mark)]
+#![allow(clippy::needless_return, clippy::unnecessary_unwrap, dead_code, unused_must_use)]
+#![feature(custom_inner_attributes)]
+
+struct TO {
+    magic: Option<usize>,
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn simple_option_bad1(to: TO) -> Option<usize> {
+    // return as a statement
+    return to.magic;
+}
+
+// formatting will add a semi-colon, which would make
+// this identical to the test case above
+#[rustfmt::skip]
+fn simple_option_bad2(to: TO) -> Option<usize> {
+    // return as an expression
+    return to.magic
+}
+
+fn simple_option_bad3(to: TO) -> Option<usize> {
+    // block value "return"
+    to.magic
+}
+
+fn simple_option_bad4(to: Option<TO>) -> Option<usize> {
+    // single line closure
+    to.and_then(|t| t.magic)
+}
+
+// formatting this will remove the block brackets, making
+// this test identical to the one above
+#[rustfmt::skip]
+fn simple_option_bad5(to: Option<TO>) -> Option<usize> {
+    // closure with body
+    to.and_then(|t| {
+        t.magic
+    })
+}
+
+fn simple_result_bad1(tr: TR) -> Result<usize, bool> {
+    return tr.magic;
+}
+
+// formatting will add a semi-colon, which would make
+// this identical to the test case above
+#[rustfmt::skip]
+fn simple_result_bad2(tr: TR) -> Result<usize, bool> {
+    return tr.magic
+}
+
+fn simple_result_bad3(tr: TR) -> Result<usize, bool> {
+    tr.magic
+}
+
+fn simple_result_bad4(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| t.magic)
+}
+
+// formatting this will remove the block brackets, making
+// this test identical to the one above
+#[rustfmt::skip]
+fn simple_result_bad5(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| {
+        t.magic
+    })
+}
+
+fn also_bad(tr: Result<TR, bool>) -> Result<usize, bool> {
+    if tr.is_ok() {
+        let t = tr.unwrap();
+        return t.magic;
+    }
+    Err(false)
+}
+
+fn false_positive_test<U, T>(x: Result<(), U>) -> Result<(), T>
+where
+    T: From<U>,
+{
+    Ok(x?)
+}
+
+fn main() {}
+
+mod question_mark_none {
+    #![clippy::msrv = "1.12.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        Some(to.magic?) // should not be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        Ok(to.magic?) // should not be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
+
+mod question_mark_result {
+    #![clippy::msrv = "1.21.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        Some(to.magic?) // should not be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        to.magic // should be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
+
+mod question_mark_both {
+    #![clippy::msrv = "1.22.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        to.magic // should be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        to.magic // should be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs
new file mode 100644
index 0000000..60ac2c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_question_mark.rs
@@ -0,0 +1,163 @@
+// run-rustfix
+
+#![warn(clippy::needless_question_mark)]
+#![allow(clippy::needless_return, clippy::unnecessary_unwrap, dead_code, unused_must_use)]
+#![feature(custom_inner_attributes)]
+
+struct TO {
+    magic: Option<usize>,
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn simple_option_bad1(to: TO) -> Option<usize> {
+    // return as a statement
+    return Some(to.magic?);
+}
+
+// formatting will add a semi-colon, which would make
+// this identical to the test case above
+#[rustfmt::skip]
+fn simple_option_bad2(to: TO) -> Option<usize> {
+    // return as an expression
+    return Some(to.magic?)
+}
+
+fn simple_option_bad3(to: TO) -> Option<usize> {
+    // block value "return"
+    Some(to.magic?)
+}
+
+fn simple_option_bad4(to: Option<TO>) -> Option<usize> {
+    // single line closure
+    to.and_then(|t| Some(t.magic?))
+}
+
+// formatting this will remove the block brackets, making
+// this test identical to the one above
+#[rustfmt::skip]
+fn simple_option_bad5(to: Option<TO>) -> Option<usize> {
+    // closure with body
+    to.and_then(|t| {
+        Some(t.magic?)
+    })
+}
+
+fn simple_result_bad1(tr: TR) -> Result<usize, bool> {
+    return Ok(tr.magic?);
+}
+
+// formatting will add a semi-colon, which would make
+// this identical to the test case above
+#[rustfmt::skip]
+fn simple_result_bad2(tr: TR) -> Result<usize, bool> {
+    return Ok(tr.magic?)
+}
+
+fn simple_result_bad3(tr: TR) -> Result<usize, bool> {
+    Ok(tr.magic?)
+}
+
+fn simple_result_bad4(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| Ok(t.magic?))
+}
+
+// formatting this will remove the block brackets, making
+// this test identical to the one above
+#[rustfmt::skip]
+fn simple_result_bad5(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| {
+        Ok(t.magic?)
+    })
+}
+
+fn also_bad(tr: Result<TR, bool>) -> Result<usize, bool> {
+    if tr.is_ok() {
+        let t = tr.unwrap();
+        return Ok(t.magic?);
+    }
+    Err(false)
+}
+
+fn false_positive_test<U, T>(x: Result<(), U>) -> Result<(), T>
+where
+    T: From<U>,
+{
+    Ok(x?)
+}
+
+fn main() {}
+
+mod question_mark_none {
+    #![clippy::msrv = "1.12.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        Some(to.magic?) // should not be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        Ok(to.magic?) // should not be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
+
+mod question_mark_result {
+    #![clippy::msrv = "1.21.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        Some(to.magic?) // should not be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        Ok(to.magic?) // should be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
+
+mod question_mark_both {
+    #![clippy::msrv = "1.22.0"]
+    fn needless_question_mark_option() -> Option<usize> {
+        struct TO {
+            magic: Option<usize>,
+        }
+        let to = TO { magic: None };
+        Some(to.magic?) // should be triggered
+    }
+
+    fn needless_question_mark_result() -> Result<usize, bool> {
+        struct TO {
+            magic: Result<usize, bool>,
+        }
+        let to = TO { magic: Ok(1_usize) };
+        Ok(to.magic?) // should be triggered
+    }
+
+    fn main() {
+        needless_question_mark_option();
+        needless_question_mark_result();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
new file mode 100644
index 0000000..b4eb218
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -0,0 +1,88 @@
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:17:12
+   |
+LL |     return Some(to.magic?);
+   |            ^^^^^^^^^^^^^^^ help: try: `to.magic`
+   |
+   = note: `-D clippy::needless-question-mark` implied by `-D warnings`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:25:12
+   |
+LL |     return Some(to.magic?)
+   |            ^^^^^^^^^^^^^^^ help: try: `to.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:30:5
+   |
+LL |     Some(to.magic?)
+   |     ^^^^^^^^^^^^^^^ help: try: `to.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:35:21
+   |
+LL |     to.and_then(|t| Some(t.magic?))
+   |                     ^^^^^^^^^^^^^^ help: try: `t.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:44:9
+   |
+LL |         Some(t.magic?)
+   |         ^^^^^^^^^^^^^^ help: try: `t.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:49:12
+   |
+LL |     return Ok(tr.magic?);
+   |            ^^^^^^^^^^^^^ help: try: `tr.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:56:12
+   |
+LL |     return Ok(tr.magic?)
+   |            ^^^^^^^^^^^^^ help: try: `tr.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:60:5
+   |
+LL |     Ok(tr.magic?)
+   |     ^^^^^^^^^^^^^ help: try: `tr.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:64:21
+   |
+LL |     tr.and_then(|t| Ok(t.magic?))
+   |                     ^^^^^^^^^^^^ help: try: `t.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:72:9
+   |
+LL |         Ok(t.magic?)
+   |         ^^^^^^^^^^^^ help: try: `t.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:79:16
+   |
+LL |         return Ok(t.magic?);
+   |                ^^^^^^^^^^^^ help: try: `t.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:132:9
+   |
+LL |         Ok(to.magic?) // should be triggered
+   |         ^^^^^^^^^^^^^ help: try: `to.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:148:9
+   |
+LL |         Some(to.magic?) // should be triggered
+   |         ^^^^^^^^^^^^^^^ help: try: `to.magic`
+
+error: Question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:156:9
+   |
+LL |         Ok(to.magic?) // should be triggered
+   |         ^^^^^^^^^^^^^ help: try: `to.magic`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index d849e09..86bfc5b 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -86,6 +86,21 @@
     }
 }
 
+macro_rules! needed_return {
+    ($e:expr) => {
+        if $e > 3 {
+            return;
+        }
+    };
+}
+
+fn test_return_in_macro() {
+    // This will return and the macro below won't be executed. Removing the `return` from the macro
+    // will change semantics.
+    needed_return!(10);
+    needed_return!(0);
+}
+
 fn main() {
     let _ = test_end_of_fn();
     let _ = test_no_semicolon();
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 29f2bd1..5106137 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -86,6 +86,21 @@
     }
 }
 
+macro_rules! needed_return {
+    ($e:expr) => {
+        if $e > 3 {
+            return;
+        }
+    };
+}
+
+fn test_return_in_macro() {
+    // This will return and the macro below won't be executed. Removing the `return` from the macro
+    // will change semantics.
+    needed_return!(10);
+    needed_return!(0);
+}
+
 fn main() {
     let _ = test_end_of_fn();
     let _ = test_no_semicolon();
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
new file mode 100644
index 0000000..8346a94
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -0,0 +1,50 @@
+// run-rustfix
+
+#![warn(clippy::ptr_as_ptr)]
+#![feature(custom_inner_attributes)]
+
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr.cast::<i32>();
+    let _ = mut_ptr.cast::<i32>();
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = (*ptr_ptr).cast::<i32>();
+    }
+
+    // Changes in mutability. Do not lint this.
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+
+    // `pointer::cast` cannot perform unsized coercions unlike `as`. Do not lint this.
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Ensure the lint doesn't produce unnecessary turbofish for inferred types.
+    let _: *const i32 = ptr.cast();
+    let _: *mut i32 = mut_ptr.cast();
+}
+
+fn _msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast` was stabilized in 1.38. Do not lint this
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+}
+
+fn _msrv_1_38() {
+    #![clippy::msrv = "1.38"]
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr.cast::<i32>();
+    let _ = mut_ptr.cast::<i32>();
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
new file mode 100644
index 0000000..b68d4bc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -0,0 +1,50 @@
+// run-rustfix
+
+#![warn(clippy::ptr_as_ptr)]
+#![feature(custom_inner_attributes)]
+
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = *ptr_ptr as *const i32;
+    }
+
+    // Changes in mutability. Do not lint this.
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+
+    // `pointer::cast` cannot perform unsized coercions unlike `as`. Do not lint this.
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Ensure the lint doesn't produce unnecessary turbofish for inferred types.
+    let _: *const i32 = ptr as *const _;
+    let _: *mut i32 = mut_ptr as _;
+}
+
+fn _msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast` was stabilized in 1.38. Do not lint this
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+}
+
+fn _msrv_1_38() {
+    #![clippy::msrv = "1.38"]
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+}
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
new file mode 100644
index 0000000..854906d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -0,0 +1,46 @@
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:10:13
+   |
+LL |     let _ = ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+   |
+   = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:11:13
+   |
+LL |     let _ = mut_ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:16:17
+   |
+LL |         let _ = *ptr_ptr as *const i32;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:29:25
+   |
+LL |     let _: *const i32 = ptr as *const _;
+   |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:30:23
+   |
+LL |     let _: *mut i32 = mut_ptr as _;
+   |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:48:13
+   |
+LL |     let _ = ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:49:13
+   |
+LL |     let _ = mut_ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index 652b611..5b96bb5 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -2,7 +2,7 @@
 // aux-build:macro_rules.rs
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
 
 #[macro_use]
 extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 6bd4796..f220d697 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -2,7 +2,7 @@
 // aux-build:macro_rules.rs
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
 
 #[macro_use]
 extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs
index 9ad16d3..b6a7bc5 100644
--- a/src/tools/clippy/tests/ui/unit_arg.rs
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -5,7 +5,8 @@
     unused_variables,
     clippy::unused_unit,
     clippy::unnecessary_wraps,
-    clippy::or_fun_call
+    clippy::or_fun_call,
+    clippy::needless_question_mark
 )]
 
 use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index c3a839a..094cff8 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:30:5
+  --> $DIR/unit_arg.rs:31:5
    |
 LL | /     foo({
 LL | |         1;
@@ -20,7 +20,7 @@
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:33:5
+  --> $DIR/unit_arg.rs:34:5
    |
 LL |     foo(foo(1));
    |     ^^^^^^^^^^^
@@ -32,7 +32,7 @@
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:34:5
+  --> $DIR/unit_arg.rs:35:5
    |
 LL | /     foo({
 LL | |         foo(1);
@@ -54,7 +54,7 @@
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:39:5
+  --> $DIR/unit_arg.rs:40:5
    |
 LL | /     b.bar({
 LL | |         1;
@@ -74,7 +74,7 @@
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:42:5
+  --> $DIR/unit_arg.rs:43:5
    |
 LL |     taking_multiple_units(foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:43:5
+  --> $DIR/unit_arg.rs:44:5
    |
 LL | /     taking_multiple_units(foo(0), {
 LL | |         foo(1);
@@ -110,7 +110,7 @@
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:47:5
+  --> $DIR/unit_arg.rs:48:5
    |
 LL | /     taking_multiple_units(
 LL | |         {
@@ -140,7 +140,7 @@
  ...
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:58:13
+  --> $DIR/unit_arg.rs:59:13
    |
 LL |     None.or(Some(foo(2)));
    |             ^^^^^^^^^^^^
@@ -154,7 +154,7 @@
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:61:5
+  --> $DIR/unit_arg.rs:62:5
    |
 LL |     foo(foo(()))
    |     ^^^^^^^^^^^^
@@ -166,7 +166,7 @@
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:94:5
+  --> $DIR/unit_arg.rs:95:5
    |
 LL |     Some(foo(1))
    |     ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
index 1b85904..94a667e 100644
--- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
@@ -1,52 +1,58 @@
-error: unknown clippy lint: clippy::if_not_els
+error: unknown lint: `clippy::All`
+  --> $DIR/unknown_clippy_lints.rs:5:10
+   |
+LL | #![allow(clippy::All)]
+   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
+   |
+   = note: `-D unknown-lints` implied by `-D warnings`
+
+error: unknown lint: `clippy::CMP_NAN`
+  --> $DIR/unknown_clippy_lints.rs:6:9
+   |
+LL | #![warn(clippy::CMP_NAN)]
+   |         ^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_nan`
+
+error: unknown lint: `clippy::if_not_els`
   --> $DIR/unknown_clippy_lints.rs:9:8
    |
 LL | #[warn(clippy::if_not_els)]
    |        ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else`
-   |
-   = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings`
 
-error: unknown clippy lint: clippy::UNNecsaRy_cAst
+error: unknown lint: `clippy::UNNecsaRy_cAst`
   --> $DIR/unknown_clippy_lints.rs:10:8
    |
 LL | #[warn(clippy::UNNecsaRy_cAst)]
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unnecessary_cast`
 
-error: unknown clippy lint: clippy::useles_transute
+error: unknown lint: `clippy::useles_transute`
   --> $DIR/unknown_clippy_lints.rs:11:8
    |
 LL | #[warn(clippy::useles_transute)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::useless_transmute`
 
-error: unknown clippy lint: clippy::dead_cod
+error: unknown lint: `clippy::dead_cod`
   --> $DIR/unknown_clippy_lints.rs:13:8
    |
 LL | #[warn(clippy::dead_cod)]
    |        ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy`
 
-error: unknown clippy lint: clippy::unused_colle
+error: unknown lint: `clippy::unused_colle`
   --> $DIR/unknown_clippy_lints.rs:15:8
    |
 LL | #[warn(clippy::unused_colle)]
    |        ^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unused_self`
 
-error: unknown clippy lint: clippy::const_static_lifetim
+error: unknown lint: `clippy::const_static_lifetim`
   --> $DIR/unknown_clippy_lints.rs:17:8
    |
 LL | #[warn(clippy::const_static_lifetim)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes`
 
-error: unknown clippy lint: clippy::All
+error: unknown lint: `clippy::All`
   --> $DIR/unknown_clippy_lints.rs:5:10
    |
 LL | #![allow(clippy::All)]
-   |          ^^^^^^^^^^^ help: lowercase the lint name: `clippy::all`
+   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
 
-error: unknown clippy lint: clippy::CMP_NAN
-  --> $DIR/unknown_clippy_lints.rs:6:9
-   |
-LL | #![warn(clippy::CMP_NAN)]
-   |         ^^^^^^^^^^^^^^^ help: lowercase the lint name: `clippy::cmp_nan`
-
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.rs b/src/tools/clippy/tests/ui/vec_init_then_push.rs
new file mode 100644
index 0000000..642ce50
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_init_then_push.rs
@@ -0,0 +1,21 @@
+#![allow(unused_variables)]
+#![warn(clippy::vec_init_then_push)]
+
+fn main() {
+    let mut def_err: Vec<u32> = Default::default();
+    def_err.push(0);
+
+    let mut new_err = Vec::<u32>::new();
+    new_err.push(1);
+
+    let mut cap_err = Vec::with_capacity(2);
+    cap_err.push(0);
+    cap_err.push(1);
+    cap_err.push(2);
+
+    let mut cap_ok = Vec::with_capacity(10);
+    cap_ok.push(0);
+
+    new_err = Vec::new();
+    new_err.push(0);
+}
diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.stderr b/src/tools/clippy/tests/ui/vec_init_then_push.stderr
new file mode 100644
index 0000000..819ed47
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_init_then_push.stderr
@@ -0,0 +1,34 @@
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:5:5
+   |
+LL | /     let mut def_err: Vec<u32> = Default::default();
+LL | |     def_err.push(0);
+   | |____________________^ help: consider using the `vec![]` macro: `let mut def_err: Vec<u32> = vec![..];`
+   |
+   = note: `-D clippy::vec-init-then-push` implied by `-D warnings`
+
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:8:5
+   |
+LL | /     let mut new_err = Vec::<u32>::new();
+LL | |     new_err.push(1);
+   | |____________________^ help: consider using the `vec![]` macro: `let mut new_err = vec![..];`
+
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:11:5
+   |
+LL | /     let mut cap_err = Vec::with_capacity(2);
+LL | |     cap_err.push(0);
+LL | |     cap_err.push(1);
+LL | |     cap_err.push(2);
+   | |____________________^ help: consider using the `vec![]` macro: `let mut cap_err = vec![..];`
+
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:19:5
+   |
+LL | /     new_err = Vec::new();
+LL | |     new_err.push(0);
+   | |____________________^ help: consider using the `vec![]` macro: `new_err = vec![..];`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs
index 5282eba..6cfc0fc 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs
@@ -94,7 +94,8 @@
     trait T: Sized {
         fn as_i32(self) {}
         fn as_u32(&self) {}
-        fn into_i32(&self) {}
+        fn into_i32(self) {}
+        fn into_i32_ref(&self) {}
         fn into_u32(self) {}
         fn is_i32(self) {}
         fn is_u32(&self) {}
@@ -117,7 +118,32 @@
     trait U {
         fn as_i32(self);
         fn as_u32(&self);
-        fn into_i32(&self);
+        fn into_i32(self);
+        fn into_i32_ref(&self);
+        fn into_u32(self);
+        fn is_i32(self);
+        fn is_u32(&self);
+        fn to_i32(self);
+        fn to_u32(&self);
+        fn from_i32(self);
+        // check whether the lint can be allowed at the function level
+        #[allow(clippy::wrong_self_convention)]
+        fn from_cake(self);
+
+        // test for false positives
+        fn as_(self);
+        fn into_(&self);
+        fn is_(self);
+        fn to_(self);
+        fn from_(self);
+        fn to_mut(&mut self);
+    }
+
+    trait C: Copy {
+        fn as_i32(self);
+        fn as_u32(&self);
+        fn into_i32(self);
+        fn into_i32_ref(&self);
         fn into_u32(self);
         fn is_i32(self);
         fn is_u32(&self);
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
index 86467eb..32bd907 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -79,58 +79,70 @@
    |                   ^^^^
 
 error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:97:21
+  --> $DIR/wrong_self_convention.rs:98:25
    |
-LL |         fn into_i32(&self) {}
-   |                     ^^^^^
+LL |         fn into_i32_ref(&self) {}
+   |                         ^^^^^
 
 error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:99:19
+  --> $DIR/wrong_self_convention.rs:100:19
    |
 LL |         fn is_i32(self) {}
    |                   ^^^^
 
 error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:101:19
+  --> $DIR/wrong_self_convention.rs:102:19
    |
 LL |         fn to_i32(self) {}
    |                   ^^^^
 
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:103:21
+  --> $DIR/wrong_self_convention.rs:104:21
    |
 LL |         fn from_i32(self) {}
    |                     ^^^^
 
 error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:118:19
+  --> $DIR/wrong_self_convention.rs:119:19
    |
 LL |         fn as_i32(self);
    |                   ^^^^
 
 error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:120:21
+  --> $DIR/wrong_self_convention.rs:122:25
    |
-LL |         fn into_i32(&self);
-   |                     ^^^^^
+LL |         fn into_i32_ref(&self);
+   |                         ^^^^^
 
 error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:122:19
+  --> $DIR/wrong_self_convention.rs:124:19
    |
 LL |         fn is_i32(self);
    |                   ^^^^
 
 error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:124:19
+  --> $DIR/wrong_self_convention.rs:126:19
    |
 LL |         fn to_i32(self);
    |                   ^^^^
 
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:126:21
+  --> $DIR/wrong_self_convention.rs:128:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
 
-error: aborting due to 22 previous errors
+error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:146:25
+   |
+LL |         fn into_i32_ref(&self);
+   |                         ^^^^^
+
+error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:152:21
+   |
+LL |         fn from_i32(self);
+   |                     ^^^^
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index dcfe1bb..1ab3aea 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -37,16 +37,7 @@
     // in intra-doc links (primitive impls are weird)
     // https://github.com/rust-lang/rust/issues/62834 is necessary to be
     // able to link to slices
-    (
-        "std/io/struct.IoSlice.html",
-        &[
-            "#method.as_mut_ptr",
-            "#method.sort_by_key",
-            "#method.make_ascii_uppercase",
-            "#method.make_ascii_lowercase",
-            "#method.get_unchecked_mut",
-        ],
-    ),
+    ("std/io/struct.IoSlice.html", &["#method.as_mut_ptr", "#method.sort_by_key"]),
     // These try to link to std::collections, but are defined in alloc
     // https://github.com/rust-lang/rust/issues/74481
     ("std/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
index 4f9c794..216a643 160000
--- a/src/tools/rustfmt
+++ b/src/tools/rustfmt
@@ -1 +1 @@
-Subproject commit 4f9c794ce1e3c77698f522c3eb1ab935f23df303
+Subproject commit 216a64300563351cad20bb3847110c14561687e0
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 384a291..d3a4454 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -85,7 +85,11 @@
     assert!(!lib_features.is_empty());
 
     super::walk_many(
-        &[&src_path.join("test/ui"), &src_path.join("test/ui-fulldeps")],
+        &[
+            &src_path.join("test/ui"),
+            &src_path.join("test/ui-fulldeps"),
+            &src_path.join("test/rustdoc-ui"),
+        ],
         &mut |path| super::filter_dirs(path),
         &mut |entry, contents| {
             let file = entry.path();
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index bc5e43d..e687901 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,8 +7,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1500;
-const ISSUES_ENTRY_LIMIT: usize = 2830;
+const ROOT_ENTRY_LIMIT: usize = 1458;
+const ISSUES_ENTRY_LIMIT: usize = 2669;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
@@ -30,7 +30,7 @@
             };
 
             let count = std::fs::read_dir(dir_path).unwrap().count();
-            if count >= limit {
+            if count > limit {
                 tidy_error!(
                     bad,
                     "following path contains more than {} entries, \