Auto merge of #81090 - ssomers:btree_drainy_refactor_2, r=Mark-Simulacrum

BTreeMap: offer merge in variants with more clarity

r? `@Mark-Simulacrum`
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/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 106ffb2..2124f1e 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -87,7 +87,6 @@
                             }
                         });
                         error?;
-                        buf.shrink_to_fit();
                         Symbol::intern(&buf)
                     } else {
                         symbol
@@ -105,7 +104,6 @@
                     }
                 });
                 error?;
-                buf.shrink_to_fit();
                 LitKind::ByteStr(buf.into())
             }
             token::ByteStrRaw(_) => {
@@ -120,7 +118,6 @@
                         }
                     });
                     error?;
-                    buf.shrink_to_fit();
                     buf
                 } else {
                     symbol.to_string().into_bytes()
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_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_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/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/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 9d37150..a7b0ff4 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -43,10 +43,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 +57,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>;
 }
 
@@ -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..a5fb8a1 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
     }
 
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 4ebc1cd..9f97d5c 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)
                         ),
                     );
                 }
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/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/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index d1c07d1..88b2378 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;
                         }
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index e64955c..0732d25 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.
             }
         }
 
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_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_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..1be06a4 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 {
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..63f95a3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -716,7 +716,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..3eeb503 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);
 
@@ -1559,7 +1559,7 @@
                 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() {
@@ -1569,7 +1569,7 @@
                 self.emit_inference_failure_err(body_id, span, arg, 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;
@@ -1579,7 +1579,7 @@
                 assert!(a.is_ty_var() && b.is_ty_var());
                 self.emit_inference_failure_err(body_id, span, a.into(), 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;
@@ -1709,9 +1709,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..5a372c0 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))
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..af91514 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -478,8 +478,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..4434323 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -399,7 +399,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 };
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index d4631c4..be80b63 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -795,9 +795,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 +805,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..6edce62 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));
         }
     }
 
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 76051d9..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
 ///
@@ -630,10 +633,16 @@
         // and about 2 * (len1 + len2) comparisons in the worst case
         // while `extend` takes O(len2 * log(len1)) operations
         // and about 1 * len2 * log_2(len1) comparisons in the worst case,
-        // assuming len1 >= len2.
+        // assuming len1 >= len2. For larger heaps, the crossover point
+        // no longer follows this reasoning and was determined empirically.
         #[inline]
         fn better_to_rebuild(len1: usize, len2: usize) -> bool {
-            2 * (len1 + len2) < len2 * log2_fast(len1)
+            let tot_len = len1 + len2;
+            if tot_len <= 2048 {
+                2 * tot_len < len2 * log2_fast(len1)
+            } else {
+                2 * tot_len < len2 * 11
+            }
         }
 
         if better_to_rebuild(self.len(), other.len()) {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 944e0e6..5e63a30 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -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
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index f91db53..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 }
         }
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/search.rs b/library/alloc/src/collections/btree/search.rs
index ed7f95f..efe94ef 100644
--- a/library/alloc/src/collections/btree/search.rs
+++ b/library/alloc/src/collections/btree/search.rs
@@ -12,8 +12,7 @@
 
 /// 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.
+/// 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.
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/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/intrinsics.rs b/library/core/src/intrinsics.rs
index 0130586..fa5f0d5 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).
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/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..2809840 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -19,7 +19,7 @@
     builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS},
     Lint,
 };
-use rustc_span::hygiene::MacroKind;
+use rustc_span::hygiene::{MacroKind, SyntaxContext};
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
@@ -770,7 +770,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()
         })
     });
 
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/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/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/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/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/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/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/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 3edbe723..7607394 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,
 ]);
 
@@ -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/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/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/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 35b057d..aaa1756 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -500,6 +500,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`
@@ -541,7 +545,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,
@@ -1375,7 +1378,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),
@@ -1650,7 +1652,6 @@
         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_IF),
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 6e81027..f7231bb 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;
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..3b71f1b 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
@@ -115,13 +115,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<_>>();
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/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 3e39a47..4c707c4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -1470,7 +1470,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;
                     }
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/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/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/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/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, \